Basically we distinguish two kinds of scopes.
- The
meta.
scopes are used to create logical units which provide semantical context for completions or plugins.
-
storage
, keyword
, variable
,punctuation
… scopes which primarily target syntax highlighting.
About snippet 1 (Python)
The whole import statement is scoped meta.statement.import.python
.
import package
from .foo import bar
from .foo import (bar as baz)
...
The second scope meta.import-list
is used to scope only (bar as baz)
.
Stacking meta scopes like that is one way to create multiple layers of logical units. This is useful especially if such scopes like meta.import-lists
are used in different contexts.
If only the import list is of interest a selector may look like meta.import-list
, which targets all those regions no matter whether they belong to meta.statement.import
or any other one.
If only certain regions are needed a selector can easily combine those by (meta.statement.import | meta.statement.whatever) & meta.import-list
.
An alternative was to put everything into one scope name, which would then look like meta.statement.import.import-list
. A real life example is meta.function-call.[identifier|arguments]
.
This solution makes general purpose selectors to match all import lists hard. You always need to address meta.statment.import.import-list, meta.statement.whatever.import-list, ...
Hence it should be used with care and only if the statements structure is very clear.
About snippet 2 (C++)
That’s an older versions of function calls. The meta.group
is a very general scope used to denote all kinds of parenthesed code sections. A selector targeting meta.function-call meta.group - meta.function-call meta.block
could be used to match function call arguments.
More recent syntaxes use meta.function-call.arguments
only or in conjunction with meta.group
.
This makes selectors a bit more straight forward: meta.function-call.arguments
is enough to target function call arguments, while meta.group
if present could be used for general purpose functions if someone wants to match all kinds of parenthesed sections no matter if they are function arguments, or expression groups.
The punctuation
is the highlighting part, which may be addressed by color schemes to give the parentheses their color. It is part of the scope naming guidelines that the related meta scope of a section should span the opening and closing punctuation. Hence those are stacked.
About snippet 3 Pthon lambda
Here two highlighting scopes storage.type
and keyword.declaration
are stacked because of some kind of backward compatibility considerations with older color schemes.
While the return value of a function in C/C++ like int
or char
may clearly be scoped storage.type
situation is more confuse in dynamically typed syntaxes like python, which just use general keywords like def
to denote function definitions. Those keywords were scoped storage.type.function
in the past.
Same applies to class
keyword. But … in a statement like class ClassName
, what is the type? Is it class
or ClassName
? We came up with class
to be a keyword.declaration
which declares a data type. Same applies to python functions/lambdas. Those keywords are more like declaration keywords than data types. Hence those were changed.
It turned out stacking those is not as backward compatible as desired. The internal ST4 beta comes with a core feature to maintain backward compatibility with older color schemes even if we remove the legacy storage.type
in such constructs. One thing still on the TODO.
Hope, that helps a bit.