diff --git a/src/TextMateSharp.Grammars.Tests/GrammarTests.cs b/src/TextMateSharp.Grammars.Tests/GrammarTests.cs index 1f56571..e414fc1 100644 --- a/src/TextMateSharp.Grammars.Tests/GrammarTests.cs +++ b/src/TextMateSharp.Grammars.Tests/GrammarTests.cs @@ -11,7 +11,7 @@ public void Get_Available_Languages_Should_Return_Content() { RegistryOptions options = new RegistryOptions(ThemeName.Light); - Assert.That(options.GetAvailableLanguages().Count, Is.EqualTo(61)); + Assert.That(options.GetAvailableLanguages().Count, Is.EqualTo(63)); } [Test] @@ -111,7 +111,10 @@ public void Assert_Every_Grammar_With_Language_Configuration_File_Has_Language_C { if (!string.IsNullOrEmpty(language.ConfigurationFile)) { - Assert.That(language.Configuration, Is.Not.Null); + if (language.Configuration == null) + { + Assert.Fail(string.Format("[{0} grammar]: Language configuration is null", language.Id)); + } } } catch (Exception ex) diff --git a/src/TextMateSharp.Grammars/GrammarNames.cs b/src/TextMateSharp.Grammars/GrammarNames.cs index 1657c7c..b6ba7db 100644 --- a/src/TextMateSharp.Grammars/GrammarNames.cs +++ b/src/TextMateSharp.Grammars/GrammarNames.cs @@ -49,6 +49,7 @@ internal class GrammarNames "SQL", "Swift", "TypescriptBasics", + "Typst", "VB", "XML", "YAML" diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/cgmanifest.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/cgmanifest.json new file mode 100644 index 0000000..3c89b56 --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/cgmanifest.json @@ -0,0 +1,17 @@ +{ + "registrations": [ + { + "component": { + "type": "git", + "git": { + "name": "Myriad-Dreamin/tinymist", + "repositoryUrl": "https://github.com/Myriad-Dreamin/tinymist", + "commitHash": "1f9a42c2e863f6b1fe8624da796e47adf44a9a83" + } + }, + "license": "Apache-2.0", + "version": "0.11.20" + } + ], + "version": 1 +} \ No newline at end of file diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/language-configuration.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/language-configuration.json new file mode 100644 index 0000000..6b7356b --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/language-configuration.json @@ -0,0 +1,72 @@ +{ + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["[", "]"], + ["{", "}"], + ["(", ")"] + ], + "autoClosingPairs": [ + { + "open": "[", + "close": "]" + }, + { + "open": "{", + "close": "}" + }, + { + "open": "(", + "close": ")" + }, + { + "open": "\"", + "close": "\"", + "notIn": ["string"] + }, + { + "open": "$", + "close": "$", + "notIn": ["string"] + }, + + ["“", "”"], + ["‘", "’"], + ["《", "》"], + ["〈", "〉"], + ["(", ")"], + ["『", "』"], + ["「", "」"], + ["【", "】"], + ["〖", "〗"], + ["〔", "〕"], + ["[", "]"], + ["{", "}"] + ], + "autoCloseBefore": ";:.,=}])>$ \n\t", + "surroundingPairs": [ + ["[", "]"], + ["{", "}"], + ["(", ")"], + ["\"", "\""], + ["*", "*"], + ["_", "_"], + ["`", "`"], + ["$", "$"], + + ["“", "”"], + ["‘", "’"], + ["《", "》"], + ["〈", "〉"], + ["(", ")"], + ["『", "』"], + ["「", "」"], + ["【", "】"], + ["〖", "〗"], + ["〔", "〕"], + ["[", "]"], + ["{", "}"] + ] +} diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/package.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/package.json new file mode 100644 index 0000000..59315a8 --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/package.json @@ -0,0 +1,1010 @@ +{ + "name": "tinymist", + "version": "0.11.20", + "description": "%description%", + "categories": [ + "Programming Languages", + "Formatters" + ], + "repository": { + "type": "git", + "url": "https://github.com/Myriad-Dreamin/tinymist" + }, + "displayName": "%displayName%", + "author": "Myriad-Dreamin", + "contributors": [ + "Myriad-Dreamin", + "Nathan Varner" + ], + "publisher": "myriad-dreamin", + "license": "Apache-2.0", + "engines": { + "vscode": "^1.82.0" + }, + "main": "./out/extension.js", + "icon": "./icons/ti-white.png", + "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "tinymist-activitybar", + "title": "Tinymist", + "icon": "./icons/ti.png" + } + ] + }, + "views": { + "tinymist-activitybar": [ + { + "id": "tinymist.side-symbol-view", + "type": "webview", + "name": "Symbol", + "when": "ext.tinymistActivated" + }, + { + "id": "tinymist.dev-kit", + "name": "DevKit View", + "when": "ext.tinymistActivated && ext.tinymistDevKit" + }, + { + "id": "tinymist.preview.content-preview", + "type": "webview", + "name": "Content", + "when": "ext.tinymistActivated" + }, + { + "id": "tinymist.label-view", + "name": "Label", + "when": "ext.tinymistActivated" + }, + { + "id": "tinymist.preview.outline", + "name": "Outline", + "when": "ext.tinymistActivated" + } + ] + }, + "taskDefinitions": [ + { + "type": "typst", + "required": [ + "command" + ], + "properties": { + "command": { + "type": "string", + "default": "export", + "description": "The command to run.", + "enum": [ + "export" + ], + "enumDescriptions": [ + "Export the document to specific format." + ] + }, + "export": { + "type": "object", + "description": "Arguments for `export` command.", + "properties": { + "format": { + "description": "The format(s) to export the document to. Defaults to `pdf`.", + "oneOf": [ + { + "type": "string", + "description": "The format to export the document to.", + "enum": [ + "pdf", + "png", + "svg", + "html", + "markdown", + "text", + "query", + "pdfpc" + ], + "enumDescriptions": [ + "PDF", + "PNG", + "SVG", + "HTML", + "Markdown", + "Plain Text", + "Query Result", + "Pdfpc (From Query)" + ], + "default": "pdf" + }, + { + "type": "array", + "description": "The formats to export the document to.", + "items": { + "type": "string", + "description": "The format to export the document to. Defaults to `pdf`.", + "enum": [ + "pdf", + "png", + "svg", + "html", + "markdown", + "text", + "query", + "pdfpc" + ], + "enumDescriptions": [ + "PDF", + "PNG", + "SVG", + "HTML", + "Markdown", + "Plain Text", + "Query Result", + "Pdfpc (From Query)" + ], + "default": "pdf" + } + } + ] + }, + "inputPath": { + "title": "Input path", + "description": "The path pattern to the entry file (main) for compilation, you can use `$focused`, `$root`, `$dir`, `$name` to do magic configuration, e.g. `$dir/$name` (default) and `$root/target/$dir/$name`. A special value `$focused` is used to point to the currently focused file in the editor.", + "type": "string", + "default": "$focused" + }, + "metadata": { + "type": "boolean", + "description": "Whether to generate metadata containing export arguments." + }, + "pdf.creationTimestamp": { + "type": [ + "string" + ], + "description": "The unix timestamp of the PDF creation. If not specified, the current time is used." + }, + "png.ppi": { + "type": "number", + "description": "The PPI (pixels per inch) to use for PNG export", + "default": 144 + }, + "fill": { + "type": "string", + "description": "The fill color. Affected formats: `png`", + "examples": [ + "white", + "#ffffff", + "#00000000" + ] + }, + "png.fill": { + "type": "string", + "description": "The fill color. Affected formats: `png`", + "examples": [ + "white", + "#ffffff", + "#00000000" + ], + "default": "white" + }, + "merged": { + "type": "boolean", + "description": "Merge the pages into a single image. Affected formats: `png`, `svg`" + }, + "svg.merged": { + "type": "boolean", + "description": "Merge the pages into a single SVG. Affected formats: `svg`" + }, + "png.merged": { + "type": "boolean", + "description": "Merge the pages into a single PNG. Affected formats: `png`" + }, + "merged.gap": { + "type": "string", + "description": "The gap between the pages when merging **with absolute typst unit**. Affected formats: `png`, `svg`", + "default": "0pt" + }, + "svg.merged.gap": { + "type": "string", + "description": "The gap between the pages when merging **with absolute typst unit**. Affected formats: `svg`", + "default": "0pt" + }, + "png.merged.gap": { + "type": "string", + "description": "The gap between the pages when merging **with absolute typst unit**. Affected formats: `png`", + "default": "0pt" + }, + "query.format": { + "type": "string", + "description": "The format of the query output. Defaults to `json`.", + "default": "json", + "enum": [ + "json", + "yaml", + "txt" + ], + "enumDescriptions": [ + "JSON", + "YAML", + "Plain Text if the result is a string, otherwise raises an error. You may specific the field to use for the query with `query.field` and assert that there is only one result with `query.one`." + ] + }, + "query.outputExtension": { + "type": "string", + "description": "The extension of the query output. Inferring from `query.format` if not specified." + }, + "query.strict": { + "type": "boolean", + "description": "Whether to strictly check the query format. Defaults to `true`." + }, + "query.pretty": { + "type": "boolean", + "description": "Whether to pretty print the query output. Defaults to `true`." + }, + "query.selector": { + "type": "string", + "description": "The selector to use for the query. Must specified if `format`." + }, + "query.field": { + "type": "string", + "description": "The field to use for the query." + }, + "query.one": { + "type": "boolean", + "description": "Whether to only return one result. Defaults to `false`." + } + } + } + } + } + ], + "configuration": { + "type": "object", + "title": "Tinymist Typst LSP", + "properties": { + "tinymist.outputPath": { + "title": "Output path", + "description": "The path pattern to store Typst artifacts, you can use `$root` or `$dir` or `$name` to do magic configuration, e.g. `$dir/$name` (default) and `$root/target/$dir/$name`.", + "type": "string", + "default": "" + }, + "tinymist.exportPdf": { + "title": "Export PDF", + "description": "The extension can export PDFs of your Typst files. This setting controls whether this feature is enabled and how often it runs.", + "type": "string", + "default": "never", + "enum": [ + "never", + "onSave", + "onType", + "onDocumentHasTitle" + ], + "enumDescriptions": [ + "Never export PDFs, you will manually run typst.", + "Export PDFs when you save a file.", + "Export PDFs as you type in a file.", + "Export PDFs when a document has a title (and save a file), which is useful to filter out template files." + ] + }, + "tinymist.rootPath": { + "title": "Root path", + "markdownDescription": "Configure the root for absolute paths in typst. Hint: you can set the rootPath to `-`, so that tinymist will always use parent directory of the file as the root path. Note: for neovim users, if it complains root not found, you must set `require(\"lspconfig\")[\"tinymist\"].setup { root_dir }` as well, see [tinymist#528](https://github.com/Myriad-Dreamin/tinymist/issues/528).", + "type": [ + "string", + "null" + ], + "default": null + }, + "tinymist.semanticTokens": { + "title": "Semantic tokens mode", + "description": "Enable or disable semantic tokens (LSP syntax highlighting)", + "type": "string", + "default": "enable", + "enum": [ + "enable", + "disable" + ], + "enumDescriptions": [ + "Use semantic tokens for syntax highlighting", + "Do not use semantic tokens for syntax highlighting" + ] + }, + "tinymist.onEnterEvent": { + "title": "Handling on enter events", + "description": "Enable or disable [experimental/onEnter](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter) (LSP onEnter feature) to allow automatic insertion of characters on enter, such as `///` for comments. Note: restarting the editor is required to change this setting.", + "type": "boolean", + "default": true + }, + "tinymist.systemFonts": { + "title": "Whether to load system fonts for Typst compiler", + "description": "A flag that determines whether to load system fonts for Typst compiler, which is useful for ensuring reproducible compilation. If set to null or not set, the extension will use the default behavior of the Typst compiler. Note: You need to restart LSP to change this options. ", + "type": "boolean", + "default": true + }, + "tinymist.fontPaths": { + "title": "Font paths for Typst compiler", + "description": "A list of file or directory path to fonts. Note: The configuration source in higher priority will **override** the configuration source in lower priority. The order of precedence is: Configuration `tinymist.fontPaths` > Configuration `tinymist.typstExtraArgs.fontPaths` > LSP's CLI Argument `--font-path` > The environment variable `TYPST_FONT_PATHS` (a path list separated by `;` (on Windows) or `:` (Otherwise)). Note: If the path to fonts is a relative path, it will be resolved based on the root directory. Note: In VSCode, you can use VSCode variables in the path, e.g. `${workspaceFolder}/fonts`.", + "type": [ + "array", + "null" + ], + "default": null + }, + "tinymist.compileStatus": { + "title": "Show/Report compilation status", + "description": "In VSCode, enable compile status meaning that the extension will show the compilation status in the status bar. Since Neovim and Helix don't have a such feature, it is disabled by default at the language server label.", + "type": "string", + "default": "enable", + "enum": [ + "enable", + "disable" + ] + }, + "tinymist.typstExtraArgs": { + "title": "Specifies the arguments for Typst as same as typst-cli", + "description": "You can pass any arguments as you like, and we will try to follow behaviors of the **same version** of typst-cli. Note: the arguments may be overridden by other settings. For example, `--font-path` will be overridden by `tinymist.fontPaths`.", + "type": "array", + "items": { + "type": "string", + "title": "arguments in order", + "description": "The arguments for Typst as same as typst-cli." + }, + "default": [] + }, + "tinymist.serverPath": { + "title": "Path to server executable", + "description": "The extension can use a local tinymist executable instead of the one bundled with the extension. This setting controls the path to the executable.", + "type": [ + "string", + "null" + ], + "default": null + }, + "tinymist.trace.server": { + "scope": "window", + "type": "string", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "Traces the communication between VS Code and the language server." + }, + "tinymist.formatterMode": { + "title": "Enable Experimental Formatter", + "description": "The extension can format Typst files using typstfmt or typstyle.", + "type": "string", + "default": "disable", + "enum": [ + "disable", + "typstyle", + "typstfmt" + ], + "enumDescriptions": [ + "Formatter is not activated.", + "Use typstyle formatter.", + "Use typstfmt formatter." + ] + }, + "tinymist.formatterPrintWidth": { + "title": "Set formatter's (unsigned) print width", + "description": "Set the print width for the formatter, which is a **soft limit** of characters per line. See [the definition of *Print Width*](https://prettier.io/docs/en/options.html#print-width). Note: this has lower priority than the formatter's specific configurations.", + "type": "number", + "default": 120 + }, + "tinymist.previewFeature": { + "title": "Enable preview features", + "description": "Enable or disable preview features of Typst. Note: restarting the editor is required to change this setting.", + "type": "string", + "default": "enable", + "enum": [ + "enable", + "disable" + ] + }, + "tinymist.preview.sysInputs": { + "type": "object", + "items": { + "type": "string" + }, + "default": {}, + "description": "key-value pairs visible through `sys.inputs`, corresponds to `--input` argument of typst cli", + "markdownDeprecationMessage": "The configuration item is ignored. Please see `tinymist.typstExtraArgs` for inputs." + }, + "tinymist.preview.systemFonts": { + "type": "boolean", + "default": true, + "description": "Whether to load system fonts. If disabled, only fonts in `typst-preview.fontPaths` is loaded", + "markdownDeprecationMessage": "The configuration item is ignored. Please use `tinymist.systemFonts` instead." + }, + "tinymist.preview.fontPaths": { + "type": "array", + "items": { + "type": "string", + "title": "Font path", + "description": "Absolute path to a directory or file containing font assets." + }, + "default": [], + "description": "List of *additional* paths to font assets used by typst-preview.", + "markdownDeprecationMessage": "The configuration item is ignored. Please use `tinymist.fontPaths` instead." + }, + "tinymist.preview.refresh": { + "title": "Refresh preview", + "description": "Refresh preview when the document is saved or when the document is changed", + "type": "string", + "enum": [ + "onSave", + "onType" + ], + "default": "onType", + "enumDescriptions": [ + "Refresh preview on save", + "Refresh preview on type" + ] + }, + "tinymist.preview.scrollSync": { + "description": "Configure scroll sync mode.", + "type": "string", + "enum": [ + "never", + "onSelectionChangeByMouse", + "onSelectionChange" + ], + "default": "onSelectionChangeByMouse", + "enumDescriptions": [ + "Disable automatic scroll sync", + "Scroll preview to current cursor position when selection changes by mouse", + "Scroll preview to current cursor position when selection changes by mouse or keyboard (any source)" + ] + }, + "tinymist.preview.partialRendering": { + "description": "Only render visible part of the document. This can improve performance but still being experimental.", + "type": "boolean", + "default": true + }, + "tinymist.preview.invertColors": { + "description": "Invert colors of the preview (useful for dark themes without cost). Please note you could see the origin colors when you hover elements in the preview. It is also possible to specify strategy to each element kind by an object map in JSON format.", + "anyOf": [ + { + "type": "string", + "description": "Specify a strategy for all elements in the preview.", + "enum": [ + "never", + "auto", + "always" + ], + "default": "never", + "enumDescriptions": [ + "Disable color inversion of the preview", + "Invert colors smartly by detecting dark/light themes in browser environment or by `typst query` your document", + "Always invert colors of the preview" + ] + }, + { + "type": "object", + "description": "Specify strategies for each element kind", + "default": {}, + "properties": { + "rest": { + "type": "string", + "enum": [ + "never", + "auto", + "always" + ], + "description": "Specify a strategy for rest elements in the preview", + "default": "never", + "enumDescriptions": [ + "Disable color inversion of the preview", + "Invert colors smartly by detecting dark/light themes in browser environment or by `typst query` your document", + "Always invert colors of the preview" + ] + }, + "image": { + "type": "string", + "enum": [ + "never", + "auto", + "always" + ], + "description": "Specify a strategy for images in the preview", + "default": "never", + "enumDescriptions": [ + "Disable color inversion of the preview", + "Invert colors smartly by detecting dark/light themes in browser environment or by `typst query` your document", + "Always invert colors of the preview" + ] + } + } + } + ] + }, + "tinymist.preview.cursorIndicator": { + "description": "(Experimental) Show typst cursor indicator in preview.", + "type": "boolean", + "default": false + }, + "tinymist.preview.pinPreviewFile": { + "description": "Declare current previewing file as entrypoint for typst-lsp or tinymist. This will make typst-lsp or tinymist to use this file as entrypoint instead of the file opened in vscode. This can improve diagnostics messages and auto completion but still being experimental.", + "type": "boolean", + "default": false, + "markdownDeprecationMessage": "This setting is deprecated and no longer needed. The extension will always pin the previewed file as the entrypoint for the language server." + } + } + }, + "configurationDefaults": { + "[typst]": { + "editor.wordWrap": "on", + "editor.semanticHighlighting.enabled": true, + "editor.tabSize": 2, + "editor.inlayHints.enabled": "off" + } + }, + "languages": [ + { + "id": "typst", + "configuration": "./language-configuration.json", + "extensions": [ + ".typ" + ], + "aliases": [ + "Typst", + "typst", + "typ" + ], + "icon": { + "light": "./icons/typst-small.png", + "dark": "./icons/typst-small.png" + } + }, + { + "id": "typst-code", + "configuration": "./language-configuration.json", + "extensions": [ + ".typc" + ], + "aliases": [ + "Typst (Code Mode)", + "typc" + ], + "icon": { + "light": "./icons/typst-small.png", + "dark": "./icons/typst-small.png" + } + }, + { + "id": "typst-markdown-injection" + } + ], + "grammars": [ + { + "language": "typst", + "scopeName": "source.typst", + "path": "./syntaxes/typst.tmLanguage.json", + "balancedBracketScopes": [ + "meta.expr", + "meta.brace", + "markup.math.typst" + ], + "unbalancedBracketScopes": [ + "markup.content.brace.typst", + "markup.raw.block.typst", + "markup.raw.inline.typst", + "string.other.label.typst", + "string.quoted.double.typst", + "constant.character.escape", + "comment.block.typst", + "comment.line.double-slash.typst" + ] + }, + { + "language": "typst-code", + "scopeName": "source.typst-code", + "path": "./syntaxes/typst-code.tmLanguage.json", + "balancedBracketScopes": [ + "meta.expr", + "meta.brace", + "markup.math.typst" + ], + "unbalancedBracketScopes": [ + "markup.content.brace.typst", + "markup.raw.block.typst", + "markup.raw.inline.typst", + "string.other.label.typst", + "string.quoted.double.typst", + "constant.character.escape", + "comment.block.typst", + "comment.line.double-slash.typst" + ] + }, + { + "language": "typst-markdown-injection", + "scopeName": "markdown.typst.codeblock", + "path": "./syntaxes/typst-markdown-injection.json", + "injectTo": [ + "text.html.markdown" + ], + "embeddedLanguages": { + "meta.embedded.block.typst": "typst", + "meta.embedded.block.typst-code": "typst-code" + } + } + ], + "semanticTokenTypes": [ + { + "id": "bool", + "description": "A boolean literal" + }, + { + "id": "punct", + "description": "Punctuation in code" + }, + { + "id": "escape", + "description": "Escape sequence" + }, + { + "id": "link", + "description": "Hyperlink" + }, + { + "id": "raw", + "description": "Raw text" + }, + { + "id": "label", + "description": "Label" + }, + { + "id": "ref", + "description": "Reference to a label" + }, + { + "id": "heading", + "description": "Heading" + }, + { + "id": "marker", + "description": "List, enum, or term list marker" + }, + { + "id": "term", + "description": "Term in a term list" + }, + { + "id": "delim", + "description": "Delimiter of a different type of markup" + }, + { + "id": "pol", + "description": "Interpolated variable" + }, + { + "id": "error", + "description": "Syntax error" + }, + { + "id": "text", + "description": "Text" + } + ], + "semanticTokenModifiers": [ + { + "id": "math", + "description": "Math mode markup" + }, + { + "id": "strong", + "description": "Strong (usually bolded) text" + }, + { + "id": "emph", + "description": "Emphasized (usually italicized) text" + } + ], + "semanticTokenScopes": [ + { + "language": "typst", + "scopes": { + "*.strong.emph": [ + "markup.bold.typst markup.italic.typst" + ], + "*.strong": [ + "markup.bold.typst" + ], + "*.emph": [ + "markup.italic.typst" + ], + "*.math": [ + "markup.math.typst" + ], + "bool": [ + "constant.language.boolean.typst" + ], + "punct": [ + "punctuation.typst", + "punctuation.definition.typst" + ], + "escape": [ + "constant.character.escape.typst", + "keyword.operator.typst", + "punctuation.definition.typst" + ], + "link": [ + "markup.underline.link.typst" + ], + "raw": [ + "markup.inline.raw.typst", + "markup.raw.inline.typst" + ], + "delim.math": [ + "punctuation.definition.math.typst", + "punctuation.definition.string.end.math.typst", + "string.quoted.other.typst" + ], + "operator.math": [ + "keyword.operator.math.typst" + ], + "heading": [ + "markup.heading.typst" + ], + "marker": [ + "markup.list.typst punctuation.definition.list.begin.typst", + "markup.list.typst", + "punctuation.definition.list.begin.typst" + ], + "term": [ + "markup.list.term.typst", + "markup.bold.term.typst" + ], + "label": [ + "string.other.link.title.typst", + "entity.name.label.typst", + "meta.link.inline.typst", + "markup.underline.link.typst" + ], + "ref": [ + "string.other.link.typst", + "markup.other.reference.typst", + "entity.name.label.typst", + "meta.link.inline.typst", + "markup.underline.link.typst" + ], + "pol": [ + "meta.interpolation.typst", + "variable.typst" + ], + "error": [ + "invalid.typst" + ] + } + } + ], + "commands": [ + { + "command": "tinymist.exportCurrentPdf", + "title": "Export the currently open file as PDF", + "category": "Typst" + }, + { + "command": "tinymist.pinMainToCurrent", + "title": "Pin the main file to the currently opened document", + "category": "Typst" + }, + { + "command": "tinymist.unpinMain", + "title": "Unpin the main file", + "category": "Typst" + }, + { + "command": "tinymist.showPdf", + "title": "Show exported PDF", + "category": "Typst", + "icon": "$(file-pdf)" + }, + { + "command": "tinymist.copyAnsiHighlight", + "title": "Copy as ANSI Code", + "category": "Typst" + }, + { + "command": "tinymist.showLog", + "title": "Tinymist: Show Log", + "description": "Show log of LSP Server", + "category": "Typst", + "icon": "$(list-flat)" + }, + { + "command": "tinymist.clearCache", + "title": "Clear all cached resources", + "category": "Typst" + }, + { + "command": "tinymist.initTemplate", + "title": "Initialize a new Typst project based on a template", + "category": "Typst" + }, + { + "command": "tinymist.initTemplateInPlace", + "title": "Insert the content of template entry in place", + "category": "Typst" + }, + { + "command": "tinymist.showTemplateGallery", + "title": "Show available Typst templates (gallery) for picking up a template to initialize", + "category": "Typst" + }, + { + "command": "tinymist.createLocalPackage", + "title": "Create Typst Local Package", + "category": "Typst" + }, + { + "command": "tinymist.openLocalPackage", + "title": "Open Typst Local Package", + "category": "Typst" + }, + { + "command": "tinymist.showSummary", + "title": "Show current document summary", + "category": "Typst" + }, + { + "command": "tinymist.showSymbolView", + "title": "Show symbol view", + "category": "Typst" + }, + { + "command": "tinymist.profileCurrentFile", + "title": "Profile and visualize execution of the current Typst file", + "category": "Typst" + }, + { + "command": "tinymist.syncLabel", + "title": "Scan workspace and collect all labels again", + "icon": "$(extensions-sync-enabled)" + }, + { + "command": "typst-preview.preview", + "title": "Typst Preview: Preview current file", + "description": "Launch typst-preview server", + "icon": "$(open-preview)", + "when": "resourceLangId == typst && editorTextFocus" + }, + { + "command": "typst-preview.browser", + "title": "Typst Preview: Preview current file in browser", + "description": "Launch typst-preview server and open the preview in your browser", + "icon": "$(open-preview)", + "when": "resourceLangId == typst && editorTextFocus" + }, + { + "command": "typst-preview.preview-slide", + "title": "Typst Preview: Preview current file in slide mode", + "description": "Launch typst-preview server in slide mode", + "icon": "$(open-preview)", + "when": "resourceLangId == typst && editorTextFocus" + }, + { + "command": "typst-preview.browser-slide", + "title": "Typst Preview: Preview current file in browser and slide mode", + "description": "Launch typst-preview server in slide mode and open the preview in your browser", + "icon": "$(open-preview)", + "when": "resourceLangId == typst && editorTextFocus" + }, + { + "command": "typst-preview.sync", + "title": "Typst Preview: Sync preview with current cursor", + "description": "Scroll preview to current cursor position", + "icon": "$(sync)", + "when": "resourceLangId == typst && editorTextFocus" + }, + { + "command": "typst-preview.noteOutline", + "title": "Note: Jumping to source location of the outline item doesn't work well if its body doesn't have source location, e.g.\n```\n#let my-heading(h) = heading(h) // will jump to here\n#my-heading(\"Title\") // will not jump to here\n```.\nHence, you may want to use `my-heading[Title]` instead to gain better experience of outline jumping.", + "description": "...", + "icon": "$(extensions-info-message)" + } + ], + "keybindings": [ + { + "command": "tinymist.onEnter", + "key": "enter", + "when": "editorTextFocus && !editorReadonly && editorLangId == typst && !suggestWidgetVisible && !editorHasMultipleSelections && vim.mode != 'Normal' && vim.mode != 'Visual' && vim.mode != 'VisualBlock' && vim.mode != 'VisualLine' && vim.mode != 'SearchInProgressMode' && vim.mode != 'CommandlineInProgress' && vim.mode != 'Replace' && vim.mode != 'EasyMotionMode' && vim.mode != 'EasyMotionInputMode' && vim.mode != 'SurroundInputMode'" + }, + { + "command": "typst-preview.preview", + "key": "ctrl+k v", + "mac": "cmd+k v", + "when": "editorLangId == typst" + } + ], + "menus": { + "commandPalette": [ + { + "command": "tinymist.exportCurrentPdf", + "when": "editorLangId == typst" + }, + { + "command": "tinymist.clearCache", + "when": "editorLangId == typst" + } + ], + "editor/title": [ + { + "command": "tinymist.showPdf", + "when": "resourceLangId == typst && editorTextFocus", + "group": "navigation" + }, + { + "command": "typst-preview.preview", + "when": "resourceLangId == typst && editorTextFocus", + "group": "navigation" + } + ], + "editor/context": [ + { + "command": "tinymist.copyAnsiHighlight", + "when": "resourceLangId == typst && editorTextFocus", + "group": "9_cutcopypaste" + } + ], + "view/title": [ + { + "command": "typst-preview.noteOutline", + "when": "view == tinymist.preview.outline", + "group": "navigation" + }, + { + "command": "tinymist.syncLabel", + "when": "view == tinymist.label-view", + "group": "navigation" + } + ] + } + }, + "activationEvents": [ + "onWebviewPanel:typst-preview" + ], + "scripts": { + "build:frontend": "cd ../../ && yarn build:preview && yarn build:editor-tools", + "build:syntax": "cd ../../syntaxes/textmate && yarn run compile && yarn run bundle", + "build-base": "esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node --target=node16", + "vscode:prepublish": "yarn run build-base -- --minify && yarn run build:frontend && node scripts/postinstall.cjs && node scripts/config-man.cjs", + "package": "vsce package --yarn", + "compile": "yarn run build-base -- --sourcemap && yarn run build:syntax && yarn run build:frontend && node scripts/postinstall.cjs", + "watch": "yarn run build-base -- --sourcemap --watch", + "check": "tsc --noEmit", + "lint": "eslint ./src --ext .ts", + "lint-fix": "eslint ./src --ext .ts --fix", + "format-check": "prettier --check .", + "format": "prettier --write .", + "test": "rimraf test-dist/ && tsc -p tsconfig.test.json && node test-dist/test/runTests.js" + }, + "dependencies": { + "vscode-languageclient": "^9.0.0", + "cpr": "^3.0.1", + "node-fetch": "^3.3.2", + "ws": "^8.13.0" + }, + "devDependencies": { + "@types/node": "^20.8.10", + "@types/vscode": "^1.82.0", + "@types/chai": "^4.3.16", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", + "@types/ws": "^8.5.5", + "@types/mocha": "^10.0.1", + "@vscode/vsce": "^2.22.0", + "@vscode/test-electron": "^2.3.9", + "mocha": "^10.2.0", + "chai": "^5.1.1", + "esbuild": "^0.19.5", + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-n": "^16.2.0", + "eslint-plugin-promise": "^6.1.1", + "ovsx": "^0.8.3", + "typescript": "^5.2.2" + } +} \ No newline at end of file diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/package.nls.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/package.nls.json new file mode 100644 index 0000000..c1844dd --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/package.nls.json @@ -0,0 +1,4 @@ +{ + "displayName": "Tinymist Typst", + "description": "An integrated language service for Typst" +} \ No newline at end of file diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst-code.tmLanguage.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst-code.tmLanguage.json new file mode 100644 index 0000000..1967261 --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst-code.tmLanguage.json @@ -0,0 +1 @@ +{"$schema":"https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json","scopeName":"source.typst-code","name":"typst-code","patterns":[{"include":"#code"}],"repository":{"common":{"patterns":[{"include":"#strictComments"},{"include":"#blockRaw"},{"include":"#inlineRaw"}]},"markup":{"patterns":[{"include":"#common"},{"include":"#markupEnterCode"},{"include":"#markupEscape"},{"name":"punctuation.definition.linebreak.typst","match":"\\\\"},{"name":"punctuation.definition.nonbreaking-space.typst","match":"\\~"},{"name":"punctuation.definition.shy.typst","match":"-\\?"},{"name":"punctuation.definition.em-dash.typst","match":"---"},{"name":"punctuation.definition.en-dash.typst","match":"--"},{"name":"punctuation.definition.ellipsis.typst","match":"\\.\\.\\."},{"name":"markup.underline.link.typst","match":"https?:\\/\\/[0-9a-zA-Z~\\/%#&='',;\\.\\+\\?\\-\\_]*"},{"include":"#markupMath"},{"include":"#markupHeading"},{"name":"punctuation.definition.list.unnumbered.typst","match":"^\\s*-\\s+"},{"name":"punctuation.definition.list.numbered.typst","match":"^\\s*([0-9]+\\.|\\+)\\s+"},{"match":"^\\s*(\\/)\\s+([^:]*)(:)","captures":{"1":{"name":"punctuation.definition.list.description.typst"},"2":{"patterns":[{"include":"#markup"}]},"3":{"name":"markup.list.term.typst"}}},{"include":"#markupLabel"},{"include":"#markupReference"}]},"markupEnterCode":{"patterns":[{"match":"(#)\\s","captures":{"1":{"name":"punctuation.definition.hash.typst"}}},{"match":"(#)(;)","captures":{"1":{"name":"punctuation.definition.hash.typst"},"2":{"name":"punctuation.terminator.statement.typst"}}},{"begin":"#(?=(?:break|continue|and|or|not|return|as|in|include|import|let|else|if|for|while|context|set|show)\\b(?!-))","end":"(?<=;)|(?<=[\\)\\]\\}])(?![;\\(\\[\\$])|(?"},"markupReference":{"name":"entity.other.reference.typst","match":"(@)[\\p{XID_Start}_](?:[\\p{XID_Continue}_\\-]|[\\.:](?!:\\s|$|([\\.:]*[^\\p{XID_Continue}_\\-\\.:])))*","captures":{"1":{"name":"punctuation.definition.reference.typst"}}},"markupEscape":{"name":"constant.character.escape.content.typst","match":"\\\\(?:[^u]|u\\{?[0-9a-zA-Z]*\\}?)"},"stringLiteral":{"name":"string.quoted.double.typst","begin":"\"","end":"\"","beginCaptures":{"0":{"name":"punctuation.definition.string.typst"}},"endCaptures":{"0":{"name":"punctuation.definition.string.typst"}},"patterns":[{"match":"(\\\\(?:[^u]|u\\{?[0-9a-zA-Z]*\\}?))|[^\\\\\"]+","captures":{"1":{"name":"constant.character.escape.string.typst"}}}]},"comments":{"patterns":[{"include":"#blockComment"},{"include":"#lineComment"}]},"strictComments":{"patterns":[{"include":"#blockComment"},{"include":"#strictLineComment"}]},"blockComment":{"name":"comment.block.typst","begin":"\\/\\*","end":"\\*\\/","beginCaptures":{"0":{"name":"punctuation.definition.comment.typst"}},"patterns":[{"include":"#blockComment"}]},"lineComment":{"name":"comment.line.double-slash.typst","begin":"\\/\\/","end":"(?=$|\\n)","beginCaptures":{"0":{"name":"punctuation.definition.comment.typst"}}},"strictLineComment":{"name":"comment.line.double-slash.typst","begin":"(?=|>","name":"keyword.operator.relational.typst"},{"begin":"(\\+=|-=|\\*=|\\/=|=)","end":"(?=[\\n;\\)\\]\\}])","beginCaptures":{"1":{"name":"keyword.operator.assignment.typst"}},"patterns":[{"include":"#expression"}]}]},"arrayOrDict":{"patterns":[{"match":"(\\()\\s*(\\))","captures":{"1":{"name":"meta.brace.round.typst"},"2":{"name":"meta.brace.round.typst"}}},{"match":"(\\()\\s*(:)\\s*(\\))","captures":{"1":{"name":"meta.brace.round.typst"},"2":{"name":"punctuation.separator.colon.typst"},"3":{"name":"meta.brace.round.typst"}}},{"begin":"\\(","end":"\\)","beginCaptures":{"0":{"name":"meta.brace.round.typst"}},"endCaptures":{"0":{"name":"meta.brace.round.typst"}},"patterns":[{"include":"#literalContent"}]}]},"literalContent":{"patterns":[{"name":"punctuation.separator.colon.typst","match":":"},{"name":"punctuation.separator.comma.typst","match":","},{"include":"#expression"}]},"includeStatement":{"name":"meta.expr.include.typst","begin":"(\\binclude\\b(?!-))\\s*","end":"(?=[\\n;\\}\\]\\)])","beginCaptures":{"1":{"name":"keyword.control.import.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"importStatement":{"name":"meta.expr.import.typst","begin":"(\\bimport\\b(?!-))\\s*","end":"(?=[\\n;\\}\\]\\)])","beginCaptures":{"1":{"name":"keyword.control.import.typst"}},"patterns":[{"include":"#comments"},{"include":"#importPathClause"},{"match":"\\:","name":"punctuation.separator.colon.typst"},{"match":"\\*","name":"keyword.operator.wildcard.typst"},{"match":"\\,","name":"punctuation.separator.comma.typst"},{"include":"#importAsClause"},{"include":"#expression"}]},"importPathClause":{"begin":"(\\bimport\\b(?!-))\\s*","end":"(?=\\:|as)","beginCaptures":{"1":{"name":"keyword.control.import.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"importAsClause":{"begin":"(\\bas\\b)\\s*","end":"(?=[\\s;\\}\\]\\)])","beginCaptures":{"1":{"name":"keyword.control.import.typst"}},"patterns":[{"include":"#comments"},{"include":"#identifier"}]},"letStatement":{"name":"meta.expr.let.typst","begin":"(?=(?:(let\\b(?!-))))","end":"(?!\\()(?=[\\s;\\}\\]\\)])","patterns":[{"include":"#comments"},{"include":"#letBindingClause"},{"include":"#letInitClause"}]},"letBindingClause":{"begin":"(let\\b(?!-))\\s*","end":"(?=[=;\\]}\\n])","beginCaptures":{"1":{"name":"storage.type.typst"}},"patterns":[{"include":"#comments"},{"begin":"(\\b[\\p{XID_Start}_][\\p{XID_Continue}_\\-]*)(\\()","end":"\\)","beginCaptures":{"1":{"name":"entity.name.function.typst","patterns":[{"include":"#primitiveFunctions"}]},"2":{"name":"meta.brace.round.typst"}},"endCaptures":{"0":{"name":"meta.brace.round.typst"}},"patterns":[{"include":"#funcParams"}]},{"begin":"\\(","end":"\\)","beginCaptures":{"0":{"name":"meta.brace.round.typst"}},"endCaptures":{"0":{"name":"meta.brace.round.typst"}},"patterns":[{"include":"#patternBindingItems"}]},{"include":"#identifier"}]},"letInitClause":{"begin":"=\\s*","end":"(?=|<|>|\\+|-|\\*|\\/|=|\\+=|-=|\\*=|\\/=)\\s*)(?=[\\[\\{\\n])|(?=[;\\n\\]}]|$)","beginCaptures":{"1":{"name":"keyword.control.conditional.typst"},"2":{"name":"keyword.control.conditional.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"elseClause":{"begin":"(\\belse)\\s*(\\{)","end":"\\}","beginCaptures":{"1":{"name":"keyword.control.conditional.typst"},"2":{"name":"meta.brace.curly.typst"}},"endCaptures":{"0":{"name":"meta.brace.curly.typst"}},"patterns":[{"include":"#code"}]},"elseContentClause":{"begin":"(\\belse)\\s*(\\[)","end":"\\]","beginCaptures":{"1":{"name":"keyword.control.conditional.typst"},"2":{"name":"meta.brace.square.typst"}},"endCaptures":{"0":{"name":"meta.brace.square.typst"}},"patterns":[{"include":"#code"},{"include":"#markupBrace"}]},"forStatement":{"name":"meta.expr.for.typst","begin":"(?=(?:(for\\b(?!-))\\s*))","end":"(?<=[\\}\\]])(?=\\s*[\\n\\S;\\}\\]\\)])(?!\\s*[\\{\\[])|(?=[;\\}\\]\\)\\n]|$)","patterns":[{"include":"#comments"},{"include":"#forClause"},{"include":"#codeBlock"},{"include":"#contentBlock"}]},"forClause":{"begin":"(for\\b)\\s*([^\\s\\}\\{\\[\\]][^\\}\\{\\[\\]]*|\\{[^\\}\\{]*(?:\\{[^\\}\\{]*(?:\\{[^\\}\\{]*(?:\\{[^\\}\\{]*(?:\\{[^\\}\\{]*(?:\\{[^\\}\\{]*(?:\\{[^\\}\\{]*\\}[^\\}\\{]*)*\\}[^\\}\\{]*)*\\}[^\\}\\{]*)*\\}[^\\}\\{]*)*\\}[^\\}\\{]*)*\\}[^\\}\\{]*)*\\})\\s*(in)\\s*","end":"(?=[;{\\[\\}\\]\\)\\n]|$)","beginCaptures":{"1":{"name":"keyword.control.loop.typst"},"2":{"patterns":[{"include":"#comments"},{"begin":"\\(","end":"\\)","beginCaptures":{"0":{"name":"meta.brace.round.typst"}},"endCaptures":{"0":{"name":"meta.brace.round.typst"}},"patterns":[{"include":"#patternBindingItems"}]},{"include":"#identifier"}]},"3":{"name":"keyword.operator.range.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"whileStatement":{"name":"meta.expr.while.typst","begin":"(?=(?:(while\\b(?!-))))","end":"(?<=\\}|\\])|(?=[;\\}\\]\\)\\n]|$)","patterns":[{"include":"#comments"},{"include":"#whileClause"},{"include":"#codeBlock"},{"include":"#contentBlock"}]},"whileClause":{"begin":"(while\\b)\\s*","end":"(?=|<|>|\\+|-|\\*|\\/|=|\\+=|-=|\\*=|\\/=)\\s+)(?=[\\[\\{])|(?=[;\\}\\]\\)\\n]|$)","beginCaptures":{"1":{"name":"keyword.control.loop.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"contextStatement":{"name":"meta.expr.context.typst","begin":"(context\\b(?!-))\\s*","end":"(?=[\\n;\\}\\]\\)])","beginCaptures":{"1":{"name":"keyword.control.other.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"setStatement":{"name":"meta.expr.set.typst","begin":"(?=(?:(set\\b(?!-))\\s*(?=|<|>|\\+|-|\\*|\\/|=|\\+=|-=|\\*=|\\/=)(?!\\s*(?:and|or|not|in|!=|==|<=|>=|<|>|\\+|-|\\*|\\/|=|\\+=|-=|\\*=|\\/=|\\.))|(?=[\\n;\\}\\]\\)])","beginCaptures":{"1":{"name":"keyword.control.conditional.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]},"showStatement":{"name":"meta.expr.show.typst","begin":"(?=(?:(show\\b(?!-))))","end":"(?=[\\s;\\{\\[\\}\\]\\)])","patterns":[{"include":"#comments"},{"include":"#showAnyClause"},{"include":"#showSelectClause"},{"include":"#showSubstClause"}]},"showAnyClause":{"match":"(show\\b)\\s*(?=\\:)","captures":{"1":{"name":"keyword.control.other.typst"}}},"showSelectClause":{"begin":"(show\\b)\\s*","end":"(?=[:;\\}\\]\\n])","beginCaptures":{"1":{"name":"keyword.control.other.typst"}},"patterns":[{"include":"#comments"},{"include":"#markupLabel"},{"include":"#expression"}]},"showSubstClause":{"begin":"(\\:)\\s*","end":"(?)","captures":{"1":{"name":"variable.parameter.typst"}}},{"begin":"(?x)(?=(?:\\([^\\)\\(]*(?:\\([^\\)\\(]*(?:\\([^\\)\\(]*(?:\\([^\\)\\(]*(?:\\([^\\)\\(]*(?:\\([^\\)\\(]*(?:\\([^\\)\\(]*\\)[^\\)\\(]*)*\\)[^\\)\\(]*)*\\)[^\\)\\(]*)*\\)[^\\)\\(]*)*\\)[^\\)\\(]*)*\\)[^\\)\\(]*)*\\)\\s*=>))","end":"(?==>)","patterns":[{"include":"#comments"},{"begin":"\\(","end":"\\)","beginCaptures":{"0":{"name":"meta.brace.round.typst"}},"endCaptures":{"0":{"name":"meta.brace.round.typst"}},"patterns":[{"include":"#funcParams"}]}]},{"begin":"=>","end":"(?<=\\}|\\])|(?:(?!\\{|\\[)(?=[\\n\\S;]))","beginCaptures":{"0":{"name":"storage.type.function.arrow.typst"}},"patterns":[{"include":"#comments"},{"include":"#expression"}]}]}}} \ No newline at end of file diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst-markdown-injection.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst-markdown-injection.json new file mode 100644 index 0000000..21bca2d --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst-markdown-injection.json @@ -0,0 +1,81 @@ +{ + "fileTypes": [], + "injectionSelector": "L:text.html.markdown", + "patterns": [ + { + "include": "#fenced-block-typst" + }, + { + "include": "#fenced-block-typst-code" + } + ], + "repository": { + "fenced-block-typst": { + "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(typ|typst)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.typst", + "patterns": [ + { + "include": "source.typst" + } + ] + } + ] + }, + "fenced-block-typst-code": { + "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(typc)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.typst-code", + "patterns": [ + { + "include": "source.typst-code" + } + ] + } + ] + } + }, + "scopeName": "markdown.typst.codeblock" +} \ No newline at end of file diff --git a/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst.tmLanguage.json b/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst.tmLanguage.json new file mode 100644 index 0000000..f43c768 --- /dev/null +++ b/src/TextMateSharp.Grammars/Resources/Grammars/typst/syntaxes/typst.tmLanguage.json @@ -0,0 +1,576 @@ +{ + "name": "typst", + "patterns": [ + { + "include": "#markup" + } + ], + "repository": { + "comments": { + "patterns": [ + { + "name": "comment.block.typst", + "begin": "/\\*", + "end": "\\*/", + "captures": { + "0": { + "name": "punctuation.definition.comment.typst" + } + }, + "patterns": [ + { + "include": "#comments" + } + ] + }, + { + "name": "comment.line.double-slash.typst", + "begin": "(?", + "captures": { + "1": { + "name": "punctuation.definition.label.typst" + } + } + }, + { + "name": "entity.other.reference.typst", + "match": "(@)[[:alpha:]_][[:alnum:]_-]*", + "captures": { + "1": { + "name": "punctuation.definition.reference.typst" + } + } + }, + { + "begin": "(#)(let|set|show)\\b", + "end": "\n|(;)|(?=])", + "beginCaptures": { + "0": { + "name": "keyword.other.typst" + }, + "1": { + "name": "punctuation.definition.keyword.typst" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.typst" + } + }, + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "name": "keyword.other.typst", + "match": "(#)(as|in)\\b", + "captures": { + "1": { + "name": "punctuation.definition.keyword.typst" + } + } + }, + { + "begin": "((#)if|(?<=(}|])\\s*)else)\\b", + "end": "\n|(?=])|(?<=}|])", + "beginCaptures": { + "0": { + "name": "keyword.control.conditional.typst" + }, + "2": { + "name": "punctuation.definition.keyword.typst" + } + }, + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "begin": "(#)(for|while)\\b", + "end": "\n|(?=])|(?<=}|])", + "beginCaptures": { + "0": { + "name": "keyword.control.loop.typst" + }, + "1": { + "name": "punctuation.definition.keyword.typst" + } + }, + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "name": "keyword.control.loop.typst", + "match": "(#)(break|continue)\\b", + "captures": { + "1": { + "name": "punctuation.definition.keyword.typst" + } + } + }, + { + "begin": "(#)(import|include|export)\\b", + "end": "\n|(;)|(?=])", + "beginCaptures": { + "0": { + "name": "keyword.control.import.typst" + }, + "1": { + "name": "punctuation.definition.keyword.typst" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.typst" + } + }, + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "name": "keyword.control.flow.typst", + "match": "(#)(return)\\b", + "captures": { + "1": { + "name": "punctuation.definition.keyword.typst" + } + } + }, + { + "comment": "Function name", + "name": "entity.name.function.typst", + "match": "((#)[[:alpha:]_][[:alnum:]_-]*!?)(?=\\[|\\()", + "captures": { + "2": { + "name": "punctuation.definition.function.typst" + } + } + }, + { + "comment": "Function arguments", + "begin": "(?<=#[[:alpha:]_][[:alnum:]_-]*!?)\\(", + "end": "\\)", + "captures": { + "0": { + "name": "punctuation.definition.group.typst" + } + }, + "patterns": [ + { + "include": "#arguments" + } + ] + }, + { + "name": "entity.other.interpolated.typst", + "match": "(#)[[:alpha:]_][.[:alnum:]_-]*", + "captures": { + "1": { + "name": "punctuation.definition.variable.typst" + } + } + }, + { + "name": "meta.block.content.typst", + "begin": "#", + "end": "\\s", + "patterns": [ + { + "include": "#code" + } + ] + } + ] + }, + "code": { + "patterns": [ + { + "include": "#common" + }, + { + "name": "meta.block.code.typst", + "begin": "{", + "end": "}", + "captures": { + "0": { + "name": "punctuation.definition.block.code.typst" + } + }, + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "name": "meta.block.content.typst", + "begin": "\\[", + "end": "\\]", + "captures": { + "0": { + "name": "punctuation.definition.block.content.typst" + } + }, + "patterns": [ + { + "include": "#markup" + } + ] + }, + { + "name": "comment.line.double-slash.typst", + "begin": "//", + "end": "\n", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.typst" + } + } + }, + { + "name": "punctuation.separator.colon.typst", + "match": ":" + }, + { + "name": "punctuation.separator.comma.typst", + "match": "," + }, + { + "name": "keyword.operator.typst", + "match": "=>|\\.\\." + }, + { + "name": "keyword.operator.relational.typst", + "match": "==|!=|<=|<|>=|>" + }, + { + "name": "keyword.operator.assignment.typst", + "match": "\\+=|-=|\\*=|/=|=" + }, + { + "name": "keyword.operator.arithmetic.typst", + "match": "\\+|\\*|/|(?