Description
A New LSP on the Horizon (WIP)
This is currently blocked until our efforts on the selector and value parsers is complete
A language service designed to run in both Monaco and VSCode, providing language capabilities for Stylable.
See capabilities description below.
Capability priorities and high level tasks
- publishDiagnostics - business logic implemented in
@stylable/core
- Stylable functionality already exists
- validate native css
- completion
- deps: improved parsing
- ...
- definition, implementation, references, typeDefinition, declaration
- deps: improved parsing,
- hover
- selectors
- deps: none
- specificity calculator
- dom structure snapper
- transformed value
- properties
- deps: aggregate CSS metadata
- description, top level syntax, link to MDN
- css custom property
- potential value
- type
- origin
- global
- value
- deps: improved parsing (value parser), aggregate CSS metadata
- info on part of value (syntax, link to MDN)
- native functions (syntax, link to MDN)
- CSS custom property / Stylable variables
- potential value
- type
- origin
- global
- mixin
- transformed snippet (with overrides)
- file paths / <url()>
- resolved absolute file paths
- server relative path can be tricky
- stylable directives
- aggregate information for all Stylable custom directives
- description
- syntax
- link to stylable.io
- aggregate information for all Stylable custom directives
- selectors
- semantic tokens
- deps: improved parsing (value parser)
- research CSS AST token type and modifier mapping
- formatting
- signatureHelp
- deps: improved parsing (value parser), context for location, JS mixin and formatter analysis
- documentColor, colorPresentation
- deps: improved parsing (value parser), context for location
- rename
- documentHighlight
- documentSymbol
- codeAction
- codeLens
- codeLens refresh
- selectionRange
- linkedEditingRange
- foldingRange
- documentLink
High level tasks
- improved parsing - custom parsers needed for . a lot of capabilities are used when the stylesheet input is broken, all behaviors must be safe and not hinder user experience
- selector parser
- implement + use
- value parser
- syntax parser
- properties and at-rules
- syntax definition list
- tooling (validation, classification, etc.)
- resilient input handling in edit mode
- selector parser
- context for location - resolve contextual information from location data
- smart completions - support a fuzzier approach and sort according to some logic
- Stylable version selection - let the user choose between the latest version of Stylable (included with the extension) or the version they're using in their project
- JS mixin and formatter analysis - determine argument typings for signature hinting
- symbol locator - given certain search criteria return a list of matching, available symbols
- aggregate CSS metadata
- dom elements information - might be good for generating native css dom lib: Native DOM Typings #1985
- inheritance, pseudo-elements, pseudo-classes
- description
- mdn link
- values - at-rules, properties, functions
- description
- mdn link
- dom elements information - might be good for generating native css dom lib: Native DOM Typings #1985
completion
Below is a mapping of all completions in which Stylable plays a part (not native CSS).
The mapping is broken down into AST parts (ish), at-rules
, rules
and declarations
.
For each completion, its location and completion type are detailed.
location - is a list of all allowed places for this completion to appear, each completion should not appear outside of its allowed locations
completion - two options, either a general description of things that need to be computed (like, available symbols) or a template string representing the completion format, with the cursor tab-jumping to the next "$" in a descending order ($0 is implicitly the end of the string unless explicitly defined otherwise)
do we suggest directives that are being deprecated? (e.g.
@namespace
)
at-rules
@st-import
- directive itself
- location: top-level
- completion:
@st-import $1 from "$2";
- [named...] inner parts - available symbols,
keyframes()
- location:
@st-import
inner directive - completion: available symbols |
keyframes($1)
- location:
keyframes(xxx)
inner parts - available keyframe symbols- location:
@st-import
named part - completion: keyframe symbols
- location:
from
- relevant path suggestions- location:
@st-import
directive - completion: path or package request
- location:
- directive itself
@st-namespace
(or@namespace
)- directive itself
- location: top-level, once per stylesheet
- completion:
@st-namespace "$1";
- directive itself
@st-global-custom-properties
- directive itself
- location: top-level
- completion:
@st-global-custom-properties --$1;
- suggested variables in scope
- location:
@st-global-custom-properties
directive - completion: known css variable names (not symbols, not imports!)
- location:
- directive itself
@keyframes
st-global(xxx)
- keyframe name wrapper- location:
@keyframes
definition - completion:
st-global($1)
- location:
@st-scope
- directive itself
- location: top-level
- completion:
@st-scope $2 {\n $1\n}
- scoping selector - selector used to scope inner scope content
- location:
@st-scope
directive - completion: selector
- location:
- directive itself
@st-custom-selector
(or `@custom-selector)- directive itself +
:--
- location: top-level
- completion:
@st-custom-selector :--$2 $1;
- selector value
- location:
@st-custom-selector
directive - completion: selector
- location:
- directive itself +
@property
st-global(--xxx)
- css var name wrapper- location: as part of a
@property
definition - completion:
st-global(--$1)
- location: as part of a
@media
(explore other nativeat-rules
)value(xxx)
- in the params- location: as part of a
@media
definition - completion:
value($1)
- location: as part of a
@st-vars
(does not exist yet)- directive itself
- location: top-level
- completion:
@st-vars $2 {\n $1\n}
- custom-type directives -
st-map
,st-array
and custom types (e.g.stBorder
when imported), including nesting- location: declaration values inside
@st-vars
- completion:
st-map($1)
|st-array($1)
|st-border($1)
- location: declaration values inside
- value suggestions in single var, and
st-map
/st-array
values- location: inside custom-values directives
- completion: any declaration value |
string
- directive itself
rules
:import
- directive itself
- location: top-level
- completion:
:import {\n $1\n}
- inner directive -
st-from
,st-default
,st-named
- location: inside
:import
directive - completion:
-st-from: "$1";
|-st-default: "$1";
|-st-named: "$1";
- location: inside
-st-named
inner parts - available named symbols,keyframes()
- location: inside
-st-named
directive - completion: available symbols from imported scope
- location: inside
-st-from
- relevant path suggestions- location: inside
-st-from
directive - completion: path or package request
- location: inside
- directive itself
:vars
- see
@st-vars
- completion:
:vars {\n $1\n}
- completion:
- see
- selectors
:st-global()
(or:global()
)- directive itself
- location: inside any selector
- completion:
:st-global($1)
- nested selector content
- location: inside
st-global()
- completion: selector
- location: inside
- directive itself
- classes -
.part
- location: inside any selector
- completion: class symbols in scope
- elements -
Comp
- location: inside any selector
- completion: element symbols in scope
- pseudo-classes
- boolean state -
:userSelected
- location: inside any selector, following a symbol that has an appropriate state defined
- completion: state symbols from the scope of the last selector subject
- state with param -
:userSelected(xxx)
- state name with parenthesis
- location: inside any selector, following a symbol that has an appropriate (enum) state defined
- completion: valid enum state values
value(xxx)
as param (considering deprecation)- location: inside a state with a param
- completion:
value($1)
- state name with parenthesis
- boolean state -
- pseudo-elements
::myPart
- according to selector context- location: inside any selector, following a symbol with an inner part defined
- completion: part symbols from the scope of the last selector subject
- custom-selector - available
:--xxx
parts- location: inside any selector, following a symbol with a custom selector defined
- completion: custom selector symbols in scope
.root
- inherently exists in every stylesheet (probably handled by.classes
completion)- location: inside any selector
- completion:
.root {$1}
declarations
- directives
-st-extends
- directive itself
- location: declaration inside the a simple rule, once per rule
- completion:
-st-extends: $1;
- value of a single class/element (multiple in the future)
- location: value of the
-st-extends
declaration - completion: classes or element symbols in scope
- location: value of the
- directive itself
-st-states
- directive itself
- location: declaration inside a class rule, once per rule
- completion:
-st-states: $1;
- state type -
myState(xxx)
- location: value of the
-st-states
declaration, inside a state definition with parenthesis - completion:
string
|number
|tag
|enum()
- location: value of the
- state param validators -
myState(string(minLength(5)))
string
- location: inside a state string type definition with parenthesis
- completion:
minLength
|maxLength
|contains
|regex
number
- location: inside a state number type definition with parenthesis
- completion:
min
|max
|multipleOf
- directive itself
-st-mixin
- directive itself
- location: declaration inside any rule, once per rule
- completion:
-st-mixin: $1;
- mixin name
- location: value of the
-st-mixin
declaration - completion: class or element symbols available in scope
- location: value of the
- CSS
- var override keys - suggesting vars used in mixin scope
- location: inside a CSS mixin with parenthesis, left side of the key/value
- completion: Stylable variable names used in the mixed in scope
- var override values - suggest values
- location: inside a CSS mixin with parenthesis, right side of the key/value
- completion: any declaration value |
string
- var override keys - suggesting vars used in mixin scope
- JS
value(xxx)
as nested arguments- see
value(xxx, yyy)
- see
- directive itself
-st-global
- directive itself
- location: declaration inside any rule
- completion:
-st-global: $1;
- value is a selector;
- location: declaration value of the
-st-global
directive - completion: selector
- location: declaration value of the
- directive itself
- values
value(xxx, yyy)
- directive itself
- location: any declaration value
- completion:
value($1)
- where
xxx
is the name of a Stylable variable in scope- location: first argument inside a
value()
directive in a declaration value - completion: Stylable variables available in scope
- location: first argument inside a
- where
yyy
is a list of comma-separated member accessors (keys) on the var based on its type (optional)- location: rest of arguments inside a
value()
directive of the appropriate type in a declaration value - completion: Stylable variable key names / indexes
- location: rest of arguments inside a
- directive itself
st-global(xxx)
(future)- keyframes
- location: wrapping keyframe name in
animation
oranimation-name
declaration values - completion:
st-global($1)
- location: wrapping keyframe name in
- CSS vars
- location: wrapping css variable usage (inside
var()
) - completion:
st-global($1)
- location: wrapping css variable usage (inside
- keyframes
- formatters
value(xxx)
as nested arguments- see
value(xxx, yyy)
- see
- directives
hover
- selectors
- including: states, pseudo-elements, custom-selectors, st-scope
- specificity?
value(xxx)
- resolved value
- any symbol (especially imported ones)
- type and origin
- path requests
- resolved path
- Stylable directives descriptions
- at-rules
@st-import
@st-namespace
@st-custom-global-properties
@st-scope
@st-custom-selector
@st-vars
- rules
:import
:global
- include in selectors?.root
- special case?
- declarations
-st-extends
-st-states
-st-mixin
-st-global
-st-from
-st-default
-st-named
- values
st-global()
value()
- seevalue(xxx)
above
- at-rules
signatureHelp
- Stylable directives
st-global()
- contextually aware (var/keyframe)value(x, y, z)
- according to var type- custom-value definition -
st-map
,st-array
and custom ones keyframes()
- in named import statements
- states with param - param type hinting
- formatter - argument hinting
- mixin - argument hinting
- CSS
- JS
Native CSS
- maintain all native input lists - elements, properties, keywords, etc.
- additive / conflicting APIs between native CSS and Stylable files - some APIs can be nicely composed (e.g. completions), but there's a big difference in how the LSP logic handles CSS vs Stylable, even for those APIs. If we decide to handle native CSS ourselves, we will need to map out all such differences
Infra / Host / Configuration
- browser compatible - needs to be able to run in Monaco
monaco vs. vscode
Some differences exists between the two LSP possible consumers, needs further research.
- completion cursor location - marking completion locations in monaco and vscode differ (using "$" in vscode, unknown in monaco)
- syntax highlighting - vscode uses textmate syntax, monaco uses monarch (
semantic tokens
may work for both cases, needs validating) - position vs. offset - vscode and monaco use different formats for indicating locations and ranges, need a set of utilities to easily traverse the two when needed
Testing
- e2e tests - using
vscode-test
to test general feature flows - unit/ix - for more granular feature testing, testing can take place on the "protocol" or directly on the APIs themselves
Research References
Metadata
Metadata
Assignees
Labels
Type
Projects
Status