Initial Commit
This commit is contained in:
commit
639b0f451d
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/
|
||||||
|
out/
|
30
.vscode/launch.json
vendored
Normal file
30
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Client",
|
||||||
|
"runtimeExecutable": "${execPath}",
|
||||||
|
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
|
||||||
|
"outFiles": ["${workspaceRoot}/client/out/**/*.js"],
|
||||||
|
"preLaunchTask": {
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Language Server E2E Test",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "${execPath}",
|
||||||
|
"args": [
|
||||||
|
"--extensionDevelopmentPath=${workspaceRoot}",
|
||||||
|
"--extensionTestsPath=${workspaceRoot}/client/out/test/index",
|
||||||
|
"${workspaceRoot}/client/testFixture"
|
||||||
|
],
|
||||||
|
"outFiles": ["${workspaceRoot}/client/out/test/**/*.js"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
2
.vscode/settings.json
vendored
Normal file
2
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{
|
||||||
|
}
|
33
.vscode/tasks.json
vendored
Normal file
33
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "compile",
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"panel": "dedicated",
|
||||||
|
"reveal": "never"
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$tsc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch",
|
||||||
|
"isBackground": true,
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"panel": "dedicated",
|
||||||
|
"reveal": "never"
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$tsc-watch"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
.vscodeignore
Normal file
4
.vscodeignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.vscode/**
|
||||||
|
.vscode-test/**
|
||||||
|
.gitignore
|
||||||
|
vsc-extension-quickstart.md
|
28
CHANGELOG.md
Normal file
28
CHANGELOG.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to the "openquest" extension will be documented in this file.
|
||||||
|
|
||||||
|
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
- Initial release
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
Added features X, Y, and Z.
|
||||||
|
|
||||||
|
---
|
29
README.md
Normal file
29
README.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# OpenQuest
|
||||||
|
A Language extension for the Quest language, a DSL for mission scripting (Metin2)
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
Supports mostly all known tipical features like:
|
||||||
|
- Quest Language Highlighting and formatting
|
||||||
|
- Lua Language embedded in respective Quest scopes
|
||||||
|
- [OpenQuest Language Server support](https://github.com/oridevteam/openquest-rs)
|
||||||
|
- Language Server connections (local and remote)
|
||||||
|
|
||||||
|
|
||||||
|
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
|
||||||
|
|
||||||
|
For example if there is an image subfolder under your extension project workspace:
|
||||||
|
|
||||||
|
\!\[feature X\]\(images/feature-x.png\)
|
||||||
|
|
||||||
|
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
The extension is able to provide everything necessary by itself,
|
||||||
|
however you can check its Settings for things you might want to change to your own
|
||||||
|
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
Nothing quite yet
|
||||||
|
|
23
client/package.json
Normal file
23
client/package.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "openquest-lsp-client",
|
||||||
|
"description": "OpenQuest VSC LSP CLient",
|
||||||
|
"author": "openquest",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publisher": "vscode",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.75.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vscode-languageclient": "^8.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.2.5",
|
||||||
|
"@types/vscode": "^1.75.1",
|
||||||
|
"@vscode/test-electron": "^2.2.3"
|
||||||
|
}
|
||||||
|
}
|
354
client/pnpm-lock.yaml
Normal file
354
client/pnpm-lock.yaml
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
lockfileVersion: '6.1'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
vscode-languageclient:
|
||||||
|
specifier: ^8.1.0
|
||||||
|
version: 8.1.0
|
||||||
|
|
||||||
|
devDependencies:
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^20.2.5
|
||||||
|
version: 20.2.5
|
||||||
|
'@types/vscode':
|
||||||
|
specifier: ^1.75.1
|
||||||
|
version: 1.75.1
|
||||||
|
'@vscode/test-electron':
|
||||||
|
specifier: ^2.2.3
|
||||||
|
version: 2.2.3
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
/@tootallnate/once@1.1.2:
|
||||||
|
resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/node@20.2.5:
|
||||||
|
resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/vscode@1.75.1:
|
||||||
|
resolution: {integrity: sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@vscode/test-electron@2.2.3:
|
||||||
|
resolution: {integrity: sha512-7DmdGYQTqRNaLHKG3j56buc9DkstriY4aV0S3Zj32u0U9/T0L8vwWAC9QGCh1meu1VXDEla1ze27TkqysHGP0Q==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
dependencies:
|
||||||
|
http-proxy-agent: 4.0.1
|
||||||
|
https-proxy-agent: 5.0.1
|
||||||
|
rimraf: 3.0.2
|
||||||
|
unzipper: 0.10.14
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/agent-base@6.0.2:
|
||||||
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
|
engines: {node: '>= 6.0.0'}
|
||||||
|
dependencies:
|
||||||
|
debug: 4.3.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/balanced-match@1.0.2:
|
||||||
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
|
/big-integer@1.6.51:
|
||||||
|
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/binary@0.3.0:
|
||||||
|
resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==}
|
||||||
|
dependencies:
|
||||||
|
buffers: 0.1.1
|
||||||
|
chainsaw: 0.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/bluebird@3.4.7:
|
||||||
|
resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/brace-expansion@1.1.11:
|
||||||
|
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||||
|
dependencies:
|
||||||
|
balanced-match: 1.0.2
|
||||||
|
concat-map: 0.0.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/brace-expansion@2.0.1:
|
||||||
|
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
|
||||||
|
dependencies:
|
||||||
|
balanced-match: 1.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/buffer-indexof-polyfill@1.0.2:
|
||||||
|
resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/buffers@0.1.1:
|
||||||
|
resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==}
|
||||||
|
engines: {node: '>=0.2.0'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/chainsaw@0.1.0:
|
||||||
|
resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==}
|
||||||
|
dependencies:
|
||||||
|
traverse: 0.3.9
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/concat-map@0.0.1:
|
||||||
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/core-util-is@1.0.3:
|
||||||
|
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/debug@4.3.4:
|
||||||
|
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||||
|
engines: {node: '>=6.0'}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
ms: 2.1.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/duplexer2@0.1.4:
|
||||||
|
resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==}
|
||||||
|
dependencies:
|
||||||
|
readable-stream: 2.3.8
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/fs.realpath@1.0.0:
|
||||||
|
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/fstream@1.0.12:
|
||||||
|
resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
inherits: 2.0.4
|
||||||
|
mkdirp: 0.5.6
|
||||||
|
rimraf: 2.7.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/glob@7.2.3:
|
||||||
|
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||||
|
dependencies:
|
||||||
|
fs.realpath: 1.0.0
|
||||||
|
inflight: 1.0.6
|
||||||
|
inherits: 2.0.4
|
||||||
|
minimatch: 3.1.2
|
||||||
|
once: 1.4.0
|
||||||
|
path-is-absolute: 1.0.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/graceful-fs@4.2.11:
|
||||||
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/http-proxy-agent@4.0.1:
|
||||||
|
resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dependencies:
|
||||||
|
'@tootallnate/once': 1.1.2
|
||||||
|
agent-base: 6.0.2
|
||||||
|
debug: 4.3.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/https-proxy-agent@5.0.1:
|
||||||
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dependencies:
|
||||||
|
agent-base: 6.0.2
|
||||||
|
debug: 4.3.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/inflight@1.0.6:
|
||||||
|
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||||
|
dependencies:
|
||||||
|
once: 1.4.0
|
||||||
|
wrappy: 1.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/inherits@2.0.4:
|
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/isarray@1.0.0:
|
||||||
|
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/listenercount@1.0.1:
|
||||||
|
resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/lru-cache@6.0.0:
|
||||||
|
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
yallist: 4.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/minimatch@3.1.2:
|
||||||
|
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: 1.1.11
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/minimatch@5.1.6:
|
||||||
|
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: 2.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/minimist@1.2.8:
|
||||||
|
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/mkdirp@0.5.6:
|
||||||
|
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
minimist: 1.2.8
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/ms@2.1.2:
|
||||||
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/once@1.4.0:
|
||||||
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||||
|
dependencies:
|
||||||
|
wrappy: 1.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/path-is-absolute@1.0.1:
|
||||||
|
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/process-nextick-args@2.0.1:
|
||||||
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/readable-stream@2.3.8:
|
||||||
|
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||||
|
dependencies:
|
||||||
|
core-util-is: 1.0.3
|
||||||
|
inherits: 2.0.4
|
||||||
|
isarray: 1.0.0
|
||||||
|
process-nextick-args: 2.0.1
|
||||||
|
safe-buffer: 5.1.2
|
||||||
|
string_decoder: 1.1.1
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/rimraf@2.7.1:
|
||||||
|
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
glob: 7.2.3
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/rimraf@3.0.2:
|
||||||
|
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
glob: 7.2.3
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/safe-buffer@5.1.2:
|
||||||
|
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/semver@7.5.1:
|
||||||
|
resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
lru-cache: 6.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/setimmediate@1.0.5:
|
||||||
|
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/string_decoder@1.1.1:
|
||||||
|
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.1.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/traverse@0.3.9:
|
||||||
|
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/unzipper@0.10.14:
|
||||||
|
resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==}
|
||||||
|
dependencies:
|
||||||
|
big-integer: 1.6.51
|
||||||
|
binary: 0.3.0
|
||||||
|
bluebird: 3.4.7
|
||||||
|
buffer-indexof-polyfill: 1.0.2
|
||||||
|
duplexer2: 0.1.4
|
||||||
|
fstream: 1.0.12
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
listenercount: 1.0.1
|
||||||
|
readable-stream: 2.3.8
|
||||||
|
setimmediate: 1.0.5
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/util-deprecate@1.0.2:
|
||||||
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/vscode-jsonrpc@8.1.0:
|
||||||
|
resolution: {integrity: sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/vscode-languageclient@8.1.0:
|
||||||
|
resolution: {integrity: sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==}
|
||||||
|
engines: {vscode: ^1.67.0}
|
||||||
|
dependencies:
|
||||||
|
minimatch: 5.1.6
|
||||||
|
semver: 7.5.1
|
||||||
|
vscode-languageserver-protocol: 3.17.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/vscode-languageserver-protocol@3.17.3:
|
||||||
|
resolution: {integrity: sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==}
|
||||||
|
dependencies:
|
||||||
|
vscode-jsonrpc: 8.1.0
|
||||||
|
vscode-languageserver-types: 3.17.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/vscode-languageserver-types@3.17.3:
|
||||||
|
resolution: {integrity: sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/wrappy@1.0.2:
|
||||||
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/yallist@4.0.0:
|
||||||
|
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||||
|
dev: false
|
275
client/src/client_handler.ts
Normal file
275
client/src/client_handler.ts
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
// Local Imports
|
||||||
|
import constants = require("./constants");
|
||||||
|
import { clients, outputChannel } from "./extension";
|
||||||
|
import * as server_binary from "./server_binary";
|
||||||
|
|
||||||
|
// External Imports
|
||||||
|
import { Duplex } from "stream";
|
||||||
|
import WebSocket, { createWebSocketStream } from 'ws';
|
||||||
|
import {
|
||||||
|
ExtensionContext, RelativePattern, WorkspaceFolder,
|
||||||
|
WorkspaceFoldersChangeEvent, workspace
|
||||||
|
} from "vscode";
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import { LanguageClient, StreamInfo, integer } from "vscode-languageclient/node";
|
||||||
|
import { ServerOptions } from 'vscode-languageclient/node';
|
||||||
|
import { TextDocument, Uri } from 'vscode';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async function openDocument(uri: Uri) {
|
||||||
|
const uriMatch = (d: TextDocument) => d.uri.toString() === uri.toString();
|
||||||
|
const doc = vscode.workspace.textDocuments.find(uriMatch);
|
||||||
|
|
||||||
|
if (doc === undefined) await vscode.workspace.openTextDocument(uri);
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async function openPestFilesInFolder(folder: Uri) {
|
||||||
|
const pattern = filesInFolderPattern(folder);
|
||||||
|
const uris = await workspace.findFiles(pattern);
|
||||||
|
|
||||||
|
return Promise.all(uris.map(openDocument));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function filesInFolderPattern(folder: Uri) {
|
||||||
|
return new RelativePattern(folder, constants.DOCUMENT_EXTENSION_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export async function startClientsForFolder(folder: WorkspaceFolder, ctx: ExtensionContext) {
|
||||||
|
// Settings on how to setup and connect the server
|
||||||
|
let serverOptions = await makeServerOptions();
|
||||||
|
|
||||||
|
if (!serverOptions) {
|
||||||
|
outputChannel.appendLine("[ERROR] Aborting server start.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
await window.showErrorMessage(
|
||||||
|
"Not starting Pest Language Server as a suitable binary was not found."
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = folder.uri;
|
||||||
|
|
||||||
|
const deleteWatcher = workspace.createFileSystemWatcher(
|
||||||
|
filesInFolderPattern(root),
|
||||||
|
true, // ignoreCreateEvents
|
||||||
|
true, // ignoreChangeEvents
|
||||||
|
false // ignoreDeleteEvents
|
||||||
|
);
|
||||||
|
|
||||||
|
const createChangeWatcher = workspace.createFileSystemWatcher(
|
||||||
|
filesInFolderPattern(root),
|
||||||
|
false, // ignoreCreateEvents
|
||||||
|
false, // ignoreChangeEvents
|
||||||
|
true // ignoreDeleteEvents
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.subscriptions.push(deleteWatcher);
|
||||||
|
ctx.subscriptions.push(createChangeWatcher);
|
||||||
|
|
||||||
|
const client = new LanguageClient(
|
||||||
|
constants.EXTENSION_NAME,
|
||||||
|
serverOptions,
|
||||||
|
{
|
||||||
|
documentSelector: [
|
||||||
|
{
|
||||||
|
language: constants.LANGUAGE_ID,
|
||||||
|
pattern: `${root.fsPath}/${constants.DOCUMENT_EXTENSION_PATTERN}`
|
||||||
|
},
|
||||||
|
],
|
||||||
|
synchronize: { fileEvents: deleteWatcher },
|
||||||
|
diagnosticCollectionName: constants.EXTENSION_NAME,
|
||||||
|
workspaceFolder: folder,
|
||||||
|
outputChannel,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
client.start(); // ctx.subscriptions.push(client.start());
|
||||||
|
ctx.subscriptions.push(createChangeWatcher.onDidCreate(openDocument));
|
||||||
|
ctx.subscriptions.push(createChangeWatcher.onDidChange(openDocument));
|
||||||
|
|
||||||
|
const openedFiles = await openPestFilesInFolder(root);
|
||||||
|
const pestFiles: Set<string> = new Set();
|
||||||
|
|
||||||
|
openedFiles.forEach(f => pestFiles.add(f.toString()));
|
||||||
|
clients.set(root.toString(), client);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes Language Server options based on workspace settings, it might:
|
||||||
|
* - Try to find where a executable path is in package managers install paths
|
||||||
|
* - Find a given executable by path in given workspace settings
|
||||||
|
* - Connect to an existing language server websocket on an address
|
||||||
|
*/
|
||||||
|
async function makeServerOptions(): Promise<ServerOptions | undefined> {
|
||||||
|
const workspaceConfig = vscode.workspace.getConfiguration(constants.SETTINGS_NAMESPACE);
|
||||||
|
const customArgs = workspaceConfig.get("serverArguments") as string[];
|
||||||
|
|
||||||
|
// Make either a configuration to spawn a server locally
|
||||||
|
// or connect to an existing local or remote one
|
||||||
|
switch (workspaceConfig.get("handlingMode")) {
|
||||||
|
// Tries to find a language server executable from known package managers
|
||||||
|
// and spawns it
|
||||||
|
case "Automatic (Package Manager)":
|
||||||
|
const serverPath = await server_binary.findLanguageServerPath();
|
||||||
|
const automaticOptions: ServerOptions = {
|
||||||
|
command: serverPath, args: customArgs
|
||||||
|
};
|
||||||
|
|
||||||
|
return automaticOptions;
|
||||||
|
|
||||||
|
// Finds specified language server in path and spawns it
|
||||||
|
case "Local Path":
|
||||||
|
const command: string = workspaceConfig.get("serverBinaryPath");
|
||||||
|
|
||||||
|
let serverOptions: ServerOptions = {
|
||||||
|
command, args: customArgs
|
||||||
|
};
|
||||||
|
|
||||||
|
return serverOptions;
|
||||||
|
|
||||||
|
// Connect to a websocket by specified address in settings
|
||||||
|
case "Remote/Local Connection":
|
||||||
|
const addr: string = workspaceConfig.get("serverAddress");
|
||||||
|
|
||||||
|
return websocketServerOptions(addr);
|
||||||
|
|
||||||
|
default:
|
||||||
|
vscode.window.showErrorMessage("[ERROR] Something that shouldn't error, errored!")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function ipcSocketServerOptions(pid: number) {
|
||||||
|
var child_process = require("child_process");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param pid
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function pipeLanguageServer(pid: number): StreamInfo {
|
||||||
|
var child_process = require("child_process");
|
||||||
|
|
||||||
|
// Obtain the stdin and stdout streams of the preexisting process using its PID
|
||||||
|
const languageServerProcess = child_process.spawn('sh', ['-c', `exec ${pid}>&0 <&${pid} 2>&1`], {
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a StreamInfo object with the input/output streams of the language server process
|
||||||
|
const streamInfo: StreamInfo = {
|
||||||
|
writer: languageServerProcess.stdin,
|
||||||
|
reader: languageServerProcess.stdout
|
||||||
|
};
|
||||||
|
|
||||||
|
return streamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generaters server options with a websocket ready connection
|
||||||
|
* @param address
|
||||||
|
*/
|
||||||
|
function websocketServerOptions(address: string): ServerOptions {
|
||||||
|
function connectToServer(hostname: string): Duplex {
|
||||||
|
const socket = new WebSocket(`ws://${hostname}/`);
|
||||||
|
|
||||||
|
const stream = createWebSocketStream(socket);
|
||||||
|
|
||||||
|
stream.on('error', (e) => {
|
||||||
|
outputChannel.appendLine(`[WS] Could not connect: ${e.message}`);
|
||||||
|
});
|
||||||
|
stream.on('open', (e) => outputChannel.appendLine(`[WS] Connected: ${e.message}`))
|
||||||
|
stream.on("data", function (chunk) {
|
||||||
|
console.log(new TextDecoder().decode(chunk));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (socket && (socket.readyState === WebSocket.CONNECTING)) {
|
||||||
|
// TODO: Delay execution while socket is connecting for a bit
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket && (socket.readyState === WebSocket.CONNECTING || socket.readyState === WebSocket.CLOSING)) {
|
||||||
|
outputChannel.append("[WS] Not connected:")
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
let connection = connectToServer(address);
|
||||||
|
|
||||||
|
return () => Promise.resolve({
|
||||||
|
reader: connection,
|
||||||
|
writer: connection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function stopClient(client: LanguageClient) {
|
||||||
|
client.diagnostics?.clear();
|
||||||
|
return client.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param workspaceFolder
|
||||||
|
*/
|
||||||
|
export async function stopClientsForFolder(workspaceFolder: string) {
|
||||||
|
const client = clients.get(workspaceFolder);
|
||||||
|
if (client) {
|
||||||
|
await stopClient(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
clients.delete(workspaceFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function updateClients(context: ExtensionContext) {
|
||||||
|
return async function ({ added, removed }: WorkspaceFoldersChangeEvent) {
|
||||||
|
for (const folder of removed) {
|
||||||
|
await stopClientsForFolder(folder.uri.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const folder of added) {
|
||||||
|
await startClientsForFolder(folder, context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
67
client/src/client_handler_other.ts
Normal file
67
client/src/client_handler_other.ts
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
function connectToServer(hostname: string, path: string): Duplex {
|
||||||
|
const ws = new WebSocket(`ws://${hostname}/${path}`);
|
||||||
|
return WebSocket.createWebSocketStream(ws);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
////function makeClient() {
|
||||||
|
// // Options to control the language client
|
||||||
|
// const clientOptions: LanguageClientOptions = {
|
||||||
|
// // Register the server for plain text documents
|
||||||
|
// documentSelector: [{ scheme: 'file', language: 'plaintext' }],
|
||||||
|
// synchronize: {
|
||||||
|
// // Notify the server about file changes to '.clientrc files contained in the workspace
|
||||||
|
// fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// // The server is implemented in node
|
||||||
|
// const serverModule = context.asAbsolutePath(
|
||||||
|
// path.join('server', 'out', 'server.js')
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // Create the language client and start it
|
||||||
|
// client = new LanguageClient(
|
||||||
|
// 'OpenQuestLSP',
|
||||||
|
// 'OpenQuest Language Server',
|
||||||
|
// serverOptionsGenerator(),
|
||||||
|
// clientOptions
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // The client will either connect or launch the language server, depending
|
||||||
|
// // on the workspace settings
|
||||||
|
// client.start();
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Make server options based on the workspace configuration
|
||||||
|
// */
|
||||||
|
//function serverOptionsGenerator(): ServerOptions {
|
||||||
|
// if (vscode.workspace.getConfiguration(constants.SETTINGS_NAMESPACE).get("serverAddress") !== null) {
|
||||||
|
// // If the extension is launched in debug mode then the debug server options are used
|
||||||
|
// // Otherwise the run options are used
|
||||||
|
// return {
|
||||||
|
// run: { module: serverModule, transport: TransportKind.ipc },
|
||||||
|
// debug: {
|
||||||
|
// module: serverModule,
|
||||||
|
// transport: TransportKind.ipc,
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// } else {
|
||||||
|
// return {
|
||||||
|
// run: { module: serverModule, transport: TransportKind.ipc },
|
||||||
|
// debug: {
|
||||||
|
// module: serverModule,
|
||||||
|
// transport: TransportKind.ipc,
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//*/
|
18
client/src/constants.ts
Normal file
18
client/src/constants.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// TODO: Check if some of these things can be accessed trough legacy code
|
||||||
|
// since they are in `package.json`, which could be accessible somehow
|
||||||
|
|
||||||
|
|
||||||
|
/** Name of the VSCode extension namespace */
|
||||||
|
export const DISPLAY_NAME: string = "OpenQuest"
|
||||||
|
export const EXTENSION_NAME: string = "openquest"
|
||||||
|
export const LANGUAGE_ID: string = "quest"
|
||||||
|
|
||||||
|
export const SETTINGS_NAMESPACE: string = EXTENSION_NAME
|
||||||
|
|
||||||
|
export const SUPPORTED_EXTENSIONS = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DOCUMENT_EXTENSION_PATTERN = "**/*.quest";
|
||||||
|
export const documentsPerExtensionInPath = (path) => `${path}/${DOCUMENT_EXTENSION_PATTERN}`;
|
||||||
|
|
87
client/src/extension.ts
Normal file
87
client/src/extension.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// Local Imports
|
||||||
|
import constants = require('./constants');
|
||||||
|
import * as client_handler from "./client_handler"
|
||||||
|
|
||||||
|
|
||||||
|
// External Imports
|
||||||
|
import { workspace, ExtensionContext } from 'vscode';
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import { LanguageClient } from 'vscode-languageclient/node';
|
||||||
|
import { startClientsForFolder } from './client_handler';
|
||||||
|
|
||||||
|
|
||||||
|
// Common and Persistent variables
|
||||||
|
export const outputChannel = vscode.window.createOutputChannel(
|
||||||
|
constants.DISPLAY_NAME, constants.LANGUAGE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
export const clients: Map<string, LanguageClient> = new Map();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function gets called when the extension is activated,
|
||||||
|
* depending on what is the trigger configuration on `package.json#activationEvents
|
||||||
|
*/
|
||||||
|
export function activate(context: ExtensionContext) {
|
||||||
|
// Use the console to output diagnostic information (console.log) and errors (console.error)
|
||||||
|
// This line of code will only be executed once when your extension is activated
|
||||||
|
outputChannel.appendLine('[INFO] Extension is now active, good deving and have fun !');
|
||||||
|
|
||||||
|
// Commands (these are defined in `package.json#contributes.configurations`)
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand(`${constants.SETTINGS_NAMESPACE}.reload_server`, () => {
|
||||||
|
// The code placed here will be executed every time this command is ran
|
||||||
|
vscode.window.showInformationMessage(`[INFO] Reloading Language Server`);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start Language Clients for each folder in the workspace
|
||||||
|
for (const folder of workspace.workspaceFolders || []) {
|
||||||
|
startClientsForFolder(folder, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client to Server synchronization
|
||||||
|
context.subscriptions.push(
|
||||||
|
workspace.onDidChangeWorkspaceFolders(client_handler.updateClients(context))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Refresh client and server settings when changes happen
|
||||||
|
context.subscriptions.push(workspace.onDidChangeConfiguration(
|
||||||
|
(event) => refreshSettings(event, context))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function deactivate(): Promise<void> {
|
||||||
|
await Promise.all([...clients.values()].map(client_handler.stopClient));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks what changes were made in workspace and user settings and acts
|
||||||
|
* accordingly, like reconnecting/relaunching language servers
|
||||||
|
*/
|
||||||
|
async function refreshSettings(event: vscode.ConfigurationChangeEvent, context: ExtensionContext) {
|
||||||
|
// Check if changes to language server paths were made
|
||||||
|
if (event.affectsConfiguration(`${constants.SETTINGS_NAMESPACE}.serverPath`)) {
|
||||||
|
for (const client of clients.values()) {
|
||||||
|
const folder = client.clientOptions.workspaceFolder;
|
||||||
|
await client_handler.stopClient(client);
|
||||||
|
|
||||||
|
if (folder) {
|
||||||
|
await startClientsForFolder(folder, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
else {
|
||||||
|
for (const client of clients.values()) {
|
||||||
|
client.sendNotification("workspace/didChangeConfiguration", {
|
||||||
|
settings: {
|
||||||
|
...workspace.getConfiguration(constants.SETTINGS_NAMESPACE),
|
||||||
|
checkForUpdates: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
client/src/server_binary.ts
Normal file
154
client/src/server_binary.ts
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
// Local Imports
|
||||||
|
import constants = require('./constants');
|
||||||
|
import { outputChannel } from './extension';
|
||||||
|
|
||||||
|
|
||||||
|
// External Imports
|
||||||
|
import * as path from 'path';
|
||||||
|
import { stat } from "fs/promises";
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to find a language server executable in the following places:
|
||||||
|
* - $PATH or $HOME directory
|
||||||
|
* - The open project's VSCode workspace settings
|
||||||
|
* - Near the unicorns (joking, this one isn't real, just like the unicorns)
|
||||||
|
*/
|
||||||
|
export async function findLanguageServerPath(): Promise<string | undefined> {
|
||||||
|
let customPath = getCustomLanguageServerPath();
|
||||||
|
|
||||||
|
if (customPath !== undefined) { return customPath }
|
||||||
|
|
||||||
|
// TODO: Think if we should also prompt and do updates
|
||||||
|
if (promptInstallLanguageServerExecutable()) {
|
||||||
|
if (installLanguageServerExecutable()) {
|
||||||
|
return searchInstalledLanguageServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for a custom language server binary set in the Workspace or User settings
|
||||||
|
*/
|
||||||
|
function getCustomLanguageServerPath(): string | undefined {
|
||||||
|
const workspaceConfig = vscode.workspace.getConfiguration(constants.EXTENSION_NAME);
|
||||||
|
|
||||||
|
// Check for custom language server path
|
||||||
|
if (workspaceConfig.get("serverBinaryPath") && vscode.workspace.workspaceFolders !== undefined) {
|
||||||
|
outputChannel.appendLine(
|
||||||
|
path.resolve(
|
||||||
|
vscode.workspace.workspaceFolders[0].uri.fsPath,
|
||||||
|
workspaceConfig.get("serverBinaryPath") as string
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return path.resolve(
|
||||||
|
vscode.workspace.workspaceFolders[0].uri.fsPath,
|
||||||
|
workspaceConfig.get("serverBinaryPath") as string
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt the user about installing the language server from a known origin
|
||||||
|
* and installs it if agreed
|
||||||
|
*/
|
||||||
|
async function promptInstallLanguageServerExecutable(): Promise<boolean> {
|
||||||
|
const choice = await vscode.window.showWarningMessage(
|
||||||
|
"Could not find a language server binary.\
|
||||||
|
Would you like to install one using `cargo install`?",
|
||||||
|
{},
|
||||||
|
"Yes"
|
||||||
|
);
|
||||||
|
// TODO: The prompt could also say what places we tried to look into
|
||||||
|
// and consequentially a better message on from where we are getting it
|
||||||
|
// and to where it is being installed
|
||||||
|
|
||||||
|
if (!choice) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download language server executable from mirrors defined in `package.json`
|
||||||
|
* and put them
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function installLanguageServerExecutable(): Promise<boolean> {
|
||||||
|
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks in known paths like HOME(Linux, Windows, Unix) and UserProfile(Windows)
|
||||||
|
*/
|
||||||
|
function searchInstalledLanguageServer() {
|
||||||
|
let base = process.env["HOME"];
|
||||||
|
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
base = process.env["USERPROFILE"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!base) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks for the cargo binary path in HOME
|
||||||
|
* @returns Path of the executables directory for cargo
|
||||||
|
*/
|
||||||
|
function lookForCargoBinPath() {
|
||||||
|
let base = process.env["HOME"];
|
||||||
|
|
||||||
|
if (!base) { return undefined}
|
||||||
|
|
||||||
|
const cargoInstallRoot = process.env["CARGO_INSTALL_ROOT"];
|
||||||
|
if (cargoInstallRoot) {
|
||||||
|
return cargoInstallRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cargoHome = process.env["CARGO_HOME"];
|
||||||
|
|
||||||
|
if (cargoHome) {
|
||||||
|
return path.join(cargoHome, "bin");
|
||||||
|
}
|
||||||
|
return path.join(base, ".cargo", "bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives language server binary name based on current environment
|
||||||
|
*/
|
||||||
|
function getBinaryName(): string {
|
||||||
|
switch (process.platform) {
|
||||||
|
case "win32":
|
||||||
|
return "openquest-ls.exe"
|
||||||
|
case "linux":
|
||||||
|
return "openquest-ls"
|
||||||
|
default:
|
||||||
|
return "openquest-ls"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks if a given path exists */
|
||||||
|
async function checkPathValidity(path: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await stat(path)
|
||||||
|
return true
|
||||||
|
} catch (_) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
0
client/testFixture/completion.txt
Normal file
0
client/testFixture/completion.txt
Normal file
1
client/testFixture/diagnostics.txt
Normal file
1
client/testFixture/diagnostics.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ANY browsers, ANY OS.
|
7
client/testWorkspace/.vscode/settings.json
vendored
Normal file
7
client/testWorkspace/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
// "openquest.handlingMode": "Remote/Local Connection",
|
||||||
|
// "openquest.serverAddress": "localhost:4000"
|
||||||
|
"openquest.handlingMode": "Local Path",
|
||||||
|
"openquest.serverBinaryPath": "/run/media/nibunta/OMTRON/Projectos/Metin_Projects/General Projects/openquest/openquest-rs/target/debug/openquest-lsp",
|
||||||
|
"openquest.serverArguments": ["--transport", "stdio"]
|
||||||
|
}
|
5
client/testWorkspace/test.lua
Normal file
5
client/testWorkspace/test.lua
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
local thing = 10
|
||||||
|
|
||||||
|
function test()
|
||||||
|
end
|
||||||
|
|
7
client/testWorkspace/test.quest
Normal file
7
client/testWorkspace/test.quest
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
define thing 10
|
||||||
|
define some 100
|
||||||
|
|
||||||
|
quest some with thing begin
|
||||||
|
state start begin
|
||||||
|
end
|
||||||
|
end
|
1
client/testWorkspace/test.txt
Normal file
1
client/testWorkspace/test.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#10
|
13
client/tsconfig.json
Normal file
13
client/tsconfig.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2020",
|
||||||
|
"lib": ["es2020"],
|
||||||
|
"outDir": "out",
|
||||||
|
"rootDir": "src",
|
||||||
|
"sourceMap": true,
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["node_modules", ".vscode-test"]
|
||||||
|
}
|
30
language-configuration.json
Normal file
30
language-configuration.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"comments": {
|
||||||
|
// symbol used for single line comment. Remove this entry if your language does not support line comments
|
||||||
|
"lineComment": "--",
|
||||||
|
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
|
||||||
|
"blockComment": [ "--[[", "]]--" ]
|
||||||
|
},
|
||||||
|
// symbols used as brackets
|
||||||
|
"brackets": [
|
||||||
|
["begin", "end"],
|
||||||
|
["[", "]"],
|
||||||
|
["(", ")"]
|
||||||
|
],
|
||||||
|
// symbols that are auto closed when typing
|
||||||
|
"autoClosingPairs": [
|
||||||
|
["begin", "end"],
|
||||||
|
["[", "]"],
|
||||||
|
["(", ")"],
|
||||||
|
["\"", "\""],
|
||||||
|
["'", "'"]
|
||||||
|
],
|
||||||
|
// symbols that can be used to surround a selection
|
||||||
|
"surroundingPairs": [
|
||||||
|
["begin", "end"],
|
||||||
|
["[", "]"],
|
||||||
|
["(", ")"],
|
||||||
|
["\"", "\""],
|
||||||
|
["'", "'"]
|
||||||
|
]
|
||||||
|
}
|
5236
package-lock.json
generated
Normal file
5236
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
103
package.json
Normal file
103
package.json
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
{
|
||||||
|
"name": "openquest",
|
||||||
|
"displayName": "OpenQuest",
|
||||||
|
"description": "Support for the Quest language, a DSL for mission scripting (Metin2)",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/OriDevTeam/openquest-rs\""
|
||||||
|
},
|
||||||
|
"license": "Apache2",
|
||||||
|
"publisher": "OriDevTeam",
|
||||||
|
"categories": [
|
||||||
|
"Programming Languages"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"quest",
|
||||||
|
"language"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.78.0"
|
||||||
|
},
|
||||||
|
"main": "./client/out/extension",
|
||||||
|
"contributes": {
|
||||||
|
"languages": [
|
||||||
|
{
|
||||||
|
"id": "quest",
|
||||||
|
"aliases": [
|
||||||
|
"Quest",
|
||||||
|
"quest"
|
||||||
|
],
|
||||||
|
"extensions": [
|
||||||
|
".quest"
|
||||||
|
],
|
||||||
|
"configuration": "./language-configuration.json",
|
||||||
|
"embeddedLanguages": { "meta.embedded.block.lua": "lua" }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grammars": [
|
||||||
|
{
|
||||||
|
"language": "quest",
|
||||||
|
"scopeName": "source.quest",
|
||||||
|
"path": "./syntaxes/quest.tmLanguage.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration": {
|
||||||
|
"title": "OpenQuest",
|
||||||
|
"properties": {
|
||||||
|
"openquest.handlingMode": {
|
||||||
|
"scope": "window",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Automatic (Package Manager)",
|
||||||
|
"Local Path",
|
||||||
|
"Remote/Local Connection"
|
||||||
|
],
|
||||||
|
"default": "Automatic (Package Manager)",
|
||||||
|
"description": "Where and how to connect to a language server, or spawn a new process of one"
|
||||||
|
},
|
||||||
|
"openquest.serverAddress": {
|
||||||
|
"scope": "window",
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Language Server address to connect to (**Example:** localhost:5050)"
|
||||||
|
},
|
||||||
|
"openquest.serverArguments": {
|
||||||
|
"scope": "window",
|
||||||
|
"type": "array",
|
||||||
|
"default": [],
|
||||||
|
"description": "Arguments to pass when initializing language server"
|
||||||
|
},
|
||||||
|
"openquest.serverBinaryPath": {
|
||||||
|
"scope": "window",
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Path of the language server executable (if not given, it will look in $PATH and consequentially $HOME)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"vscode:prepublish": "pnpm run compile",
|
||||||
|
"compile": "tsc -b",
|
||||||
|
"postinstall": "cd client && pnpm install && cd ..",
|
||||||
|
"watch": "tsc -b -w",
|
||||||
|
"lint": "eslint ./client/src ./server/src --ext .ts,.tsx",
|
||||||
|
"test": "sh ./scripts/e2e.sh",
|
||||||
|
"package-y2j": "js-yaml package.yaml > package.json",
|
||||||
|
"grammar-y2j": "js-yaml syntaxes/quest.tmGrammar.yaml > syntaxes/quest.tmGrammar.json"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"generator-code": "^1.7.7",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"ws": "^8.13.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/mocha": "^9.1.1",
|
||||||
|
"@types/node": "^16.18.34",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
||||||
|
"@typescript-eslint/parser": "^5.59.9",
|
||||||
|
"@types/ws": "^8.5.5",
|
||||||
|
"eslint": "^8.42.0",
|
||||||
|
"mocha": "^9.2.2",
|
||||||
|
"typescript": "^5.1.3"
|
||||||
|
}
|
||||||
|
}
|
80
packagee.yaml
Normal file
80
packagee.yaml
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
name: openquest
|
||||||
|
displayName: OpenQuest
|
||||||
|
description: Support for the Quest language, a DSL for mission scripting (Metin2)
|
||||||
|
version: 0.0.1
|
||||||
|
repository:
|
||||||
|
type: git
|
||||||
|
url: https://github.com/OriDevTeam/openquest-rs"
|
||||||
|
license: Apache2
|
||||||
|
publisher: OriDevTeam
|
||||||
|
categories:
|
||||||
|
- Programming Languages
|
||||||
|
keywords:
|
||||||
|
- quest
|
||||||
|
- language
|
||||||
|
engines: {vscode: ^1.78.0}
|
||||||
|
main: ./client/out/extension
|
||||||
|
contributes:
|
||||||
|
languages:
|
||||||
|
- id: quest
|
||||||
|
aliases:
|
||||||
|
- Quest
|
||||||
|
- quest
|
||||||
|
extensions:
|
||||||
|
- .quest
|
||||||
|
configuration: ./language-configuration.json
|
||||||
|
grammars:
|
||||||
|
- language: quest
|
||||||
|
scopeName: source.quest
|
||||||
|
path: ./syntaxes/quest.tmLanguage.json
|
||||||
|
configuration:
|
||||||
|
title: OpenQuest
|
||||||
|
properties:
|
||||||
|
openquest.handlingMode:
|
||||||
|
scope: window
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- Local Path
|
||||||
|
- WebSocket
|
||||||
|
default: Local Path
|
||||||
|
description: >-
|
||||||
|
Where and how to connect to a language server, or spawn a new process
|
||||||
|
of one
|
||||||
|
openquest.serverAddress:
|
||||||
|
scope: window
|
||||||
|
type: string
|
||||||
|
markdownDescription: Language Server address to connect to (**Example:** localhost:5050)
|
||||||
|
openquest.serverArguments:
|
||||||
|
scope: window
|
||||||
|
type: string
|
||||||
|
description: Arguments to pass when initializing language server
|
||||||
|
openquest.serverBinaryPath:
|
||||||
|
scope: window
|
||||||
|
type: string
|
||||||
|
markdownDescription: >-
|
||||||
|
Path of the language server executable (if not given, it will look in
|
||||||
|
$PATH and consequentially $HOME)
|
||||||
|
scripts:
|
||||||
|
vscode:prepublish: pnpm run compile
|
||||||
|
compile: tsc -b
|
||||||
|
postinstall: cd client && pnpm install && cd ..
|
||||||
|
watch: tsc -b -w
|
||||||
|
lint: eslint ./client/src ./server/src --ext .ts,.tsx
|
||||||
|
test: sh ./scripts/e2e.sh
|
||||||
|
package-y2j: js-yaml package.yaml > package.json
|
||||||
|
grammar-y2j: js-yaml syntaxes/quest.tmGrammar.yaml > syntaxes/quest.tmGrammar.json
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
generator-code: ^1.7.7
|
||||||
|
js-yaml: ^4.1.0
|
||||||
|
ws: ^8.13.0
|
||||||
|
|
||||||
|
devDependencies:
|
||||||
|
'@types/mocha': ^9.1.1
|
||||||
|
'@types/node': ^16.18.34
|
||||||
|
'@typescript-eslint/eslint-plugin': ^5.59.9
|
||||||
|
'@typescript-eslint/parser': ^5.59.9
|
||||||
|
'@types/ws': ^8.5.5
|
||||||
|
eslint: ^8.42.0
|
||||||
|
mocha: ^9.2.2
|
||||||
|
typescript: ^5.1.3
|
33
syntaxes/quest.tmGrammar.json
Normal file
33
syntaxes/quest.tmGrammar.json
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
|
||||||
|
"scopeName": "source.quest",
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"include": "#quest_clause"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"quest": {
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"include": "#define_substitution"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include": "#quest_clause"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"define_substitution": {
|
||||||
|
"name": "keyword.local.define_substitution"
|
||||||
|
},
|
||||||
|
"quest_clause": {
|
||||||
|
"name": "keyword.control.quest_clause"
|
||||||
|
},
|
||||||
|
"state_clause": {
|
||||||
|
"name": "keyword.control.state_clause"
|
||||||
|
},
|
||||||
|
"when_clause": {
|
||||||
|
"name": "keyword.control.when_clause"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
syntaxes/quest.tmGrammar.yaml
Normal file
31
syntaxes/quest.tmGrammar.yaml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
$schema: https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json
|
||||||
|
scopeName: source.quest
|
||||||
|
|
||||||
|
patterns:
|
||||||
|
- {include: "#quest_clause"}
|
||||||
|
|
||||||
|
repository:
|
||||||
|
quest:
|
||||||
|
patterns:
|
||||||
|
- {include: "#define_substitution"}
|
||||||
|
- {include: "#quest_clause"}
|
||||||
|
|
||||||
|
# Pattern syntax:
|
||||||
|
# define <name> <value(string, decimal, float, any)>
|
||||||
|
define_substitution:
|
||||||
|
name: keyword.local.define_substitution
|
||||||
|
|
||||||
|
# Pattern syntax:
|
||||||
|
# quest <name> begin <define* | state_clause+> end
|
||||||
|
quest_clause:
|
||||||
|
name: keyword.control.quest_clause
|
||||||
|
|
||||||
|
# Pattern syntax:
|
||||||
|
# state <name> begin <with_clause+> end
|
||||||
|
state_clause:
|
||||||
|
name: keyword.control.state_clause
|
||||||
|
|
||||||
|
# Pattern syntax:
|
||||||
|
# when <name | name.cond> with <lua_expression> begin <lua_expression> end
|
||||||
|
when_clause:
|
||||||
|
name: keyword.control.when_clause
|
59
syntaxes/quest.tmLanguage.json
Normal file
59
syntaxes/quest.tmLanguage.json
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
|
||||||
|
"name": "Quest",
|
||||||
|
"scopeName": "source.quest",
|
||||||
|
"patterns": [
|
||||||
|
{"include": "#define_substitution"},
|
||||||
|
{"include": "#quest_clause"}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
|
||||||
|
"define_substitution": {
|
||||||
|
"name": "keyword.control.quest",
|
||||||
|
"match": "\\b(define)\\s(.+)\\s(.+)\\b",
|
||||||
|
"captures": {
|
||||||
|
"1": {"name": "keyword.function"},
|
||||||
|
"2": {"name": "entity.other.attribute-name"},
|
||||||
|
"3": {"name": "variable.other"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"quest_clause": {
|
||||||
|
"begin": "\\b(quest)\\s(.+)\\s(with)\\s(.+)\\s(begin)",
|
||||||
|
"beginCaptures": {
|
||||||
|
"1": {"name": "keyword"},
|
||||||
|
"2": {"name": "entity.other.attribute-name"},
|
||||||
|
"3": {"name": "keyword"},
|
||||||
|
"4": {"name": "variable.other"},
|
||||||
|
"5": {"name": "punctuation.paren.open"}
|
||||||
|
},
|
||||||
|
"end": "end", "endCaptures": {"0": {"name": "punctuation.paren.close"}},
|
||||||
|
"patterns": [{"include": "#state_clause"}]
|
||||||
|
},
|
||||||
|
|
||||||
|
"state_clause": {
|
||||||
|
"begin": "(state)\\s(.+)\\s(begin)",
|
||||||
|
"beginCaptures": {
|
||||||
|
"1": {"name": "keyword"},
|
||||||
|
"2": {"name": "entity.other.attribute-name"},
|
||||||
|
"3": {"name": "punctuation.paren.open"}
|
||||||
|
},
|
||||||
|
"end": "end", "endCaptures": {"0": {"name": "punctuation.paren.close"}},
|
||||||
|
"patterns": [{"include": "#with_clause"}]
|
||||||
|
},
|
||||||
|
|
||||||
|
"with_clause": {
|
||||||
|
"name": "keyword.control.with_clause",
|
||||||
|
"begin": "when\\s(.+)\\sbegin",
|
||||||
|
"beginCaptures": {
|
||||||
|
"0": {"name": "punctuation.paren.open"},
|
||||||
|
"1": {"name": "storage.modifier.quest"}
|
||||||
|
},
|
||||||
|
"end": "end", "endCaptures": {"0": {"name": "punctuation.paren.close"}}
|
||||||
|
},
|
||||||
|
|
||||||
|
"lua_scope": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2020",
|
||||||
|
"lib": ["es2020"],
|
||||||
|
"outDir": "out",
|
||||||
|
"rootDir": "src",
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
".vscode-test"
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./client" },
|
||||||
|
]
|
||||||
|
}
|
29
vsc-extension-quickstart.md
Normal file
29
vsc-extension-quickstart.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Welcome to your VS Code Extension
|
||||||
|
|
||||||
|
## What's in the folder
|
||||||
|
|
||||||
|
* This folder contains all of the files necessary for your extension.
|
||||||
|
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
|
||||||
|
* `syntaxes/quest.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
|
||||||
|
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
|
||||||
|
|
||||||
|
## Get up and running straight away
|
||||||
|
|
||||||
|
* Make sure the language configuration settings in `language-configuration.json` are accurate.
|
||||||
|
* Press `F5` to open a new window with your extension loaded.
|
||||||
|
* Create a new file with a file name suffix matching your language.
|
||||||
|
* Verify that syntax highlighting works and that the language configuration settings are working.
|
||||||
|
|
||||||
|
## Make changes
|
||||||
|
|
||||||
|
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
|
||||||
|
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
|
||||||
|
|
||||||
|
## Add more language features
|
||||||
|
|
||||||
|
* To add features such as IntelliSense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
|
||||||
|
|
||||||
|
## Install your extension
|
||||||
|
|
||||||
|
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
|
||||||
|
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.
|
Loading…
Reference in a new issue