Compare commits

..

No commits in common. "main" and "cache" have entirely different histories.
main ... cache

11 changed files with 305 additions and 592 deletions

View file

@ -2,25 +2,20 @@
All notable changes to this project will be documented in this file.
## Version 1.2.0 (2025-01-15)
## Unreleased Version 1.2.0 (2025-XX-XX)
### Added
- New caching mechanism for references, tagRenderings and filters.
This allows the completions to show _all_ filters, not just the ones in `filters.json` and `questions.json`.
It's also possible to look up uses of a filter or a tagRendering.
The caching will take about 30 seconds to complete, but will be saved so it only needs to be done once. On subsequent activations, the cache will be updated if there are changes to the files. Also, it's updated whenever you save or remove a file in your editor. It is also possible to disable this feature in settings, however this will disable the autocompletion for filters and tagRenderings that are not in the `filters.json` and `questions.json` files, as well as the implementation support.
- Autocompletion for `icon` fields, giving the built-in icons as suggestions. ([#7](https://github.com/RobinLinde/MapCompleteVScode/issues/7))
### Fixed
- Icons with mappings are not clickable anymore. ([#14](https://github.com/RobinLinde/MapCompleteVScode/issues/14))
The caching will take about 30 seconds to complete, but it will only run once per session, and will update individual files as they are saved or removed.
## Version 1.1.1 (2025-01-07)
### Fixed
- TagRenderings, filters and colours with in override or overrideAll were not working correctly.
- TagsRenderings, filters and colours with in override or overrideAll were not working correctly.
- Colours were not correctly parsed when using hex colours (oops).
- All files were included in the extension, not just the compiled ones. This made the extension about 50kb larger than it needed to be.

View file

@ -25,10 +25,9 @@ Currently the following features are supported:
- License info:
- Definition support for paths in license_info.json files
Upon the first activation of this extension it will scan the workspace for all layers, tagRenderings and filters and cache them. This will take about 30 seconds, but the results are saved so they will only be updated when there are changes to the files. Alternatively, it is possible to manually update the cache by running the "MapComplete: Update cache" command.
It is also possible to deactivate the caching using setting `mapcomplete.caching`, but this will disable the implementation support, as well as the autocompletion for filters and tagRenderings that are not in the `filters.json` and `questions.json` files.
To achieve some of these feature, on startup the extension will parse all the files, which takes about 30 seconds. This will only happen once per session, and will update individual files as they are saved or removed.
![Demo showing tagRendering definition and autocomplete, color picker and autocomplete for filters](images/demo.gif)
![Demo showing autcomplete for layers and icon definition](images/demo.gif)
All notable changes to this project are documented in the [CHANGELOG](CHANGELOG.md) file.
@ -57,5 +56,3 @@ It's also possible to install builds for any commit in any branch by checking ou
## 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".
![Demo showing implementation support for tagRenderings](images/implementation.gif)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 KiB

After

Width:  |  Height:  |  Size: 584 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 662 KiB

182
package-lock.json generated
View file

@ -12,13 +12,13 @@
"jsonc-parser": "^3.3.1"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@stylistic/eslint-plugin": "^2.13.0",
"@eslint/js": "^9.13.0",
"@stylistic/eslint-plugin": "^2.9.0",
"@types/node": "^22",
"@types/vscode": "^1.73.0",
"eslint": "^9.18.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"eslint": "^9.13.0",
"typescript": "^5.7.2",
"typescript-eslint": "^8.19.1"
},
"engines": {
"vscode": "^1.73.0"
@ -106,9 +106,9 @@
}
},
"node_modules/@eslint/core": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz",
"integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@ -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.17.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
"integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
"dev": true,
"license": "MIT",
"engines": {
@ -187,13 +187,12 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz",
"integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^0.10.0",
"levn": "^0.4.1"
},
"engines": {
@ -271,7 +270,6 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@ -285,7 +283,6 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
}
@ -295,7 +292,6 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@ -305,9 +301,9 @@
}
},
"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": "2.12.1",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.12.1.tgz",
"integrity": "sha512-fubZKIHSPuo07FgRTn6S4Nl0uXPRPYVNpyZzIDGfp7Fny6JjNus6kReLD7NI380JXi4HtUTSOZ34LBuNPO1XLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -355,17 +351,16 @@
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz",
"integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==",
"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.19.1",
"@typescript-eslint/type-utils": "8.19.1",
"@typescript-eslint/utils": "8.19.1",
"@typescript-eslint/visitor-keys": "8.19.1",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@ -385,16 +380,15 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz",
"integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==",
"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.19.1",
"@typescript-eslint/types": "8.19.1",
"@typescript-eslint/typescript-estree": "8.19.1",
"@typescript-eslint/visitor-keys": "8.19.1",
"debug": "^4.3.4"
},
"engines": {
@ -410,14 +404,13 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz",
"integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0"
"@typescript-eslint/types": "8.19.1",
"@typescript-eslint/visitor-keys": "8.19.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -428,14 +421,13 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz",
"integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "8.20.0",
"@typescript-eslint/utils": "8.20.0",
"@typescript-eslint/typescript-estree": "8.19.1",
"@typescript-eslint/utils": "8.19.1",
"debug": "^4.3.4",
"ts-api-utils": "^2.0.0"
},
@ -452,11 +444,10 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz",
"integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@ -466,14 +457,13 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz",
"integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/types": "8.19.1",
"@typescript-eslint/visitor-keys": "8.19.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@ -493,16 +483,15 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz",
"integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==",
"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.19.1",
"@typescript-eslint/types": "8.19.1",
"@typescript-eslint/typescript-estree": "8.19.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -517,13 +506,12 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz",
"integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/types": "8.19.1",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@ -609,7 +597,6 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@ -619,7 +606,6 @@
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
@ -735,19 +721,19 @@
}
},
"node_modules/eslint": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz",
"integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==",
"version": "9.17.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
"integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
"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.9.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.18.0",
"@eslint/plugin-kit": "^0.2.5",
"@eslint/js": "9.17.0",
"@eslint/plugin-kit": "^0.2.3",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1",
@ -924,7 +910,6 @@
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@ -941,7 +926,6 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
@ -968,7 +952,6 @@
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
"dev": true,
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
}
@ -991,7 +974,6 @@
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -1067,8 +1049,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true,
"license": "MIT"
"dev": true
},
"node_modules/has-flag": {
"version": "4.0.0",
@ -1145,7 +1126,6 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@ -1261,7 +1241,6 @@
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
}
@ -1271,7 +1250,6 @@
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@ -1285,7 +1263,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
},
@ -1298,7 +1275,6 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@ -1457,8 +1433,7 @@
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
]
},
"node_modules/resolve-from": {
"version": "4.0.0",
@ -1475,7 +1450,6 @@
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
@ -1500,7 +1474,6 @@
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"queue-microtask": "^1.2.2"
}
@ -1510,7 +1483,6 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@ -1572,7 +1544,6 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@ -1606,9 +1577,9 @@
}
},
"node_modules/typescript": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@ -1620,15 +1591,14 @@
}
},
"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.19.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.1.tgz",
"integrity": "sha512-LKPUQpdEMVOeKluHi8md7rwLcoXHhwvWp3x+sJkMuq3gGm9yaYJtPo8sRZSblMFJ5pcOGCAak/scKf1mvZDlQw==",
"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.19.1",
"@typescript-eslint/parser": "8.19.1",
"@typescript-eslint/utils": "8.19.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View file

