.. include:: /include/substitutions.txt .. include:: /include/external_links.txt .. include:: /include/custom_roles.txt .. _scope selectors and context: **************************** Scope, Selectors and Context **************************** Scope ***** *Scope* is the "characteristics of the caret's location in a text file". Syntax definitions make Sublime |nbsp| Text aware of the Scope for any given position in a file. They do so by generating *scope names* to provide metadata about language tokens. This metadata is updated on-the-fly every time the caret moves in any kind of document, but it is especially applicable in source code where the metadata reveals the nature of the area that the caret is currently sitting in (e.g. keyword, keyword category, string, variable, constant, number, symbol, comment, etc.). Each language token may have one or more :ref:`Scope Names ` associated with it. When multiple Scope names apply to a given caret location, their ordering is defined and important. The list of Scope names that apply to the current caret location is called the "current Scope". Example in a C Source Code file: .. code-block:: c /* Caret is in function name "some_func": * v */ void some_func(int * op) { int a = *op; int b = a + 2; } Resulting Scope (space-separated Scope Names):: "source.c meta.function.c entity.name.function.c" Example of current Scope for various caret positions of this string in a C file (you will need to scroll the below to the right to see the current Scope of each point): .. code-block:: c void some_func(int * op, char * name, bool aboolIsValue) { // | | | | || | | | | | | | | | | // | | | | || | | | | | | | | | +-- source.c meta.function.c meta.block.c punctuation.section.block.begin.c // | | | | || | | | | | | | | +---- source.c meta.function.parameters.c meta.group.c punctuation.section.group.end.c // | | | | || | | | | | | | +------------ source.c meta.function.parameters.c meta.group.c variable.parameter.c // | | | | || | | | | | | +-------------------- source.c meta.function.parameters.c meta.group.c storage.type.c // | | | | || | | | | | +----------------------- source.c meta.function.parameters.c meta.group.c punctuation.separator.c // | | | | || | | | | +-------------------------- source.c meta.function.parameters.c meta.group.c variable.parameter.c // | | | | || | | | +----------------------------- source.c meta.function.parameters.c meta.group.c keyword.operator.c // | | | | || | | +-------------------------------- source.c meta.function.parameters.c meta.group.c storage.type.c // | | | | || | +------------------------------------ source.c meta.function.parameters.c meta.group.c punctuation.separator.c // | | | | || +-------------------------------------- source.c meta.function.parameters.c meta.group.c variable.parameter.c // | | | | |+---------------------------------------- source.c meta.function.parameters.c meta.group.c keyword.operator.c // | | | | +----------------------------------------- source.c meta.function.parameters.c meta.group.c // | | | +------------------------------------------- source.c meta.function.parameters.c meta.group.c storage.type.c // | | +--------------------------------------------- source.c meta.function.parameters.c meta.group.c punctuation.section.group.begin.c // | +--------------------------------------------------- source.c meta.function.c entity.name.function.c // +-------------------------------------------------------- source.c storage.type.c An astute observer will note that the space between the ``int`` data type and the ``*`` in the formal parameter declaration still registers as ``source.c meta.function.parameters.c meta.group.c``---the current Scope still knows it's inside the parentheses in a set of function parameters. Current Scope is the basis for syntax highlighting in Sublime |nbsp| Text, among many other things. .. _scope name: Scope Name ********** A Scope Name is one of the space-separated elements of a scope. In the above C Scope example, each of these is a Scope Name: - source.c - meta.function.c - entity.name.function.c .. _selector: Selector ******** A Selector is a string that is evaluated against the current Scope, and triggers a ``True`` or ``False`` result based on that evaluation. Its use is to determine whether a particular 'thing' is applicable based on the nature of the current :term:`caret` location, i.e. its :term:`Scope`. If you're familiar with CSS, Sublime |nbsp| Text Selectors behave like selectors in a CSS file: they are a very efficient method of determining whether something "applies" or not. Selectors are used in a variety of subsystems in Sublime |nbsp| Text: - Key Bindings (tests whether a key mapping is applicable based on caret Scope) - Build System (tests whether a build system is applicable based on caret Scope) In Key Bindings, a Selector is an optional element of a Key Binding's :term:`Context` element. The Boolean results of evaluating all Selectors in a Context element are logically AND-ed to determine when that Key Binding can be applied to the current :term:`caret` location. See `Basic Match`_ for examples of Selectors. Basic Match *********** A Selector is compared to each `Scope Name`_ from first to last and if that Scope Name BEGINS WITH the Selector string and uses WHOLE WORDS, then it is a match (i.e. True result). When a Selector string has multiple space-separated :ref:`Scope Names ` in it, each must match one Scope Name, AND ALSO match in the same order the Scope Names appear in the Scope. Example Selectors that would match the above C++ example: - "source" - "entity.name" - "source entity" - "source entity.name" - "source entity.name.function" - "source entity.name.function.c++" - "source.c++ entity.name.function" Note that "entity source" *would not match* because it is out of sequence. Basic evaluation of a Selector goes like this: :TEST1: Do any of the current space-separated scope names START WITH the Selector and match a whole word? :TEST2: If so, do the remaining scope names (names appearing after the initial matching name) also appear in the Selector in the same order, and also use whole words? Constraint: the Selector must use whole words. This Python code matches the behavior of this test except it does not enforce whole names, whereas Sublime |nbsp| Text does: .. code-block:: python def _match_on_remaining_names(sel_names, scope_names): """ Does `sel_names` match `scope_names`? This means: - for each Selector Name in `sel_names`: - is it found at the beginning of one of the remaining Scope Names in `scope_names` in the same sequence? :param sel_names: List of remaining Selector Names :param scope_names: List of remaining Scope Names :return: Whether `sel_names` matches `scope_names` """ is_match = False first_sel_name = sel_names[0] for i, scope_name in enumerate(scope_names): if scope_name.startswith(first_sel_name): is_match = True break if is_match: # Are there any remaining Selector Names? if len(sel_names) > 1: # 'i' is index of Scope Name matched. # Are there any Scope Names after 'i'? if len(scope_names) > i + 1: # Attempt match with remaining Scope Names. remaining_sel_names = sel_names[1:] remaining_scope_names = scope_names[i + 1:] is_match = _match_on_remaining_names(remaining_sel_names, remaining_scope_names) else: # There are more Selector Names but no more Scope Names. # Not a match. is_match = False return is_match def _evaluate_selector_against_scope(selector, scope): """ Does `selector` match `scope`? This means: - for each Selector Name in `selector`: - is it found at the beginning of one of the Scope Names in `scope` in the same sequence? Return the result. :param selector: Selector string, e.g. "source entity.name: :param scope: Scope, e.g. "source.c++ meta.function.c++ meta.toc-list.full-identifier.c++ entity.name.function.c++" :return: Whether `selector` matches `scope` """ is_match = False sel_names = selector.split(' ') scope_names = scope.split(' ') if sel_names and scope_names: is_match = _match_on_remaining_names(sel_names, scope_names) return is_match def _match_test(selector, scope, should_match: bool): is_match = _evaluate_selector_against_scope(_selector, _scope) print(f'is_match = [{is_match}]', end='') if is_match == should_match: print(' OK') else: print(' Failed') print(f' Selector: [{selector}]') print(f' Scope : [{scope}]') # Test match. _selector = "source entity.name" _scope = "source.c++ meta.function.c++ meta.toc-list.full-identifier.c++ entity.name.function.c++" _match_test(_selector, _scope, True) # Test non-match (out of sequence). _selector = "source entity.name meta" _match_test(_selector, _scope, False) # Test match (in sequence). _selector = "source meta entity.name" _match_test(_selector, _scope, True) # Output: # is_match = [True] OK # is_match = [False] OK # is_match = [True] OK Logical Operators in Selectors ****************************** Precedence (Highest to Lowest): .. container:: tighter-table-4 +-------------+---------+ | Symbol | Meaning | +=============+=========+ | (...) | Grouping| +-------------+---------+ | \- | NOT | +-------------+---------+ | & | AND | +-------------+---------+ | \| | OR | +-------------+---------+ | \, | OR | +-------------+---------+ Operators with equivalent precedence are evaluated left to right. So the following two expressions are equivalent: .. code-block:: text a , b & -c | d , e (a , ((b & (- c)) | d)) , e Example: .. container:: tighter-table-4 +---------------------------+------------------------------+---------+ | Scope Name | Selector | Matches | +===========================+==============================+=========+ | source.php meta.block.php | source - (keyword | storage) | Yes | +---------------------------+------------------------------+---------+ | source.php meta.block.php | (source - source.php) | text | No | +---------------------------+------------------------------+---------+ Context ******* Context is an optional section of a Key Binding that contains 1 or more conditional expressions that determine if a Key Binding is appropriate to be used. When there is more than one such condition, ALL of them must return a ``True`` value when evaluated in order for the Key Binding to be used. Selectors can be used to provide one or more conditional expression for this purpose. API *** The following are Sublime |nbsp| Text API functions related to Scope, Selectors and Context. These are all methods of the ``View`` class. These must be used within a ``TextCommand``. .. code-block:: py def scope_name(self, pt: Point) -> str: """ :returns: The syntax scope name assigned to the character at the given point. """ def match_selector(self, pt: Point, selector: str) -> bool: """ :returns: Whether the provided scope selector matches the `Point`. """ def score_selector(self, pt: Point, selector: str) -> int: """ Equivalent to:: sublime.score_selector(view.scope_name(pt), selector) See `sublime.score_selector`. """ def find_by_selector(self, selector: str) -> list[Region]: """ Find all regions in the file matching the given selector. :returns: The list of matched regions. """ def extract_tokens_with_scopes(self, region: Region) -> list[tuple[Region, str]]: """ :param region: The region from which to extract tokens and scopes. :returns: A list of pairs containing the `Region` and the scope of each token. .. since: 3172 """ def extract_scope(self, pt: Point) -> Region: """ :returns: The extent of the syntax scope name assigned to the character at the given `Point`, narrower syntax scope names included. """ def expand_to_scope(self, pt: Point, selector: str) -> Optional[Region]: """ Expand by the provided scope selector from the `Point`. :param pt: The point from which to expand. :param selector: The scope selector to match. :returns: The matched `Region`, if any. .. since: 4130 """ def meta_info(self, key: str, pt: Point) -> Value: """ Look up the preference ``key`` for the scope at the provided `Point` from all matching ``.tmPreferences`` files. Examples of keys are ``TM_COMMENT_START`` and ``showInSymbolList``. """ def context_backtrace(self, pt: Point) -> list[ContextStackFrame]: """ Get a backtrace of `ContextStackFrame`\\ s at the provided `Point`. Note this function is particularly slow. .. since:: 4127 """ def style(self) -> dict[str, str]: """ See `style_for_scope`. :returns: The global style settings for the view. All colors are normalized to the six character hex form with a leading hash, e.g. ``#ff0000``. .. since:: 3150 """ def style_for_scope(self, scope: str) -> dict[str, Value]: """ Accepts a string scope name and returns a ``dict`` of style information including the keys: * ``"foreground": str`` * ``"selection_foreground": str`` (only if set) * ``"background": str`` (only if set) * ``"bold": bool`` * ``"italic": bool`` * .. since:: 4063 ``"glow": bool`` (only if set) * .. since:: 4075 ``"underline": bool`` (only if set) * .. since:: 4075 ``"stippled_underline": bool`` (only if set) * .. since:: 4075 ``"squiggly_underline": bool`` (only if set) * ``"source_line": str`` * ``"source_column": int`` * ``"source_file": int`` The foreground and background colors are normalized to the six character hex form with a leading hash, e.g. ``#ff0000``. """ The following are functions of the ``sublime`` module. (``sublime.func_name(...)``) .. code-block:: py def score_selector(scope_name: str, selector: str) -> int: """ Match the ``selector`` against the given ``scope_name``, returning a score for how well they match. A score of ``0`` means no match, above ``0`` means a match. Different selectors may be compared against the same scope: a higher score means the selector is a better match for the scope. """