Compare commits

...

14 commits
v1.2.1 ... main

12 changed files with 359 additions and 254 deletions

View file

@ -0,0 +1,23 @@
on:
push:
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"
jobs:
build:
runs-on: docker
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Install VSCE
run: npm install -g vsce
- name: Build
run: vsce package -o mapcomplete.vsix --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: mapcomplete
path: mapcomplete.vsix

View file

@ -8,9 +8,13 @@ on:
- "**.md"
jobs:
lint:
runs-on: ubuntu-latest
runs-on: docker
steps:
- uses: actions/checkout@v4
- uses: https://source.mapcomplete.org/actions/checkout@v4
- name: Set up Node.js
uses: https://source.mapcomplete.org/actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm install
- name: Lint

View file

@ -1,16 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
commit-message:
prefix: "⬆️"
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
commit-message:
prefix: "⬆️"
open-pull-requests-limit: 10

View file

@ -1,24 +0,0 @@
name: Build extension
on:
push:
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Instal VSCE
run: npm install -g vsce
- name: Build
run: vsce package -o mapcomplete.vsix
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: mapcomplete
path: mapcomplete.vsix

View file

@ -2,6 +2,22 @@
All notable changes to this project will be documented in this file.
## Version 1.2.3 (2025-04-XX)
### Fixed
- Instead of using implementations the extension now correctly used references.
## Version 1.2.2 (2025-03-01)
This is the last release of the extension on GitHub, from now on you'll be able to find the source code on the [MapComplete Forgejo](https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode). Releases will still be available on the VScode Marketplace and Open VSX as well.
### Fixed
- When a tagRendering is re-used by `layer.*`, it's also picked up by the implementation support ([#34](https://github.com/RobinLinde/MapCompleteVScode/issues/34)).
- Fix a wrong ID for the refresh command.
- Handle labels (mostly) correctly in the implementation support. ([#35](https://github.com/RobinLinde/MapCompleteVScode/issues/35))
## Version 1.2.1 (2025-02-20)
### Fixed

View file

@ -1,6 +1,6 @@
# MapCompleteVScode
This is a Visual Studio Code extension for [MapComplete](https://github.com/pietervdvn/MapComplete).
This is a Visual Studio Code extension for [MapComplete](https://source.mapcomplete.org/MapComplete/MapComplete).
It adds autocompletion and defintion support for the MapComplete theme and layer configuration files.
Currently the following features are supported:
@ -50,12 +50,12 @@ ext install robin-van-der-linde.mapcompletevscode
### From the .vsix file
You can also install the extension from the .vsix file. You can download the latest version from the [releases page](https://github.com/RobinLinde/MapCompleteVScode/releases). After downloading the .vsix file, you should be able to install it by going to extensions in Visual Studio Code and clicking on the three dots in the top right corner. Then click on "Install from VSIX..." and select the downloaded .vsix file.
You can also install the extension from the .vsix file. You can download the latest version from the [releases page](https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/releases). After downloading the .vsix file, you should be able to install it by going to extensions in Visual Studio Code and clicking on the three dots in the top right corner. Then click on "Install from VSIX..." and select the downloaded .vsix file.
It's also possible to install builds for any commit in any branch by checking out the workflow run for the commit you want to install, and downloading the .vsix file from the artifacts.
## Usage
Most of the features should be pretty self-explanatory. As for the implementation support, the 'anchor' for this is the id property of the layer, tagRendering or filter. This means that if you want to see where a layer is used, you should be able to see all uses by using `CTRL+F12` on the id property of the layer, or by right-clicking on the id property and selecting "Go to Implementations".
Most of the features should be pretty self-explanatory. As for references support, the 'anchor' for this is the id property of the layer, tagRendering or filter. This means that if you want to see where a layer is used, you should be able to see all uses by using `SHIFT+F12` on the id property of the layer, or by right-clicking on the id property and selecting "Go to References".
![Demo showing implementation support for tagRenderings](images/implementation.gif)

View file

@ -7,4 +7,4 @@ For convenience, this license is also available in the [`LICENSE.txt`](LICENSE.t
## Files
- [`demo.gif`](demo.gif): A demo of the extension in action.
- [`icon.png`](icon.png): The icon of the extension. Originally created by [pietervdvn](https://github.com/pietervdvn).
- [`icon.png`](icon.png): The icon of the extension. Originally created by [pietervdvn](https://source.mapcomplete.org/pietervdvn).

178
package-lock.json generated
View file

@ -1,24 +1,24 @@
{
"name": "mapcompletevscode",
"version": "1.2.1",
"version": "1.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mapcompletevscode",
"version": "1.2.1",
"version": "1.2.2",
"license": "MIT",
"dependencies": {
"jsonc-parser": "^3.3.1"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@stylistic/eslint-plugin": "^2.13.0",
"@eslint/js": "^9.20.0",
"@stylistic/eslint-plugin": "^4.0.1",
"@types/node": "^22",
"@types/vscode": "^1.73.0",
"eslint": "^9.18.0",
"eslint": "^9.20.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"typescript-eslint": "^8.24.1"
},
"engines": {
"vscode": "^1.73.0"
@ -167,9 +167,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz",
"integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==",
"version": "9.20.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz",
"integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -305,13 +305,13 @@
}
},
"node_modules/@stylistic/eslint-plugin": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.13.0.tgz",
"integrity": "sha512-RnO1SaiCFHn666wNz2QfZEFxvmiNRqhzaMXHXxXXKt+MEP7aajlPxUSMIQpKAaJfverpovEYqjBOXDq6dDcaOQ==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.0.1.tgz",
"integrity": "sha512-RwKkRKiDrF4ptiur54ckDhOByQYKYZ1dEmI5K8BJCmuGpauFJXzVL1UQYTA2zq702CqMFdYiJcVFJWfokIgFxw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/utils": "^8.13.0",
"@typescript-eslint/utils": "^8.23.0",
"eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0",
"estraverse": "^5.3.0",
@ -321,7 +321,7 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=8.40.0"
"eslint": ">=9.0.0"
}
},
"node_modules/@types/estree": {
@ -348,28 +348,28 @@
}
},
"node_modules/@types/vscode": {
"version": "1.96.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz",
"integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==",
"version": "1.97.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.97.0.tgz",
"integrity": "sha512-ueE73loeOTe7olaVyqP9mrRI54kVPJifUPjblZo9fYcv1CuVLPOEKEkqW0GkqPC454+nCEoigLWnC2Pp7prZ9w==",
"dev": true,
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.20.0.tgz",
"integrity": "sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz",
"integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.20.0",
"@typescript-eslint/type-utils": "8.20.0",
"@typescript-eslint/utils": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/type-utils": "8.24.1",
"@typescript-eslint/utils": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.0.0"
"ts-api-utils": "^2.0.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -385,16 +385,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.20.0.tgz",
"integrity": "sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz",
"integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.20.0",
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/typescript-estree": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/typescript-estree": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1",
"debug": "^4.3.4"
},
"engines": {
@ -410,14 +410,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.20.0.tgz",
"integrity": "sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz",
"integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0"
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -428,16 +428,16 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.20.0.tgz",
"integrity": "sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz",
"integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "8.20.0",
"@typescript-eslint/utils": "8.20.0",
"@typescript-eslint/typescript-estree": "8.24.1",
"@typescript-eslint/utils": "8.24.1",
"debug": "^4.3.4",
"ts-api-utils": "^2.0.0"
"ts-api-utils": "^2.0.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -452,9 +452,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.20.0.tgz",
"integrity": "sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz",
"integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==",
"dev": true,
"license": "MIT",
"engines": {
@ -466,20 +466,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.20.0.tgz",
"integrity": "sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz",
"integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
"ts-api-utils": "^2.0.0"
"ts-api-utils": "^2.0.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -493,16 +493,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.20.0.tgz",
"integrity": "sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz",
"integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.20.0",
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/typescript-estree": "8.20.0"
"@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/typescript-estree": "8.24.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -517,13 +517,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.20.0.tgz",
"integrity": "sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz",
"integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/types": "8.24.1",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@ -735,18 +735,18 @@
}
},
"node_modules/eslint": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz",
"integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==",
"version": "9.20.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz",
"integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.10.0",
"@eslint/core": "^0.11.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.18.0",
"@eslint/js": "9.20.0",
"@eslint/plugin-kit": "^0.2.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@ -824,6 +824,19 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/@eslint/core": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz",
"integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -964,9 +977,9 @@
"license": "MIT"
},
"node_modules/fastq": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
"dev": true,
"license": "ISC",
"dependencies": {
@ -1506,9 +1519,9 @@
}
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"dev": true,
"license": "ISC",
"bin": {
@ -1581,10 +1594,11 @@
}
},
"node_modules/ts-api-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
"integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
"integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.12"
},
@ -1620,15 +1634,15 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.20.0.tgz",
"integrity": "sha512-Kxz2QRFsgbWj6Xcftlw3Dd154b3cEPFqQC+qMZrMypSijPd4UanKKvoKDrJ4o8AIfZFKAF+7sMaEIR8mTElozA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.1.tgz",
"integrity": "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.20.0",
"@typescript-eslint/parser": "8.20.0",
"@typescript-eslint/utils": "8.20.0"
"@typescript-eslint/eslint-plugin": "8.24.1",
"@typescript-eslint/parser": "8.24.1",
"@typescript-eslint/utils": "8.24.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View file

@ -1,7 +1,7 @@
{
"name": "mapcompletevscode",
"displayName": "MapComplete VScode",
"version": "1.2.1",
"version": "1.2.2",
"publisher": "robin-van-der-linde",
"author": {
"name": "Robin van der Linde",
@ -11,7 +11,11 @@
"icon": "images/icon.png",
"repository": {
"type": "git",
"url": "https://github.com/RobinLinde/MapCompleteVSCode.git"
"url": "https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode.git"
},
"homepage": "https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode",
"bugs": {
"url": "https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/issues"
},
"description": "Extension providing autocompletion and definition supoort for MapComplete themes and layers.",
"keywords": [
@ -36,16 +40,20 @@
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"lint": "eslint",
"watch": "tsc -watch -p ./"
"watch": "tsc -watch -p ./",
"package": "vsce package --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/",
"publish:vsc": "vsce publish --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/",
"publish:ovsx": "ovsx publish --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/",
"publish": "npm run publish:vsc && npm run publish:ovsx"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@stylistic/eslint-plugin": "^2.13.0",
"@eslint/js": "^9.20.0",
"@stylistic/eslint-plugin": "^4.0.1",
"@types/node": "^22",
"@types/vscode": "^1.73.0",
"eslint": "^9.18.0",
"eslint": "^9.20.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"typescript-eslint": "^8.24.1"
},
"dependencies": {
"jsonc-parser": "^3.3.1"

View file

@ -4,11 +4,11 @@ import { colorProvider, iconDefinitionProvider } from "./generic";
import {
filterCompletionProvider,
filterDefinitionProvider,
filterImplementationProvider,
layerImplementationProvider,
filterReferenceProvider,
layerReferenceProvider,
tagRenderingCompletionProvider,
tagRenderingDefinitionProvider,
tagRenderingImplementationProvider,
tagRenderingReferenceProvider,
} from "./layers";
import { pathDefinitionProvider } from "./license_info";
import { CacheWorker } from "./utils/cache";
@ -29,7 +29,7 @@ export async function activate(context: vscode.ExtensionContext) {
});
// Listen for refreshCache command
vscode.commands.registerCommand("mapcomplete.refreshCache", async () => {
vscode.commands.registerCommand("mapcomplete.refresh", async () => {
if (cacheWorker) {
await cacheWorker.refreshCache();
}
@ -44,9 +44,9 @@ export async function activate(context: vscode.ExtensionContext) {
tagRenderingDefinitionProvider,
filterCompletionProvider,
filterDefinitionProvider,
tagRenderingImplementationProvider,
filterImplementationProvider,
layerImplementationProvider
tagRenderingReferenceProvider,
filterReferenceProvider,
layerReferenceProvider
);
// Activate all license info related features

View file

@ -173,20 +173,20 @@ export const tagRenderingDefinitionProvider =
}
);
export const tagRenderingImplementationProvider =
vscode.languages.registerImplementationProvider(
export const tagRenderingReferenceProvider =
vscode.languages.registerReferenceProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/*/*/*.json",
},
{
async provideImplementation(
async provideReferences(
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("tagRenderingImplementationProvider");
console.log("tagRenderingReferenceProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
@ -207,7 +207,7 @@ export const tagRenderingImplementationProvider =
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
const links: vscode.Location[] = [];
for (const reference of references) {
console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
@ -217,19 +217,13 @@ export const tagRenderingImplementationProvider =
// Check if we have a targetUri
if (reference.reference?.from.uri) {
links.push({
originSelectionRange: new vscode.Range(
reference.reference?.to?.range?.[0]?.line ?? 0,
reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
range: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
uri: reference.reference?.from?.uri,
});
} else {
console.error("Incomplete reference", reference);
@ -407,20 +401,20 @@ export const filterDefinitionProvider =
}
);
export const filterImplementationProvider =
vscode.languages.registerImplementationProvider(
export const filterReferenceProvider =
vscode.languages.registerReferenceProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/*/*/*.json",
},
{
async provideImplementation(
async provideReferences(
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("filterImplementationProvider");
console.log("filterReferenceProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
@ -442,7 +436,7 @@ export const filterImplementationProvider =
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
const links: vscode.Location[] = [];
for (const reference of references) {
console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
@ -452,19 +446,13 @@ export const filterImplementationProvider =
// Check if we have a targetUri
if (reference.reference?.from.uri) {
links.push({
originSelectionRange: new vscode.Range(
reference.reference?.to?.range?.[0]?.line ?? 0,
reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
range: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
uri: reference.reference?.from?.uri,
});
} else {
console.error("Incomplete reference", reference);
@ -484,20 +472,20 @@ export const filterImplementationProvider =
}
);
export const layerImplementationProvider =
vscode.languages.registerImplementationProvider(
export const layerReferenceProvider =
vscode.languages.registerReferenceProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/layers/*/*.json",
},
{
async provideImplementation(
async provideReferences(
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("layerImplementationProvider");
console.log("layerReferenceProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
@ -519,7 +507,7 @@ export const layerImplementationProvider =
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
const links: vscode.Location[] = [];
for (const reference of references) {
console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
@ -529,19 +517,13 @@ export const layerImplementationProvider =
// Check if we have a targetUri
if (reference.reference?.from.uri) {
links.push({
originSelectionRange: new vscode.Range(
reference.reference?.to?.range?.[0]?.line ?? 0,
reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
range: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
uri: reference.reference?.from?.uri,
});
} else {
console.error("Incomplete reference", reference);

View file

@ -471,9 +471,85 @@ export class CacheWorker {
}
}
/**
* Find one or more matching tagRenderings in a layer definition text
*
* @param text the text of the layer definition
* @param identifier the identifier of the tagRendering to find, in theory this can be an id, a label or something with a wildcard
* @returns
*/
private findTagRenderingInText(
text: string,
identifier: string
): { paths: JSONPath[]; ids: string[] } {
const json = JSON.parse(text);
const tagRenderings = json.tagRenderings;
const tagRenderingIds: string[] = tagRenderings.map(
(tr: { id: string }) => tr.id
);
const tagRenderingLabels: string[][] = tagRenderings.map(
(tr: { labels: string[] }) => tr.labels
);
if (identifier.includes("*")) {
// This is a wildcard, so we need to handle it differently
const pattern = identifier.split(".")?.pop();
if (pattern) {
const regex = new RegExp(pattern.replace("*", ".*"));
const matchingTagRenderings = tagRenderingIds.filter((tr) =>
regex.test(tr)
);
const labelIndices: number[] = [];
for (let i = 0; i < tagRenderingLabels.length; i++) {
if (tagRenderingLabels[i] !== undefined) {
for (const label of tagRenderingLabels[i]) {
if (regex.test(label)) {
labelIndices.push(i);
}
}
}
}
return {
paths: [
...matchingTagRenderings.map((tr) => ["tagRenderings", tr]),
...labelIndices.map((i) => ["tagRenderings", i]),
],
ids: [
...matchingTagRenderings,
...labelIndices.map((i) => tagRenderingIds[i]),
],
};
}
} else {
// Single identifier, we just need to look through the ids and labels
const idIndex = tagRenderingIds.indexOf(identifier);
if (idIndex !== -1) {
return {
paths: [["tagRenderings", idIndex]],
ids: [identifier],
};
} else {
// Not found by id, so we need to look through the labels, which can match with more than one tagRendering
const labelIndices: number[] = [];
for (let i = 0; i < tagRenderingLabels.length; i++) {
if (tagRenderingLabels[i]?.includes(identifier)) {
labelIndices.push(i);
}
}
return {
paths: labelIndices.map((i) => ["tagRenderings", i]),
ids: labelIndices.map((i) => tagRenderingIds[i]),
};
}
}
return {
ids: [],
paths: [],
};
}
/**
* Save tag renderings to cache
* TODO: references for tagRenderings can also be a label/group, which we don't support yet
*
* @param text Text representation of layer
* @param from The theme or layer where the layer is from, e.g. layers.bicycle_rental or themes.cyclofix.layers.0
@ -528,32 +604,37 @@ export class CacheWorker {
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === tagRendering.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
id: tagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
const results = this.findTagRenderingInText(toText, tagRendering);
for (let i = 0; i < results.paths.length; i++) {
const toRange = getStartEnd(toText, results.paths[i]);
// Determine the ID of the to of the reference (original to item, but with last part replaced by the tagRendering ID)
const toId = [...to.split(".").slice(0, -1), results.ids[i]].join(
"."
);
this.cache.items.push({
id: tagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: toId,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
});
}
} else if (typeof tagRendering === "object") {
// This is a tagRendering, or a reference to one, but with an override
if (tagRendering.builtin) {
@ -591,32 +672,40 @@ export class CacheWorker {
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === tagRendering.builtin.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
id: tagRendering.builtin,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
const results = this.findTagRenderingInText(
toText,
tagRendering.builtin
);
for (let i = 0; i < results.paths.length; i++) {
const toRange = getStartEnd(toText, results.paths[i]);
// Determine the ID of the to of the reference (original to item, but with last part replaced by the tagRendering ID)
const toId = [...to.split(".").slice(0, -1), results.ids[i]].join(
"."
);
this.cache.items.push({
id: tagRendering.builtin,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: toId,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
});
}
} else {
// Multiple tagRenderings
for (const builtinTagRendering of tagRendering.builtin) {
@ -649,32 +738,41 @@ export class CacheWorker {
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === builtinTagRendering.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
id: builtinTagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
const results = this.findTagRenderingInText(
toText,
builtinTagRendering
);
for (let i = 0; i < results.paths.length; i++) {
const toRange = getStartEnd(toText, results.paths[i]);
// Determine the ID of the to of the reference (original to item, but with last part replaced by the tagRendering ID)
const toId = [
...to.split(".").slice(0, -1),
results.ids[i],
].join(".");
this.cache.items.push({
id: builtinTagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: toId,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
});
}
}
}
} else if (!referencesOnly) {