@ -39,34 +39,15 @@
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@stylistic/eslint-plugin": "^2.13.0",
"@eslint/js": "^9.13.0",
"@stylistic/eslint-plugin": "^2.9.0",
"@types/node": "^22",
"@types/vscode": "^1.73.0",
"eslint": "^9.18.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"eslint": "^9.13.0",
"typescript": "^5.7.2",
"typescript-eslint": "^8.19.1"
},
"dependencies": {
"jsonc-parser": "^3.3.1"
},
"contributes": {
"configuration": {
"type": "object",
"title": "MapComplete",
"properties": {
"mapcomplete.caching": {
"type": "boolean",
"default": true,
"description": "Enable caching of MapComplete themes and layers."
}
}
},
"commands": [
{
"command": "mapcomplete.refresh",
"title": "MapComplete: Refresh cache for themes, layers, filters and tagRenderings"
}
]
}
}

View file

@ -14,27 +14,6 @@ import { pathDefinitionProvider } from "./license_info";
import { CacheWorker } from "./utils/cache";
export async function activate(context: vscode.ExtensionContext) {
let cacheWorker: CacheWorker | undefined;
// Listen for changes in the caching setting
vscode.workspace.onDidChangeConfiguration(async (e) => {
if (e.affectsConfiguration("mapcomplete.caching")) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
cacheWorker = await CacheWorker.create(context);
} else {
cacheWorker?.dispose();
cacheWorker = undefined;
}
}
});
// Listen for refreshCache command
vscode.commands.registerCommand("mapcomplete.refreshCache", async () => {
if (cacheWorker) {
await cacheWorker.refreshCache();
}
});
// Activate all theme related features
context.subscriptions.push(layerCompletionProvider, layerDefinitionProvider);
@ -55,8 +34,9 @@ export async function activate(context: vscode.ExtensionContext) {
// Activate all generic features
context.subscriptions.push(iconDefinitionProvider, colorProvider);
// Activate the cache worker, if caching is enabled
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
cacheWorker = await CacheWorker.create(context);
}
// Upon activation, we also scan the workspace for all themes and layers
// and save them in a cache, so we can quickly look up definitions and completions
// for each theme and layer
// We should also listen for changes in the workspace, so we can update the cache
CacheWorker.create(context);
}

