diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2023-04-11 17:30:08 +0300 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2023-04-11 18:41:56 +0300 |
| commit | a38b64e1a1bf14dd9c42629f219b0e422aebe52a (patch) | |
| tree | 8cc08f712ddd3f8573d2b7c8aa243fcd1b6e52df /atk16-syntax | |
| parent | e240ef3e9a2854cfe390b47fb0b3d519c095193b (diff) | |
Add hover and go to definition to extension
Diffstat (limited to 'atk16-syntax')
| -rw-r--r-- | atk16-syntax/README.md | 9 | ||||
| -rw-r--r-- | atk16-syntax/atk16-syntax-0.0.1.vsix | bin | 0 -> 4725 bytes | |||
| -rw-r--r-- | atk16-syntax/extension.js | 197 | ||||
| -rw-r--r-- | atk16-syntax/language-configuration.json | 41 | ||||
| -rw-r--r-- | atk16-syntax/package.json | 39 | ||||
| -rw-r--r-- | atk16-syntax/syntaxes/atk16.tmLanguage.json | 52 | ||||
| -rw-r--r-- | atk16-syntax/themes/atk16-color-theme.json | 41 |
7 files changed, 379 insertions, 0 deletions
diff --git a/atk16-syntax/README.md b/atk16-syntax/README.md new file mode 100644 index 0000000..da81144 --- /dev/null +++ b/atk16-syntax/README.md @@ -0,0 +1,9 @@ +# VSCode syntax highlighting extension for ATK16 assembly + +## Installation + +In `atk16-syntax-highlighting` directory, run: + + npx @vscode/vsce package + +Then go to VSCode > Command Palette > Extensions: Install from VSIX and select the generated `.vsix` file. diff --git a/atk16-syntax/atk16-syntax-0.0.1.vsix b/atk16-syntax/atk16-syntax-0.0.1.vsix Binary files differnew file mode 100644 index 0000000..b6aa9dc --- /dev/null +++ b/atk16-syntax/atk16-syntax-0.0.1.vsix diff --git a/atk16-syntax/extension.js b/atk16-syntax/extension.js new file mode 100644 index 0000000..e49dd07 --- /dev/null +++ b/atk16-syntax/extension.js @@ -0,0 +1,197 @@ +const vscode = require('vscode'); +const path = require('path'); + +class ATK16HoverProvider { + async provideHover(document, position, token) { + const range = document.getWordRangeAtPosition(position, /[\w-/.]+/); + const labelText = document.getText(range); + const subroutineDefinition = await findSubroutineInDocument(document, labelText); + if (subroutineDefinition) { + const hoverText = new vscode.MarkdownString(subroutineDefinition); + hoverText.isTrusted = true; + return new vscode.Hover(hoverText); + } + + // Search for labels in included files + for (let i = 0; i < document.lineCount; i++) { + const line = document.lineAt(i); + const includeMatch = line.text.match(/@include\s+(\S+)/); + if (includeMatch) { + const includedFilePath = path.join( + path.dirname(document.fileName), + `${includeMatch[1]}.atk16` + ); + + if (await vscode.workspace.fs.stat(vscode.Uri.file(includedFilePath))) { + const includedDocument = await vscode.workspace.openTextDocument( + includedFilePath + ); + const subroutineDefinition = await findSubroutineInDocument(includedDocument, labelText); + if (subroutineDefinition) { + const hoverText = new vscode.MarkdownString(subroutineDefinition); + hoverText.isTrusted = true; + return new vscode.Hover(hoverText); + } + } + } + } + + return null; + } +} + +class ATK16DefinitionProvider { + async provideDefinition(document, position, token) { + const range = document.getWordRangeAtPosition(position, /[\w-/.]+/); + const text = document.getText(range); + + const line = document.lineAt(position); + const includeMatch = line.text.match(/@include\s+(\S+)/); + const useMatch = line.text.match(/@use\s+(\S+):/); + + if (includeMatch && includeMatch[1] === text) { + const includedFilePath = path.join( + path.dirname(document.fileName), + `${includeMatch[1]}.atk16` + ); + + try { + await vscode.workspace.fs.stat(vscode.Uri.file(includedFilePath)); + return new vscode.Location( + vscode.Uri.file(includedFilePath), + new vscode.Position(0, 0) + ); + } catch (err) { + vscode.window.showErrorMessage( + `ATK16: File not found: ${includedFilePath}` + ); + } + } else if (useMatch && useMatch[1] === text) { + const includedFilePath = path.join( + path.dirname(document.fileName), + `${useMatch[1]}.py` + ); + + try { + await vscode.workspace.fs.stat(vscode.Uri.file(includedFilePath)); + return new vscode.Location( + vscode.Uri.file(includedFilePath), + new vscode.Position(0, 0) + ); + } catch (err) { + vscode.window.showErrorMessage( + `ATK16: File not found: ${includedFilePath}` + ); + } + } else { + const labelText = document.getText(range); + let labelLocation = await findLabelInDocument(document, labelText); + if (labelLocation) { + return labelLocation; + } + + // Search for labels in included files + for (let i = 0; i < document.lineCount; i++) { + const line = document.lineAt(i); + const includeMatch = line.text.match(/@include\s+(\S+)/); + if (includeMatch) { + const includedFilePath = path.join( + path.dirname(document.fileName), + `${includeMatch[1]}.atk16` + ); + + if (await vscode.workspace.fs.stat(vscode.Uri.file(includedFilePath))) { + const includedDocument = await vscode.workspace.openTextDocument( + includedFilePath + ); + labelLocation = await findLabelInDocument(includedDocument, labelText); + if (labelLocation) { + return labelLocation; + } + } + } + } + } + + return null; + } +} + +async function findLabelInDocument(document, labelText) { + for (let i = 0; i < document.lineCount; i++) { + const line = document.lineAt(i); + if (line.text.includes(`@label ${labelText}`)) { + return new vscode.Location(document.uri, line.range.start); + } + } + return null; +} + +async function findSubroutineInDocument(document, labelText) { + let name = null; + const params = []; + const returns = []; + let extra = ""; + for (let i = 0; i < document.lineCount; i++) { + const line = document.lineAt(i); + if (line.text.includes(`@label ${labelText}`)) { + let labelDefinition = ''; + for (let j = i + 1; j < document.lineCount; j++) { + const docLine = document.lineAt(j); + const docCommentMatch = docLine.text.match(/;\? (.*)/); + if (docCommentMatch) { + const lineText = docCommentMatch[1]; + const parts = lineText.split(/\s/); + if (lineText.startsWith('subroutine')) { + name = parts[parts.length - 1]; + } else if (lineText.startsWith('param')) { + const [_, reg, ...desc] = parts; + params.push([reg, desc.join(" ")]) + } else if (lineText.startsWith('return')) { + const [_, reg, ...desc] = parts; + returns.push([reg, desc.join(" ")]) + } else { + extra += `${lineText}\n`; + } + } else { + break; + } + } + } + } + + if (name === null) return null; + + let definition = `### ${name}\n_Subroutine_\n\n`; + definition += extra; + if (params.length > 0) { + definition += "\n\n|Reg|Parameter|\n"; + definition += "|:---|:---|\n"; + } + for (const [reg, desc] of params) { + definition += `|${reg}|${desc}|\n`; + } + + if (returns.length > 0) { + definition += "\n|Reg|Return|\n"; + definition += "|:---|:---|\n"; + } + for (const [reg, desc] of returns) { + definition += `|${reg}|${desc}|\n`; + } + return definition; +} + +function activate(context) { + context.subscriptions.push( + vscode.languages.registerDefinitionProvider('atk16', new ATK16DefinitionProvider()), + vscode.languages.registerHoverProvider('atk16', new ATK16HoverProvider()) + ); +} + +function deactivate() {} + +module.exports = { + activate, + deactivate, +};
\ No newline at end of file diff --git a/atk16-syntax/language-configuration.json b/atk16-syntax/language-configuration.json new file mode 100644 index 0000000..c186b1b --- /dev/null +++ b/atk16-syntax/language-configuration.json @@ -0,0 +1,41 @@ +{ + "comments": { + "lineComment": ";" + }, + "brackets": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ] + ], + "autoClosingPairs": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ], + [ + "\"", + "\"" + ], + [ + "'", + "'" + ] + ] +}
\ No newline at end of file diff --git a/atk16-syntax/package.json b/atk16-syntax/package.json new file mode 100644 index 0000000..bdfbb74 --- /dev/null +++ b/atk16-syntax/package.json @@ -0,0 +1,39 @@ +{ + "name": "atk16-syntax", + "displayName": "ATK16 Syntax", + "description": "Syntax highlighting and support for ATK16 assembly language", + "version": "0.0.1", + "publisher": "JanTuomi", + "engines": { + "vscode": "^1.60.0" + }, + "categories": ["Programming Languages"], + "activationEvents": [ + "onLanguage:atk16" + ], + "main": "./extension.js", + "contributes": { + "languages": [ + { + "id": "atk16", + "aliases": ["ATK16 Assembly", "atk16"], + "extensions": [".atk16"], + "configuration": "./language-configuration.json" + } + ], + "grammars": [ + { + "language": "atk16", + "scopeName": "source.atk16", + "path": "./syntaxes/atk16.tmLanguage.json" + } + ], + "themes": [ + { + "label": "ATK16 Color Theme", + "uiTheme": "vs-dark", + "path": "./themes/atk16-color-theme.json" + } + ] + } +} diff --git a/atk16-syntax/syntaxes/atk16.tmLanguage.json b/atk16-syntax/syntaxes/atk16.tmLanguage.json new file mode 100644 index 0000000..1faadf9 --- /dev/null +++ b/atk16-syntax/syntaxes/atk16.tmLanguage.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "ATK16", + "patterns": [ + { + "name": "comment.documentation.atk16", + "match": ";\\?.*$" + }, + { + "name": "comment.line.semicolon.atk16", + "match": ";.*" + }, + { + "name": "keyword.control.directive.atk16", + "match": "^@\\w+" + }, + { + "name": "variable.other.register.atk16", + "match": "R\\w+" + }, + { + "name": "constant.numeric.hex.atk16", + "match": "0x[0-9a-fA-F]+" + }, + { + "name": "constant.numeric.binary.atk16", + "match": "0b[01]+" + }, + { + "name": "constant.numeric.decimal.atk16", + "match": "[0-9]+" + }, + { + "name": "entity.name.function.atk16", + "match": "\\w+(?=\\s*\\()" + }, + { + "name": "entity.name.label.atk16", + "match": "\\w+(?=\\s*:)" + }, + { + "name": "keyword.control.instruction.atk16", + "match": "^\\s+[a-zA-Z]+" + }, + { + "name": "constant.language.flag.atk16", + "match": "\\b(carry|overflow|zero|sign)\\b" + } + ], + "repository": {}, + "scopeName": "source.atk16" +} diff --git a/atk16-syntax/themes/atk16-color-theme.json b/atk16-syntax/themes/atk16-color-theme.json new file mode 100644 index 0000000..d1aebb9 --- /dev/null +++ b/atk16-syntax/themes/atk16-color-theme.json @@ -0,0 +1,41 @@ +{ + "name": "ATK16", + "type": "dark", + "colors": { + "editor.background": "#1E1E1E", + "editor.foreground": "#D4D4D4", + "editor.lineHighlightBackground": "#2D2D30" + }, + "tokenColors": [ + { + "scope": "keyword.control.directive.atk16", + "settings": {} + }, + { + "scope": "variable.parameter.register.atk16", + "settings": {} + }, + { + "scope": "constant.numeric.binary.atk16", + "settings": {} + }, + { + "scope": "keyword.control.instruction.atk16", + "settings": {} + }, + { + "scope": "support.function.atk16", + "settings": {} + }, + { + "scope": "entity.name.label.atk16", + "settings": {} + }, + { + "scope": "comment.documentation.atk16", + "settings": { + "fontStyle": "italic" + } + } + ] +}
\ No newline at end of file |
