diff --git a/README.md b/README.md index 66f813b..e29bd94 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,19 @@ This is the README for your extension "stencila". After writing up a brief description, we recommend including the following sections. +## Testing locally + +In order to test the extension in `VSCode`, you will need to do the following: + +1. run `npm install` +2. run `npm run compile` +3. open a `.smd` file (e.g. `src/fixtures/syntax.smd`) & hit `F5` to open a + debug session with the extension installed. + +> [!WARNING] +> The following sections are the ones defined by the initial template. We intend +> to rewrite as we go. + ## Features Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. @@ -29,23 +42,11 @@ This extension contributes the following settings: ## Known Issues -Calling out known issues can help limit users opening duplicate issues against your extension. - -## Release Notes - -Users appreciate release notes as you update your extension. - -### 1.0.0 - -Initial release of ... -### 1.0.1 -Fixed issue #. - -### 1.1.0 +## Release Notes -Added features X, Y, and Z. +See [the changelog](./CHANGELOG.md) --- @@ -54,18 +55,3 @@ Added features X, Y, and Z. Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension. * [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines) - -## Working with Markdown - -You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: - -* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux). -* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux). -* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets. - -## For more information - -* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) -* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) - -**Enjoy!** diff --git a/icons/images/stencila-icon-32x32.svg b/icons/images/stencila-icon-32x32.svg new file mode 100644 index 0000000..6ea720b --- /dev/null +++ b/icons/images/stencila-icon-32x32.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/icons/stencila-icon-theme.json b/icons/stencila-icon-theme.json new file mode 100644 index 0000000..0462e91 --- /dev/null +++ b/icons/stencila-icon-theme.json @@ -0,0 +1,12 @@ +{ + "iconDefinitions": { + "_stencila_light": { + "iconPath": "./images/stencila-icon-32x32.svg" + } + }, + "light": { + "fileExtensions": { + "smd": "_stencila_light" + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index e0b4760..f031d7a 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,21 @@ "language": "smd", "path": "./syntaxes/smd/snippets.json" } + ], + "themes": [ + { + "id": "Stencila Light", + "label": "Stencila light", + "uiTheme": "vs", + "path": "./themes/stencila-light-color-theme.json" + } + ], + "iconThemes": [ + { + "id": "stencila", + "label": "Stencila Icons", + "path": "./icons/stencila-icon-theme.json" + } ] }, "scripts": { diff --git a/src/extension.ts b/src/extension.ts index eb22c2d..c5bdf1b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -19,6 +19,11 @@ export function activate(context: vscode.ExtensionContext) { vscode.window.showInformationMessage('Hello World from Stencila!'); }); + // Define the default theme for this extension. + // Inside your extension's activation code + vscode.workspace.getConfiguration('workbench') + .update('colorTheme', 'Stencila Light', vscode.ConfigurationTarget.Global); + context.subscriptions.push(disposable); } diff --git a/src/fixtures/syntax.smd b/src/fixtures/syntax.smd index a84b144..395a378 100644 --- a/src/fixtures/syntax.smd +++ b/src/fixtures/syntax.smd @@ -36,11 +36,73 @@ The area of a circle is $2 \pi r^2$. ```js // Javascript code function foo(){} + +import { VIEWS } from '../views/views' + +import './main.css' + +import './shoelace' + +/** + * Application Wrapper + * + * Wraps the application in the `app-chrome`. Contains the main header and + * footer. + */ +@customElement('stencila-main-app') +@withTwind() +export class App extends LitElement { + /** + * The currently open documents + * + * This property is initialized (as an HTML attribute) with one document id, + * by the server, based on the URL path (including paths that resolved to main.*, + * index.*, or README.* in the home directory of the server (the directory it was started in)). + * + * While the app is running [document id, file name] pairs are added or removed + * from this list (e.g. by clicking on the directory tree, closing a tab). + * + * A list is used here (rather than say an object with `DocumentId` as the key) + * to allow for reordering of tabs by the user. + */ + @property({ type: Array }) + docs: (File & { docId: DocumentId })[] = [] + + /** + * The id of the document, in `docs`, that is currently active + */ + @state() + activeDoc: DocumentId | null + + /** + * The current view of the current document + * + * If there is no `view` attribute then this will be dynamically + * determined based on the maximum access level that the user has for + * the document. + */ + @property() + view?: DocumentView = 'live' +} ``` ```py # Python code def foo: pass +from stencila import _stencila + +async def from_string(string: str, format: str | None = "json") -> Node: + """ + Decode a Stencila Schema node from a string. + + Args: + string (str): The string to decode to a node. + format (Optional[str]): The format to decode from. Defaults to "json". + + Returns: + Node: A Stencila Schema node. + """ + return from_json(await _stencila.convert.from_string(string, {"format": format})) ``` ```r diff --git a/syntaxes/smd/configuration.json b/syntaxes/smd/configuration.json index d269163..e6ebfd9 100644 --- a/syntaxes/smd/configuration.json +++ b/syntaxes/smd/configuration.json @@ -11,7 +11,8 @@ { "open": "[", "close": "]" }, { "open": "(", "close": ")" }, { "open": "'", "close": "'", "notIn": ["string"] }, - { "open": "\"", "close": "\"", "notIn": ["string"] } + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "```", "close": "```"} ], "surroundingPairs": [ { "open": "{", "close": "}" }, @@ -26,7 +27,7 @@ "folding": { "$comment": "Basic folding. More advanced folding to be provided by language server.", "markers": { - "start": "^:{3,}\\s*(if|for|with|insert|delete)", + "start": "^:{3,}\\s*(if|for|with|insert|delete|table|figure)", "end": "^:{3,}\\s*$" } }, diff --git a/syntaxes/smd/snippets.json b/syntaxes/smd/snippets.json index 0595c6b..b871c4d 100644 --- a/syntaxes/smd/snippets.json +++ b/syntaxes/smd/snippets.json @@ -65,6 +65,16 @@ "prefix": ["::: if"], "body": ["::: if ${1:expression}", "", "$0", "", ":::"] }, + "Elif Block": { + "description": "Only show block content if the preceeding 'if' conditions are false and its own condition is true.", + "prefix": ["::: elif"], + "body": ["::: elif ${1:expression}", "", "$0", "", ":::"] + }, + "Else Block": { + "description": "Only show block content if none of the preceeding conditions are true.", + "prefix": ["::: else"], + "body": ["::: else", "", "$0", "", ":::"] + }, "For Block": { "description": "Repeat block content for each value of a variable in an expression.", "prefix": ["::: for"], diff --git a/syntaxes/smd/tmGrammar.yaml b/syntaxes/smd/tmGrammar.yaml index 14c542b..7c1a4d2 100644 --- a/syntaxes/smd/tmGrammar.yaml +++ b/syntaxes/smd/tmGrammar.yaml @@ -230,9 +230,9 @@ repository: $ captures: "1": { name: markup.heading } # semicolons - "2": { name: keyword.control } # do - "3": { name: punctuation.definition } # @ - "4": { name: variable.name } # assignee + "2": { name: keyword.control.stencila } # do + "3": { name: decorator.keyword.stencila } # @ + "4": { name: decorator.keyword.stencila } # assignee "5": { name: comment.line } # message with-block: @@ -262,9 +262,9 @@ repository: )? \]\] captures: - "1": { name: keyword.control } # do - "2": { name: punctuation.definition } # @ - "3": { name: variable.name } # assignee + "1": { name: keyword.control.stencila } # do + "2": { name: decorator.keyword.stencila } # @ + "3": { name: decorator.keyword.stencila } # assignee "4": { name: comment.line } # message "5": { name: keyword.control } # >> @@ -288,9 +288,9 @@ repository: $ captures: "1": { name: markup.heading } # semicolons - "2": { name: keyword.control } # insert - "3": { name: token.info-token } # accept - "4": { name: token.error-token } # reject + "2": { name: keyword.control.stencila } # insert + "3": { name: accept.stencila } # accept + "4": { name: error.stencila } # reject insert-inline: name: meta.stencila.insert-inline @@ -303,7 +303,7 @@ repository: (.*?) \]\] captures: - "1": { name: keyword.control } # insert + "1": { name: keyword.control.stencila } # insert delete-block: name: meta.stencila.delete-block @@ -324,8 +324,8 @@ repository: captures: "1": { name: markup.heading } # semicolons "2": { name: keyword.control } # delete - "3": { name: token.info-token } # accept - "4": { name: token.error-token } # reject + "3": { name: accept.stencila } # accept + "4": { name: error.stencila } # reject delete-inline: name: meta.stencila.delete-inline @@ -359,8 +359,8 @@ repository: captures: "1": { name: markup.heading } # semicolons "2": { name: keyword.control } # replace - "3": { name: token.info-token } # accept - "4": { name: token.error-token } # reject + "3": { name: accept.stencila } # accept + "4": { name: error.stencila } # reject replace-inline: name: meta.stencila.replace-inline @@ -385,8 +385,8 @@ repository: match: ^(:{3,})\s*(include)\s+(.*)$ captures: "1": { name: markup.heading } # semicolons - "2": { name: keyword.control } # include - "3": { name: variable.name } # source + "2": { name: keyword.control.stencila } # include + "3": { name: variable.name.stencila } # source ########## CallBlock ########## @@ -395,8 +395,8 @@ repository: match: ^(:{3,})\s*(call)\s+(.*)$ captures: "1": { name: markup.heading } # semicolons - "2": { name: keyword.control } # call - "3": { name: variable.name } # source + "2": { name: keyword.control.stencila } # include + "3": { name: variable.name.stencila } # source ########## IfBlock ########## @@ -500,6 +500,11 @@ repository: # The following grammar rules are taken from the VSCode builtin Markdown grammar at # https://github.com/microsoft/vscode-markdown-tm-grammar/blob/main/markdown.tmLanguage.base.yaml # usually with little modification, particularly to regular expressions. + heading: + name: meta.stencila.heading + match: (?:^|\G)[ ]{0,3}(#{1,6}\s+(.*?)(\s+#{1,6})?\s*)$ + patterns: + - { include: punctuation.definition.heading.markdown } paragraph: name: meta.stencila.paragraph diff --git a/themes/stencila-light-color-theme.json b/themes/stencila-light-color-theme.json new file mode 100644 index 0000000..9a3ebea --- /dev/null +++ b/themes/stencila-light-color-theme.json @@ -0,0 +1,126 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Stencila Light", + "colors": { + "activityBar.activeBorder": "#2568EF", + "activityBar.background": "#F5F5F5", + "activityBar.dropBorder": "#2568EF", + "activityBar.foreground": "#2568EF", + "activityBar.inactiveForeground": "#666666", + "activityBarBadge.background": "#2568EF", + "activityBarBadge.foreground": "#ffffff", + "editorGutter.modifiedBackground": "#66FF66", + "editorGutter.addedBackground": "#BCFFBC", + "editorLineNumber.foreground": "#B0B0B0", + "editorLineNumber.activeForeground": "#2568EF", + "statusBar.background": "#2568EF", + "statusBar.border": "#2568EF", + "statusBar.foreground": "#FFFFFF", + "statusBarItem.hoverBackground": "#215DD7", + "statusBar.debuggingBackground": "#2568EF", + "statusBar.noFolderBackground": "#2568EF", + }, + "tokenColors": [{ + "scope": [ + "meta.embedded", + "comment.line", + "comment", + "support.type" + ], + "settings": { + "foreground": "#1B8951", + } + }, { + "scope": ["string"], + "settings": { + "foreground": "#8C1A40" + } + }, { + "scope": [ + "keyword.operator", + "meta.stencila.paragraph" + ], + "settings": { + "foreground": "#666666", + } + }, { + "scope": [ + "keyword.operator.star", + "meta.stencila" + ], + "settings": { + "foreground": "#171817", + } + }, { + "scope": [ + "error.stencila", + "meta.stencila.instruction-inline", + "meta.stencila.parameter" + ], + "settings": { + "foreground": "#D94D7B", + } + }, { + "scope": [ + "constant.language", + "entity.name.tag.yaml", + "entity.name.type.js", + "keyword.other", + "meta.brace", + "accept.stencila", + "decorator.stencila.keyword", + "variable.name.stencila", + "punctuation.separator.key-value.mapping.yaml", + "storage.type", + "storage", + ], + "settings": { + "foreground": "#2568EF", + } + }, { + "scope": [ + "meta.decorator.js", + "support.function" + ], + "settings": { + "foreground": "#5C8EF3", + } + }, { + "scope": [ + "meta.object-literal", + "meta.object.type", + "variable.object.property" + ], + "settings": { + "foreground": "#092D77", + } + }, { + "scope": [ + "keyword.control.flow", + "keyword.control.export", + "keyword.control.from", + "keyword.control.import", + "keyword.control.preamble.latex", + "keyword.control.stencila", + ], + "settings": { + "foreground": "#7957D5" + } + }, { + "scope": [ + "entity.name.type.class", + "entity.other.inherited-class" + ], + "settings": { + "fontStyle": "italic" + } + }, { + "scope": [ + "meta.stencila.heading", + ], + "settings": { + "fontStyle": "underline" + } + }] +} +