aboutsummaryrefslogtreecommitdiffstats
path: root/atk16-syntax
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2023-04-11 17:30:08 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2023-04-11 18:41:56 +0300
commita38b64e1a1bf14dd9c42629f219b0e422aebe52a (patch)
tree8cc08f712ddd3f8573d2b7c8aa243fcd1b6e52df /atk16-syntax
parente240ef3e9a2854cfe390b47fb0b3d519c095193b (diff)
Add hover and go to definition to extension
Diffstat (limited to 'atk16-syntax')
-rw-r--r--atk16-syntax/README.md9
-rw-r--r--atk16-syntax/atk16-syntax-0.0.1.vsixbin0 -> 4725 bytes
-rw-r--r--atk16-syntax/extension.js197
-rw-r--r--atk16-syntax/language-configuration.json41
-rw-r--r--atk16-syntax/package.json39
-rw-r--r--atk16-syntax/syntaxes/atk16.tmLanguage.json52
-rw-r--r--atk16-syntax/themes/atk16-color-theme.json41
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
new file mode 100644
index 0000000..b6aa9dc
--- /dev/null
+++ b/atk16-syntax/atk16-syntax-0.0.1.vsix
Binary files differ
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