From a38b9f8c480b8cc7fdba07edccfba66b214c9be6 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 24 May 2025 06:27:13 +0200 Subject: [PATCH 1/7] Custom syntax highlighting --- web/astro.config.mjs | 13 + .../generate-lua-tmlanguage.js | 50 + web/mta_highlighting/generate-tmlanguage.cmd | 3 + web/mta_highlighting/lua-base.tmLanguage.json | 957 +++++++++++++++++ web/package-lock.json | 416 +++++++- web/package.json | 2 + web/src/grammars/lua-mta.tmLanguage.json | 964 ++++++++++++++++++ web/src/themes/mtasa_lua-theme_dark.json | 382 +++++++ web/src/themes/mtasa_lua-theme_light.json | 377 +++++++ 9 files changed, 3158 insertions(+), 6 deletions(-) create mode 100644 web/mta_highlighting/generate-lua-tmlanguage.js create mode 100644 web/mta_highlighting/generate-tmlanguage.cmd create mode 100644 web/mta_highlighting/lua-base.tmLanguage.json create mode 100644 web/src/grammars/lua-mta.tmLanguage.json create mode 100644 web/src/themes/mtasa_lua-theme_dark.json create mode 100644 web/src/themes/mtasa_lua-theme_light.json diff --git a/web/astro.config.mjs b/web/astro.config.mjs index 6023884d..e821effe 100644 --- a/web/astro.config.mjs +++ b/web/astro.config.mjs @@ -15,6 +15,19 @@ export default defineConfig({ }, integrations: [ starlight({ + expressiveCode: { + themes: [JSON.parse(fs.readFileSync('./src/themes/mtasa_lua-theme_dark.json', 'utf-8')), JSON.parse(fs.readFileSync('./src/themes/mtasa_lua-theme_light.json', 'utf-8'))], + shiki: { + langs: [ + { + id: 'lua', + scopeName: 'source.lua.mta', + ...JSON.parse(fs.readFileSync('./src/grammars/lua-mta.tmLanguage.json', 'utf-8')), + }, + ], + }, + }, + plugins: [ mtasaStarlightThemePlugin(), ], diff --git a/web/mta_highlighting/generate-lua-tmlanguage.js b/web/mta_highlighting/generate-lua-tmlanguage.js new file mode 100644 index 00000000..43438293 --- /dev/null +++ b/web/mta_highlighting/generate-lua-tmlanguage.js @@ -0,0 +1,50 @@ +import fs from 'fs'; +import path from 'path'; +import yaml from 'js-yaml'; +import { glob } from 'glob'; + +const functionsDir = path.resolve('../../functions'); +const basePath = path.resolve('./lua-base.tmLanguage.json'); +const outputPath = path.resolve('../src/grammars/lua-mta.tmLanguage.json'); + +function extractFunctionsWithScope(yamlContent) { + if (yamlContent.shared?.name) { + return [{ name: yamlContent.shared.name, scope: 'support.function.mta-shared' }]; + } else if (yamlContent.client?.name) { + return [{ name: yamlContent.client.name, scope: 'support.function.mta-client' }]; + } else if (yamlContent.server?.name) { + return [{ name: yamlContent.server.name, scope: 'support.function.mta-server' }]; + } + return []; +} + +async function generateTmLanguage() { + const files = await glob('**/*.yaml', { cwd: functionsDir, absolute: true }); + + const functionsMap = Object.fromEntries( + ['shared', 'server', 'client'].map(scope => [`support.function.mta-${scope}`, new Set()]) + ); + + files.forEach(file => { + const yamlContent = yaml.load(fs.readFileSync(file, 'utf-8')); + console.log('Processing file:', file); + + const items = Array.isArray(yamlContent) ? yamlContent : [yamlContent]; + items.flatMap(extractFunctionsWithScope).forEach(({ name, scope }) => functionsMap[scope].add(name)); + }); + + const patterns = Object.entries(functionsMap) + .filter(([, namesSet]) => namesSet.size > 0) + .map(([scope, namesSet]) => ({ + match: `\\b(${Array.from(namesSet).join('|')})\\b`, + name: scope, + })); + + const baseGrammar = JSON.parse(fs.readFileSync(basePath, 'utf-8')); + baseGrammar.patterns = [...patterns, ...(baseGrammar.patterns || [])]; + + fs.writeFileSync(outputPath, JSON.stringify(baseGrammar, null, 2)); + console.log(`Done!`); +} + +generateTmLanguage(); diff --git a/web/mta_highlighting/generate-tmlanguage.cmd b/web/mta_highlighting/generate-tmlanguage.cmd new file mode 100644 index 00000000..c6fbeb32 --- /dev/null +++ b/web/mta_highlighting/generate-tmlanguage.cmd @@ -0,0 +1,3 @@ +@echo off +node generate-lua-tmlanguage.js +pause \ No newline at end of file diff --git a/web/mta_highlighting/lua-base.tmLanguage.json b/web/mta_highlighting/lua-base.tmLanguage.json new file mode 100644 index 00000000..3843abbe --- /dev/null +++ b/web/mta_highlighting/lua-base.tmLanguage.json @@ -0,0 +1,957 @@ +{ + "displayName": "Lua", + "name": "lua", + "patterns": [ + { + "begin": "\\b(?:(local)\\s+)?(function)\\b(?![,:])", + "beginCaptures": { + "1": { + "name": "keyword.local.lua" + }, + "2": { + "name": "keyword.control.lua" + } + }, + "end": "(?<=[-\\]\"')\\[{}])", + "name": "meta.function.lua", + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.parameters.begin.lua" + } + }, + "end": "(\\))|(?=[-\\]\"'.\\[{}])", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.finish.lua" + } + }, + "name": "meta.parameter.lua", + "patterns": [ + { + "include": "#comment" + }, + { + "match": "[A-Z_a-z][0-9A-Z_a-z]*", + "name": "variable.parameter.function.lua" + }, + { + "match": ",", + "name": "punctuation.separator.arguments.lua" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.arguments.lua" + } + }, + "end": "(?=[),])", + "patterns": [ + { + "include": "#emmydoc.type" + } + ] + } + ] + }, + { + "match": "\\b([A-Z_a-z][0-9A-Z_a-z]*)\\b\\s*(?=:)", + "name": "entity.name.class.lua" + }, + { + "match": "\\b([A-Z_a-z][0-9A-Z_a-z]*)\\b", + "name": "entity.name.function.lua" + } + ] + }, + { + "match": "(?" + }, + { + "match": "<[*A-Z_a-z][-*.0-9A-Z_a-z]*>", + "name": "storage.type.generic.lua" + }, + { + "match": "\\b(break|do|else|for|if|elseif|goto|return|then|repeat|while|until|end|in)\\b", + "name": "keyword.control.lua" + }, + { + "match": "\\b(local)\\b", + "name": "keyword.local.lua" + }, + { + "match": "\\b(function)\\b(?![,:])", + "name": "keyword.control.lua" + }, + { + "match": "(?=?|(?]", + "name": "keyword.operator.lua" + } + ] + }, + { + "begin": "(?<=---)[\\t ]*@see", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "match": "\\b([*A-Z_a-z][-*.0-9A-Z_a-z]*)", + "name": "support.class.lua" + }, + { + "match": "#", + "name": "keyword.operator.lua" + } + ] + }, + { + "begin": "(?<=---)[\\t ]*@diagnostic", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "begin": "([-0-9A-Z_a-z]+)[\\t ]*(:)?", + "beginCaptures": { + "1": { + "name": "keyword.other.unit" + }, + "2": { + "name": "keyword.operator.unit" + } + }, + "end": "(?=\\n)", + "patterns": [ + { + "match": "\\b([*A-Z_a-z][-0-9A-Z_a-z]*)", + "name": "support.class.lua" + }, + { + "match": ",", + "name": "keyword.operator.lua" + } + ] + } + ] + }, + { + "begin": "(?<=---)[\\t ]*@module", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "include": "#string" + } + ] + }, + { + "match": "(?<=---)[\\t ]*@(async|nodiscard)", + "name": "storage.type.annotation.lua" + }, + { + "begin": "(?<=---)\\|\\s*[+>]?", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "include": "#string" + } + ] + } + ] + }, + "emmydoc.type": { + "patterns": [ + { + "begin": "\\bfun\\b", + "beginCaptures": { + "0": { + "name": "keyword.control.lua" + } + }, + "end": "(?=[#\\s])", + "patterns": [ + { + "match": "[(),:?][\\t ]*", + "name": "keyword.operator.lua" + }, + { + "match": "([A-Z_a-z][-\\]*,.0-9<>A-\\[_a-z]*)(?", + "name": "storage.type.generic.lua" + }, + { + "match": "\\basync\\b", + "name": "entity.name.tag.lua" + }, + { + "match": "[,:?`{|}][\\t ]*", + "name": "keyword.operator.lua" + }, + { + "begin": "(?=[\"'*.A-\\[_a-z])", + "end": "(?=[#),:?|}\\s])", + "patterns": [ + { + "match": "([-\\]*,.0-9<>A-\\[_a-z]+)(?=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -1930,6 +1989,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/bare-events": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", @@ -2104,6 +2169,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/brotli": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", @@ -2368,6 +2442,20 @@ "node-fetch": "^2.7.0" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/crossws": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", @@ -2576,6 +2664,12 @@ "node": ">=4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -2879,6 +2973,22 @@ "unicode-trie": "^2.0.0" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -2923,6 +3033,29 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, + "node_modules/glob": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", + "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/h3": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.3.tgz", @@ -3546,6 +3679,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4723,6 +4877,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -4732,6 +4901,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -4956,6 +5134,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, "node_modules/package-manager-detector": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", @@ -5039,6 +5223,40 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -5150,9 +5368,9 @@ } }, "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", "license": "MIT", "dependencies": { "chownr": "^1.1.1", @@ -5747,6 +5965,27 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/shiki": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.4.2.tgz", @@ -5763,6 +6002,18 @@ "@types/hast": "^3.0.4" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -5933,6 +6184,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -5962,6 +6255,28 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -5990,9 +6305,9 @@ } }, "node_modules/tar-fs": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", - "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.9.tgz", + "integrity": "sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==", "license": "MIT", "dependencies": { "pump": "^3.0.0", @@ -6608,6 +6923,21 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", @@ -6649,6 +6979,80 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/web/package.json b/web/package.json index 5c6d6017..2d010e9b 100644 --- a/web/package.json +++ b/web/package.json @@ -13,6 +13,8 @@ "@astrojs/starlight": "^0.34.3", "@multitheftauto/starlight-theme-mtasa": "^1.4.1", "astro": "^5.7.13", + "glob": "^11.0.2", + "js-yaml": "^4.1.0", "marked": "^15.0.6", "sharp": "^0.32.5" }, diff --git a/web/src/grammars/lua-mta.tmLanguage.json b/web/src/grammars/lua-mta.tmLanguage.json new file mode 100644 index 00000000..459925bc --- /dev/null +++ b/web/src/grammars/lua-mta.tmLanguage.json @@ -0,0 +1,964 @@ +{ + "displayName": "Lua", + "name": "lua", + "patterns": [ + { + "match": "\\b(getPlayerName|setElementPosition|setElementHealth|getElementPosition|getElementHealth|showCursor|isCursorShowing)\\b", + "name": "support.function.mta-shared" + }, + { + "match": "\\b(setCursorPosition|setCursorAlpha|getCursorPosition|getCursorAlpha)\\b", + "name": "support.function.mta-client" + }, + { + "begin": "\\b(?:(local)\\s+)?(function)\\b(?![,:])", + "beginCaptures": { + "1": { + "name": "keyword.local.lua" + }, + "2": { + "name": "keyword.control.lua" + } + }, + "end": "(?<=[-\\]\"')\\[{}])", + "name": "meta.function.lua", + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.parameters.begin.lua" + } + }, + "end": "(\\))|(?=[-\\]\"'.\\[{}])", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.finish.lua" + } + }, + "name": "meta.parameter.lua", + "patterns": [ + { + "include": "#comment" + }, + { + "match": "[A-Z_a-z][0-9A-Z_a-z]*", + "name": "variable.parameter.function.lua" + }, + { + "match": ",", + "name": "punctuation.separator.arguments.lua" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.arguments.lua" + } + }, + "end": "(?=[),])", + "patterns": [ + { + "include": "#emmydoc.type" + } + ] + } + ] + }, + { + "match": "\\b([A-Z_a-z][0-9A-Z_a-z]*)\\b\\s*(?=:)", + "name": "entity.name.class.lua" + }, + { + "match": "\\b([A-Z_a-z][0-9A-Z_a-z]*)\\b", + "name": "entity.name.function.lua" + } + ] + }, + { + "match": "(?" + }, + { + "match": "<[*A-Z_a-z][-*.0-9A-Z_a-z]*>", + "name": "storage.type.generic.lua" + }, + { + "match": "\\b(break|do|else|for|if|elseif|goto|return|then|repeat|while|until|end|in)\\b", + "name": "keyword.control.lua" + }, + { + "match": "\\b(local)\\b", + "name": "keyword.local.lua" + }, + { + "match": "\\b(function)\\b(?![,:])", + "name": "keyword.control.lua" + }, + { + "match": "(?=?|(?]", + "name": "keyword.operator.lua" + } + ] + }, + { + "begin": "(?<=---)[\\t ]*@see", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "match": "\\b([*A-Z_a-z][-*.0-9A-Z_a-z]*)", + "name": "support.class.lua" + }, + { + "match": "#", + "name": "keyword.operator.lua" + } + ] + }, + { + "begin": "(?<=---)[\\t ]*@diagnostic", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "begin": "([-0-9A-Z_a-z]+)[\\t ]*(:)?", + "beginCaptures": { + "1": { + "name": "keyword.other.unit" + }, + "2": { + "name": "keyword.operator.unit" + } + }, + "end": "(?=\\n)", + "patterns": [ + { + "match": "\\b([*A-Z_a-z][-0-9A-Z_a-z]*)", + "name": "support.class.lua" + }, + { + "match": ",", + "name": "keyword.operator.lua" + } + ] + } + ] + }, + { + "begin": "(?<=---)[\\t ]*@module", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "include": "#string" + } + ] + }, + { + "match": "(?<=---)[\\t ]*@(async|nodiscard)", + "name": "storage.type.annotation.lua" + }, + { + "begin": "(?<=---)\\|\\s*[+>]?", + "beginCaptures": { + "0": { + "name": "storage.type.annotation.lua" + } + }, + "end": "(?=[\\n#@])", + "patterns": [ + { + "include": "#string" + } + ] + } + ] + }, + "emmydoc.type": { + "patterns": [ + { + "begin": "\\bfun\\b", + "beginCaptures": { + "0": { + "name": "keyword.control.lua" + } + }, + "end": "(?=[#\\s])", + "patterns": [ + { + "match": "[(),:?][\\t ]*", + "name": "keyword.operator.lua" + }, + { + "match": "([A-Z_a-z][-\\]*,.0-9<>A-\\[_a-z]*)(?", + "name": "storage.type.generic.lua" + }, + { + "match": "\\basync\\b", + "name": "entity.name.tag.lua" + }, + { + "match": "[,:?`{|}][\\t ]*", + "name": "keyword.operator.lua" + }, + { + "begin": "(?=[\"'*.A-\\[_a-z])", + "end": "(?=[#),:?|}\\s])", + "patterns": [ + { + "match": "([-\\]*,.0-9<>A-\\[_a-z]+)(? Date: Sat, 24 May 2025 17:11:19 +0200 Subject: [PATCH 2/7] auto run generate-lua-tmlanguage --- web/mta_highlighting/generate-lua-tmlanguage.js | 10 +++++++--- web/package.json | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/web/mta_highlighting/generate-lua-tmlanguage.js b/web/mta_highlighting/generate-lua-tmlanguage.js index 43438293..6bf59aea 100644 --- a/web/mta_highlighting/generate-lua-tmlanguage.js +++ b/web/mta_highlighting/generate-lua-tmlanguage.js @@ -2,10 +2,14 @@ import fs from 'fs'; import path from 'path'; import yaml from 'js-yaml'; import { glob } from 'glob'; +import { fileURLToPath } from 'url'; -const functionsDir = path.resolve('../../functions'); -const basePath = path.resolve('./lua-base.tmLanguage.json'); -const outputPath = path.resolve('../src/grammars/lua-mta.tmLanguage.json'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const functionsDir = path.resolve(__dirname, '../../functions'); +const basePath = path.resolve(__dirname, './lua-base.tmLanguage.json'); +const outputPath = path.resolve(__dirname, '../src/grammars/lua-mta.tmLanguage.json'); function extractFunctionsWithScope(yamlContent) { if (yamlContent.shared?.name) { diff --git a/web/package.json b/web/package.json index 2d010e9b..a250b09a 100644 --- a/web/package.json +++ b/web/package.json @@ -3,8 +3,10 @@ "type": "module", "version": "0.0.1", "scripts": { + "predev": "node mta_highlighting/generate-lua-tmlanguage.js", "dev": "astro dev", "start": "astro dev", + "prebuild": "node mta_highlighting/generate-lua-tmlanguage.js", "build": "astro build", "preview": "astro preview", "astro": "astro" From e48cd01eb2f88f69ff35eee6803d783c5a117498 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 24 May 2025 17:14:07 +0200 Subject: [PATCH 3/7] Fix syntax highlight --- web/src/pages/[func].astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/pages/[func].astro b/web/src/pages/[func].astro index efe303a7..d5457a4e 100644 --- a/web/src/pages/[func].astro +++ b/web/src/pages/[func].astro @@ -123,7 +123,7 @@ let funcSyntaxes = parseFunctionSyntaxes(func.id, func.data); ) || (

{syntax.type.charAt(0).toUpperCase() + syntax.type.slice(1)} Syntax

)} - + {syntax.parameters.length > 0 && ( <> {syntax.parameters.some((param: any) => !param.default) && ( From ff0f65b5e325c6c0a2dad86e67082143ee769bd1 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 24 May 2025 21:34:28 +0200 Subject: [PATCH 4/7] Clickable keywords and functions --- web/astro.config.mjs | 13 ------ web/ec.config.mjs | 17 ++++++++ .../generate-lua-tmlanguage.js | 9 ++++ web/public/mta-keywords_linker.js | 41 +++++++++++++++++++ web/src/components/CodeExamplesSection.astro | 2 + web/src/grammars/lua-mta.tmLanguage.json | 4 ++ web/src/styles/custom.css | 9 ++++ web/src/themes/mtasa_lua-theme_dark.json | 8 ++++ web/src/themes/mtasa_lua-theme_light.json | 9 ++++ 9 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 web/ec.config.mjs create mode 100644 web/public/mta-keywords_linker.js diff --git a/web/astro.config.mjs b/web/astro.config.mjs index e821effe..6023884d 100644 --- a/web/astro.config.mjs +++ b/web/astro.config.mjs @@ -15,19 +15,6 @@ export default defineConfig({ }, integrations: [ starlight({ - expressiveCode: { - themes: [JSON.parse(fs.readFileSync('./src/themes/mtasa_lua-theme_dark.json', 'utf-8')), JSON.parse(fs.readFileSync('./src/themes/mtasa_lua-theme_light.json', 'utf-8'))], - shiki: { - langs: [ - { - id: 'lua', - scopeName: 'source.lua.mta', - ...JSON.parse(fs.readFileSync('./src/grammars/lua-mta.tmLanguage.json', 'utf-8')), - }, - ], - }, - }, - plugins: [ mtasaStarlightThemePlugin(), ], diff --git a/web/ec.config.mjs b/web/ec.config.mjs new file mode 100644 index 00000000..adcf63a3 --- /dev/null +++ b/web/ec.config.mjs @@ -0,0 +1,17 @@ +import fs from 'fs'; + +export default { + themes: [ + JSON.parse(fs.readFileSync('./src/themes/mtasa_lua-theme_dark.json', 'utf-8')), + JSON.parse(fs.readFileSync('./src/themes/mtasa_lua-theme_light.json', 'utf-8')), + ], + shiki: { + langs: [ + { + id: 'lua', + scopeName: 'source.lua.mta', + ...JSON.parse(fs.readFileSync('./src/grammars/lua-mta.tmLanguage.json', 'utf-8')), + }, + ], + }, +}; diff --git a/web/mta_highlighting/generate-lua-tmlanguage.js b/web/mta_highlighting/generate-lua-tmlanguage.js index 6bf59aea..97fe2fea 100644 --- a/web/mta_highlighting/generate-lua-tmlanguage.js +++ b/web/mta_highlighting/generate-lua-tmlanguage.js @@ -11,6 +11,8 @@ const functionsDir = path.resolve(__dirname, '../../functions'); const basePath = path.resolve(__dirname, './lua-base.tmLanguage.json'); const outputPath = path.resolve(__dirname, '../src/grammars/lua-mta.tmLanguage.json'); +const mtaKeywords = ['string','bool','boolean','number','int','float','element','player','vehicle','ped','object','building']; + function extractFunctionsWithScope(yamlContent) { if (yamlContent.shared?.name) { return [{ name: yamlContent.shared.name, scope: 'support.function.mta-shared' }]; @@ -44,6 +46,13 @@ async function generateTmLanguage() { name: scope, })); + if (mtaKeywords.length > 0) { + patterns.push({ + match: `\\b(${mtaKeywords.join('|')})\\b`, + name: 'keyword.mta', + }); + } + const baseGrammar = JSON.parse(fs.readFileSync(basePath, 'utf-8')); baseGrammar.patterns = [...patterns, ...(baseGrammar.patterns || [])]; diff --git a/web/public/mta-keywords_linker.js b/web/public/mta-keywords_linker.js new file mode 100644 index 00000000..599e3ff3 --- /dev/null +++ b/web/public/mta-keywords_linker.js @@ -0,0 +1,41 @@ +import tmLanguage from "../src/grammars/lua-mta.tmLanguage.json"; + +function extractFunctions() { + const wantedScopes = new Set([ + "support.function.mta-shared", + "support.function.mta-server", + "support.function.mta-client", + 'keyword.mta' + ]); + + return tmLanguage.patterns?.reduce((funcs, { match, name }) => { + if (match && wantedScopes.has(name)) { + funcs.push(...match.match(/\\b\(([^)]+)\)\\b/)?.[1]?.split("|") || []); + } + return funcs; + }, []) || []; +} + +const allFunctions = new Set(extractFunctions()); + +function initKeywordLinker() { + function onDomReady() { + const spans = [ + ...document.querySelectorAll(".examples-section .code-example pre code span"), + ...document.querySelectorAll(".function-syntax span, .expressive-code span") + ]; + + spans.forEach(span => { + const text = span.textContent; + if (allFunctions.has(text)) { + span.innerHTML = `${text}`; + } + }); + } + + document.readyState === "loading" + ? window.addEventListener("DOMContentLoaded", onDomReady) + : onDomReady(); +} + +initKeywordLinker(); diff --git a/web/src/components/CodeExamplesSection.astro b/web/src/components/CodeExamplesSection.astro index e4f63c41..caf98112 100644 --- a/web/src/components/CodeExamplesSection.astro +++ b/web/src/components/CodeExamplesSection.astro @@ -27,3 +27,5 @@ const { codeExamples } = Astro.props; ))} )} + + diff --git a/web/src/grammars/lua-mta.tmLanguage.json b/web/src/grammars/lua-mta.tmLanguage.json index 459925bc..7239f464 100644 --- a/web/src/grammars/lua-mta.tmLanguage.json +++ b/web/src/grammars/lua-mta.tmLanguage.json @@ -10,6 +10,10 @@ "match": "\\b(setCursorPosition|setCursorAlpha|getCursorPosition|getCursorAlpha)\\b", "name": "support.function.mta-client" }, + { + "match": "\\b(string|bool|boolean|number|int|float|element|player|vehicle|ped|object|building)\\b", + "name": "keyword.mta" + }, { "begin": "\\b(?:(local)\\s+)?(function)\\b(?![,:])", "beginCaptures": { diff --git a/web/src/styles/custom.css b/web/src/styles/custom.css index 31372848..c40df4fa 100644 --- a/web/src/styles/custom.css +++ b/web/src/styles/custom.css @@ -46,3 +46,12 @@ .side-server { color: var(--color-type-server); } + +.mta-keyword-link { + color: inherit; + text-decoration: none; +} + +.mta-keyword-link:hover { + font-weight: 100; +} \ No newline at end of file diff --git a/web/src/themes/mtasa_lua-theme_dark.json b/web/src/themes/mtasa_lua-theme_dark.json index 5f6f2587..0ff81353 100644 --- a/web/src/themes/mtasa_lua-theme_dark.json +++ b/web/src/themes/mtasa_lua-theme_dark.json @@ -47,6 +47,14 @@ } }, + { + "scope": "keyword.mta", + "settings": { + "foreground": "#6edbdb", + "fontStyle": "bold" + } + }, + { "scope": "meta.function.lua", "settings": { diff --git a/web/src/themes/mtasa_lua-theme_light.json b/web/src/themes/mtasa_lua-theme_light.json index e54d9978..1f7b8529 100644 --- a/web/src/themes/mtasa_lua-theme_light.json +++ b/web/src/themes/mtasa_lua-theme_light.json @@ -42,6 +42,15 @@ "fontStyle": "bold" } }, + + { + "scope": "keyword.mta", + "settings": { + "foreground": "#6edb9a", + "fontStyle": "bold" + } + }, + { "scope": "meta.function.lua", "settings": { From 9ed8a7944016c7cace6c070c49b1221fc052def1 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 24 May 2025 22:12:54 +0200 Subject: [PATCH 5/7] Ignore tmLanguage --- web/.gitignore | 3 + web/src/grammars/lua-mta.tmLanguage.json | 968 ----------------------- 2 files changed, 3 insertions(+), 968 deletions(-) delete mode 100644 web/src/grammars/lua-mta.tmLanguage.json diff --git a/web/.gitignore b/web/.gitignore index 6240da8b..c0cec659 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -19,3 +19,6 @@ pnpm-debug.log* # macOS-specific files .DS_Store + +# tmLanguage file +src/grammars/ \ No newline at end of file diff --git a/web/src/grammars/lua-mta.tmLanguage.json b/web/src/grammars/lua-mta.tmLanguage.json deleted file mode 100644 index 7239f464..00000000 --- a/web/src/grammars/lua-mta.tmLanguage.json +++ /dev/null @@ -1,968 +0,0 @@ -{ - "displayName": "Lua", - "name": "lua", - "patterns": [ - { - "match": "\\b(getPlayerName|setElementPosition|setElementHealth|getElementPosition|getElementHealth|showCursor|isCursorShowing)\\b", - "name": "support.function.mta-shared" - }, - { - "match": "\\b(setCursorPosition|setCursorAlpha|getCursorPosition|getCursorAlpha)\\b", - "name": "support.function.mta-client" - }, - { - "match": "\\b(string|bool|boolean|number|int|float|element|player|vehicle|ped|object|building)\\b", - "name": "keyword.mta" - }, - { - "begin": "\\b(?:(local)\\s+)?(function)\\b(?![,:])", - "beginCaptures": { - "1": { - "name": "keyword.local.lua" - }, - "2": { - "name": "keyword.control.lua" - } - }, - "end": "(?<=[-\\]\"')\\[{}])", - "name": "meta.function.lua", - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(\\()", - "beginCaptures": { - "1": { - "name": "punctuation.definition.parameters.begin.lua" - } - }, - "end": "(\\))|(?=[-\\]\"'.\\[{}])", - "endCaptures": { - "1": { - "name": "punctuation.definition.parameters.finish.lua" - } - }, - "name": "meta.parameter.lua", - "patterns": [ - { - "include": "#comment" - }, - { - "match": "[A-Z_a-z][0-9A-Z_a-z]*", - "name": "variable.parameter.function.lua" - }, - { - "match": ",", - "name": "punctuation.separator.arguments.lua" - }, - { - "begin": ":", - "beginCaptures": { - "0": { - "name": "punctuation.separator.arguments.lua" - } - }, - "end": "(?=[),])", - "patterns": [ - { - "include": "#emmydoc.type" - } - ] - } - ] - }, - { - "match": "\\b([A-Z_a-z][0-9A-Z_a-z]*)\\b\\s*(?=:)", - "name": "entity.name.class.lua" - }, - { - "match": "\\b([A-Z_a-z][0-9A-Z_a-z]*)\\b", - "name": "entity.name.function.lua" - } - ] - }, - { - "match": "(?" - }, - { - "match": "<[*A-Z_a-z][-*.0-9A-Z_a-z]*>", - "name": "storage.type.generic.lua" - }, - { - "match": "\\b(break|do|else|for|if|elseif|goto|return|then|repeat|while|until|end|in)\\b", - "name": "keyword.control.lua" - }, - { - "match": "\\b(local)\\b", - "name": "keyword.local.lua" - }, - { - "match": "\\b(function)\\b(?![,:])", - "name": "keyword.control.lua" - }, - { - "match": "(?=?|(?]", - "name": "keyword.operator.lua" - } - ] - }, - { - "begin": "(?<=---)[\\t ]*@see", - "beginCaptures": { - "0": { - "name": "storage.type.annotation.lua" - } - }, - "end": "(?=[\\n#@])", - "patterns": [ - { - "match": "\\b([*A-Z_a-z][-*.0-9A-Z_a-z]*)", - "name": "support.class.lua" - }, - { - "match": "#", - "name": "keyword.operator.lua" - } - ] - }, - { - "begin": "(?<=---)[\\t ]*@diagnostic", - "beginCaptures": { - "0": { - "name": "storage.type.annotation.lua" - } - }, - "end": "(?=[\\n#@])", - "patterns": [ - { - "begin": "([-0-9A-Z_a-z]+)[\\t ]*(:)?", - "beginCaptures": { - "1": { - "name": "keyword.other.unit" - }, - "2": { - "name": "keyword.operator.unit" - } - }, - "end": "(?=\\n)", - "patterns": [ - { - "match": "\\b([*A-Z_a-z][-0-9A-Z_a-z]*)", - "name": "support.class.lua" - }, - { - "match": ",", - "name": "keyword.operator.lua" - } - ] - } - ] - }, - { - "begin": "(?<=---)[\\t ]*@module", - "beginCaptures": { - "0": { - "name": "storage.type.annotation.lua" - } - }, - "end": "(?=[\\n#@])", - "patterns": [ - { - "include": "#string" - } - ] - }, - { - "match": "(?<=---)[\\t ]*@(async|nodiscard)", - "name": "storage.type.annotation.lua" - }, - { - "begin": "(?<=---)\\|\\s*[+>]?", - "beginCaptures": { - "0": { - "name": "storage.type.annotation.lua" - } - }, - "end": "(?=[\\n#@])", - "patterns": [ - { - "include": "#string" - } - ] - } - ] - }, - "emmydoc.type": { - "patterns": [ - { - "begin": "\\bfun\\b", - "beginCaptures": { - "0": { - "name": "keyword.control.lua" - } - }, - "end": "(?=[#\\s])", - "patterns": [ - { - "match": "[(),:?][\\t ]*", - "name": "keyword.operator.lua" - }, - { - "match": "([A-Z_a-z][-\\]*,.0-9<>A-\\[_a-z]*)(?", - "name": "storage.type.generic.lua" - }, - { - "match": "\\basync\\b", - "name": "entity.name.tag.lua" - }, - { - "match": "[,:?`{|}][\\t ]*", - "name": "keyword.operator.lua" - }, - { - "begin": "(?=[\"'*.A-\\[_a-z])", - "end": "(?=[#),:?|}\\s])", - "patterns": [ - { - "match": "([-\\]*,.0-9<>A-\\[_a-z]+)(? Date: Sun, 25 May 2025 15:15:33 +0200 Subject: [PATCH 6/7] Fix clickable keywords on build --- web/mta_highlighting/generate-lua-tmlanguage.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/mta_highlighting/generate-lua-tmlanguage.js b/web/mta_highlighting/generate-lua-tmlanguage.js index 97fe2fea..269020e1 100644 --- a/web/mta_highlighting/generate-lua-tmlanguage.js +++ b/web/mta_highlighting/generate-lua-tmlanguage.js @@ -10,6 +10,7 @@ const __dirname = path.dirname(__filename); const functionsDir = path.resolve(__dirname, '../../functions'); const basePath = path.resolve(__dirname, './lua-base.tmLanguage.json'); const outputPath = path.resolve(__dirname, '../src/grammars/lua-mta.tmLanguage.json'); +const publicPath = path.resolve(__dirname, '../public/lua-mta.tmLanguage.json'); const mtaKeywords = ['string','bool','boolean','number','int','float','element','player','vehicle','ped','object','building']; @@ -57,6 +58,10 @@ async function generateTmLanguage() { baseGrammar.patterns = [...patterns, ...(baseGrammar.patterns || [])]; fs.writeFileSync(outputPath, JSON.stringify(baseGrammar, null, 2)); + + // Create file also in public directory for clickable keywords (public/mta-keywords_linker.js) + fs.copyFileSync(outputPath, publicPath); + console.log(`Done!`); } From 5f842ccfe1bb4c54b804ba7a8f58efb14054f6d4 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 25 May 2025 15:27:41 +0200 Subject: [PATCH 7/7] Update mta-keywords_linker.js --- web/public/mta-keywords_linker.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/web/public/mta-keywords_linker.js b/web/public/mta-keywords_linker.js index 599e3ff3..2eb91d45 100644 --- a/web/public/mta-keywords_linker.js +++ b/web/public/mta-keywords_linker.js @@ -1,11 +1,11 @@ -import tmLanguage from "../src/grammars/lua-mta.tmLanguage.json"; +let allFunctions = new Set(); -function extractFunctions() { +function extractFunctions(tmLanguage) { const wantedScopes = new Set([ "support.function.mta-shared", "support.function.mta-server", "support.function.mta-client", - 'keyword.mta' + "keyword.mta" ]); return tmLanguage.patterns?.reduce((funcs, { match, name }) => { @@ -16,8 +16,6 @@ function extractFunctions() { }, []) || []; } -const allFunctions = new Set(extractFunctions()); - function initKeywordLinker() { function onDomReady() { const spans = [ @@ -33,9 +31,15 @@ function initKeywordLinker() { }); } - document.readyState === "loading" - ? window.addEventListener("DOMContentLoaded", onDomReady) - : onDomReady(); + fetch('/lua-mta.tmLanguage.json') + .then(res => res.json()) + .then(json => { + allFunctions = new Set(extractFunctions(json)); + document.readyState === "loading" + ? window.addEventListener("DOMContentLoaded", onDomReady) + : onDomReady(); + }) + .catch(err => console.error("Failed to load JSON grammar:", err)); } initKeywordLinker();