View file

@ -12,62 +12,6 @@ import {
vsCodeToHex,
} from "./utils/color";
/**
* This provider will provide completions for icons, based on the files in the assets/svg folder
*/
export const iconCompletionProvider =
vscode.languages.registerCompletionItemProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/*/*/*.json",
},
{
async provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
) {
console.log("iconCompletionProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const regexes = [/icon$/, /icon.render/, /icon.mappings.\d+.then$/];
if (regexes.some((regex) => regex.exec(jsonPath))) {
// We need to look at all the files in the assets/svg folder
const svgFolder = path.join(
(vscode.workspace.workspaceFolders
? vscode.workspace.workspaceFolders[0].uri.fsPath
: "") || "",
"assets",
"svg"
);
const files = await vscode.workspace.fs.readDirectory(
vscode.Uri.file(svgFolder)
);
const icons: vscode.CompletionItem[] = [];
files.forEach((file) => {
if (file[1] === 1) {
if (file[0].endsWith(".svg")) {
const name = file[0].split(".")[0];
icons.push({
label: name,
kind: vscode.CompletionItemKind.File,
insertText: name,
});
}
}
});
return icons;
}
},
}
);
/**
* Icon definition provider
*
@ -96,12 +40,6 @@ export const iconDefinitionProvider =
const iconPath = getValueFromPath(text, rawJsonPath);
console.log("Found reference to icon", iconPath);
// Check if there is a mapping in there, cause we can't predict the icon path
const regex = /{{.+}}/;
if (regex.exec(iconPath)) {
return [];
}
let fullIconPath: string;
// Check if the path starts with a dot, if so, it's a relative path

View file

@ -185,66 +185,64 @@ export const tagRenderingImplementationProvider =
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("tagRenderingImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
console.log("tagRenderingImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
const regex = /^tagRenderings(\+)?\.\d+\.id$/;
const regex = /^tagRenderings(\+)?\.\d+\.id$/;
if (regex.exec(jsonPath)) {
const tagRenderingId = getValueFromPath(text, rawJsonPath);
const layerName = document.fileName.split("/").pop()?.split(".")[0];
const to = `layers.${layerName}.tagRenderings.${tagRenderingId}`;
if (regex.exec(jsonPath)) {
const tagRenderingId = getValueFromPath(text, rawJsonPath);
const layerName = document.fileName.split("/").pop()?.split(".")[0];
const to = `layers.${layerName}.tagRenderings.${tagRenderingId}`;
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
if (references.length === 0) {
return null;
} else {
console.log(`Found ${references.length} references to ${to}`);
if (references.length === 0) {
return null;
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
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}`,
reference
);
const links: vscode.DefinitionLink[] = [];
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}`,
reference
);
// 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(
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,
});
} else {
console.error("Incomplete reference", reference);
}
// 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(
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,
});
} else {
console.error("Incomplete reference", reference);
}
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
}
return null;
}
return null;
},
}
);
@ -419,67 +417,65 @@ export const filterImplementationProvider =
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("filterImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
console.log("filterImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
const regex = /^filter(\+)?\.\d+\.id$/;
const regex = /^filter(\+)?\.\d+\.id$/;
if (regex.exec(jsonPath)) {
const filterId = getValueFromPath(text, rawJsonPath);
const layerName = document.fileName.split("/").pop()?.split(".")[0];
const to = `layers.${layerName}.filter.${filterId}`;
if (regex.exec(jsonPath)) {
const filterId = getValueFromPath(text, rawJsonPath);
const layerName = document.fileName.split("/").pop()?.split(".")[0];
const to = `layers.${layerName}.filter.${filterId}`;
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
if (references.length === 0) {
console.log("No references found to", to);
return null;
} else {
console.log(`Found ${references.length} references to ${to}`);
if (references.length === 0) {
console.log("No references found to", to);
return null;
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
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}`,
reference
);
const links: vscode.DefinitionLink[] = [];
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}`,
reference
);
// 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(
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,
});
} else {
console.error("Incomplete reference", reference);
}
// 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(
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,
});
} else {
console.error("Incomplete reference", reference);
}
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
}
return null;
}
return null;
},
}
);
@ -496,63 +492,61 @@ export const layerImplementationProvider =
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("layerImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
console.log("layerImplementationProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
// Easiest regex in this package for sure
const regex = /^id$/;
// Easiest regex in this package for sure
const regex = /^id$/;
if (regex.exec(jsonPath)) {
const layerId = getValueFromPath(text, rawJsonPath);
const to = `layers.${layerId}`;
if (regex.exec(jsonPath)) {
const layerId = getValueFromPath(text, rawJsonPath);
const to = `layers.${layerId}`;
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
try {
const cache = await Cache.create();
const references = cache.getReferences(to);
if (references.length === 0) {
console.log("No references found to", to);
return null;
} else {
console.log(`Found ${references.length} references to ${to}`);
if (references.length === 0) {
console.log("No references found to", to);
return null;
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
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}`,
reference
);
const links: vscode.DefinitionLink[] = [];
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}`,
reference
);
// 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(
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,
});
} else {
console.error("Incomplete reference", reference);
}
// 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(
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,
});
} else {
console.error("Incomplete reference", reference);
}
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
console.log(`Found ${links.length} implementations`);
return links;
}
} catch (error) {
console.error("Error get implementation", error);
}
}
},

View file

@ -18,16 +18,7 @@ export class CacheWorker {
/**
* List of cache items
*/
private cache: CacheData = {
timestamp: 0,
items: [],
files: {},
};
/**
* File system watcher
*/
private watcher: vscode.FileSystemWatcher | undefined;
private cache: CacheItem[] = [];
/**
* Creates a new cache
@ -39,7 +30,6 @@ export class CacheWorker {
context: vscode.ExtensionContext
): Promise<CacheWorker> {
const cache = new CacheWorker(context);
await cache.loadCacheFromFile();
await cache.scanWorkspace();
return cache;
}
@ -56,22 +46,11 @@ export class CacheWorker {
this.createFileSystemWatcher();
}
/**
* Disposes the cache worker
*/
public dispose() {
// Save the cache before disposing
this.save();
// Dispose the file system watcher
this.watcher?.dispose();
}
/**
* Saves the current cache to the storage as JSON
* TODO: Find a more elegant way to do this
*/
private save() {
this.cache.timestamp = Date.now();
const jsonString = JSON.stringify(this.cache);
// Save it in the cache.json file in the .cache folder in the workspace
const workspaceFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
@ -83,48 +62,16 @@ export class CacheWorker {
}
}
/**
* Load the cache from the .cache/cache.json file
*/
private async loadCacheFromFile() {
try {
const workspaceFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
const cacheUri = vscode.Uri.file(`${workspaceFolder}/.cache/cache.json`);
const cache = await vscode.workspace.fs.readFile(cacheUri);
const cacheString = new TextDecoder().decode(cache);
this.cache = JSON.parse(cacheString);
} catch (error) {
console.error("Failed to load cache from file:", error);
this.cache = { timestamp: 0, items: [], files: {} };
}
}
/**
* Completely clears the cache
*/
private async clearCache() {
this.cache = { timestamp: 0, items: [], files: {} };
this.save();
}
/**
* Refreshes the cache
*/
async refreshCache() {
await this.clearCache();
await this.scanWorkspace();
}
/**
* Create a file system watcher
*/
private createFileSystemWatcher() {
this.watcher = vscode.workspace.createFileSystemWatcher(
const watcher = vscode.workspace.createFileSystemWatcher(
"**/assets/**/*.json"
);
this.watcher.onDidChange(this.onChanged, this, this.context.subscriptions);
this.watcher.onDidCreate(this.onCreated, this, this.context.subscriptions);
this.watcher.onDidDelete(this.onDeleted, this, this.context.subscriptions);
watcher.onDidChange(this.onChanged, this, this.context.subscriptions);
watcher.onDidCreate(this.onCreated, this, this.context.subscriptions);
watcher.onDidDelete(this.onDeleted, this, this.context.subscriptions);
}
private onChanged(uri: vscode.Uri) {
@ -143,36 +90,10 @@ export class CacheWorker {
* Scans the workspace for all themes and layers
*/
private async scanWorkspace() {
let changedFiles = 0;
let unchangedFiles = 0;
const files = await vscode.workspace.findFiles("assets/*/*/*.json");
const files = await vscode.workspace.findFiles("**/assets/**/*.json");
for (const file of files) {
if (
file.fsPath.endsWith("license_info.json") ||
file.fsPath.endsWith(".proto.json") ||
file.fsPath.endsWith("layers/favourite/favourite.json")
) {
continue;
}
const stats = await vscode.workspace.fs.stat(file);
if (stats.mtime > (this.cache.files[file.fsPath] || 0)) {
console.log(
"File has changed",
file.fsPath,
"last modified",
stats.mtime,
"cache",
this.cache.files[file.fsPath]
);
this.saveFileToCache(file);
changedFiles++;
} else {
unchangedFiles++;
}
this.saveFileToCache(file);
}
console.log(
`Scanned workspace: ${changedFiles} changed files, ${unchangedFiles} unchanged files`
);
}
/**
@ -220,7 +141,7 @@ export class CacheWorker {
* @param uri File URI
*/
private deleteFileFromCache(uri: vscode.Uri) {
this.cache.items = this.cache.items.filter(
this.cache = this.cache.filter(
(item) => item.filePath.fsPath !== uri.fsPath
);
@ -263,7 +184,7 @@ export class CacheWorker {
`**/assets/layers/${layer}/${layer}.json`
);
this.cache.items.push({
this.cache.push({
id: layer,
filePath: uri,
jsonPath: ["layers"],
@ -300,7 +221,7 @@ export class CacheWorker {
`**/assets/layers/${layer.builtin}/${layer.builtin}.json`
);
this.cache.items.push({
this.cache.push({
id: layer.builtin,
filePath: uri,
jsonPath: ["layers"],
@ -337,7 +258,7 @@ export class CacheWorker {
`**/assets/layers/${builtinLayer}/${builtinLayer}.json`
);
this.cache.items.push({
this.cache.push({
id: builtinLayer,
filePath: uri,
jsonPath: ["layers"],
@ -367,12 +288,6 @@ export class CacheWorker {
}
}
// We also need to update the timestamp for this file
// First, we need to get the last modified date of the file
const stats = await vscode.workspace.fs.stat(uri);
this.cache.files[uri.fsPath] = stats.mtime;
// Save the cache
this.save();
this.printCache();
}
@ -396,15 +311,6 @@ export class CacheWorker {
const from = `layers.${uriFileName.split(".")[0]}`;
await this.saveLayerTextToCache(text, uri, from);
// We also need to update the timestamp for this file
// First, we need to get the last modified date of the file
const stats = await vscode.workspace.fs.stat(uri);
this.cache.files[uri.fsPath] = stats.mtime;
// Save the cache
this.save();
this.printCache();
}
/**
@ -469,6 +375,9 @@ export class CacheWorker {
} else {
console.log("No filters found in", filePath);
}
this.save();
this.printCache();
}
/**
@ -535,7 +444,7 @@ export class CacheWorker {
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
this.cache.push({
id: tagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
@ -598,7 +507,7 @@ export class CacheWorker {
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
this.cache.push({
id: tagRendering.builtin,
filePath: fromUri,
jsonPath: ["tagRenderings"],
@ -656,7 +565,7 @@ export class CacheWorker {
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
this.cache.push({
id: builtinTagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
@ -680,7 +589,7 @@ export class CacheWorker {
} else if (!referencesOnly) {
// We've now had all possible references, so now we must have an acutal tagRendering
console.log(`TagRendering found in ${from}`);
this.cache.items.push({
this.cache.push({
id: `${json.id}.${tagRendering.id}`,
filePath: fromUri,
jsonPath: ["tagRenderings"],
@ -754,7 +663,7 @@ export class CacheWorker {
}
const toRange = getStartEnd(toText, ["filter", toFilterIndex]);
this.cache.items.push({
this.cache.push({
id: filter,
filePath: fromUri,
jsonPath: ["filters"],
@ -776,7 +685,7 @@ export class CacheWorker {
} else if (typeof filter === "object" && !referencesOnly) {
// This is a filter, which can be reused
console.log(`Filter found in ${from}`);
this.cache.items.push({
this.cache.push({
id: `${json.id}.${filter.id}`,
filePath: fromUri,
jsonPath: ["filters"],
@ -799,11 +708,7 @@ export class CacheWorker {
* Cache for interacting with the cache
*/
export class Cache {
private cache: CacheData = {
timestamp: 0,
items: [],
files: {},
};
private cache: CacheItem[] = [];
public static async create() {
const cache = new Cache();
@ -837,7 +742,7 @@ export class Cache {
public getTagRenderings(): vscode.CompletionItem[] {
console.log("Getting tag renderings from cache");
const tagRenderings: vscode.CompletionItem[] = [];
for (const item of this.cache.items) {
for (const item of this.cache) {
if (item.type === "tagRendering") {
if (item.id.startsWith("questions.")) {
const completionItem = new vscode.CompletionItem(
@ -863,7 +768,7 @@ export class Cache {
public getFilters(): vscode.CompletionItem[] {
console.log("Getting filters from cache");
const filters: vscode.CompletionItem[] = [];
for (const item of this.cache.items) {
for (const item of this.cache) {
if (item.type === "filter") {
if (item.id.startsWith("filters.")) {
const completionItem = new vscode.CompletionItem(
@ -890,7 +795,7 @@ export class Cache {
* @returns List of references
*/
public getReferences(to: string): CacheItem[] {
return this.cache.items.filter((item) => {
return this.cache.filter((item) => {
if (item.type === "reference") {
return item.reference?.to.id === to;
}
@ -899,28 +804,6 @@ export class Cache {
}
}
/**
* Layout of a cache data file
*/
interface CacheData {
/**
* Timestamp when the cache was last updated
*/
timestamp: number;
/**
* List of cache items
*/
items: CacheItem[];
/**
* List of files, together with their last modified timestamp
*
* The timestamp is defined as the number of milliseconds since January 1, 1970, 00:00:00 UTC
*/
files: Record<string, number>;
}
/**
* A cached item
* Can be a tagRendering or filter from a(n) (inline) layer

View file

@ -33,20 +33,16 @@ export async function getAvailableLayers(): Promise<string[]> {
}
/**
* Utility function to get the tagRenderings from all available layers
* Utility function to get the tagRenderings from the questions layer
*
* This function first tries to get all of the tagRenderings from the cache, and if that fails, it falls back to the questions.json file
*
* @returns List of CompletionItems for tagRenderings
*/
export async function getTagRenderings(): Promise<vscode.CompletionItem[]> {
// First, we try to get the tagRenderings from the cache, if it is enabled
// First, we try to get the tagRenderings from the cache
// If the cache is not available, instead return the tagRenderings from the questions layer
if (!vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
return getTagRenderingsUncached();
}
try {
const cache = await Cache.create();
return cache.getTagRenderings();
@ -56,58 +52,46 @@ export async function getTagRenderings(): Promise<vscode.CompletionItem[]> {
error
);
return getTagRenderingsUncached();
}
}
const tagRenderings: vscode.CompletionItem[] = [];
/**
* Utility function to get the tagRenderings from the questions layer
*
* @returns List of CompletionItems for tagRenderings
*/
async function getTagRenderingsUncached(): Promise<vscode.CompletionItem[]> {
const tagRenderings: vscode.CompletionItem[] = [];
// Open the questions layer file
const questionsFile = await vscode.workspace.findFiles(
"assets/layers/questions/questions.json",
"**/node_modules/**"
);
if (questionsFile.length === 0) {
console.error("questions.json not found");
return [];
}
const content = await vscode.workspace.fs.readFile(questionsFile[0]);
const questions = JSON.parse(new TextDecoder().decode(content));
for (const tagRendering of questions.tagRenderings) {
tagRenderings.push(
new vscode.CompletionItem(
tagRendering.id,
vscode.CompletionItemKind.Value
)
// Open the questions layer file
const questionsFile = await vscode.workspace.findFiles(
"assets/layers/questions/questions.json",
"**/node_modules/**"
);
}
return tagRenderings;
if (questionsFile.length === 0) {
console.error("questions.json not found");
return [];
}
const content = await vscode.workspace.fs.readFile(questionsFile[0]);
const questions = JSON.parse(new TextDecoder().decode(content));
for (const tagRendering of questions.tagRenderings) {
tagRenderings.push(
new vscode.CompletionItem(
tagRendering.id,
vscode.CompletionItemKind.Value
)
);
}
return tagRenderings;
}
}
/**
* Utility function to get the filters from all available layers
* Utility function to get the filters from the filters layer
*
* This function first tries to get all of the filters from the cache, and if that fails, it falls back to the filters.json file
*
* @returns List of CompletionItems for tagRenderings
*/
export async function getFilters(): Promise<vscode.CompletionItem[]> {
// First, we try to get the filters from the cache, if it is enabled
// First, we try to get the filters from the cache
// If the cache is not available, instead return the filters from the filters layer
if (!vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
return getFiltersUncached();
}
try {
const cache = await Cache.create();
return cache.getFilters();
@ -117,37 +101,28 @@ export async function getFilters(): Promise<vscode.CompletionItem[]> {
error
);
return getFiltersUncached();
}
}
const filtersList: vscode.CompletionItem[] = [];
/**
* Utility function to get the filters from the filters layer
*
* @returns List of CompletionItems for tagRenderings
*/
async function getFiltersUncached(): Promise<vscode.CompletionItem[]> {
const filtersList: vscode.CompletionItem[] = [];
// Open the filters layer file
const filtersFile = await vscode.workspace.findFiles(
"assets/layers/filters/filters.json",
"**/node_modules/**"
);
if (filtersFile.length === 0) {
console.error("filters.json not found");
return [];
}
const content = await vscode.workspace.fs.readFile(filtersFile[0]);
const filters = JSON.parse(new TextDecoder().decode(content));
for (const filter of filters.filter) {
filtersList.push(
new vscode.CompletionItem(filter.id, vscode.CompletionItemKind.Value)
// Open the filters layer file
const filtersFile = await vscode.workspace.findFiles(
"assets/layers/filters/filters.json",
"**/node_modules/**"
);
}
return filtersList;
if (filtersFile.length === 0) {
console.error("filters.json not found");
return [];
}
const content = await vscode.workspace.fs.readFile(filtersFile[0]);
const filters = JSON.parse(new TextDecoder().decode(content));
for (const filter of filters.filter) {
filtersList.push(
new vscode.CompletionItem(filter.id, vscode.CompletionItemKind.Value)
);
}
return filtersList;
}
}