diff --git a/.vscode/launch.json b/.vscode/launch.json index 18837656..02ecd063 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,12 +8,6 @@ "host": "${config:pygls.server.debugHost}", "port": "${config:pygls.server.debugPort}" }, - "pathMappings": [ - { - "localRoot": "${workspaceFolder}", - "remoteRoot": "." - } - ], "justMyCode": false }, { diff --git a/docs/assets/semantic-tokens-example.png b/docs/assets/semantic-tokens-example.png new file mode 100644 index 00000000..be9d3a36 Binary files /dev/null and b/docs/assets/semantic-tokens-example.png differ diff --git a/docs/generate_token_visualisation.py b/docs/generate_token_visualisation.py new file mode 100644 index 00000000..a11c245e --- /dev/null +++ b/docs/generate_token_visualisation.py @@ -0,0 +1,664 @@ +"""Script for generating the interactive semantic token display for the docs.""" + +from __future__ import annotations + +import argparse +import enum +import operator +import pathlib +import string +import textwrap +import typing +from dataclasses import dataclass, field +from functools import reduce + +if typing.TYPE_CHECKING: + from typing import List, Optional, Tuple, Type + + +class TokenModifier(enum.IntFlag): + """Represents a token modifier""" + + deprecated = enum.auto() + readonly = enum.auto() + defaultLibrary = enum.auto() + definition = enum.auto() + + +@dataclass +class Token: + line: int + offset: int + text: str + + tok_type: str + tok_modifiers: List[TokenModifier] = field(default_factory=list) + + @property + def tok_id(self): + return f"tok-{self.text}-{id(self)}" + + def __iter__(self): + return iter(self.text) + + def __len__(self): + return len(self.text) + + +POSITIONS_LAYOUT = string.Template( + """\ +
', + f"{indent(1)}{name}", + f"{indent(1)}=", + f"{indent(1)}", + f'{indent(2)}{current}', + f"{indent(2)}-", + f'{indent(2)}{previous}', + f"{indent(1)}", + f"{indent(1)}=", + f"{indent(1)}{current - previous}", + "
", + ] + + return "\n".join(lines) + + +def render_token_position_calcs_and_styles(tokens: list[Token]) -> Tuple[str, str]: + """Render the set of line and offset calculations.""" + calc_lines = [] + style_lines = [] + + prev_line = 1 + prev_offset = 0 + + for token in tokens: + tok_id = token.tok_id + + style_lines.extend( + [ + f'#tok-positions:has([data-tok="{tok_id}"]:hover) li[data-tok="{tok_id}"],', + f'#tok-positions:has([data-tok="{tok_id}"]:hover) td[data-tok="{tok_id}"] {{', + f"{indent(1)}border: solid 1px;", + f"{indent(1)}background: var(--tok-highlight-color);", + "}", + "", + f'#tok-positions:has([data-tok="{tok_id}"]:hover) td[data-line="{prev_line}"] {{', + f"{indent(1)}background: var(--tok-before-color);", + f"{indent(1)}color: white;", + "}", + "", + f'#tok-positions:has([data-tok="{tok_id}"]:hover) td[data-line="{prev_line + token.line}"] {{', + f"{indent(1)}background: var(--tok-after-color);", + f"{indent(1)}color: white;", + "}", + "", + f'#tok-positions:has([data-tok="{tok_id}"]:hover) p[data-tok="{tok_id}"] {{', + f"{indent(1)}display: grid;", + "}", + "", + ] + ) + + calc_lines.append( + render_position_calculation("Line", tok_id, prev_line, token.line) + ) + + if token.line > 0: + prev_line += token.line + prev_offset = 0 + + style_lines.extend( + [ + f'#tok-positions:has([data-tok="{tok_id}"]:hover) td[data-offset="{prev_offset}"] {{', + f"{indent(1)}background: var(--tok-before-color);", + f"{indent(1)}color: white;", + "}", + "", + f'#tok-positions:has([data-tok="{tok_id}"]:hover) td[data-offset="{prev_offset + token.offset}"] {{', + f"{indent(1)}background: var(--tok-after-color);", + f"{indent(1)}color: white;", + "}", + "", + ] + ) + + calc_lines.append( + render_position_calculation("Offset", tok_id, prev_offset, token.offset) + ) + prev_offset += token.offset + + return "\n".join(calc_lines), "\n".join(style_lines) + + +def render_token_modifier_calcs_and_styles( + tokens: list[Token], modifiers: Type[enum.IntFlag] +) -> Tuple[str, str]: + """Render the set of modifier calculations.""" + calc_lines = [] + style_lines = [] + mod_index = {mod.value: i for i, mod in enumerate(modifiers)} + + for token in tokens: + tok_id = token.tok_id + + style_lines.extend( + [ + f'#tok-modifiers:has([data-tok="{tok_id}"]:hover) li[data-tok="{tok_id}"] {{', + f"{indent(1)}border: solid 1px;", + f"{indent(1)}background: var(--tok-highlight-color);", + "}", + "", + ] + ) + + if len(token.tok_modifiers) > 0: + total = reduce(operator.or_, token.tok_modifiers) + sum_ = " + ".join(str(m.value) for m in token.tok_modifiers) + calc_lines.append(f'{total} = {sum_}
') + + style_lines.extend( + [ + f'#tok-modifiers:has([data-tok="{tok_id}"]:hover) #tok-modifier-calcs p[data-tok="{tok_id}"] {{', + f"{indent(1)}display: block;", + "}", + "", + ] + ) + + for modifier in token.tok_modifiers: + mod_id = mod_index[modifier.value] + style_lines.extend( + [ + f'#tok-modifiers:has([data-tok="{tok_id}"]:hover) li[data-mod="{mod_id}"],', + f'#tok-modifiers:has([data-tok="{tok_id}"]:hover) td[data-mod="{mod_id}"] {{', + f"{indent(1)}border: solid 1px;", + f"{indent(1)}background: var(--tok-highlight-color);", + "}", + "", + ] + ) + + return "\n".join(calc_lines), "\n".join(style_lines) + + +if __name__ == "__main__": + args = cli.parse_args() + + main(args.output) diff --git a/docs/source/examples/semantic-tokens.rst b/docs/source/examples/semantic-tokens.rst new file mode 100644 index 00000000..22d31dba --- /dev/null +++ b/docs/source/examples/semantic-tokens.rst @@ -0,0 +1,7 @@ +.. _example-semantic-tokens: + +Semantic Tokens +=============== + +.. example-server:: semantic_tokens.py + :start-at: import enum diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst index d421314a..e7ad2351 100644 --- a/docs/source/getting-started.rst +++ b/docs/source/getting-started.rst @@ -98,6 +98,13 @@ Each of the following example servers are focused on implementing a particular s :octicon:`pencil` + .. grid-item-card:: Semantic Tokens + :link: /examples/semantic-tokens + :link-type: doc + :text-align: center + + :octicon:`file-binary` + .. grid-item-card:: Symbols :link: /examples/symbols :link-type: doc diff --git a/docs/source/howto.rst b/docs/source/howto.rst index dd539571..b2fb5f43 100644 --- a/docs/source/howto.rst +++ b/docs/source/howto.rst @@ -5,5 +5,6 @@ How To Guides :maxdepth: 1 Handle Invalid DataIndex | +3 | +2 | +1 | +0 | +
2Index | +8 | +4 | +2 | +1 | +
8 = 8
+5 = 1 + 4
+2 = 2
++ | 0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 | +9 | +10 | +
1 | +c | ++ | = | ++ | s | +q | +r | +t | +( | ++ | + |
2 | ++ | + | a | +^ | +2 | ++ | + | ++ | b | +^ | +2 | +
3 | +) | ++ | + | + | + | + | + | + | + | + | + |
+ Line + = + + 1 + - + 1 + + = + 0 +
++ Offset + = + + 0 + - + 0 + + = + 0 +
++ Line + = + + 1 + - + 1 + + = + 0 +
++ Offset + = + + 2 + - + 0 + + = + 2 +
++ Line + = + + 1 + - + 1 + + = + 0 +
++ Offset + = + + 4 + - + 2 + + = + 2 +
++ Line + = + + 1 + - + 1 + + = + 0 +
++ Offset + = + + 8 + - + 4 + + = + 4 +
++ Line + = + + 2 + - + 1 + + = + 1 +
++ Offset + = + + 2 + - + 0 + + = + 2 +
++ Line + = + + 2 + - + 2 + + = + 0 +
++ Offset + = + + 3 + - + 2 + + = + 1 +
++ Line + = + + 2 + - + 2 + + = + 0 +
++ Offset + = + + 4 + - + 3 + + = + 1 +
++ Line + = + + 2 + - + 2 + + = + 0 +
++ Offset + = + + 6 + - + 4 + + = + 2 +
++ Line + = + + 2 + - + 2 + + = + 0 +
++ Offset + = + + 8 + - + 6 + + = + 2 +
++ Line + = + + 2 + - + 2 + + = + 0 +
++ Offset + = + + 9 + - + 8 + + = + 1 +
++ Line + = + + 2 + - + 2 + + = + 0 +
++ Offset + = + + 10 + - + 9 + + = + 1 +
++ Line + = + + 3 + - + 2 + + = + 1 +
++ Offset + = + + 0 + - + 0 + + = + 0 +
+