├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ └── issue.md ├── dependabot.yml └── workflows │ ├── ci.yml │ └── codeql-analysis.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── biome.json ├── coc-rust-analyzer-configurations.json ├── esbuild.mjs ├── generate-config-schema.js ├── package-lock.json ├── package.json ├── src ├── client.ts ├── commands.ts ├── config.ts ├── ctx.ts ├── downloader.ts ├── index.ts └── lsp_ext.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | 7 | [*.{js,ts}] 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | max_line_length = 120 12 | 13 | [*.json] 14 | indent_style = space 15 | indent_size = 2 16 | trim_trailing_whitespace = true 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: issue 3 | about: issue 4 | title: '' 5 | labels: '' 6 | assignees: fannheyward 7 | 8 | --- 9 | 10 | **What's the output of `:CocInfo`** 11 | 12 | **What's the output of `:CocCommand rust-analyzer.serverVersion`** 13 | 14 | **What's your coc-rust-analyzer version? You can get it from `:CocList extensions`** 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | open-pull-requests-limit: 10 5 | directory: "/" 6 | schedule: 7 | interval: monthly 8 | groups: 9 | dev-dependencies-ts-eslint: 10 | patterns: 11 | - "@typescript-eslint/*" 12 | reviewers: 13 | - fannheyward 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | node-version: [20] 19 | 20 | env: 21 | NODE_ENV: test 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Use Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | - name: npm ci 30 | run: | 31 | npm ci 32 | - name: npm check 33 | run: | 34 | npm run check 35 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning - action" 2 | 3 | on: 4 | push: 5 | branches: [master, ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master] 9 | schedule: 10 | - cron: '0 17 * * 6' 11 | 12 | jobs: 13 | CodeQL-Build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | with: 21 | # We must fetch at least the immediate parents so that if this is 22 | # a pull request then we can checkout the head. 23 | fetch-depth: 2 24 | 25 | # Initializes the CodeQL tools for scanning. 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@v3 28 | # Override language selection by uncommenting this and choosing your languages 29 | # with: 30 | # languages: go, javascript, csharp, python, cpp, java 31 | 32 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 33 | # If this step fails, then you should remove it and run the build manually (see below) 34 | - name: Autobuild 35 | uses: github/codeql-action/autobuild@v3 36 | 37 | # ℹ️ Command-line programs to run using the OS shell. 38 | # 📚 https://git.io/JvXDl 39 | 40 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 41 | # and modify them (or add more) to build your code if your project 42 | # uses a compiled language 43 | 44 | #- run: | 45 | # make bootstrap 46 | # make release 47 | 48 | - name: Perform CodeQL Analysis 49 | uses: github/codeql-action/analyze@v3 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | node_modules 3 | tsconfig.json 4 | *.map 5 | .tags 6 | .DS_Store 7 | esbuild.js 8 | esbuild.mjs 9 | webpack.config.js 10 | biome.json 11 | coc-rust-analyzer-configurations.json 12 | generate-config-schema.js 13 | yarn.lock 14 | yarn-error.log 15 | .editorconfig 16 | .eslintrc.js 17 | .github 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Heyward Fann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coc-rust-analyzer 2 | 3 | 4 | GitHub Sponsors 5 | Patreon donate button 6 | PayPal donate button 7 | 8 | [rust-analyzer](https://github.com/rust-lang/rust-analyzer) for Vim/Neovim, works as an extension with coc.nvim. 9 | 10 | 11 | 10 12 | 13 | ## Install 14 | 15 | `:CocInstall coc-rust-analyzer` 16 | 17 | > remove `rust-analyzer` config from `coc-settings.json` if you've set 18 | 19 | ## Notes 20 | 21 | It's recommended to add `$CARGO_HOME` to `workspace.ignoredFolders` to stop rust-analyzer runs `cargo check` on sysroot crates: 22 | 23 | ```json 24 | "workspace.ignoredFolders": [ 25 | "$HOME", 26 | "$HOME/.cargo/**", 27 | "$HOME/.rustup/**" 28 | ], 29 | ``` 30 | 31 | ## Configurations 32 | 33 | This extension is configured using a jsonc file. You can open this configuration file using the command `:CocConfig`, and it is typically located at `$HOME/.config/nvim/coc-settings.json`. You can get the configurations list from the [package.json](https://github.com/fannheyward/coc-rust-analyzer/blob/master/package.json#L72) file of this extension. 34 | 35 | ## Commands 36 | 37 | You can use these commands by `:CocCommand XYZ`. 38 | 39 | | Command | Description | 40 | | -- | -- | 41 | | rust-analyzer.analyzerStatus | Show rust-analyzer status | 42 | | rust-analyzer.debug | List available runnables of current file and debug the selected one | 43 | | rust-analyzer.expandMacro | Expand macro recursively | 44 | | rust-analyzer.explainError | Explain the currently hovered error message | 45 | | rust-analyzer.joinLines | Join lines | 46 | | rust-analyzer.matchingBrace | Find matching brace | 47 | | rust-analyzer.memoryUsage | Memory Usage (Clears Database) | 48 | | rust-analyzer.moveItemUp | Move item up | 49 | | rust-analyzer.moveItemDown | Move item down | 50 | | rust-analyzer.openDocs | Open docs under cursor | 51 | | rust-analyzer.parentModule | Locate parent module | 52 | | rust-analyzer.peekTests | Peek related tests | 53 | | rust-analyzer.reload | Restart rust-analyzer server | 54 | | rust-analyzer.reloadWorkspace | Reload workspace | 55 | | rust-analyzer.run | List available runnables of current file and run the selected one | 56 | | rust-analyzer.serverVersion | Show current Rust Analyzer server version | 57 | | rust-analyzer.ssr | Structural Search Replace | 58 | | rust-analyzer.viewSyntaxTree | Show syntax tree | 59 | | rust-analyzer.testCurrent | Test Current | 60 | | rust-analyzer.install | Install latest `rust-analyzer` from [GitHub release](https://github.com/rust-lang/rust-analyzer/releases) | 61 | | rust-analyzer.upgrade | Download latest `rust-analyzer` from [GitHub release](https://github.com/rust-lang/rust-analyzer/releases) | 62 | | rust-analyzer.viewHir | View Hir | 63 | | rust-analyzer.viewMir | View Mir | 64 | | rust-analyzer.viewFileText | View File Text | 65 | | rust-analyzer.viewCrateGraph | View Crate Graph | 66 | | rust-analyzer.viewFullCrateGraph | View Crate Graph (Full) | 67 | | rust-analyzer.shuffleCrateGraph | Shuffle Crate Graph | 68 | | rust-analyzer.runFlycheck | Run flycheck | 69 | | rust-analyzer.cancelFlycheck | Cancel running flychecks | 70 | | rust-analyzer.clearFlycheck | Clear flycheck diagnostics | 71 | | rust-analyzer.rebuildProcMacros | Rebuild proc macros and build scripts | 72 | | rust-analyzer.interpretFunction | Interpret Function | 73 | 74 | ## License 75 | 76 | MIT 77 | 78 | --- 79 | 80 | > This extension is built with [create-coc-extension](https://github.com/fannheyward/create-coc-extension) 81 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", 3 | "files": { 4 | "includes": ["**", "!**/src/lsp_ext.ts"] 5 | }, 6 | "formatter": { 7 | "enabled": true, 8 | "indentStyle": "space", 9 | "indentWidth": 2, 10 | "lineWidth": 120 11 | }, 12 | "javascript": { 13 | "formatter": { 14 | "quoteStyle": "single" 15 | } 16 | }, 17 | "assist": { "actions": { "source": { "organizeImports": "off" } } }, 18 | "linter": { 19 | "enabled": true, 20 | "rules": { 21 | "recommended": true, 22 | "complexity": { 23 | "useLiteralKeys": "off" 24 | }, 25 | "style": { 26 | "useNumberNamespace": "off", 27 | "noNonNullAssertion": "off", 28 | "noParameterAssign": "error", 29 | "useAsConstAssertion": "error", 30 | "useDefaultParameterLast": "error", 31 | "useEnumInitializers": "error", 32 | "useSelfClosingElements": "error", 33 | "useSingleVarDeclarator": "error", 34 | "noUnusedTemplateLiteral": "error", 35 | "noInferrableTypes": "error", 36 | "noUselessElse": "error" 37 | }, 38 | "suspicious": { 39 | "noExplicitAny": "off" 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /coc-rust-analyzer-configurations.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.enable": { 3 | "type": "boolean", 4 | "markdownDescription": "Enable `coc-rust-analyzer`", 5 | "default": true 6 | }, 7 | "rust-analyzer.disableProgressNotifications": { 8 | "type": "boolean", 9 | "default": false, 10 | "markdownDescription": "Disable initialization and workdone progress notifications" 11 | }, 12 | "rust-analyzer.disablePullDiagnostic": { 13 | "type": "boolean", 14 | "default": true, 15 | "markdownDescription": "Disable pullDiagnostic feature" 16 | }, 17 | "rust-analyzer.terminal.startinsert": { 18 | "type": "boolean", 19 | "default": false, 20 | "markdownDescription": "Enter insert mode after terminal displayed" 21 | }, 22 | "rust-analyzer.debug.runtime": { 23 | "type": "string", 24 | "default": "termdebug", 25 | "enum": ["termdebug", "vimspector", "nvim-dap"], 26 | "markdownDescription": "Choose which debug runtime to use", 27 | "enumDescriptions": [ 28 | "`\"termdebug\"` use vim/neovim builtin debugger - gdb", 29 | "`\"vimspector\"` use vimspector plugin", 30 | "`\"nvim-dap\"` use nvim-dap plugin" 31 | ] 32 | }, 33 | "rust-analyzer.debug.vimspector.configuration.name": { 34 | "type": "string", 35 | "default": "launch", 36 | "markdownDescription": "Specify the name of the vimspector configuration name. The following args will be passed to the configuration: `Executable` and `Args` (both strings)" 37 | }, 38 | "rust-analyzer.debug.nvimdap.configuration.template": { 39 | "type": "string", 40 | "default": "", 41 | "markdownDescription": "Configuration template used to invoked dap.run([conf](https://github.com/mfussenegger/nvim-dap/blob/0e6b7c47dd70e80793ed39271b2aa712d9366dbc/doc/dap.txt#L656C2-L656C2)). The template will be instantiate like this: `$exe` will be replaced with executable path, `$args` will be replaced with arguments." 42 | }, 43 | "rust-analyzer.server.path": { 44 | "type": ["null", "string"], 45 | "default": null, 46 | "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then \"rust-analyzer.updates.channel\" setting is not used" 47 | }, 48 | "rust-analyzer.server.extraEnv": { 49 | "type": ["null", "object"], 50 | "default": null, 51 | "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging." 52 | }, 53 | "rust-analyzer.restartServerOnConfigChange": { 54 | "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.", 55 | "default": false, 56 | "type": "boolean" 57 | }, 58 | "rust-analyzer.trace.server": { 59 | "type": "string", 60 | "scope": "window", 61 | "enum": ["off", "messages", "verbose"], 62 | "enumDescriptions": ["No traces", "Error only", "Full log"], 63 | "default": "off", 64 | "markdownDescription": "Trace requests to the rust-analyzer" 65 | }, 66 | "rust-analyzer.updates.prompt": { 67 | "type": ["boolean", "string"], 68 | "enum": [true, false, "neverDownload"], 69 | "default": true, 70 | "markdownDescription": "Prompt the user before downloading rust-analyzer" 71 | }, 72 | "rust-analyzer.updates.checkOnStartup": { 73 | "type": "boolean", 74 | "default": true, 75 | "markdownDescription": "Auto-check rust-analyzer updates on startup" 76 | }, 77 | "rust-analyzer.updates.channel": { 78 | "type": "string", 79 | "default": "stable", 80 | "enum": ["stable", "nightly"], 81 | "markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs", 82 | "enumDescriptions": [ 83 | "`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general", 84 | "`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**" 85 | ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /esbuild.mjs: -------------------------------------------------------------------------------- 1 | import * as esbuild from 'esbuild'; 2 | 3 | const options = { 4 | entryPoints: ['src/index.ts'], 5 | bundle: true, 6 | sourcemap: process.env.NODE_ENV === 'development', 7 | mainFields: ['module', 'main'], 8 | external: ['coc.nvim'], 9 | platform: 'node', 10 | target: 'node16', 11 | outfile: 'lib/index.js', 12 | }; 13 | 14 | if (process.argv.length > 2 && process.argv[2] === '--watch') { 15 | const ctx = await esbuild.context(options); 16 | await ctx.watch(); 17 | console.log('watching...'); 18 | } else { 19 | const result = await esbuild.build(options); 20 | if (result.errors.length) { 21 | console.error(result.errors); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /generate-config-schema.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { execSync } = require('child_process'); 3 | const packageJson = require('./package.json'); 4 | const coc_ra_config = require('./coc-rust-analyzer-configurations.json'); 5 | 6 | const not_supported = [ 7 | 'rust-analyzer.hover.actions.debug.enable', 8 | 'rust-analyzer.hover.actions.enable', 9 | 'rust-analyzer.hover.actions.gotoTypeDef.enable', 10 | 'rust-analyzer.hover.actions.implementations.enable', 11 | 'rust-analyzer.hover.actions.references.enable', 12 | 'rust-analyzer.hover.actions.run.enable', 13 | ]; 14 | 15 | let schema = execSync('rust-analyzer --print-config-schema', { encoding: 'utf8' }); 16 | schema = JSON.parse(schema); 17 | for (const item of schema) { 18 | const p = item.properties; 19 | for (const key in p) { 20 | if (!not_supported.includes(key)) { 21 | coc_ra_config[key] = p[key]; 22 | } 23 | } 24 | } 25 | packageJson.contributes.configuration.properties = coc_ra_config; 26 | fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2) + '\n'); 27 | 28 | for (const x of Object.keys(coc_ra_config).sort()) { 29 | console.log(`| \`${x}\` | ${coc_ra_config[x].markdownDescription} | \`${coc_ra_config[x].default || null}\` |`); 30 | } 31 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coc-rust-analyzer", 3 | "version": "0.85.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "coc-rust-analyzer", 9 | "version": "0.85.0", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@biomejs/biome": "^2.2.0", 13 | "@types/adm-zip": "^0.5.7", 14 | "@types/node": "16", 15 | "@types/node-fetch": "2.6.13", 16 | "@types/which": "^3.0.4", 17 | "adm-zip": "0.5.12", 18 | "coc.nvim": "^0.0.83-next.18", 19 | "esbuild": "^0.25.9", 20 | "https-proxy-agent": "^7.0.6", 21 | "node-fetch": "2.6.7", 22 | "typescript": "^5.9.2", 23 | "vscode-languageserver-protocol": "^3.17.5", 24 | "which": "^4.0.0" 25 | }, 26 | "engines": { 27 | "coc": "^0.0.80" 28 | } 29 | }, 30 | "node_modules/@biomejs/biome": { 31 | "version": "2.2.4", 32 | "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.4.tgz", 33 | "integrity": "sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==", 34 | "dev": true, 35 | "license": "MIT OR Apache-2.0", 36 | "bin": { 37 | "biome": "bin/biome" 38 | }, 39 | "engines": { 40 | "node": ">=14.21.3" 41 | }, 42 | "funding": { 43 | "type": "opencollective", 44 | "url": "https://opencollective.com/biome" 45 | }, 46 | "optionalDependencies": { 47 | "@biomejs/cli-darwin-arm64": "2.2.4", 48 | "@biomejs/cli-darwin-x64": "2.2.4", 49 | "@biomejs/cli-linux-arm64": "2.2.4", 50 | "@biomejs/cli-linux-arm64-musl": "2.2.4", 51 | "@biomejs/cli-linux-x64": "2.2.4", 52 | "@biomejs/cli-linux-x64-musl": "2.2.4", 53 | "@biomejs/cli-win32-arm64": "2.2.4", 54 | "@biomejs/cli-win32-x64": "2.2.4" 55 | } 56 | }, 57 | "node_modules/@biomejs/cli-darwin-arm64": { 58 | "version": "2.2.4", 59 | "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.4.tgz", 60 | "integrity": "sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==", 61 | "cpu": [ 62 | "arm64" 63 | ], 64 | "dev": true, 65 | "license": "MIT OR Apache-2.0", 66 | "optional": true, 67 | "os": [ 68 | "darwin" 69 | ], 70 | "engines": { 71 | "node": ">=14.21.3" 72 | } 73 | }, 74 | "node_modules/@biomejs/cli-darwin-x64": { 75 | "version": "2.2.4", 76 | "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.4.tgz", 77 | "integrity": "sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==", 78 | "cpu": [ 79 | "x64" 80 | ], 81 | "dev": true, 82 | "license": "MIT OR Apache-2.0", 83 | "optional": true, 84 | "os": [ 85 | "darwin" 86 | ], 87 | "engines": { 88 | "node": ">=14.21.3" 89 | } 90 | }, 91 | "node_modules/@biomejs/cli-linux-arm64": { 92 | "version": "2.2.4", 93 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.4.tgz", 94 | "integrity": "sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==", 95 | "cpu": [ 96 | "arm64" 97 | ], 98 | "dev": true, 99 | "license": "MIT OR Apache-2.0", 100 | "optional": true, 101 | "os": [ 102 | "linux" 103 | ], 104 | "engines": { 105 | "node": ">=14.21.3" 106 | } 107 | }, 108 | "node_modules/@biomejs/cli-linux-arm64-musl": { 109 | "version": "2.2.4", 110 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.4.tgz", 111 | "integrity": "sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==", 112 | "cpu": [ 113 | "arm64" 114 | ], 115 | "dev": true, 116 | "license": "MIT OR Apache-2.0", 117 | "optional": true, 118 | "os": [ 119 | "linux" 120 | ], 121 | "engines": { 122 | "node": ">=14.21.3" 123 | } 124 | }, 125 | "node_modules/@biomejs/cli-linux-x64": { 126 | "version": "2.2.4", 127 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.4.tgz", 128 | "integrity": "sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==", 129 | "cpu": [ 130 | "x64" 131 | ], 132 | "dev": true, 133 | "license": "MIT OR Apache-2.0", 134 | "optional": true, 135 | "os": [ 136 | "linux" 137 | ], 138 | "engines": { 139 | "node": ">=14.21.3" 140 | } 141 | }, 142 | "node_modules/@biomejs/cli-linux-x64-musl": { 143 | "version": "2.2.4", 144 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.4.tgz", 145 | "integrity": "sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==", 146 | "cpu": [ 147 | "x64" 148 | ], 149 | "dev": true, 150 | "license": "MIT OR Apache-2.0", 151 | "optional": true, 152 | "os": [ 153 | "linux" 154 | ], 155 | "engines": { 156 | "node": ">=14.21.3" 157 | } 158 | }, 159 | "node_modules/@biomejs/cli-win32-arm64": { 160 | "version": "2.2.4", 161 | "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.4.tgz", 162 | "integrity": "sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==", 163 | "cpu": [ 164 | "arm64" 165 | ], 166 | "dev": true, 167 | "license": "MIT OR Apache-2.0", 168 | "optional": true, 169 | "os": [ 170 | "win32" 171 | ], 172 | "engines": { 173 | "node": ">=14.21.3" 174 | } 175 | }, 176 | "node_modules/@biomejs/cli-win32-x64": { 177 | "version": "2.2.4", 178 | "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.4.tgz", 179 | "integrity": "sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==", 180 | "cpu": [ 181 | "x64" 182 | ], 183 | "dev": true, 184 | "license": "MIT OR Apache-2.0", 185 | "optional": true, 186 | "os": [ 187 | "win32" 188 | ], 189 | "engines": { 190 | "node": ">=14.21.3" 191 | } 192 | }, 193 | "node_modules/@esbuild/aix-ppc64": { 194 | "version": "0.25.10", 195 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", 196 | "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", 197 | "cpu": [ 198 | "ppc64" 199 | ], 200 | "dev": true, 201 | "license": "MIT", 202 | "optional": true, 203 | "os": [ 204 | "aix" 205 | ], 206 | "engines": { 207 | "node": ">=18" 208 | } 209 | }, 210 | "node_modules/@esbuild/android-arm": { 211 | "version": "0.25.10", 212 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", 213 | "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", 214 | "cpu": [ 215 | "arm" 216 | ], 217 | "dev": true, 218 | "license": "MIT", 219 | "optional": true, 220 | "os": [ 221 | "android" 222 | ], 223 | "engines": { 224 | "node": ">=18" 225 | } 226 | }, 227 | "node_modules/@esbuild/android-arm64": { 228 | "version": "0.25.10", 229 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", 230 | "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", 231 | "cpu": [ 232 | "arm64" 233 | ], 234 | "dev": true, 235 | "license": "MIT", 236 | "optional": true, 237 | "os": [ 238 | "android" 239 | ], 240 | "engines": { 241 | "node": ">=18" 242 | } 243 | }, 244 | "node_modules/@esbuild/android-x64": { 245 | "version": "0.25.10", 246 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", 247 | "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", 248 | "cpu": [ 249 | "x64" 250 | ], 251 | "dev": true, 252 | "license": "MIT", 253 | "optional": true, 254 | "os": [ 255 | "android" 256 | ], 257 | "engines": { 258 | "node": ">=18" 259 | } 260 | }, 261 | "node_modules/@esbuild/darwin-arm64": { 262 | "version": "0.25.10", 263 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", 264 | "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", 265 | "cpu": [ 266 | "arm64" 267 | ], 268 | "dev": true, 269 | "license": "MIT", 270 | "optional": true, 271 | "os": [ 272 | "darwin" 273 | ], 274 | "engines": { 275 | "node": ">=18" 276 | } 277 | }, 278 | "node_modules/@esbuild/darwin-x64": { 279 | "version": "0.25.10", 280 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", 281 | "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", 282 | "cpu": [ 283 | "x64" 284 | ], 285 | "dev": true, 286 | "license": "MIT", 287 | "optional": true, 288 | "os": [ 289 | "darwin" 290 | ], 291 | "engines": { 292 | "node": ">=18" 293 | } 294 | }, 295 | "node_modules/@esbuild/freebsd-arm64": { 296 | "version": "0.25.10", 297 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", 298 | "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", 299 | "cpu": [ 300 | "arm64" 301 | ], 302 | "dev": true, 303 | "license": "MIT", 304 | "optional": true, 305 | "os": [ 306 | "freebsd" 307 | ], 308 | "engines": { 309 | "node": ">=18" 310 | } 311 | }, 312 | "node_modules/@esbuild/freebsd-x64": { 313 | "version": "0.25.10", 314 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", 315 | "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", 316 | "cpu": [ 317 | "x64" 318 | ], 319 | "dev": true, 320 | "license": "MIT", 321 | "optional": true, 322 | "os": [ 323 | "freebsd" 324 | ], 325 | "engines": { 326 | "node": ">=18" 327 | } 328 | }, 329 | "node_modules/@esbuild/linux-arm": { 330 | "version": "0.25.10", 331 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", 332 | "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", 333 | "cpu": [ 334 | "arm" 335 | ], 336 | "dev": true, 337 | "license": "MIT", 338 | "optional": true, 339 | "os": [ 340 | "linux" 341 | ], 342 | "engines": { 343 | "node": ">=18" 344 | } 345 | }, 346 | "node_modules/@esbuild/linux-arm64": { 347 | "version": "0.25.10", 348 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", 349 | "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", 350 | "cpu": [ 351 | "arm64" 352 | ], 353 | "dev": true, 354 | "license": "MIT", 355 | "optional": true, 356 | "os": [ 357 | "linux" 358 | ], 359 | "engines": { 360 | "node": ">=18" 361 | } 362 | }, 363 | "node_modules/@esbuild/linux-ia32": { 364 | "version": "0.25.10", 365 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", 366 | "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", 367 | "cpu": [ 368 | "ia32" 369 | ], 370 | "dev": true, 371 | "license": "MIT", 372 | "optional": true, 373 | "os": [ 374 | "linux" 375 | ], 376 | "engines": { 377 | "node": ">=18" 378 | } 379 | }, 380 | "node_modules/@esbuild/linux-loong64": { 381 | "version": "0.25.10", 382 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", 383 | "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", 384 | "cpu": [ 385 | "loong64" 386 | ], 387 | "dev": true, 388 | "license": "MIT", 389 | "optional": true, 390 | "os": [ 391 | "linux" 392 | ], 393 | "engines": { 394 | "node": ">=18" 395 | } 396 | }, 397 | "node_modules/@esbuild/linux-mips64el": { 398 | "version": "0.25.10", 399 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", 400 | "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", 401 | "cpu": [ 402 | "mips64el" 403 | ], 404 | "dev": true, 405 | "license": "MIT", 406 | "optional": true, 407 | "os": [ 408 | "linux" 409 | ], 410 | "engines": { 411 | "node": ">=18" 412 | } 413 | }, 414 | "node_modules/@esbuild/linux-ppc64": { 415 | "version": "0.25.10", 416 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", 417 | "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", 418 | "cpu": [ 419 | "ppc64" 420 | ], 421 | "dev": true, 422 | "license": "MIT", 423 | "optional": true, 424 | "os": [ 425 | "linux" 426 | ], 427 | "engines": { 428 | "node": ">=18" 429 | } 430 | }, 431 | "node_modules/@esbuild/linux-riscv64": { 432 | "version": "0.25.10", 433 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", 434 | "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", 435 | "cpu": [ 436 | "riscv64" 437 | ], 438 | "dev": true, 439 | "license": "MIT", 440 | "optional": true, 441 | "os": [ 442 | "linux" 443 | ], 444 | "engines": { 445 | "node": ">=18" 446 | } 447 | }, 448 | "node_modules/@esbuild/linux-s390x": { 449 | "version": "0.25.10", 450 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", 451 | "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", 452 | "cpu": [ 453 | "s390x" 454 | ], 455 | "dev": true, 456 | "license": "MIT", 457 | "optional": true, 458 | "os": [ 459 | "linux" 460 | ], 461 | "engines": { 462 | "node": ">=18" 463 | } 464 | }, 465 | "node_modules/@esbuild/linux-x64": { 466 | "version": "0.25.10", 467 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", 468 | "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", 469 | "cpu": [ 470 | "x64" 471 | ], 472 | "dev": true, 473 | "license": "MIT", 474 | "optional": true, 475 | "os": [ 476 | "linux" 477 | ], 478 | "engines": { 479 | "node": ">=18" 480 | } 481 | }, 482 | "node_modules/@esbuild/netbsd-arm64": { 483 | "version": "0.25.10", 484 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", 485 | "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", 486 | "cpu": [ 487 | "arm64" 488 | ], 489 | "dev": true, 490 | "license": "MIT", 491 | "optional": true, 492 | "os": [ 493 | "netbsd" 494 | ], 495 | "engines": { 496 | "node": ">=18" 497 | } 498 | }, 499 | "node_modules/@esbuild/netbsd-x64": { 500 | "version": "0.25.10", 501 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", 502 | "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", 503 | "cpu": [ 504 | "x64" 505 | ], 506 | "dev": true, 507 | "license": "MIT", 508 | "optional": true, 509 | "os": [ 510 | "netbsd" 511 | ], 512 | "engines": { 513 | "node": ">=18" 514 | } 515 | }, 516 | "node_modules/@esbuild/openbsd-arm64": { 517 | "version": "0.25.10", 518 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", 519 | "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", 520 | "cpu": [ 521 | "arm64" 522 | ], 523 | "dev": true, 524 | "license": "MIT", 525 | "optional": true, 526 | "os": [ 527 | "openbsd" 528 | ], 529 | "engines": { 530 | "node": ">=18" 531 | } 532 | }, 533 | "node_modules/@esbuild/openbsd-x64": { 534 | "version": "0.25.10", 535 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", 536 | "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", 537 | "cpu": [ 538 | "x64" 539 | ], 540 | "dev": true, 541 | "license": "MIT", 542 | "optional": true, 543 | "os": [ 544 | "openbsd" 545 | ], 546 | "engines": { 547 | "node": ">=18" 548 | } 549 | }, 550 | "node_modules/@esbuild/openharmony-arm64": { 551 | "version": "0.25.10", 552 | "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", 553 | "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", 554 | "cpu": [ 555 | "arm64" 556 | ], 557 | "dev": true, 558 | "license": "MIT", 559 | "optional": true, 560 | "os": [ 561 | "openharmony" 562 | ], 563 | "engines": { 564 | "node": ">=18" 565 | } 566 | }, 567 | "node_modules/@esbuild/sunos-x64": { 568 | "version": "0.25.10", 569 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", 570 | "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", 571 | "cpu": [ 572 | "x64" 573 | ], 574 | "dev": true, 575 | "license": "MIT", 576 | "optional": true, 577 | "os": [ 578 | "sunos" 579 | ], 580 | "engines": { 581 | "node": ">=18" 582 | } 583 | }, 584 | "node_modules/@esbuild/win32-arm64": { 585 | "version": "0.25.10", 586 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", 587 | "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", 588 | "cpu": [ 589 | "arm64" 590 | ], 591 | "dev": true, 592 | "license": "MIT", 593 | "optional": true, 594 | "os": [ 595 | "win32" 596 | ], 597 | "engines": { 598 | "node": ">=18" 599 | } 600 | }, 601 | "node_modules/@esbuild/win32-ia32": { 602 | "version": "0.25.10", 603 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", 604 | "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", 605 | "cpu": [ 606 | "ia32" 607 | ], 608 | "dev": true, 609 | "license": "MIT", 610 | "optional": true, 611 | "os": [ 612 | "win32" 613 | ], 614 | "engines": { 615 | "node": ">=18" 616 | } 617 | }, 618 | "node_modules/@esbuild/win32-x64": { 619 | "version": "0.25.10", 620 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", 621 | "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", 622 | "cpu": [ 623 | "x64" 624 | ], 625 | "dev": true, 626 | "license": "MIT", 627 | "optional": true, 628 | "os": [ 629 | "win32" 630 | ], 631 | "engines": { 632 | "node": ">=18" 633 | } 634 | }, 635 | "node_modules/@types/adm-zip": { 636 | "version": "0.5.7", 637 | "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.7.tgz", 638 | "integrity": "sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==", 639 | "dev": true, 640 | "license": "MIT", 641 | "dependencies": { 642 | "@types/node": "*" 643 | } 644 | }, 645 | "node_modules/@types/node": { 646 | "version": "16.18.126", 647 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", 648 | "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", 649 | "dev": true 650 | }, 651 | "node_modules/@types/node-fetch": { 652 | "version": "2.6.13", 653 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", 654 | "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", 655 | "dev": true, 656 | "license": "MIT", 657 | "dependencies": { 658 | "@types/node": "*", 659 | "form-data": "^4.0.4" 660 | } 661 | }, 662 | "node_modules/@types/which": { 663 | "version": "3.0.4", 664 | "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.4.tgz", 665 | "integrity": "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==", 666 | "dev": true, 667 | "license": "MIT" 668 | }, 669 | "node_modules/adm-zip": { 670 | "version": "0.5.12", 671 | "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", 672 | "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==", 673 | "dev": true, 674 | "license": "MIT", 675 | "engines": { 676 | "node": ">=6.0" 677 | } 678 | }, 679 | "node_modules/agent-base": { 680 | "version": "7.1.3", 681 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", 682 | "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", 683 | "dev": true, 684 | "engines": { 685 | "node": ">= 14" 686 | } 687 | }, 688 | "node_modules/asynckit": { 689 | "version": "0.4.0", 690 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 691 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 692 | "dev": true, 693 | "license": "MIT" 694 | }, 695 | "node_modules/call-bind-apply-helpers": { 696 | "version": "1.0.2", 697 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", 698 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", 699 | "dev": true, 700 | "license": "MIT", 701 | "dependencies": { 702 | "es-errors": "^1.3.0", 703 | "function-bind": "^1.1.2" 704 | }, 705 | "engines": { 706 | "node": ">= 0.4" 707 | } 708 | }, 709 | "node_modules/coc.nvim": { 710 | "version": "0.0.83-next.24", 711 | "resolved": "https://registry.npmjs.org/coc.nvim/-/coc.nvim-0.0.83-next.24.tgz", 712 | "integrity": "sha512-5U1efxofnRxNlr4Y05n/bqsd/TSNYrIAoL0AOs55n2l4bUz6IeekmTL0V47mi0/P8fkQQokOuYbV4qELCxxbWA==", 713 | "dev": true, 714 | "engines": { 715 | "node": ">=16.18.0" 716 | }, 717 | "funding": { 718 | "type": "opencollective", 719 | "url": "https://opencollective.com/cocnvim" 720 | }, 721 | "peerDependencies": { 722 | "@types/node": "^16.18.0" 723 | } 724 | }, 725 | "node_modules/combined-stream": { 726 | "version": "1.0.8", 727 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 728 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 729 | "dev": true, 730 | "license": "MIT", 731 | "dependencies": { 732 | "delayed-stream": "~1.0.0" 733 | }, 734 | "engines": { 735 | "node": ">= 0.8" 736 | } 737 | }, 738 | "node_modules/debug": { 739 | "version": "4.4.0", 740 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 741 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 742 | "dev": true, 743 | "dependencies": { 744 | "ms": "^2.1.3" 745 | }, 746 | "engines": { 747 | "node": ">=6.0" 748 | }, 749 | "peerDependenciesMeta": { 750 | "supports-color": { 751 | "optional": true 752 | } 753 | } 754 | }, 755 | "node_modules/delayed-stream": { 756 | "version": "1.0.0", 757 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 758 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 759 | "dev": true, 760 | "license": "MIT", 761 | "engines": { 762 | "node": ">=0.4.0" 763 | } 764 | }, 765 | "node_modules/dunder-proto": { 766 | "version": "1.0.1", 767 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 768 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 769 | "dev": true, 770 | "license": "MIT", 771 | "dependencies": { 772 | "call-bind-apply-helpers": "^1.0.1", 773 | "es-errors": "^1.3.0", 774 | "gopd": "^1.2.0" 775 | }, 776 | "engines": { 777 | "node": ">= 0.4" 778 | } 779 | }, 780 | "node_modules/es-define-property": { 781 | "version": "1.0.1", 782 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", 783 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", 784 | "dev": true, 785 | "license": "MIT", 786 | "engines": { 787 | "node": ">= 0.4" 788 | } 789 | }, 790 | "node_modules/es-errors": { 791 | "version": "1.3.0", 792 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 793 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 794 | "dev": true, 795 | "license": "MIT", 796 | "engines": { 797 | "node": ">= 0.4" 798 | } 799 | }, 800 | "node_modules/es-object-atoms": { 801 | "version": "1.1.1", 802 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", 803 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", 804 | "dev": true, 805 | "license": "MIT", 806 | "dependencies": { 807 | "es-errors": "^1.3.0" 808 | }, 809 | "engines": { 810 | "node": ">= 0.4" 811 | } 812 | }, 813 | "node_modules/es-set-tostringtag": { 814 | "version": "2.1.0", 815 | "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", 816 | "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", 817 | "dev": true, 818 | "license": "MIT", 819 | "dependencies": { 820 | "es-errors": "^1.3.0", 821 | "get-intrinsic": "^1.2.6", 822 | "has-tostringtag": "^1.0.2", 823 | "hasown": "^2.0.2" 824 | }, 825 | "engines": { 826 | "node": ">= 0.4" 827 | } 828 | }, 829 | "node_modules/esbuild": { 830 | "version": "0.25.10", 831 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", 832 | "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", 833 | "dev": true, 834 | "hasInstallScript": true, 835 | "license": "MIT", 836 | "bin": { 837 | "esbuild": "bin/esbuild" 838 | }, 839 | "engines": { 840 | "node": ">=18" 841 | }, 842 | "optionalDependencies": { 843 | "@esbuild/aix-ppc64": "0.25.10", 844 | "@esbuild/android-arm": "0.25.10", 845 | "@esbuild/android-arm64": "0.25.10", 846 | "@esbuild/android-x64": "0.25.10", 847 | "@esbuild/darwin-arm64": "0.25.10", 848 | "@esbuild/darwin-x64": "0.25.10", 849 | "@esbuild/freebsd-arm64": "0.25.10", 850 | "@esbuild/freebsd-x64": "0.25.10", 851 | "@esbuild/linux-arm": "0.25.10", 852 | "@esbuild/linux-arm64": "0.25.10", 853 | "@esbuild/linux-ia32": "0.25.10", 854 | "@esbuild/linux-loong64": "0.25.10", 855 | "@esbuild/linux-mips64el": "0.25.10", 856 | "@esbuild/linux-ppc64": "0.25.10", 857 | "@esbuild/linux-riscv64": "0.25.10", 858 | "@esbuild/linux-s390x": "0.25.10", 859 | "@esbuild/linux-x64": "0.25.10", 860 | "@esbuild/netbsd-arm64": "0.25.10", 861 | "@esbuild/netbsd-x64": "0.25.10", 862 | "@esbuild/openbsd-arm64": "0.25.10", 863 | "@esbuild/openbsd-x64": "0.25.10", 864 | "@esbuild/openharmony-arm64": "0.25.10", 865 | "@esbuild/sunos-x64": "0.25.10", 866 | "@esbuild/win32-arm64": "0.25.10", 867 | "@esbuild/win32-ia32": "0.25.10", 868 | "@esbuild/win32-x64": "0.25.10" 869 | } 870 | }, 871 | "node_modules/form-data": { 872 | "version": "4.0.4", 873 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", 874 | "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", 875 | "dev": true, 876 | "license": "MIT", 877 | "dependencies": { 878 | "asynckit": "^0.4.0", 879 | "combined-stream": "^1.0.8", 880 | "es-set-tostringtag": "^2.1.0", 881 | "hasown": "^2.0.2", 882 | "mime-types": "^2.1.12" 883 | }, 884 | "engines": { 885 | "node": ">= 6" 886 | } 887 | }, 888 | "node_modules/function-bind": { 889 | "version": "1.1.2", 890 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 891 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 892 | "dev": true, 893 | "license": "MIT", 894 | "funding": { 895 | "url": "https://github.com/sponsors/ljharb" 896 | } 897 | }, 898 | "node_modules/get-intrinsic": { 899 | "version": "1.3.0", 900 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", 901 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", 902 | "dev": true, 903 | "license": "MIT", 904 | "dependencies": { 905 | "call-bind-apply-helpers": "^1.0.2", 906 | "es-define-property": "^1.0.1", 907 | "es-errors": "^1.3.0", 908 | "es-object-atoms": "^1.1.1", 909 | "function-bind": "^1.1.2", 910 | "get-proto": "^1.0.1", 911 | "gopd": "^1.2.0", 912 | "has-symbols": "^1.1.0", 913 | "hasown": "^2.0.2", 914 | "math-intrinsics": "^1.1.0" 915 | }, 916 | "engines": { 917 | "node": ">= 0.4" 918 | }, 919 | "funding": { 920 | "url": "https://github.com/sponsors/ljharb" 921 | } 922 | }, 923 | "node_modules/get-proto": { 924 | "version": "1.0.1", 925 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", 926 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", 927 | "dev": true, 928 | "license": "MIT", 929 | "dependencies": { 930 | "dunder-proto": "^1.0.1", 931 | "es-object-atoms": "^1.0.0" 932 | }, 933 | "engines": { 934 | "node": ">= 0.4" 935 | } 936 | }, 937 | "node_modules/gopd": { 938 | "version": "1.2.0", 939 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", 940 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", 941 | "dev": true, 942 | "license": "MIT", 943 | "engines": { 944 | "node": ">= 0.4" 945 | }, 946 | "funding": { 947 | "url": "https://github.com/sponsors/ljharb" 948 | } 949 | }, 950 | "node_modules/has-symbols": { 951 | "version": "1.1.0", 952 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", 953 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", 954 | "dev": true, 955 | "license": "MIT", 956 | "engines": { 957 | "node": ">= 0.4" 958 | }, 959 | "funding": { 960 | "url": "https://github.com/sponsors/ljharb" 961 | } 962 | }, 963 | "node_modules/has-tostringtag": { 964 | "version": "1.0.2", 965 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", 966 | "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", 967 | "dev": true, 968 | "license": "MIT", 969 | "dependencies": { 970 | "has-symbols": "^1.0.3" 971 | }, 972 | "engines": { 973 | "node": ">= 0.4" 974 | }, 975 | "funding": { 976 | "url": "https://github.com/sponsors/ljharb" 977 | } 978 | }, 979 | "node_modules/hasown": { 980 | "version": "2.0.2", 981 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 982 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 983 | "dev": true, 984 | "license": "MIT", 985 | "dependencies": { 986 | "function-bind": "^1.1.2" 987 | }, 988 | "engines": { 989 | "node": ">= 0.4" 990 | } 991 | }, 992 | "node_modules/https-proxy-agent": { 993 | "version": "7.0.6", 994 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", 995 | "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", 996 | "dev": true, 997 | "dependencies": { 998 | "agent-base": "^7.1.2", 999 | "debug": "4" 1000 | }, 1001 | "engines": { 1002 | "node": ">= 14" 1003 | } 1004 | }, 1005 | "node_modules/isexe": { 1006 | "version": "3.1.1", 1007 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", 1008 | "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", 1009 | "dev": true, 1010 | "license": "ISC", 1011 | "engines": { 1012 | "node": ">=16" 1013 | } 1014 | }, 1015 | "node_modules/math-intrinsics": { 1016 | "version": "1.1.0", 1017 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", 1018 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", 1019 | "dev": true, 1020 | "license": "MIT", 1021 | "engines": { 1022 | "node": ">= 0.4" 1023 | } 1024 | }, 1025 | "node_modules/mime-db": { 1026 | "version": "1.52.0", 1027 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1028 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1029 | "dev": true, 1030 | "license": "MIT", 1031 | "engines": { 1032 | "node": ">= 0.6" 1033 | } 1034 | }, 1035 | "node_modules/mime-types": { 1036 | "version": "2.1.35", 1037 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1038 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1039 | "dev": true, 1040 | "license": "MIT", 1041 | "dependencies": { 1042 | "mime-db": "1.52.0" 1043 | }, 1044 | "engines": { 1045 | "node": ">= 0.6" 1046 | } 1047 | }, 1048 | "node_modules/ms": { 1049 | "version": "2.1.3", 1050 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1051 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1052 | "dev": true 1053 | }, 1054 | "node_modules/node-fetch": { 1055 | "version": "2.6.7", 1056 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 1057 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 1058 | "dev": true, 1059 | "dependencies": { 1060 | "whatwg-url": "^5.0.0" 1061 | }, 1062 | "engines": { 1063 | "node": "4.x || >=6.0.0" 1064 | }, 1065 | "peerDependencies": { 1066 | "encoding": "^0.1.0" 1067 | }, 1068 | "peerDependenciesMeta": { 1069 | "encoding": { 1070 | "optional": true 1071 | } 1072 | } 1073 | }, 1074 | "node_modules/tr46": { 1075 | "version": "0.0.3", 1076 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1077 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 1078 | "dev": true 1079 | }, 1080 | "node_modules/typescript": { 1081 | "version": "5.9.3", 1082 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 1083 | "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 1084 | "dev": true, 1085 | "license": "Apache-2.0", 1086 | "bin": { 1087 | "tsc": "bin/tsc", 1088 | "tsserver": "bin/tsserver" 1089 | }, 1090 | "engines": { 1091 | "node": ">=14.17" 1092 | } 1093 | }, 1094 | "node_modules/vscode-jsonrpc": { 1095 | "version": "8.2.0", 1096 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", 1097 | "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", 1098 | "dev": true, 1099 | "engines": { 1100 | "node": ">=14.0.0" 1101 | } 1102 | }, 1103 | "node_modules/vscode-languageserver-protocol": { 1104 | "version": "3.17.5", 1105 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", 1106 | "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", 1107 | "dev": true, 1108 | "dependencies": { 1109 | "vscode-jsonrpc": "8.2.0", 1110 | "vscode-languageserver-types": "3.17.5" 1111 | } 1112 | }, 1113 | "node_modules/vscode-languageserver-types": { 1114 | "version": "3.17.5", 1115 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", 1116 | "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", 1117 | "dev": true 1118 | }, 1119 | "node_modules/webidl-conversions": { 1120 | "version": "3.0.1", 1121 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1122 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 1123 | "dev": true 1124 | }, 1125 | "node_modules/whatwg-url": { 1126 | "version": "5.0.0", 1127 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1128 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0= sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1129 | "dev": true, 1130 | "dependencies": { 1131 | "tr46": "~0.0.3", 1132 | "webidl-conversions": "^3.0.0" 1133 | } 1134 | }, 1135 | "node_modules/which": { 1136 | "version": "4.0.0", 1137 | "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", 1138 | "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", 1139 | "dev": true, 1140 | "license": "ISC", 1141 | "dependencies": { 1142 | "isexe": "^3.1.1" 1143 | }, 1144 | "bin": { 1145 | "node-which": "bin/which.js" 1146 | }, 1147 | "engines": { 1148 | "node": "^16.13.0 || >=18.0.0" 1149 | } 1150 | } 1151 | } 1152 | } 1153 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coc-rust-analyzer", 3 | "version": "0.85.0", 4 | "description": "rust-analyzer for Vim/Neovim, works as an extension with coc.nvim", 5 | "author": "Heyward Fann ", 6 | "license": "MIT", 7 | "main": "lib/index.js", 8 | "keywords": [ 9 | "coc.nvim" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/fannheyward/coc-rust-analyzer.git" 14 | }, 15 | "engines": { 16 | "coc": "^0.0.80" 17 | }, 18 | "activationEvents": [ 19 | "onLanguage:rust" 20 | ], 21 | "scripts": { 22 | "check": "biome check src", 23 | "schema": "node ./generate-config-schema.js", 24 | "build": "node esbuild.mjs", 25 | "watch": "node esbuild.mjs --watch", 26 | "prepare": "node esbuild.mjs" 27 | }, 28 | "devDependencies": { 29 | "@biomejs/biome": "^2.2.0", 30 | "@types/adm-zip": "^0.5.7", 31 | "@types/node": "16", 32 | "@types/node-fetch": "2.6.13", 33 | "@types/which": "^3.0.4", 34 | "adm-zip": "0.5.12", 35 | "coc.nvim": "^0.0.83-next.18", 36 | "esbuild": "^0.25.9", 37 | "https-proxy-agent": "^7.0.6", 38 | "node-fetch": "2.6.7", 39 | "typescript": "^5.9.2", 40 | "vscode-languageserver-protocol": "^3.17.5", 41 | "which": "^4.0.0" 42 | }, 43 | "prettier": { 44 | "singleQuote": true, 45 | "printWidth": 180, 46 | "semi": true 47 | }, 48 | "contributes": { 49 | "rootPatterns": [ 50 | { 51 | "filetype": "rust", 52 | "patterns": [ 53 | "Cargo.toml", 54 | "rust-project.json" 55 | ] 56 | } 57 | ], 58 | "jsonValidation": [ 59 | { 60 | "fileMatch": "rust-project.json", 61 | "url": "https://json.schemastore.org/rust-project.json" 62 | }, 63 | { 64 | "fileMatch": ".rust-project.json", 65 | "url": "https://json.schemastore.org/rust-project.json" 66 | } 67 | ], 68 | "configuration": { 69 | "type": "object", 70 | "title": "coc-rust-analyzer configuration", 71 | "properties": { 72 | "rust-analyzer.enable": { 73 | "type": "boolean", 74 | "markdownDescription": "Enable `coc-rust-analyzer`", 75 | "default": true 76 | }, 77 | "rust-analyzer.disableProgressNotifications": { 78 | "type": "boolean", 79 | "default": false, 80 | "markdownDescription": "Disable initialization and workdone progress notifications" 81 | }, 82 | "rust-analyzer.disablePullDiagnostic": { 83 | "type": "boolean", 84 | "default": true, 85 | "markdownDescription": "Disable pullDiagnostic feature" 86 | }, 87 | "rust-analyzer.terminal.startinsert": { 88 | "type": "boolean", 89 | "default": false, 90 | "markdownDescription": "Enter insert mode after terminal displayed" 91 | }, 92 | "rust-analyzer.debug.runtime": { 93 | "type": "string", 94 | "default": "termdebug", 95 | "enum": [ 96 | "termdebug", 97 | "vimspector", 98 | "nvim-dap" 99 | ], 100 | "markdownDescription": "Choose which debug runtime to use", 101 | "enumDescriptions": [ 102 | "`\"termdebug\"` use vim/neovim builtin debugger - gdb", 103 | "`\"vimspector\"` use vimspector plugin", 104 | "`\"nvim-dap\"` use nvim-dap plugin" 105 | ] 106 | }, 107 | "rust-analyzer.debug.vimspector.configuration.name": { 108 | "type": "string", 109 | "default": "launch", 110 | "markdownDescription": "Specify the name of the vimspector configuration name. The following args will be passed to the configuration: `Executable` and `Args` (both strings)" 111 | }, 112 | "rust-analyzer.debug.nvimdap.configuration.template": { 113 | "type": "string", 114 | "default": "", 115 | "markdownDescription": "Configuration template used to invoked dap.run([conf](https://github.com/mfussenegger/nvim-dap/blob/0e6b7c47dd70e80793ed39271b2aa712d9366dbc/doc/dap.txt#L656C2-L656C2)). The template will be instantiate like this: `$exe` will be replaced with executable path, `$args` will be replaced with arguments." 116 | }, 117 | "rust-analyzer.server.path": { 118 | "type": [ 119 | "null", 120 | "string" 121 | ], 122 | "default": null, 123 | "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then \"rust-analyzer.updates.channel\" setting is not used" 124 | }, 125 | "rust-analyzer.server.extraEnv": { 126 | "type": [ 127 | "null", 128 | "object" 129 | ], 130 | "default": null, 131 | "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging." 132 | }, 133 | "rust-analyzer.restartServerOnConfigChange": { 134 | "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.", 135 | "default": false, 136 | "type": "boolean" 137 | }, 138 | "rust-analyzer.trace.server": { 139 | "type": "string", 140 | "scope": "window", 141 | "enum": [ 142 | "off", 143 | "messages", 144 | "verbose" 145 | ], 146 | "enumDescriptions": [ 147 | "No traces", 148 | "Error only", 149 | "Full log" 150 | ], 151 | "default": "off", 152 | "markdownDescription": "Trace requests to the rust-analyzer" 153 | }, 154 | "rust-analyzer.updates.prompt": { 155 | "type": [ 156 | "boolean", 157 | "string" 158 | ], 159 | "enum": [ 160 | true, 161 | false, 162 | "neverDownload" 163 | ], 164 | "default": true, 165 | "markdownDescription": "Prompt the user before downloading rust-analyzer" 166 | }, 167 | "rust-analyzer.updates.checkOnStartup": { 168 | "type": "boolean", 169 | "default": true, 170 | "markdownDescription": "Auto-check rust-analyzer updates on startup" 171 | }, 172 | "rust-analyzer.updates.channel": { 173 | "type": "string", 174 | "default": "stable", 175 | "enum": [ 176 | "stable", 177 | "nightly" 178 | ], 179 | "markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs", 180 | "enumDescriptions": [ 181 | "`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general", 182 | "`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**" 183 | ] 184 | }, 185 | "rust-analyzer.assist.emitMustUse": { 186 | "markdownDescription": "Insert #[must_use] when generating `as_` methods for enum variants.", 187 | "default": false, 188 | "type": "boolean" 189 | }, 190 | "rust-analyzer.assist.expressionFillDefault": { 191 | "markdownDescription": "Placeholder expression to use for missing expressions in assists.", 192 | "default": "todo", 193 | "type": "string", 194 | "enum": [ 195 | "todo", 196 | "default" 197 | ], 198 | "enumDescriptions": [ 199 | "Fill missing expressions with the `todo` macro", 200 | "Fill missing expressions with reasonable defaults, `new` or `default` constructors." 201 | ] 202 | }, 203 | "rust-analyzer.assist.preferSelf": { 204 | "markdownDescription": "Prefer to use `Self` over the type name when inserting a type (e.g. in \"fill match arms\" assist).", 205 | "default": false, 206 | "type": "boolean" 207 | }, 208 | "rust-analyzer.assist.termSearch.borrowcheck": { 209 | "markdownDescription": "Enable borrow checking for term search code assists. If set to false, also there will be\nmore suggestions, but some of them may not borrow-check.", 210 | "default": true, 211 | "type": "boolean" 212 | }, 213 | "rust-analyzer.assist.termSearch.fuel": { 214 | "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 1800).", 215 | "default": 1800, 216 | "type": "integer", 217 | "minimum": 0 218 | }, 219 | "rust-analyzer.cachePriming.enable": { 220 | "markdownDescription": "Warm up caches on project load.", 221 | "default": true, 222 | "type": "boolean" 223 | }, 224 | "rust-analyzer.cachePriming.numThreads": { 225 | "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick\nautomatically.", 226 | "default": "physical", 227 | "anyOf": [ 228 | { 229 | "type": "number", 230 | "minimum": 0, 231 | "maximum": 255 232 | }, 233 | { 234 | "type": "string", 235 | "enum": [ 236 | "physical", 237 | "logical" 238 | ], 239 | "enumDescriptions": [ 240 | "Use the number of physical cores", 241 | "Use the number of logical cores" 242 | ] 243 | } 244 | ] 245 | }, 246 | "rust-analyzer.cargo.allTargets": { 247 | "markdownDescription": "Pass `--all-targets` to cargo invocation.", 248 | "default": true, 249 | "type": "boolean" 250 | }, 251 | "rust-analyzer.cargo.autoreload": { 252 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.", 253 | "default": true, 254 | "type": "boolean" 255 | }, 256 | "rust-analyzer.cargo.buildScripts.enable": { 257 | "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.", 258 | "default": true, 259 | "type": "boolean" 260 | }, 261 | "rust-analyzer.cargo.buildScripts.invocationStrategy": { 262 | "markdownDescription": "Specifies the invocation strategy to use when running the build scripts command.\nIf `per_workspace` is set, the command will be executed for each Rust workspace with the\nworkspace as the working directory.\nIf `once` is set, the command will be executed once with the opened project as the\nworking directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", 263 | "default": "per_workspace", 264 | "type": "string", 265 | "enum": [ 266 | "per_workspace", 267 | "once" 268 | ], 269 | "enumDescriptions": [ 270 | "The command will be executed for each Rust workspace with the workspace as the working directory.", 271 | "The command will be executed once with the opened project as the working directory." 272 | ] 273 | }, 274 | "rust-analyzer.cargo.buildScripts.overrideCommand": { 275 | "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#`.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets --keep-going\n```\n\nNote: The option must be specified as an array of command line arguments, with\nthe first argument being the name of the command to run.", 276 | "default": null, 277 | "type": [ 278 | "null", 279 | "array" 280 | ], 281 | "items": { 282 | "type": "string" 283 | } 284 | }, 285 | "rust-analyzer.cargo.buildScripts.rebuildOnSave": { 286 | "markdownDescription": "Rerun proc-macros building/build-scripts running when proc-macro\nor build-script sources change and are saved.", 287 | "default": true, 288 | "type": "boolean" 289 | }, 290 | "rust-analyzer.cargo.buildScripts.useRustcWrapper": { 291 | "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.", 292 | "default": true, 293 | "type": "boolean" 294 | }, 295 | "rust-analyzer.cargo.cfgs": { 296 | "markdownDescription": "List of cfg options to enable with the given values.\n\nTo enable a name without a value, use `\"key\"`.\nTo enable a name with a value, use `\"key=value\"`.\nTo disable, prefix the entry with a `!`.", 297 | "default": [ 298 | "debug_assertions", 299 | "miri" 300 | ], 301 | "type": "array", 302 | "items": { 303 | "type": "string" 304 | } 305 | }, 306 | "rust-analyzer.cargo.extraArgs": { 307 | "markdownDescription": "Extra arguments that are passed to every cargo invocation.", 308 | "default": [], 309 | "type": "array", 310 | "items": { 311 | "type": "string" 312 | } 313 | }, 314 | "rust-analyzer.cargo.extraEnv": { 315 | "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.", 316 | "default": {}, 317 | "type": "object" 318 | }, 319 | "rust-analyzer.cargo.features": { 320 | "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.", 321 | "default": [], 322 | "anyOf": [ 323 | { 324 | "type": "string", 325 | "enum": [ 326 | "all" 327 | ], 328 | "enumDescriptions": [ 329 | "Pass `--all-features` to cargo" 330 | ] 331 | }, 332 | { 333 | "type": "array", 334 | "items": { 335 | "type": "string" 336 | } 337 | } 338 | ] 339 | }, 340 | "rust-analyzer.cargo.noDefaultFeatures": { 341 | "markdownDescription": "Whether to pass `--no-default-features` to cargo.", 342 | "default": false, 343 | "type": "boolean" 344 | }, 345 | "rust-analyzer.cargo.noDeps": { 346 | "markdownDescription": "Whether to skip fetching dependencies. If set to \"true\", the analysis is performed\nentirely offline, and Cargo metadata for dependencies is not fetched.", 347 | "default": false, 348 | "type": "boolean" 349 | }, 350 | "rust-analyzer.cargo.sysroot": { 351 | "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.", 352 | "default": "discover", 353 | "type": [ 354 | "null", 355 | "string" 356 | ] 357 | }, 358 | "rust-analyzer.cargo.sysrootSrc": { 359 | "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.", 360 | "default": null, 361 | "type": [ 362 | "null", 363 | "string" 364 | ] 365 | }, 366 | "rust-analyzer.cargo.target": { 367 | "markdownDescription": "Compilation target override (target tuple).", 368 | "default": null, 369 | "type": [ 370 | "null", 371 | "string" 372 | ] 373 | }, 374 | "rust-analyzer.cargo.targetDir": { 375 | "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` and initial build-script and proc-macro\nbuilding from locking the `Cargo.lock` at the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.", 376 | "default": null, 377 | "anyOf": [ 378 | { 379 | "type": "null" 380 | }, 381 | { 382 | "type": "boolean" 383 | }, 384 | { 385 | "type": "string" 386 | } 387 | ] 388 | }, 389 | "rust-analyzer.cfg.setTest": { 390 | "markdownDescription": "Set `cfg(test)` for local crates. Defaults to true.", 391 | "default": true, 392 | "type": "boolean" 393 | }, 394 | "rust-analyzer.checkOnSave": { 395 | "markdownDescription": "Run the check command for diagnostics on save.", 396 | "default": true, 397 | "type": "boolean" 398 | }, 399 | "rust-analyzer.check.allTargets": { 400 | "markdownDescription": "Check all targets and tests (`--all-targets`). Defaults to\n`#rust-analyzer.cargo.allTargets#`.", 401 | "default": null, 402 | "type": [ 403 | "null", 404 | "boolean" 405 | ] 406 | }, 407 | "rust-analyzer.check.command": { 408 | "markdownDescription": "Cargo command to use for `cargo check`.", 409 | "default": "check", 410 | "type": "string" 411 | }, 412 | "rust-analyzer.check.extraArgs": { 413 | "markdownDescription": "Extra arguments for `cargo check`.", 414 | "default": [], 415 | "type": "array", 416 | "items": { 417 | "type": "string" 418 | } 419 | }, 420 | "rust-analyzer.check.extraEnv": { 421 | "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", 422 | "default": {}, 423 | "type": "object" 424 | }, 425 | "rust-analyzer.check.features": { 426 | "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", 427 | "default": null, 428 | "anyOf": [ 429 | { 430 | "type": "string", 431 | "enum": [ 432 | "all" 433 | ], 434 | "enumDescriptions": [ 435 | "Pass `--all-features` to cargo" 436 | ] 437 | }, 438 | { 439 | "type": "array", 440 | "items": { 441 | "type": "string" 442 | } 443 | }, 444 | { 445 | "type": "null" 446 | } 447 | ] 448 | }, 449 | "rust-analyzer.check.ignore": { 450 | "markdownDescription": "List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore.\n\nFor example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,...", 451 | "default": [], 452 | "type": "array", 453 | "items": { 454 | "type": "string" 455 | }, 456 | "uniqueItems": true 457 | }, 458 | "rust-analyzer.check.invocationStrategy": { 459 | "markdownDescription": "Specifies the invocation strategy to use when running the check command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.check.overrideCommand#`\nis set.", 460 | "default": "per_workspace", 461 | "type": "string", 462 | "enum": [ 463 | "per_workspace", 464 | "once" 465 | ], 466 | "enumDescriptions": [ 467 | "The command will be executed for each Rust workspace with the workspace as the working directory.", 468 | "The command will be executed once with the opened project as the working directory." 469 | ] 470 | }, 471 | "rust-analyzer.check.noDefaultFeatures": { 472 | "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", 473 | "default": null, 474 | "type": [ 475 | "null", 476 | "boolean" 477 | ] 478 | }, 479 | "rust-analyzer.check.overrideCommand": { 480 | "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the future.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n\nNote: The option must be specified as an array of command line arguments, with\nthe first argument being the name of the command to run.", 481 | "default": null, 482 | "type": [ 483 | "null", 484 | "array" 485 | ], 486 | "items": { 487 | "type": "string" 488 | } 489 | }, 490 | "rust-analyzer.check.targets": { 491 | "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", 492 | "default": null, 493 | "anyOf": [ 494 | { 495 | "type": "null" 496 | }, 497 | { 498 | "type": "string" 499 | }, 500 | { 501 | "type": "array", 502 | "items": { 503 | "type": "string" 504 | } 505 | } 506 | ] 507 | }, 508 | "rust-analyzer.check.workspace": { 509 | "markdownDescription": "Whether `--workspace` should be passed to `cargo check`.\nIf false, `-p ` will be passed instead if applicable. In case it is not, no\ncheck will be performed.", 510 | "default": true, 511 | "type": "boolean" 512 | }, 513 | "rust-analyzer.completion.addSemicolonToUnit": { 514 | "markdownDescription": "Automatically add a semicolon when completing unit-returning functions.\n\nIn `match` arms it completes a comma instead.", 515 | "default": true, 516 | "type": "boolean" 517 | }, 518 | "rust-analyzer.completion.autoAwait.enable": { 519 | "markdownDescription": "Show method calls and field accesses completions with `await` prefixed to them when\ncompleting on a future.", 520 | "default": true, 521 | "type": "boolean" 522 | }, 523 | "rust-analyzer.completion.autoIter.enable": { 524 | "markdownDescription": "Show method call completions with `iter()` or `into_iter()` prefixed to them when\ncompleting on a type that has them.", 525 | "default": true, 526 | "type": "boolean" 527 | }, 528 | "rust-analyzer.completion.autoimport.enable": { 529 | "markdownDescription": "Show completions that automatically add imports when completed.\n\nNote that your client must specify the `additionalTextEdits` LSP client capability to\ntruly have this feature enabled.", 530 | "default": true, 531 | "type": "boolean" 532 | }, 533 | "rust-analyzer.completion.autoimport.exclude": { 534 | "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more\nverbose form `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait\nitself.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", 535 | "default": [ 536 | { 537 | "path": "core::borrow::Borrow", 538 | "type": "methods" 539 | }, 540 | { 541 | "path": "core::borrow::BorrowMut", 542 | "type": "methods" 543 | } 544 | ], 545 | "type": "array", 546 | "items": { 547 | "anyOf": [ 548 | { 549 | "type": "string" 550 | }, 551 | { 552 | "type": "object", 553 | "properties": { 554 | "path": { 555 | "type": "string" 556 | }, 557 | "type": { 558 | "type": "string", 559 | "enum": [ 560 | "always", 561 | "methods" 562 | ], 563 | "enumDescriptions": [ 564 | "Do not show this item or its methods (if it is a trait) in auto-import completions.", 565 | "Do not show this traits methods in auto-import completions." 566 | ] 567 | } 568 | } 569 | } 570 | ] 571 | } 572 | }, 573 | "rust-analyzer.completion.autoself.enable": { 574 | "markdownDescription": "Show method calls and field access completions with `self` prefixed to them when\ninside a method.", 575 | "default": true, 576 | "type": "boolean" 577 | }, 578 | "rust-analyzer.completion.callable.snippets": { 579 | "markdownDescription": "Add parenthesis and argument snippets when completing function.", 580 | "default": "fill_arguments", 581 | "type": "string", 582 | "enum": [ 583 | "fill_arguments", 584 | "add_parentheses", 585 | "none" 586 | ], 587 | "enumDescriptions": [ 588 | "Add call parentheses and pre-fill arguments.", 589 | "Add call parentheses.", 590 | "Do no snippet completions for callables." 591 | ] 592 | }, 593 | "rust-analyzer.completion.excludeTraits": { 594 | "markdownDescription": "A list of full paths to traits whose methods to exclude from completion.\n\nMethods from these traits won't be completed, even if the trait is in scope. However,\nthey will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or\n`T where T: Trait`.\n\nNote that the trait themselves can still be completed.", 595 | "default": [], 596 | "type": "array", 597 | "items": { 598 | "type": "string" 599 | } 600 | }, 601 | "rust-analyzer.completion.fullFunctionSignatures.enable": { 602 | "markdownDescription": "Show full function / method signatures in completion docs.", 603 | "default": false, 604 | "type": "boolean" 605 | }, 606 | "rust-analyzer.completion.hideDeprecated": { 607 | "markdownDescription": "Omit deprecated items from completions. By default they are marked as deprecated but not\nhidden.", 608 | "default": false, 609 | "type": "boolean" 610 | }, 611 | "rust-analyzer.completion.limit": { 612 | "markdownDescription": "Maximum number of completions to return. If `None`, the limit is infinite.", 613 | "default": null, 614 | "type": [ 615 | "null", 616 | "integer" 617 | ], 618 | "minimum": 0 619 | }, 620 | "rust-analyzer.completion.postfix.enable": { 621 | "markdownDescription": "Show postfix snippets like `dbg`, `if`, `not`, etc.", 622 | "default": true, 623 | "type": "boolean" 624 | }, 625 | "rust-analyzer.completion.privateEditable.enable": { 626 | "markdownDescription": "Show completions of private items and fields that are defined in the current workspace\neven if they are not visible at the current position.", 627 | "default": false, 628 | "type": "boolean" 629 | }, 630 | "rust-analyzer.completion.snippets.custom": { 631 | "markdownDescription": "Custom completion snippets.", 632 | "default": { 633 | "Ok": { 634 | "postfix": "ok", 635 | "body": "Ok(${receiver})", 636 | "description": "Wrap the expression in a `Result::Ok`", 637 | "scope": "expr" 638 | }, 639 | "Box::pin": { 640 | "postfix": "pinbox", 641 | "body": "Box::pin(${receiver})", 642 | "requires": "std::boxed::Box", 643 | "description": "Put the expression into a pinned `Box`", 644 | "scope": "expr" 645 | }, 646 | "Arc::new": { 647 | "postfix": "arc", 648 | "body": "Arc::new(${receiver})", 649 | "requires": "std::sync::Arc", 650 | "description": "Put the expression into an `Arc`", 651 | "scope": "expr" 652 | }, 653 | "Some": { 654 | "postfix": "some", 655 | "body": "Some(${receiver})", 656 | "description": "Wrap the expression in an `Option::Some`", 657 | "scope": "expr" 658 | }, 659 | "Err": { 660 | "postfix": "err", 661 | "body": "Err(${receiver})", 662 | "description": "Wrap the expression in a `Result::Err`", 663 | "scope": "expr" 664 | }, 665 | "Rc::new": { 666 | "postfix": "rc", 667 | "body": "Rc::new(${receiver})", 668 | "requires": "std::rc::Rc", 669 | "description": "Put the expression into an `Rc`", 670 | "scope": "expr" 671 | } 672 | }, 673 | "type": "object" 674 | }, 675 | "rust-analyzer.completion.termSearch.enable": { 676 | "markdownDescription": "Enable term search based snippets like `Some(foo.bar().baz())`.", 677 | "default": false, 678 | "type": "boolean" 679 | }, 680 | "rust-analyzer.completion.termSearch.fuel": { 681 | "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 1000).", 682 | "default": 1000, 683 | "type": "integer", 684 | "minimum": 0 685 | }, 686 | "rust-analyzer.diagnostics.disabled": { 687 | "markdownDescription": "List of rust-analyzer diagnostics to disable.", 688 | "default": [], 689 | "type": "array", 690 | "items": { 691 | "type": "string" 692 | }, 693 | "uniqueItems": true 694 | }, 695 | "rust-analyzer.diagnostics.enable": { 696 | "markdownDescription": "Show native rust-analyzer diagnostics.", 697 | "default": true, 698 | "type": "boolean" 699 | }, 700 | "rust-analyzer.diagnostics.experimental.enable": { 701 | "markdownDescription": "Show experimental rust-analyzer diagnostics that might have more false positives than\nusual.", 702 | "default": false, 703 | "type": "boolean" 704 | }, 705 | "rust-analyzer.diagnostics.remapPrefix": { 706 | "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths. This should be the\nreverse mapping of what is passed to `rustc` as `--remap-path-prefix`.", 707 | "default": {}, 708 | "type": "object" 709 | }, 710 | "rust-analyzer.diagnostics.styleLints.enable": { 711 | "markdownDescription": "Run additional style lints.", 712 | "default": false, 713 | "type": "boolean" 714 | }, 715 | "rust-analyzer.diagnostics.warningsAsHint": { 716 | "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code and will not show up\nin the `Problems Panel`.", 717 | "default": [], 718 | "type": "array", 719 | "items": { 720 | "type": "string" 721 | } 722 | }, 723 | "rust-analyzer.diagnostics.warningsAsInfo": { 724 | "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in\nthe `Problems Panel`.", 725 | "default": [], 726 | "type": "array", 727 | "items": { 728 | "type": "string" 729 | } 730 | }, 731 | "rust-analyzer.document.symbol.search.excludeLocals": { 732 | "markdownDescription": "Exclude all locals from document symbol search.", 733 | "default": true, 734 | "type": "boolean" 735 | }, 736 | "rust-analyzer.files.exclude": { 737 | "markdownDescription": "List of files to ignore\n\nThese paths (file/directories) will be ignored by rust-analyzer. They are relative to\nthe workspace root, and globs are not supported. You may also need to add the folders to\nCode's `files.watcherExclude`.", 738 | "default": [], 739 | "type": "array", 740 | "items": { 741 | "type": "string" 742 | } 743 | }, 744 | "rust-analyzer.files.watcher": { 745 | "markdownDescription": "Controls file watching implementation.", 746 | "default": "client", 747 | "type": "string", 748 | "enum": [ 749 | "client", 750 | "server" 751 | ], 752 | "enumDescriptions": [ 753 | "Use the client (editor) to watch files for changes", 754 | "Use server-side file watching" 755 | ] 756 | }, 757 | "rust-analyzer.highlightRelated.branchExitPoints.enable": { 758 | "markdownDescription": "Highlight related return values while the cursor is on any `match`, `if`, or match arm\narrow (`=>`).", 759 | "default": true, 760 | "type": "boolean" 761 | }, 762 | "rust-analyzer.highlightRelated.breakPoints.enable": { 763 | "markdownDescription": "Highlight related references while the cursor is on `break`, `loop`, `while`, or `for`\nkeywords.", 764 | "default": true, 765 | "type": "boolean" 766 | }, 767 | "rust-analyzer.highlightRelated.closureCaptures.enable": { 768 | "markdownDescription": "Highlight all captures of a closure while the cursor is on the `|` or move keyword of a closure.", 769 | "default": true, 770 | "type": "boolean" 771 | }, 772 | "rust-analyzer.highlightRelated.exitPoints.enable": { 773 | "markdownDescription": "Highlight all exit points while the cursor is on any `return`, `?`, `fn`, or return type\narrow (`->`).", 774 | "default": true, 775 | "type": "boolean" 776 | }, 777 | "rust-analyzer.highlightRelated.references.enable": { 778 | "markdownDescription": "Highlight related references while the cursor is on any identifier.", 779 | "default": true, 780 | "type": "boolean" 781 | }, 782 | "rust-analyzer.highlightRelated.yieldPoints.enable": { 783 | "markdownDescription": "Highlight all break points for a loop or block context while the cursor is on any\n`async` or `await` keywords.", 784 | "default": true, 785 | "type": "boolean" 786 | }, 787 | "rust-analyzer.hover.actions.updateTest.enable": { 788 | "markdownDescription": "Show `Update Test` action. Only applies when `#rust-analyzer.hover.actions.enable#` and\n`#rust-analyzer.hover.actions.run.enable#` are set.", 789 | "default": true, 790 | "type": "boolean" 791 | }, 792 | "rust-analyzer.hover.documentation.enable": { 793 | "markdownDescription": "Show documentation on hover.", 794 | "default": true, 795 | "type": "boolean" 796 | }, 797 | "rust-analyzer.hover.documentation.keywords.enable": { 798 | "markdownDescription": "Show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.", 799 | "default": true, 800 | "type": "boolean" 801 | }, 802 | "rust-analyzer.hover.dropGlue.enable": { 803 | "markdownDescription": "Show drop glue information on hover.", 804 | "default": true, 805 | "type": "boolean" 806 | }, 807 | "rust-analyzer.hover.links.enable": { 808 | "markdownDescription": "Use markdown syntax for links on hover.", 809 | "default": true, 810 | "type": "boolean" 811 | }, 812 | "rust-analyzer.hover.maxSubstitutionLength": { 813 | "markdownDescription": "Show what types are used as generic arguments in calls etc. on hover, and limit the max\nlength to show such types, beyond which they will be shown with ellipsis.\n\nThis can take three values: `null` means \"unlimited\", the string `\"hide\"` means to not\nshow generic substitutions at all, and a number means to limit them to X characters.\n\nThe default is 20 characters.", 814 | "default": 20, 815 | "anyOf": [ 816 | { 817 | "type": "null" 818 | }, 819 | { 820 | "type": "string", 821 | "enum": [ 822 | "hide" 823 | ] 824 | }, 825 | { 826 | "type": "integer" 827 | } 828 | ] 829 | }, 830 | "rust-analyzer.hover.memoryLayout.alignment": { 831 | "markdownDescription": "How to render the align information in a memory layout hover.", 832 | "default": "hexadecimal", 833 | "anyOf": [ 834 | { 835 | "type": "null" 836 | }, 837 | { 838 | "type": "string", 839 | "enum": [ 840 | "both", 841 | "decimal", 842 | "hexadecimal" 843 | ], 844 | "enumDescriptions": [ 845 | "Render as 12 (0xC)", 846 | "Render as 12", 847 | "Render as 0xC" 848 | ] 849 | } 850 | ] 851 | }, 852 | "rust-analyzer.hover.memoryLayout.enable": { 853 | "markdownDescription": "Show memory layout data on hover.", 854 | "default": true, 855 | "type": "boolean" 856 | }, 857 | "rust-analyzer.hover.memoryLayout.niches": { 858 | "markdownDescription": "How to render the niche information in a memory layout hover.", 859 | "default": false, 860 | "type": [ 861 | "null", 862 | "boolean" 863 | ] 864 | }, 865 | "rust-analyzer.hover.memoryLayout.offset": { 866 | "markdownDescription": "How to render the offset information in a memory layout hover.", 867 | "default": "hexadecimal", 868 | "anyOf": [ 869 | { 870 | "type": "null" 871 | }, 872 | { 873 | "type": "string", 874 | "enum": [ 875 | "both", 876 | "decimal", 877 | "hexadecimal" 878 | ], 879 | "enumDescriptions": [ 880 | "Render as 12 (0xC)", 881 | "Render as 12", 882 | "Render as 0xC" 883 | ] 884 | } 885 | ] 886 | }, 887 | "rust-analyzer.hover.memoryLayout.padding": { 888 | "markdownDescription": "How to render the padding information in a memory layout hover.", 889 | "default": null, 890 | "anyOf": [ 891 | { 892 | "type": "null" 893 | }, 894 | { 895 | "type": "string", 896 | "enum": [ 897 | "both", 898 | "decimal", 899 | "hexadecimal" 900 | ], 901 | "enumDescriptions": [ 902 | "Render as 12 (0xC)", 903 | "Render as 12", 904 | "Render as 0xC" 905 | ] 906 | } 907 | ] 908 | }, 909 | "rust-analyzer.hover.memoryLayout.size": { 910 | "markdownDescription": "How to render the size information in a memory layout hover.", 911 | "default": "both", 912 | "anyOf": [ 913 | { 914 | "type": "null" 915 | }, 916 | { 917 | "type": "string", 918 | "enum": [ 919 | "both", 920 | "decimal", 921 | "hexadecimal" 922 | ], 923 | "enumDescriptions": [ 924 | "Render as 12 (0xC)", 925 | "Render as 12", 926 | "Render as 0xC" 927 | ] 928 | } 929 | ] 930 | }, 931 | "rust-analyzer.hover.show.enumVariants": { 932 | "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.", 933 | "default": 5, 934 | "type": [ 935 | "null", 936 | "integer" 937 | ], 938 | "minimum": 0 939 | }, 940 | "rust-analyzer.hover.show.fields": { 941 | "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if\nempty.", 942 | "default": 5, 943 | "type": [ 944 | "null", 945 | "integer" 946 | ], 947 | "minimum": 0 948 | }, 949 | "rust-analyzer.hover.show.traitAssocItems": { 950 | "markdownDescription": "How many associated items of a trait to display when hovering a trait.", 951 | "default": null, 952 | "type": [ 953 | "null", 954 | "integer" 955 | ], 956 | "minimum": 0 957 | }, 958 | "rust-analyzer.imports.granularity.enforce": { 959 | "markdownDescription": "Enforce the import granularity setting for all files. If set to false rust-analyzer will\ntry to keep import styles consistent per file.", 960 | "default": false, 961 | "type": "boolean" 962 | }, 963 | "rust-analyzer.imports.granularity.group": { 964 | "markdownDescription": "How imports should be grouped into use statements.", 965 | "default": "crate", 966 | "type": "string", 967 | "enum": [ 968 | "preserve", 969 | "crate", 970 | "module", 971 | "item", 972 | "one" 973 | ], 974 | "enumDescriptions": [ 975 | "Do not change the granularity of any imports and preserve the original structure written by the developer.", 976 | "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", 977 | "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", 978 | "Flatten imports so that each has its own use statement.", 979 | "Merge all imports into a single use statement as long as they have the same visibility and attributes." 980 | ] 981 | }, 982 | "rust-analyzer.imports.group.enable": { 983 | "markdownDescription": "Group inserted imports by the [following\norder](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are\nseparated by newlines.", 984 | "default": true, 985 | "type": "boolean" 986 | }, 987 | "rust-analyzer.imports.merge.glob": { 988 | "markdownDescription": "Allow import insertion to merge new imports into single path glob imports like `use\nstd::fmt::*;`.", 989 | "default": true, 990 | "type": "boolean" 991 | }, 992 | "rust-analyzer.imports.preferNoStd": { 993 | "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.", 994 | "default": false, 995 | "type": "boolean" 996 | }, 997 | "rust-analyzer.imports.preferPrelude": { 998 | "markdownDescription": "Prefer import paths containing a `prelude` module.", 999 | "default": false, 1000 | "type": "boolean" 1001 | }, 1002 | "rust-analyzer.imports.prefix": { 1003 | "markdownDescription": "The path structure for newly inserted paths to use.", 1004 | "default": "crate", 1005 | "type": "string", 1006 | "enum": [ 1007 | "plain", 1008 | "self", 1009 | "crate" 1010 | ], 1011 | "enumDescriptions": [ 1012 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", 1013 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.", 1014 | "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from." 1015 | ] 1016 | }, 1017 | "rust-analyzer.imports.prefixExternPrelude": { 1018 | "markdownDescription": "Prefix external (including std, core) crate imports with `::`.\n\nE.g. `use ::std::io::Read;`.", 1019 | "default": false, 1020 | "type": "boolean" 1021 | }, 1022 | "rust-analyzer.inlayHints.bindingModeHints.enable": { 1023 | "markdownDescription": "Show inlay type hints for binding modes.", 1024 | "default": false, 1025 | "type": "boolean" 1026 | }, 1027 | "rust-analyzer.inlayHints.chainingHints.enable": { 1028 | "markdownDescription": "Show inlay type hints for method chains.", 1029 | "default": true, 1030 | "type": "boolean" 1031 | }, 1032 | "rust-analyzer.inlayHints.closingBraceHints.enable": { 1033 | "markdownDescription": "Show inlay hints after a closing `}` to indicate what item it belongs to.", 1034 | "default": true, 1035 | "type": "boolean" 1036 | }, 1037 | "rust-analyzer.inlayHints.closingBraceHints.minLines": { 1038 | "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).", 1039 | "default": 25, 1040 | "type": "integer", 1041 | "minimum": 0 1042 | }, 1043 | "rust-analyzer.inlayHints.closureCaptureHints.enable": { 1044 | "markdownDescription": "Show inlay hints for closure captures.", 1045 | "default": false, 1046 | "type": "boolean" 1047 | }, 1048 | "rust-analyzer.inlayHints.closureReturnTypeHints.enable": { 1049 | "markdownDescription": "Show inlay type hints for return types of closures.", 1050 | "default": "never", 1051 | "type": "string", 1052 | "enum": [ 1053 | "always", 1054 | "never", 1055 | "with_block" 1056 | ], 1057 | "enumDescriptions": [ 1058 | "Always show type hints for return types of closures.", 1059 | "Never show type hints for return types of closures.", 1060 | "Only show type hints for return types of closures with blocks." 1061 | ] 1062 | }, 1063 | "rust-analyzer.inlayHints.closureStyle": { 1064 | "markdownDescription": "Closure notation in type and chaining inlay hints.", 1065 | "default": "impl_fn", 1066 | "type": "string", 1067 | "enum": [ 1068 | "impl_fn", 1069 | "rust_analyzer", 1070 | "with_id", 1071 | "hide" 1072 | ], 1073 | "enumDescriptions": [ 1074 | "`impl_fn`: `impl FnMut(i32, u64) -> i8`", 1075 | "`rust_analyzer`: `|i32, u64| -> i8`", 1076 | "`with_id`: `{closure#14352}`, where that id is the unique number of the closure in r-a internals", 1077 | "`hide`: Shows `...` for every closure type" 1078 | ] 1079 | }, 1080 | "rust-analyzer.inlayHints.discriminantHints.enable": { 1081 | "markdownDescription": "Show enum variant discriminant hints.", 1082 | "default": "never", 1083 | "type": "string", 1084 | "enum": [ 1085 | "always", 1086 | "never", 1087 | "fieldless" 1088 | ], 1089 | "enumDescriptions": [ 1090 | "Always show all discriminant hints.", 1091 | "Never show discriminant hints.", 1092 | "Only show discriminant hints on fieldless enum variants." 1093 | ] 1094 | }, 1095 | "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": { 1096 | "markdownDescription": "Show inlay hints for type adjustments.", 1097 | "default": "never", 1098 | "type": "string", 1099 | "enum": [ 1100 | "always", 1101 | "never", 1102 | "reborrow" 1103 | ], 1104 | "enumDescriptions": [ 1105 | "Always show all adjustment hints.", 1106 | "Never show adjustment hints.", 1107 | "Only show auto borrow and dereference adjustment hints." 1108 | ] 1109 | }, 1110 | "rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe": { 1111 | "markdownDescription": "Hide inlay hints for type adjustments outside of `unsafe` blocks.", 1112 | "default": false, 1113 | "type": "boolean" 1114 | }, 1115 | "rust-analyzer.inlayHints.expressionAdjustmentHints.mode": { 1116 | "markdownDescription": "Show inlay hints as postfix ops (`.*` instead of `*`, etc).", 1117 | "default": "prefix", 1118 | "type": "string", 1119 | "enum": [ 1120 | "prefix", 1121 | "postfix", 1122 | "prefer_prefix", 1123 | "prefer_postfix" 1124 | ], 1125 | "enumDescriptions": [ 1126 | "Always show adjustment hints as prefix (`*expr`).", 1127 | "Always show adjustment hints as postfix (`expr.*`).", 1128 | "Show prefix or postfix depending on which uses less parenthesis, preferring prefix.", 1129 | "Show prefix or postfix depending on which uses less parenthesis, preferring postfix." 1130 | ] 1131 | }, 1132 | "rust-analyzer.inlayHints.genericParameterHints.const.enable": { 1133 | "markdownDescription": "Show const generic parameter name inlay hints.", 1134 | "default": true, 1135 | "type": "boolean" 1136 | }, 1137 | "rust-analyzer.inlayHints.genericParameterHints.lifetime.enable": { 1138 | "markdownDescription": "Show generic lifetime parameter name inlay hints.", 1139 | "default": false, 1140 | "type": "boolean" 1141 | }, 1142 | "rust-analyzer.inlayHints.genericParameterHints.type.enable": { 1143 | "markdownDescription": "Show generic type parameter name inlay hints.", 1144 | "default": false, 1145 | "type": "boolean" 1146 | }, 1147 | "rust-analyzer.inlayHints.implicitDrops.enable": { 1148 | "markdownDescription": "Show implicit drop hints.", 1149 | "default": false, 1150 | "type": "boolean" 1151 | }, 1152 | "rust-analyzer.inlayHints.implicitSizedBoundHints.enable": { 1153 | "markdownDescription": "Show inlay hints for the implied type parameter `Sized` bound.", 1154 | "default": false, 1155 | "type": "boolean" 1156 | }, 1157 | "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { 1158 | "markdownDescription": "Show inlay type hints for elided lifetimes in function signatures.", 1159 | "default": "never", 1160 | "type": "string", 1161 | "enum": [ 1162 | "always", 1163 | "never", 1164 | "skip_trivial" 1165 | ], 1166 | "enumDescriptions": [ 1167 | "Always show lifetime elision hints.", 1168 | "Never show lifetime elision hints.", 1169 | "Only show lifetime elision hints if a return type is involved." 1170 | ] 1171 | }, 1172 | "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": { 1173 | "markdownDescription": "Prefer using parameter names as the name for elided lifetime hints if possible.", 1174 | "default": false, 1175 | "type": "boolean" 1176 | }, 1177 | "rust-analyzer.inlayHints.maxLength": { 1178 | "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.", 1179 | "default": 25, 1180 | "type": [ 1181 | "null", 1182 | "integer" 1183 | ], 1184 | "minimum": 0 1185 | }, 1186 | "rust-analyzer.inlayHints.parameterHints.enable": { 1187 | "markdownDescription": "Show function parameter name inlay hints at the call site.", 1188 | "default": true, 1189 | "type": "boolean" 1190 | }, 1191 | "rust-analyzer.inlayHints.rangeExclusiveHints.enable": { 1192 | "markdownDescription": "Show exclusive range inlay hints.", 1193 | "default": false, 1194 | "type": "boolean" 1195 | }, 1196 | "rust-analyzer.inlayHints.reborrowHints.enable": { 1197 | "markdownDescription": "Show inlay hints for compiler inserted reborrows.\n\nThis setting is deprecated in favor of\n#rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.", 1198 | "default": "never", 1199 | "type": "string", 1200 | "enum": [ 1201 | "always", 1202 | "never", 1203 | "mutable" 1204 | ], 1205 | "enumDescriptions": [ 1206 | "Always show reborrow hints.", 1207 | "Never show reborrow hints.", 1208 | "Only show mutable reborrow hints." 1209 | ] 1210 | }, 1211 | "rust-analyzer.inlayHints.renderColons": { 1212 | "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.", 1213 | "default": true, 1214 | "type": "boolean" 1215 | }, 1216 | "rust-analyzer.inlayHints.typeHints.enable": { 1217 | "markdownDescription": "Show inlay type hints for variables.", 1218 | "default": true, 1219 | "type": "boolean" 1220 | }, 1221 | "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": { 1222 | "markdownDescription": "Hide inlay type hints for `let` statements that initialize to a closure.\n\nOnly applies to closures with blocks, same as\n`#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.", 1223 | "default": false, 1224 | "type": "boolean" 1225 | }, 1226 | "rust-analyzer.inlayHints.typeHints.hideClosureParameter": { 1227 | "markdownDescription": "Hide inlay parameter type hints for closures.", 1228 | "default": false, 1229 | "type": "boolean" 1230 | }, 1231 | "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": { 1232 | "markdownDescription": "Hide inlay type hints for constructors.", 1233 | "default": false, 1234 | "type": "boolean" 1235 | }, 1236 | "rust-analyzer.interpret.tests": { 1237 | "markdownDescription": "Enable the experimental support for interpreting tests.", 1238 | "default": false, 1239 | "type": "boolean" 1240 | }, 1241 | "rust-analyzer.joinLines.joinAssignments": { 1242 | "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.", 1243 | "default": true, 1244 | "type": "boolean" 1245 | }, 1246 | "rust-analyzer.joinLines.joinElseIf": { 1247 | "markdownDescription": "Join lines inserts else between consecutive ifs.", 1248 | "default": true, 1249 | "type": "boolean" 1250 | }, 1251 | "rust-analyzer.joinLines.removeTrailingComma": { 1252 | "markdownDescription": "Join lines removes trailing commas.", 1253 | "default": true, 1254 | "type": "boolean" 1255 | }, 1256 | "rust-analyzer.joinLines.unwrapTrivialBlock": { 1257 | "markdownDescription": "Join lines unwraps trivial blocks.", 1258 | "default": true, 1259 | "type": "boolean" 1260 | }, 1261 | "rust-analyzer.lens.debug.enable": { 1262 | "markdownDescription": "Show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", 1263 | "default": true, 1264 | "type": "boolean" 1265 | }, 1266 | "rust-analyzer.lens.enable": { 1267 | "markdownDescription": "Show CodeLens in Rust files.", 1268 | "default": true, 1269 | "type": "boolean" 1270 | }, 1271 | "rust-analyzer.lens.implementations.enable": { 1272 | "markdownDescription": "Show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", 1273 | "default": true, 1274 | "type": "boolean" 1275 | }, 1276 | "rust-analyzer.lens.location": { 1277 | "markdownDescription": "Where to render annotations.", 1278 | "default": "above_name", 1279 | "type": "string", 1280 | "enum": [ 1281 | "above_name", 1282 | "above_whole_item" 1283 | ], 1284 | "enumDescriptions": [ 1285 | "Render annotations above the name of the item.", 1286 | "Render annotations above the whole item, including documentation comments and attributes." 1287 | ] 1288 | }, 1289 | "rust-analyzer.lens.references.adt.enable": { 1290 | "markdownDescription": "Show `References` lens for Struct, Enum, and Union. Only applies when\n`#rust-analyzer.lens.enable#` is set.", 1291 | "default": false, 1292 | "type": "boolean" 1293 | }, 1294 | "rust-analyzer.lens.references.enumVariant.enable": { 1295 | "markdownDescription": "Show `References` lens for Enum Variants. Only applies when\n`#rust-analyzer.lens.enable#` is set.", 1296 | "default": false, 1297 | "type": "boolean" 1298 | }, 1299 | "rust-analyzer.lens.references.method.enable": { 1300 | "markdownDescription": "Show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", 1301 | "default": false, 1302 | "type": "boolean" 1303 | }, 1304 | "rust-analyzer.lens.references.trait.enable": { 1305 | "markdownDescription": "Show `References` lens for Trait. Only applies when `#rust-analyzer.lens.enable#` is\nset.", 1306 | "default": false, 1307 | "type": "boolean" 1308 | }, 1309 | "rust-analyzer.lens.run.enable": { 1310 | "markdownDescription": "Show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", 1311 | "default": true, 1312 | "type": "boolean" 1313 | }, 1314 | "rust-analyzer.lens.updateTest.enable": { 1315 | "markdownDescription": "Show `Update Test` lens. Only applies when `#rust-analyzer.lens.enable#` and\n`#rust-analyzer.lens.run.enable#` are set.", 1316 | "default": true, 1317 | "type": "boolean" 1318 | }, 1319 | "rust-analyzer.linkedProjects": { 1320 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\n\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, `.rs` files (which\nwill be treated as standalone files) or JSON objects in `rust-project.json` format.", 1321 | "default": [], 1322 | "type": "array", 1323 | "items": { 1324 | "type": [ 1325 | "string", 1326 | "object" 1327 | ] 1328 | } 1329 | }, 1330 | "rust-analyzer.lru.capacity": { 1331 | "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.", 1332 | "default": null, 1333 | "type": [ 1334 | "null", 1335 | "integer" 1336 | ], 1337 | "minimum": 0, 1338 | "maximum": 65535 1339 | }, 1340 | "rust-analyzer.lru.query.capacities": { 1341 | "markdownDescription": "The LRU capacity of the specified queries.", 1342 | "default": {}, 1343 | "type": "object" 1344 | }, 1345 | "rust-analyzer.notifications.cargoTomlNotFound": { 1346 | "markdownDescription": "Show `can't find Cargo.toml` error message.", 1347 | "default": true, 1348 | "type": "boolean" 1349 | }, 1350 | "rust-analyzer.numThreads": { 1351 | "markdownDescription": "The number of worker threads in the main loop. The default `null` means to pick\nautomatically.", 1352 | "default": null, 1353 | "anyOf": [ 1354 | { 1355 | "type": "null" 1356 | }, 1357 | { 1358 | "type": "number", 1359 | "minimum": 0, 1360 | "maximum": 255 1361 | }, 1362 | { 1363 | "type": "string", 1364 | "enum": [ 1365 | "physical", 1366 | "logical" 1367 | ], 1368 | "enumDescriptions": [ 1369 | "Use the number of physical cores", 1370 | "Use the number of logical cores" 1371 | ] 1372 | } 1373 | ] 1374 | }, 1375 | "rust-analyzer.procMacro.attributes.enable": { 1376 | "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.", 1377 | "default": true, 1378 | "type": "boolean" 1379 | }, 1380 | "rust-analyzer.procMacro.enable": { 1381 | "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.", 1382 | "default": true, 1383 | "type": "boolean" 1384 | }, 1385 | "rust-analyzer.procMacro.ignored": { 1386 | "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.", 1387 | "default": {}, 1388 | "type": "object" 1389 | }, 1390 | "rust-analyzer.procMacro.server": { 1391 | "markdownDescription": "Internal config, path to proc-macro server executable.", 1392 | "default": null, 1393 | "type": [ 1394 | "null", 1395 | "string" 1396 | ] 1397 | }, 1398 | "rust-analyzer.references.excludeImports": { 1399 | "markdownDescription": "Exclude imports from find-all-references.", 1400 | "default": false, 1401 | "type": "boolean" 1402 | }, 1403 | "rust-analyzer.references.excludeTests": { 1404 | "markdownDescription": "Exclude tests from find-all-references and call-hierarchy.", 1405 | "default": false, 1406 | "type": "boolean" 1407 | }, 1408 | "rust-analyzer.runnables.command": { 1409 | "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", 1410 | "default": null, 1411 | "type": [ 1412 | "null", 1413 | "string" 1414 | ] 1415 | }, 1416 | "rust-analyzer.runnables.extraArgs": { 1417 | "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.", 1418 | "default": [], 1419 | "type": "array", 1420 | "items": { 1421 | "type": "string" 1422 | } 1423 | }, 1424 | "rust-analyzer.runnables.extraTestBinaryArgs": { 1425 | "markdownDescription": "Additional arguments to be passed through Cargo to launched tests, benchmarks, or\ndoc-tests.\n\nUnless the launched target uses a\n[custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),\nthey will end up being interpreted as options to\n[`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).", 1426 | "default": [ 1427 | "--show-output" 1428 | ], 1429 | "type": "array", 1430 | "items": { 1431 | "type": "string" 1432 | } 1433 | }, 1434 | "rust-analyzer.rustc.source": { 1435 | "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.", 1436 | "default": null, 1437 | "type": [ 1438 | "null", 1439 | "string" 1440 | ] 1441 | }, 1442 | "rust-analyzer.rustfmt.extraArgs": { 1443 | "markdownDescription": "Additional arguments to `rustfmt`.", 1444 | "default": [], 1445 | "type": "array", 1446 | "items": { 1447 | "type": "string" 1448 | } 1449 | }, 1450 | "rust-analyzer.rustfmt.overrideCommand": { 1451 | "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting. This should be the equivalent of `rustfmt` here, and\nnot that of `cargo fmt`. The file contents will be passed on the\nstandard input and the formatted result will be read from the\nstandard output.\n\nNote: The option must be specified as an array of command line arguments, with\nthe first argument being the name of the command to run.", 1452 | "default": null, 1453 | "type": [ 1454 | "null", 1455 | "array" 1456 | ], 1457 | "items": { 1458 | "type": "string" 1459 | } 1460 | }, 1461 | "rust-analyzer.rustfmt.rangeFormatting.enable": { 1462 | "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.", 1463 | "default": false, 1464 | "type": "boolean" 1465 | }, 1466 | "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": { 1467 | "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.", 1468 | "default": true, 1469 | "type": "boolean" 1470 | }, 1471 | "rust-analyzer.semanticHighlighting.nonStandardTokens": { 1472 | "markdownDescription": "Emit non-standard tokens and modifiers\n\nWhen enabled, rust-analyzer will emit tokens and modifiers that are not part of the\nstandard set of semantic tokens.", 1473 | "default": true, 1474 | "type": "boolean" 1475 | }, 1476 | "rust-analyzer.semanticHighlighting.operator.enable": { 1477 | "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.", 1478 | "default": true, 1479 | "type": "boolean" 1480 | }, 1481 | "rust-analyzer.semanticHighlighting.operator.specialization.enable": { 1482 | "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.", 1483 | "default": false, 1484 | "type": "boolean" 1485 | }, 1486 | "rust-analyzer.semanticHighlighting.punctuation.enable": { 1487 | "markdownDescription": "Use semantic tokens for punctuation.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.", 1488 | "default": false, 1489 | "type": "boolean" 1490 | }, 1491 | "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": { 1492 | "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.", 1493 | "default": false, 1494 | "type": "boolean" 1495 | }, 1496 | "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": { 1497 | "markdownDescription": "Use specialized semantic tokens for punctuation.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.", 1498 | "default": false, 1499 | "type": "boolean" 1500 | }, 1501 | "rust-analyzer.semanticHighlighting.strings.enable": { 1502 | "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.", 1503 | "default": true, 1504 | "type": "boolean" 1505 | }, 1506 | "rust-analyzer.signatureInfo.detail": { 1507 | "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.", 1508 | "default": "full", 1509 | "type": "string", 1510 | "enum": [ 1511 | "full", 1512 | "parameters" 1513 | ], 1514 | "enumDescriptions": [ 1515 | "Show the entire signature.", 1516 | "Show only the parameters." 1517 | ] 1518 | }, 1519 | "rust-analyzer.signatureInfo.documentation.enable": { 1520 | "markdownDescription": "Show documentation.", 1521 | "default": true, 1522 | "type": "boolean" 1523 | }, 1524 | "rust-analyzer.typing.triggerChars": { 1525 | "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing\n expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in\n expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the\n expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", 1526 | "default": "=.", 1527 | "type": [ 1528 | "null", 1529 | "string" 1530 | ] 1531 | }, 1532 | "rust-analyzer.vfs.extraIncludes": { 1533 | "markdownDescription": "Additional paths to include in the VFS. Generally for code that is\ngenerated or otherwise managed by a build system outside of Cargo,\nthough Cargo might be the eventual consumer.", 1534 | "default": [], 1535 | "type": "array", 1536 | "items": { 1537 | "type": "string" 1538 | } 1539 | }, 1540 | "rust-analyzer.workspace.discoverConfig": { 1541 | "markdownDescription": "Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].\n\n[`DiscoverWorkspaceConfig`] also requires setting `progress_label` and `files_to_watch`.\n`progress_label` is used for the title in progress indicators, whereas `files_to_watch`\nis used to determine which build system-specific files should be watched in order to\nreload rust-analyzer.\n\nBelow is an example of a valid configuration:\n```json\n\"rust-analyzer.workspace.discoverConfig\": {\n \"command\": [\n \"rust-project\",\n \"develop-json\"\n ],\n \"progressLabel\": \"rust-analyzer\",\n \"filesToWatch\": [\n \"BUCK\"\n ]\n}\n```\n\n## On `DiscoverWorkspaceConfig::command`\n\n**Warning**: This format is provisional and subject to change.\n\n[`DiscoverWorkspaceConfig::command`] *must* return a JSON object corresponding to\n`DiscoverProjectData::Finished`:\n\n```norun\n#[derive(Debug, Clone, Deserialize, Serialize)]\n#[serde(tag = \"kind\")]\n#[serde(rename_all = \"snake_case\")]\nenum DiscoverProjectData {\n Finished { buildfile: Utf8PathBuf, project: ProjectJsonData },\n Error { error: String, source: Option },\n Progress { message: String },\n}\n```\n\nAs JSON, `DiscoverProjectData::Finished` is:\n\n```json\n{\n // the internally-tagged representation of the enum.\n \"kind\": \"finished\",\n // the file used by a non-Cargo build system to define\n // a package or target.\n \"buildfile\": \"rust-analyzer/BUILD\",\n // the contents of a rust-project.json, elided for brevity\n \"project\": {\n \"sysroot\": \"foo\",\n \"crates\": []\n }\n}\n```\n\nIt is encouraged, but not required, to use the other variants on `DiscoverProjectData`\nto provide a more polished end-user experience.\n\n`DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`, which will be\nsubstituted with the JSON-serialized form of the following enum:\n\n```norun\n#[derive(PartialEq, Clone, Debug, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub enum DiscoverArgument {\n Path(AbsPathBuf),\n Buildfile(AbsPathBuf),\n}\n```\n\nThe JSON representation of `DiscoverArgument::Path` is:\n\n```json\n{\n \"path\": \"src/main.rs\"\n}\n```\n\nSimilarly, the JSON representation of `DiscoverArgument::Buildfile` is:\n\n```json\n{\n \"buildfile\": \"BUILD\"\n}\n```\n\n`DiscoverArgument::Path` is used to find and generate a `rust-project.json`, and\ntherefore, a workspace, whereas `DiscoverArgument::buildfile` is used to to update an\nexisting workspace. As a reference for implementors, buck2's `rust-project` will likely\nbe useful: https://github.com/facebook/buck2/tree/main/integrations/rust-project.", 1542 | "default": null, 1543 | "anyOf": [ 1544 | { 1545 | "type": "null" 1546 | }, 1547 | { 1548 | "type": "object", 1549 | "properties": { 1550 | "command": { 1551 | "type": "array", 1552 | "items": { 1553 | "type": "string" 1554 | } 1555 | }, 1556 | "progressLabel": { 1557 | "type": "string" 1558 | }, 1559 | "filesToWatch": { 1560 | "type": "array", 1561 | "items": { 1562 | "type": "string" 1563 | } 1564 | } 1565 | } 1566 | } 1567 | ] 1568 | }, 1569 | "rust-analyzer.workspace.symbol.search.excludeImports": { 1570 | "markdownDescription": "Exclude all imports from workspace symbol search.\n\nIn addition to regular imports (which are always excluded),\nthis option removes public imports (better known as re-exports)\nand removes imports that rename the imported symbol.", 1571 | "default": false, 1572 | "type": "boolean" 1573 | }, 1574 | "rust-analyzer.workspace.symbol.search.kind": { 1575 | "markdownDescription": "Workspace symbol search kind.", 1576 | "default": "only_types", 1577 | "type": "string", 1578 | "enum": [ 1579 | "only_types", 1580 | "all_symbols" 1581 | ], 1582 | "enumDescriptions": [ 1583 | "Search for types only.", 1584 | "Search for all symbols kinds." 1585 | ] 1586 | }, 1587 | "rust-analyzer.workspace.symbol.search.limit": { 1588 | "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.", 1589 | "default": 128, 1590 | "type": "integer", 1591 | "minimum": 0 1592 | }, 1593 | "rust-analyzer.workspace.symbol.search.scope": { 1594 | "markdownDescription": "Workspace symbol search scope.", 1595 | "default": "workspace", 1596 | "type": "string", 1597 | "enum": [ 1598 | "workspace", 1599 | "workspace_and_dependencies" 1600 | ], 1601 | "enumDescriptions": [ 1602 | "Search in current workspace only.", 1603 | "Search in current workspace and dependencies." 1604 | ] 1605 | } 1606 | } 1607 | }, 1608 | "commands": [ 1609 | { 1610 | "command": "rust-analyzer.analyzerStatus", 1611 | "title": "Status", 1612 | "category": "rust-analyzer" 1613 | }, 1614 | { 1615 | "command": "rust-analyzer.memoryUsage", 1616 | "title": "Memory Usage (Clears Database)", 1617 | "category": "rust-analyzer" 1618 | }, 1619 | { 1620 | "command": "rust-analyzer.reloadWorkspace", 1621 | "title": "Reload workspace", 1622 | "category": "rust-analyzer" 1623 | }, 1624 | { 1625 | "command": "rust-analyzer.joinLines", 1626 | "title": "Join lines", 1627 | "category": "rust-analyzer" 1628 | }, 1629 | { 1630 | "command": "rust-analyzer.matchingBrace", 1631 | "title": "Find matching brace", 1632 | "category": "rust-analyzer" 1633 | }, 1634 | { 1635 | "command": "rust-analyzer.openDocs", 1636 | "title": "Open docs under cursor", 1637 | "category": "rust-analyzer" 1638 | }, 1639 | { 1640 | "command": "rust-analyzer.openCargoToml", 1641 | "title": "Open Cargo.toml", 1642 | "category": "rust-analyzer" 1643 | }, 1644 | { 1645 | "command": "rust-analyzer.parentModule", 1646 | "title": "Locate parent module", 1647 | "category": "rust-analyzer" 1648 | }, 1649 | { 1650 | "command": "rust-analyzer.reload", 1651 | "title": "Restart server", 1652 | "category": "rust-analyzer" 1653 | }, 1654 | { 1655 | "command": "rust-analyzer.run", 1656 | "title": "Run", 1657 | "category": "rust-analyzer" 1658 | }, 1659 | { 1660 | "command": "rust-analyzer.debug", 1661 | "title": "Debug", 1662 | "category": "rust-analyzer" 1663 | }, 1664 | { 1665 | "command": "rust-analyzer.ssr", 1666 | "title": "Structural Search Replace", 1667 | "category": "rust-analyzer" 1668 | }, 1669 | { 1670 | "command": "rust-analyzer.serverVersion", 1671 | "title": "Show current Rust Analyzer server version", 1672 | "category": "rust-analyzer" 1673 | }, 1674 | { 1675 | "command": "rust-analyzer.viewSyntaxTree", 1676 | "title": "View Syntax Tree", 1677 | "category": "rust-analyzer" 1678 | }, 1679 | { 1680 | "command": "rust-analyzer.testCurrent", 1681 | "title": "Test Current", 1682 | "category": "rust-analyzer" 1683 | }, 1684 | { 1685 | "command": "rust-analyzer.install", 1686 | "title": "Install Rust Analyzer from GitHub release", 1687 | "category": "rust-analyzer" 1688 | }, 1689 | { 1690 | "command": "rust-analyzer.upgrade", 1691 | "title": "Upgrade Rust Analyzer from GitHub release", 1692 | "category": "rust-analyzer" 1693 | }, 1694 | { 1695 | "command": "rust-analyzer.expandMacro", 1696 | "title": "Expand macro recursively at caret", 1697 | "category": "rust-analyzer" 1698 | }, 1699 | { 1700 | "command": "rust-analyzer.viewHir", 1701 | "title": "View Hir", 1702 | "category": "rust-analyzer" 1703 | }, 1704 | { 1705 | "command": "rust-analyzer.viewMir", 1706 | "title": "View Mir", 1707 | "category": "rust-analyzer" 1708 | }, 1709 | { 1710 | "command": "rust-analyzer.viewFileText", 1711 | "title": "View File Text (as seen by the server)", 1712 | "category": "rust-analyzer" 1713 | }, 1714 | { 1715 | "command": "rust-analyzer.viewItemTree", 1716 | "title": "Debug ItemTree", 1717 | "category": "rust-analyzer" 1718 | }, 1719 | { 1720 | "command": "rust-analyzer.viewCrateGraph", 1721 | "title": "View Crate Graph", 1722 | "category": "rust-analyzer" 1723 | }, 1724 | { 1725 | "command": "rust-analyzer.shuffleCrateGraph", 1726 | "title": "Shuffle Crate Graph", 1727 | "category": "rust-analyzer" 1728 | }, 1729 | { 1730 | "command": "rust-analyzer.viewFullCrateGraph", 1731 | "title": "View Crate Graph (Full)", 1732 | "category": "rust-analyzer" 1733 | }, 1734 | { 1735 | "command": "rust-analyzer.echoRunCommandLine", 1736 | "title": "Echo Run Command Line", 1737 | "category": "rust-analyzer" 1738 | }, 1739 | { 1740 | "command": "rust-analyzer.peekTests", 1741 | "title": "Peek related tests", 1742 | "category": "rust-analyzer" 1743 | }, 1744 | { 1745 | "command": "rust-analyzer.moveItemUp", 1746 | "title": "Move item up", 1747 | "category": "rust-analyzer" 1748 | }, 1749 | { 1750 | "command": "rust-analyzer.moveItemDown", 1751 | "title": "Move item down", 1752 | "category": "rust-analyzer" 1753 | }, 1754 | { 1755 | "command": "rust-analyzer.runFlycheck", 1756 | "title": "Run flycheck", 1757 | "category": "rust-analyzer" 1758 | }, 1759 | { 1760 | "command": "rust-analyzer.cancelFlycheck", 1761 | "title": "Cancel running flychecks", 1762 | "category": "rust-analyzer" 1763 | }, 1764 | { 1765 | "command": "rust-analyzer.clearFlycheck", 1766 | "title": "Clear flycheck diagnostics", 1767 | "category": "rust-analyzer" 1768 | }, 1769 | { 1770 | "command": "rust-analyzer.rebuildProcMacros", 1771 | "title": "Rebuild proc macros and build scripts", 1772 | "category": "rust-analyzer" 1773 | }, 1774 | { 1775 | "command": "rust-analyzer.interpretFunction", 1776 | "title": "Interpret Function", 1777 | "category": "rust-analyzer" 1778 | }, 1779 | { 1780 | "command": "rust-analyzer.explainError", 1781 | "title": "Explain the currently hovered diagnostic", 1782 | "category": "rust-analyzer" 1783 | } 1784 | ] 1785 | } 1786 | } 1787 | -------------------------------------------------------------------------------- /src/client.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LanguageClient, 3 | Uri, 4 | window, 5 | workspace, 6 | type CodeActionKind, 7 | type Command, 8 | type Executable, 9 | type LanguageClientOptions, 10 | type Position, 11 | type Range, 12 | type ServerOptions, 13 | type StaticFeature, 14 | } from 'coc.nvim'; 15 | import { CodeAction, CodeActionRequest, type CodeActionParams } from 'vscode-languageserver-protocol'; 16 | import type { Config } from './config'; 17 | import * as ra from './lsp_ext'; 18 | 19 | class ExperimentalFeatures implements StaticFeature { 20 | fillClientCapabilities(capabilities: any): void { 21 | const caps: any = capabilities.experimental ?? {}; 22 | caps.snippetTextEdit = true; 23 | caps.serverStatusNotification = true; 24 | caps.localDocs = true; 25 | caps.commands = { 26 | commands: [ 27 | 'rust-analyzer.runSingle', 28 | 'rust-analyzer.debugSingle', 29 | 'rust-analyzer.showReferences', 30 | 'rust-analyzer.gotoLocation', 31 | 'editor.action.triggerParameterHints', 32 | ], 33 | }; 34 | capabilities.experimental = caps; 35 | } 36 | initialize(): void {} 37 | dispose(): void {} 38 | } 39 | 40 | function isCodeActionWithoutEditsAndCommands(value: any): boolean { 41 | const candidate: CodeAction = value; 42 | return ( 43 | candidate && 44 | (candidate.diagnostics === void 0 || Array.isArray(candidate.diagnostics)) && 45 | (candidate.kind === void 0 || typeof candidate.kind === 'string') && 46 | candidate.edit === void 0 && 47 | candidate.command === void 0 48 | ); 49 | } 50 | 51 | export function createClient(bin: string, config: Config): LanguageClient { 52 | let folder = '.'; 53 | if (workspace.workspaceFolders.length) { 54 | folder = Uri.parse(workspace.workspaceFolders[0].uri).fsPath; 55 | } 56 | 57 | const env = Object.assign(Object.assign({}, process.env), config.serverExtraEnv); 58 | const run: Executable = { 59 | command: process.platform === 'win32' ? `"${bin}"` : bin, 60 | options: { env, cwd: folder, shell: process.platform === 'win32' }, 61 | }; 62 | 63 | const initializationOptions = workspace.getConfiguration('rust-analyzer'); 64 | const disabledFeatures: string[] = []; 65 | if (config.disableProgressNotifications) { 66 | disabledFeatures.push('progress'); 67 | } 68 | if (!config.inlayHint.enable) { 69 | disabledFeatures.push('inlayHint'); 70 | } 71 | if (config.disablePullDiagnostic) { 72 | disabledFeatures.push('pullDiagnostic'); 73 | } 74 | const serverOptions: ServerOptions = run; 75 | const clientOptions: LanguageClientOptions = { 76 | documentSelector: [{ language: 'rust' }], 77 | initializationOptions, 78 | disabledFeatures, 79 | progressOnInitialization: !config.disableProgressNotifications, 80 | middleware: { 81 | async provideHover(document, position, token) { 82 | let positionOrRange: Range | Position | null = null; 83 | const mode = (await workspace.nvim.call('mode')) as string; 84 | if (mode === 'v' || mode === 'V') { 85 | await workspace.nvim.call('eval', 'feedkeys("\\", "in")'); 86 | positionOrRange = await window.getSelectedRange(mode); 87 | } 88 | if (!positionOrRange) positionOrRange = position; 89 | const param: ra.HoverParams = { 90 | position: positionOrRange || position, 91 | textDocument: { uri: document.uri }, 92 | }; 93 | return await client.sendRequest(ra.hover, param, token); 94 | }, 95 | async provideCodeActions(document, range, context, token) { 96 | const params: CodeActionParams = { 97 | textDocument: { uri: document.uri }, 98 | range, 99 | context, 100 | }; 101 | const values = await client.sendRequest(CodeActionRequest.type.method, params, token); 102 | if (values === null) return undefined; 103 | const result: (CodeAction | Command)[] = []; 104 | for (const item of values as (Command | CodeAction)[]) { 105 | if (CodeAction.is(item)) { 106 | result.push(item); 107 | continue; 108 | } 109 | 110 | if (!isCodeActionWithoutEditsAndCommands(item)) { 111 | console.error('isCodeActionWithoutEditsAndCommands:', JSON.stringify(item)); 112 | continue; 113 | } 114 | 115 | const command: Command = { 116 | command: 'rust-analyzer.resolveCodeAction', 117 | title: item.title, 118 | arguments: [item], 119 | }; 120 | const kind: CodeActionKind = (item as any).kind; 121 | const action = CodeAction.create(item.title, command, kind); 122 | action.edit = {}; 123 | result.push(action); 124 | } 125 | return result; 126 | }, 127 | }, 128 | }; 129 | 130 | const client = new LanguageClient('rust-analyzer', 'Rust Analyzer Language Server', serverOptions, clientOptions); 131 | // HACK: This is an awful way of filtering out the decorations notifications 132 | // However, pending proper support, this is the most effecitve approach 133 | // Proper support for this would entail a change to vscode-languageclient to allow not notifying on certain messages 134 | // Or the ability to disable the serverside component of highlighting (but this means that to do tracing we need to disable hihlighting) 135 | // This also requires considering our settings strategy, which is work which needs doing 136 | // @ts-expect-error The tracer is private to vscode-languageclient, but we need access to it to not log publishDecorations requests 137 | client._tracer = { 138 | log: (msg: string | unknown, data?: string) => { 139 | if (typeof msg === 'string') { 140 | if (msg.includes('rust-analyzer/publishDecorations') || msg.includes('rust-analyzer/decorationsRequest')) { 141 | // Don't log publish decorations requests 142 | } else { 143 | client.traceMessage(msg, data); 144 | } 145 | } else { 146 | // @ts-expect-error 147 | client.logObjectTrace(msg); 148 | } 149 | }, 150 | }; 151 | client.registerFeature(new ExperimentalFeatures()); 152 | 153 | return client; 154 | } 155 | -------------------------------------------------------------------------------- /src/commands.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type CodeAction, 3 | commands, 4 | type Documentation, 5 | Location, 6 | nvim, 7 | type Position, 8 | Range, 9 | type SnippetTextEdit, 10 | type Terminal, 11 | type TerminalOptions, 12 | type TextDocumentPositionParams, 13 | type TextEdit, 14 | Uri, 15 | window, 16 | workspace, 17 | type WorkspaceEdit, 18 | } from 'coc.nvim'; 19 | import { spawn, spawnSync } from 'node:child_process'; 20 | import { randomBytes } from 'node:crypto'; 21 | import { existsSync, writeFileSync } from 'node:fs'; 22 | import { tmpdir } from 'node:os'; 23 | import { join } from 'node:path'; 24 | import readline from 'node:readline'; 25 | import { CodeActionResolveRequest, TextDocumentEdit } from 'vscode-languageserver-protocol'; 26 | import { type Cmd, type Ctx, isCargoTomlDocument, isRustDocument } from './ctx'; 27 | import * as ra from './lsp_ext'; 28 | 29 | let terminal: Terminal | undefined; 30 | 31 | class RunnableQuickPick { 32 | label: string; 33 | 34 | constructor(public runnable: ra.Runnable) { 35 | this.label = runnable.label; 36 | } 37 | } 38 | 39 | function isInRange(range: Range, position: Position): boolean { 40 | const lineWithin = range.start.line <= position.line && range.end.line >= position.line; 41 | const charWithin = range.start.character <= position.character && range.end.line >= position.character; 42 | return lineWithin && charWithin; 43 | } 44 | 45 | function codeFormat(expanded: ra.ExpandedMacro): string { 46 | let result = `// Recursive expansion of ${expanded.name}! macro\n`; 47 | result += `// ${'='.repeat(result.length - 3)}`; 48 | result += '\n\n'; 49 | result += expanded.expansion; 50 | 51 | return result; 52 | } 53 | 54 | export function reload(ctx: Ctx): Cmd { 55 | return async () => { 56 | window.showInformationMessage('Reloading rust-analyzer...'); 57 | 58 | await ctx.client.stop(); 59 | await ctx.client.start(); 60 | 61 | window.showInformationMessage('Reloaded rust-analyzer'); 62 | }; 63 | } 64 | 65 | export function analyzerStatus(ctx: Ctx): Cmd { 66 | return async () => { 67 | const { document } = await workspace.getCurrentState(); 68 | if (!isRustDocument(document)) return; 69 | const params: ra.AnalyzerStatusParams = { 70 | textDocument: { uri: document.uri }, 71 | }; 72 | const ret = await ctx.client.sendRequest(ra.analyzerStatus, params); 73 | window.echoLines(ret.split('\n')); 74 | }; 75 | } 76 | 77 | export function memoryUsage(ctx: Ctx): Cmd { 78 | return async () => { 79 | const ret = await ctx.client.sendRequest(ra.memoryUsage); 80 | window.echoLines(ret.split('\n')); 81 | }; 82 | } 83 | 84 | export function matchingBrace(ctx: Ctx): Cmd { 85 | return async () => { 86 | const { document, position } = await workspace.getCurrentState(); 87 | if (!isRustDocument(document)) return; 88 | 89 | const params: ra.MatchingBraceParams = { 90 | textDocument: { uri: document.uri }, 91 | positions: [position], 92 | }; 93 | 94 | const response = await ctx.client.sendRequest(ra.matchingBrace, params); 95 | if (response.length > 0) { 96 | workspace.jumpTo(document.uri, response[0]); 97 | } 98 | }; 99 | } 100 | 101 | export function joinLines(ctx: Ctx): Cmd { 102 | return async () => { 103 | const doc = await workspace.document; 104 | if (!isRustDocument(doc.textDocument)) return; 105 | 106 | let range: Range | null = null; 107 | const mode = (await workspace.nvim.call('visualmode')) as string; 108 | if (mode) range = await window.getSelectedRange(mode); 109 | if (!range) { 110 | const state = await workspace.getCurrentState(); 111 | range = Range.create(state.position, state.position); 112 | } 113 | const param: ra.JoinLinesParams = { 114 | textDocument: { uri: doc.uri }, 115 | ranges: [range], 116 | }; 117 | const items = await ctx.client.sendRequest(ra.joinLines, param); 118 | await doc.applyEdits(items); 119 | }; 120 | } 121 | 122 | export function parentModule(ctx: Ctx): Cmd { 123 | return async () => { 124 | const { document, position } = await workspace.getCurrentState(); 125 | if (!(isRustDocument(document) || isCargoTomlDocument(document))) return; 126 | 127 | const param: TextDocumentPositionParams = { 128 | textDocument: { uri: document.uri }, 129 | position, 130 | }; 131 | 132 | const locations = await ctx.client.sendRequest(ra.parentModule, param); 133 | if (!locations) return; 134 | 135 | if (locations.length === 1) { 136 | const loc = locations[0]; 137 | const uri = Location.is(loc) ? loc.uri : loc.targetUri; 138 | const pos = Location.is(loc) ? loc.range?.start : loc.targetRange?.start; 139 | workspace.jumpTo(uri, pos); 140 | } else { 141 | const uri = document.uri; 142 | const refs: Location[] = []; 143 | for (const l of locations) { 144 | refs.push(Location.is(l) ? l : Location.create(l.targetUri, l.targetRange)); 145 | } 146 | await commands.executeCommand('editor.action.showReferences', Uri.parse(uri), position, refs); 147 | } 148 | }; 149 | } 150 | 151 | export function ssr(ctx: Ctx): Cmd { 152 | return async () => { 153 | const input = await workspace.callAsync('input', ['Enter request like: foo($a, $b) ==>> ($a).foo($b): ']); 154 | workspace.nvim.command('normal! :', true); 155 | if (!input) { 156 | return; 157 | } 158 | 159 | if (!input.includes('==>>')) { 160 | return; 161 | } 162 | 163 | const selections: Range[] = []; 164 | const mode = await workspace.nvim.call('visualmode'); 165 | if (mode) { 166 | const range = await window.getSelectedRange(mode.toString()); 167 | if (range) selections.push(range); 168 | } 169 | 170 | const { document, position } = await workspace.getCurrentState(); 171 | const param: ra.SsrParams = { 172 | query: input, 173 | parseOnly: false, 174 | textDocument: { uri: document.uri }, 175 | position, 176 | selections, 177 | }; 178 | 179 | window.withProgress({ title: 'Structured search replacing...', cancellable: false }, async () => { 180 | const edit = await ctx.client.sendRequest(ra.ssr, param); 181 | await workspace.applyEdit(edit); 182 | }); 183 | }; 184 | } 185 | 186 | export function serverVersion(ctx: Ctx): Cmd { 187 | return async () => { 188 | const bin = ctx.resolveBin(); 189 | if (!bin) { 190 | const msg = 'Rust Analyzer is not found'; 191 | window.showErrorMessage(msg); 192 | return; 193 | } 194 | 195 | const version = spawnSync(bin, ['--version'], { encoding: 'utf-8' }).stdout.toString(); 196 | window.showInformationMessage(version); 197 | }; 198 | } 199 | 200 | async function fetchRunnable(ctx: Ctx): Promise { 201 | const { document, position } = await workspace.getCurrentState(); 202 | if (!isRustDocument(document)) return []; 203 | 204 | window.showInformationMessage('Fetching runnable...'); 205 | 206 | const params: ra.RunnablesParams = { 207 | textDocument: { uri: document.uri }, 208 | position, 209 | }; 210 | 211 | return await ctx.client.sendRequest(ra.runnables, params); 212 | } 213 | 214 | async function pickRunnable(ctx: Ctx): Promise { 215 | const runnables = await fetchRunnable(ctx); 216 | if (!runnables.length) return; 217 | 218 | const items: RunnableQuickPick[] = []; 219 | for (const r of runnables) { 220 | items.push(new RunnableQuickPick(r)); 221 | } 222 | 223 | const idx = await window.showQuickpick(items.map((o) => o.label)); 224 | if (idx === -1) return; 225 | 226 | return items[idx].runnable; 227 | } 228 | 229 | export function run(ctx: Ctx): Cmd { 230 | return async () => { 231 | const runnable = await pickRunnable(ctx); 232 | if (!runnable) return; 233 | 234 | await runSingle(ctx)(runnable); 235 | }; 236 | } 237 | 238 | export function testCurrent(ctx: Ctx): Cmd { 239 | return async () => { 240 | const runnables = await fetchRunnable(ctx); 241 | if (!runnables.length) { 242 | window.showInformationMessage('No runnables found'); 243 | return; 244 | } 245 | 246 | const testRunnable = runnables.find((run) => run.label.startsWith('cargo test')); 247 | if (!testRunnable) return; 248 | 249 | await runSingle(ctx)(testRunnable); 250 | }; 251 | } 252 | 253 | export function debug(ctx: Ctx): Cmd { 254 | return async () => { 255 | const runnable = await pickRunnable(ctx); 256 | if (!runnable) return; 257 | 258 | await debugSingle(ctx)(runnable); 259 | }; 260 | } 261 | 262 | export function debugSingle(ctx: Ctx): Cmd { 263 | return async (runnable: ra.Runnable) => { 264 | const { document } = await workspace.getCurrentState(); 265 | if (!runnable || !isRustDocument(document)) return; 266 | 267 | let args: string[] = []; 268 | if (runnable.kind === 'cargo') { 269 | // TODO: runnable.args.overrideCargo? 270 | args = [...runnable.args.cargoArgs]; 271 | if (runnable.args.executableArgs.length > 0) { 272 | runnable.args['executableArgs'][0] = `'${runnable.args['executableArgs'][0]}'`; 273 | args.push('--', ...runnable.args.executableArgs); 274 | } 275 | } else { 276 | args = [...runnable.args.args]; 277 | } 278 | 279 | // do not run tests, we will run through gdb 280 | if (args[0] === 'test') { 281 | args.push('--no-run'); 282 | } 283 | 284 | if (args[0] === 'run') { 285 | args[0] = 'build'; 286 | } 287 | 288 | // output as json 289 | args.push('--message-format=json'); 290 | 291 | console.debug(`${runnable.kind} ${args}`); 292 | // We can extract a list of generated executables from the output of cargo, 293 | // but if multiple executables are generated we need a way to find out which 294 | // one should be used for debugging. 295 | // From the arguments given to cargo, we can infer the kind and name of the executable 296 | // and filter the list of executables accordingly. 297 | let expectedKind: string | undefined; 298 | let expectedName: string | undefined; 299 | const cargoArgs = runnable.kind === 'cargo' ? runnable.args.cargoArgs : []; 300 | for (const arg of cargoArgs) { 301 | // Find the argument indicating the kind of the executable. 302 | if (expectedKind === undefined) { 303 | switch (arg) { 304 | case '--bin': 305 | expectedKind = 'bin'; 306 | break; 307 | case '--lib': 308 | expectedKind = 'lib'; 309 | break; 310 | case '--test': 311 | expectedKind = 'test'; 312 | break; 313 | case '--example': 314 | expectedKind = 'example'; 315 | break; 316 | case '--bench': 317 | expectedKind = 'bench'; 318 | break; 319 | } 320 | } else { 321 | // expectedKind is defined if the previous argument matched one of the cases above. 322 | // In all of these cases except for '--lib' the name of the executable is the 323 | // argument analyzed in this iteration. 324 | if (expectedKind !== 'lib') { 325 | expectedName = arg; 326 | } 327 | // Stop iterating over the arguments, since we now have the information we need. 328 | break; 329 | } 330 | } 331 | // If the kind is 'lib' then the name of the executable is not yet known. 332 | // However, it will be the name of the package, so if we find the 333 | // --package argument we can get the name of the executable from it. 334 | if (expectedName === undefined) { 335 | let foundPackageArgument = false; 336 | for (const arg of cargoArgs) { 337 | if (foundPackageArgument) { 338 | expectedName = arg; 339 | break; 340 | } 341 | if (arg === '--package') { 342 | foundPackageArgument = true; 343 | } 344 | } 345 | } 346 | console.debug(`Expected kind: ${expectedKind}`); 347 | console.debug(`Expected name: ${expectedName}`); 348 | 349 | const proc = spawn(runnable.kind, args, { shell: true }); 350 | 351 | const stderr_rl = readline.createInterface({ 352 | input: proc.stderr, 353 | crlfDelay: Infinity, 354 | }); 355 | window.withProgress({ title: 'Building Debug Target', cancellable: false }, async (progress) => { 356 | for await (const line of stderr_rl) { 357 | if (!line) { 358 | continue; 359 | } 360 | const message = line.trimStart(); 361 | progress.report({ message: message }); 362 | } 363 | }); 364 | 365 | const rl = readline.createInterface({ 366 | input: proc.stdout, 367 | crlfDelay: Infinity, 368 | }); 369 | 370 | let executable = null; 371 | for await (const line of rl) { 372 | if (!line) { 373 | continue; 374 | } 375 | 376 | let cargoMessage = {}; 377 | try { 378 | cargoMessage = JSON.parse(line); 379 | } catch (e) { 380 | console.error(e); 381 | continue; 382 | } 383 | 384 | if (!cargoMessage) { 385 | console.debug(`Skipping cargo message: ${cargoMessage}`); 386 | } 387 | 388 | if (cargoMessage['reason'] !== 'compiler-artifact') { 389 | console.debug(`Not artifact: ${cargoMessage['reason']}`); 390 | continue; 391 | } 392 | 393 | if (expectedKind !== undefined && !cargoMessage['target']['kind'].includes(expectedKind)) { 394 | console.debug(`Wrong kind: ${cargoMessage['target']['kind']}, expected ${expectedKind}`); 395 | continue; 396 | } 397 | 398 | if (expectedName !== undefined && cargoMessage['target']['name'] !== expectedName) { 399 | console.debug(`Wrong name: ${cargoMessage['target']['name']}, expected ${expectedName}`); 400 | continue; 401 | } 402 | 403 | if (cargoMessage['executable']) { 404 | executable = cargoMessage['executable']; 405 | break; 406 | } 407 | } 408 | 409 | if (!executable) { 410 | throw new Error('Could not find executable'); 411 | } 412 | 413 | const executableArgs = runnable.kind === 'cargo' ? runnable.args.executableArgs.join(' ') : ''; 414 | 415 | console.info(`Debugging executable: ${executable} ${executableArgs}`); 416 | 417 | const runtime = ctx.config.debug.runtime; 418 | if (runtime === 'termdebug') { 419 | await workspace.nvim.command(`TermdebugCommand ${executable} ${executableArgs}`); 420 | return; 421 | } 422 | 423 | if (runtime === 'vimspector') { 424 | const name = ctx.config.debug.vimspectorConfiguration.name; 425 | const configuration = { configuration: name, Executable: executable, Args: executableArgs }; 426 | await workspace.nvim.call('vimspector#LaunchWithSettings', configuration); 427 | return; 428 | } 429 | 430 | if (runtime === 'nvim-dap') { 431 | const template = ctx.config.debug.nvimdapConfiguration.template; 432 | const args = executableArgs 433 | .split(' ') 434 | .filter((s) => s !== '') 435 | .map((s) => `"${s}"`) 436 | .join(','); 437 | const configuration = template?.replace('$exe', `"${executable}"`).replace('$args', `{${args}}`); 438 | await workspace.nvim.lua(`require("dap").run(${configuration})`); 439 | return; 440 | } 441 | 442 | throw new Error(`Invalid debug runtime: ${runtime}`); 443 | }; 444 | } 445 | 446 | export function runSingle(ctx: Ctx): Cmd { 447 | return async (runnable: ra.Runnable) => { 448 | const { document } = await workspace.getCurrentState(); 449 | if (!runnable || !isRustDocument(document)) return; 450 | 451 | let args: string[] = []; 452 | if (runnable.kind === 'cargo') { 453 | // TODO: runnable.args.overrideCargo? 454 | args = [...runnable.args.cargoArgs]; 455 | if (runnable.args.executableArgs.length > 0) { 456 | runnable.args['executableArgs'][0] = `'${runnable.args['executableArgs'][0]}'`; 457 | args.push('--', ...runnable.args.executableArgs); 458 | } 459 | } else { 460 | args = [...runnable.args.args]; 461 | } 462 | 463 | const cmd = `${runnable.kind} ${args.join(' ')}`; 464 | const opt: TerminalOptions = { 465 | name: runnable.label, 466 | cwd: runnable.args.cwd, 467 | }; 468 | if (terminal) { 469 | terminal.dispose(); 470 | terminal = undefined; 471 | } 472 | terminal = await window.createTerminal(opt); 473 | terminal.sendText(cmd); 474 | if (ctx.config.terminal.startinsert) { 475 | await workspace.nvim.command('startinsert'); 476 | } 477 | }; 478 | } 479 | 480 | export function viewSyntaxTree(ctx: Ctx): Cmd { 481 | return async () => { 482 | const doc = await workspace.document; 483 | if (!isRustDocument(doc.textDocument)) return; 484 | 485 | const mode = await workspace.nvim.call('visualmode'); 486 | let range: Range | null = null; 487 | if (mode) range = await window.getSelectedRange(mode.toString()); 488 | const param: ra.SyntaxTreeParams = { 489 | textDocument: { uri: doc.uri }, 490 | range, 491 | }; 492 | 493 | const ret = await ctx.client.sendRequest(ra.viewSyntaxTree, param); 494 | if (!ret) return; 495 | const nvim = workspace.nvim; 496 | nvim.pauseNotification(); 497 | nvim.command('edit +setl\\ buftype=nofile [SyntaxTree]', true); 498 | nvim.command('setl nobuflisted bufhidden=wipe', true); 499 | nvim.call('append', [0, ret.split('\n')], true); 500 | nvim.command('exe 1', true); 501 | await nvim.resumeNotification(true); 502 | }; 503 | } 504 | 505 | export function expandMacro(ctx: Ctx): Cmd { 506 | return async () => { 507 | const { document, position } = await workspace.getCurrentState(); 508 | if (!isRustDocument(document)) return; 509 | 510 | const param: TextDocumentPositionParams = { 511 | textDocument: { uri: document.uri }, 512 | position, 513 | }; 514 | 515 | const expanded = await ctx.client.sendRequest(ra.expandMacro, param); 516 | if (!expanded) return; 517 | 518 | const lines = codeFormat(expanded).split('\n'); 519 | const nvim = workspace.nvim; 520 | nvim.pauseNotification(); 521 | nvim.command('edit +setl\\ buftype=nofile [Macro]', true); 522 | nvim.command('setl nobuflisted bufhidden=wipe', true); 523 | nvim.command('setl filetype=rust', true); 524 | nvim.call('append', [0, lines], true); 525 | nvim.command('exe 1', true); 526 | await nvim.resumeNotification(true); 527 | }; 528 | } 529 | 530 | export function explainError(ctx: Ctx): Cmd { 531 | return async () => { 532 | const { document, position } = await workspace.getCurrentState(); 533 | if (!isRustDocument(document)) return; 534 | 535 | const diag = ctx.client.diagnostics?.get(document.uri)?.find((diagnostic) => isInRange(diagnostic.range, position)); 536 | if (diag?.code) { 537 | const explanation = spawnSync('rustc', ['--explain', `${diag.code}`], { encoding: 'utf-8' }).stdout.toString(); 538 | 539 | const docs: Documentation[] = []; 540 | let isCode = false; 541 | for (const part of explanation.split('```\n')) { 542 | docs.push({ content: part, filetype: isCode ? 'rust' : 'markdown' }); 543 | isCode = !isCode; 544 | } 545 | 546 | const float = window.createFloatFactory({}); 547 | await float.show(docs); 548 | } 549 | }; 550 | } 551 | 552 | export function reloadWorkspace(ctx: Ctx): Cmd { 553 | return async () => { 554 | await ctx.client?.sendRequest(ra.reloadWorkspace); 555 | }; 556 | } 557 | 558 | export function showReferences(): Cmd { 559 | return async (uri: string, position: Position, locations: Location[]) => { 560 | if (!uri) { 561 | return; 562 | } 563 | await commands.executeCommand('editor.action.showReferences', Uri.parse(uri), position, locations); 564 | }; 565 | } 566 | 567 | export function install(ctx: Ctx): Cmd { 568 | return async () => { 569 | await ctx.installServerFromGitHub(); 570 | }; 571 | } 572 | 573 | export function upgrade(ctx: Ctx) { 574 | return async () => { 575 | await ctx.checkUpdate(false); 576 | }; 577 | } 578 | 579 | export async function applySnippetWorkspaceEdit(edit: WorkspaceEdit) { 580 | if (!edit?.documentChanges?.length) { 581 | return; 582 | } 583 | 584 | for (const change of edit.documentChanges) { 585 | if ('kind' in change || !TextDocumentEdit.is(change)) { 586 | continue; 587 | } 588 | 589 | const newEdits: (TextEdit | SnippetTextEdit)[] = []; 590 | 591 | for (const indel of change.edits) { 592 | if (!('insertTextFormat' in indel)) { 593 | // plain text edit 594 | newEdits.push(indel); 595 | continue; 596 | } 597 | 598 | const hasSnippet = indel.newText.match(/\$\d+|\{\d+:[^}]*\}/); 599 | if (hasSnippet) { 600 | newEdits.push({ 601 | range: indel.range, 602 | snippet: { kind: 'snippet', value: indel.newText }, 603 | } as SnippetTextEdit); 604 | } else { 605 | newEdits.push(indel); 606 | } 607 | } 608 | 609 | const current = await workspace.document; 610 | if (current.uri !== change.textDocument.uri) { 611 | await workspace.loadFile(change.textDocument.uri); 612 | await workspace.jumpTo(change.textDocument.uri); 613 | } 614 | 615 | await workspace.applyEdit({ 616 | documentChanges: [{ textDocument: { uri: change.textDocument.uri, version: null }, edits: newEdits }], 617 | }); 618 | } 619 | } 620 | 621 | export function applySnippetWorkspaceEditCommand(): Cmd { 622 | return async (edit: WorkspaceEdit) => { 623 | await applySnippetWorkspaceEdit(edit); 624 | }; 625 | } 626 | 627 | export function runFlycheck(ctx: Ctx): Cmd { 628 | return async () => { 629 | const { document } = await workspace.getCurrentState(); 630 | if (!isRustDocument(document)) return; 631 | 632 | ctx.client.sendNotification(ra.runFlycheck, { textDocument: { uri: document.uri } }); 633 | }; 634 | } 635 | 636 | export function cancelFlycheck(ctx: Ctx): Cmd { 637 | return async () => { 638 | ctx.client.sendNotification(ra.cancelFlycheck); 639 | }; 640 | } 641 | 642 | export function clearFlycheck(ctx: Ctx): Cmd { 643 | return async () => { 644 | ctx.client.sendNotification(ra.clearFlycheck); 645 | }; 646 | } 647 | 648 | export function resolveCodeAction(ctx: Ctx): Cmd { 649 | return async (params: CodeAction) => { 650 | params.command = undefined; 651 | const item = (await ctx.client.sendRequest(CodeActionResolveRequest.method, params)) as CodeAction; 652 | if (!item?.edit) return; 653 | 654 | const wsEditWithoutTextEdits: WorkspaceEdit = { 655 | documentChanges: item.edit.documentChanges?.filter((change) => 'kind' in change), 656 | }; 657 | await workspace.applyEdit(wsEditWithoutTextEdits); 658 | await applySnippetWorkspaceEdit(item.edit); 659 | }; 660 | } 661 | 662 | export function openDocs(ctx: Ctx): Cmd { 663 | return async () => { 664 | const { document, position } = await workspace.getCurrentState(); 665 | if (!isRustDocument(document)) return; 666 | 667 | const param: TextDocumentPositionParams = { 668 | textDocument: { uri: document.uri }, 669 | position, 670 | }; 671 | const doclink = await ctx.client.sendRequest(ra.openDocs, param); 672 | if (doclink) { 673 | if (doclink.local) { 674 | const exist = existsSync(Uri.parse(doclink.local).fsPath); 675 | if (exist) { 676 | await nvim.call('coc#ui#open_url', doclink.local); 677 | return; 678 | } 679 | } 680 | if (doclink.web) { 681 | await commands.executeCommand('vscode.open', Uri.parse(doclink.web)); 682 | } 683 | } 684 | }; 685 | } 686 | 687 | export function openCargoToml(ctx: Ctx): Cmd { 688 | return async () => { 689 | const { document } = await workspace.getCurrentState(); 690 | if (!isRustDocument(document)) return; 691 | 692 | const location = await ctx.client.sendRequest(ra.openCargoToml, { 693 | textDocument: { uri: document.uri }, 694 | }); 695 | if (!location) return; 696 | 697 | await workspace.jumpTo(location.uri); 698 | }; 699 | } 700 | 701 | function viewXir(ctx: Ctx, xir: 'HIR' | 'MIR'): Cmd { 702 | return async () => { 703 | const { document, position } = await workspace.getCurrentState(); 704 | if (!isRustDocument(document)) return; 705 | 706 | const param: TextDocumentPositionParams = { 707 | textDocument: { uri: document.uri }, 708 | position, 709 | }; 710 | const req = xir === 'HIR' ? ra.viewHir : ra.viewMir; 711 | const ret = await ctx.client.sendRequest(req, param); 712 | if (!ret) return; 713 | const nvim = workspace.nvim; 714 | nvim.pauseNotification(); 715 | nvim.command(`edit +setl\\ buftype=nofile [${xir}]`, true); 716 | nvim.command('setl nobuflisted bufhidden=wipe', true); 717 | nvim.call('append', [0, ret.split('\n')], true); 718 | nvim.command('exe 1', true); 719 | await nvim.resumeNotification(true); 720 | }; 721 | } 722 | 723 | export function viewHir(ctx: Ctx): Cmd { 724 | return viewXir(ctx, 'HIR'); 725 | } 726 | 727 | export function viewMir(ctx: Ctx): Cmd { 728 | return viewXir(ctx, 'MIR'); 729 | } 730 | 731 | export function interpretFunction(ctx: Ctx): Cmd { 732 | return async () => { 733 | const { document, position } = await workspace.getCurrentState(); 734 | if (!isRustDocument(document)) return; 735 | 736 | const param: TextDocumentPositionParams = { 737 | textDocument: { uri: document.uri }, 738 | position, 739 | }; 740 | const ret = await ctx.client.sendRequest(ra.interpretFunction, param); 741 | if (!ret) return; 742 | const nvim = workspace.nvim; 743 | nvim.pauseNotification(); 744 | nvim.command('edit +setl\\ buftype=nofile [interpretFunction]', true); 745 | nvim.command('setl nobuflisted bufhidden=wipe', true); 746 | nvim.call('append', [0, ret.split('\n')], true); 747 | nvim.command('exe 1', true); 748 | await nvim.resumeNotification(true); 749 | }; 750 | } 751 | 752 | export function viewFileText(ctx: Ctx): Cmd { 753 | return async () => { 754 | const { document } = await workspace.getCurrentState(); 755 | if (!isRustDocument(document)) return; 756 | 757 | const ret = await ctx.client.sendRequest(ra.viewFileText, { uri: document.uri }); 758 | if (!ret) return; 759 | 760 | const nvim = workspace.nvim; 761 | nvim.pauseNotification(); 762 | nvim.command('edit +setl\\ buftype=nofile [TEXT]', true); 763 | nvim.command('setl nobuflisted bufhidden=wipe', true); 764 | nvim.call('append', [0, ret.split('\n')], true); 765 | nvim.command('exe 1', true); 766 | await nvim.resumeNotification(true); 767 | }; 768 | } 769 | 770 | export function echoRunCommandLine(ctx: Ctx) { 771 | return async () => { 772 | const runnable = await pickRunnable(ctx); 773 | if (!runnable) return; 774 | 775 | let args: string[] = []; 776 | if (runnable.kind === 'cargo') { 777 | // TODO: runnable.args.overrideCargo? 778 | args = [...runnable.args.cargoArgs]; 779 | if (runnable.args.executableArgs.length > 0) { 780 | runnable.args['executableArgs'][0] = `'${runnable.args['executableArgs'][0]}'`; 781 | args.push('--', ...runnable.args.executableArgs); 782 | } 783 | } else { 784 | args = [...runnable.args.args]; 785 | } 786 | const commandLine = ['cargo', ...args].join(' '); 787 | window.echoLines([commandLine]); 788 | }; 789 | } 790 | 791 | export function peekTests(ctx: Ctx): Cmd { 792 | return async () => { 793 | const { document, position } = await workspace.getCurrentState(); 794 | if (!isRustDocument(document)) return; 795 | 796 | const tests = await ctx.client.sendRequest(ra.relatedTests, { 797 | textDocument: { uri: document.uri }, 798 | position, 799 | }); 800 | const locations: Location[] = tests.map((it) => 801 | Location.create(it.runnable.location!.targetUri, it.runnable.location!.targetSelectionRange), 802 | ); 803 | await commands.executeCommand('editor.action.showReferences', Uri.parse(document.uri), position, locations); 804 | }; 805 | } 806 | 807 | function moveItem(ctx: Ctx, direction: ra.Direction): Cmd { 808 | return async () => { 809 | const { document, position } = await workspace.getCurrentState(); 810 | if (!isRustDocument(document)) return; 811 | 812 | let range: Range | null = null; 813 | const mode = (await workspace.nvim.call('visualmode')) as string; 814 | if (mode) range = await window.getSelectedRange(mode); 815 | if (!range) range = Range.create(position, position); 816 | const params: ra.MoveItemParams = { 817 | direction, 818 | textDocument: { uri: document.uri }, 819 | range, 820 | }; 821 | const edits = await ctx.client.sendRequest(ra.moveItem, params); 822 | if (!edits?.length) return; 823 | 824 | const wsEdit: WorkspaceEdit = { 825 | documentChanges: [{ textDocument: { uri: document.uri, version: document.version }, edits }], 826 | }; 827 | await applySnippetWorkspaceEdit(wsEdit); 828 | }; 829 | } 830 | 831 | export function moveItemUp(ctx: Ctx): Cmd { 832 | return moveItem(ctx, 'Up'); 833 | } 834 | 835 | export function moveItemDown(ctx: Ctx): Cmd { 836 | return moveItem(ctx, 'Down'); 837 | } 838 | 839 | function crateGraph(ctx: Ctx, full: boolean): Cmd { 840 | return async () => { 841 | const dot = await ctx.client.sendRequest(ra.viewCrateGraph, { full }); 842 | const html = ` 843 | 844 | 845 | 846 | 850 | 851 | 852 |
853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 898 | 899 | 900 | `; 901 | 902 | const tempFile = join(tmpdir(), `${randomBytes(5).toString('hex')}.html`); 903 | writeFileSync(tempFile, html, { encoding: 'utf-8' }); 904 | window.showMessage(`Crate Graph: ${tempFile}`); 905 | await workspace.nvim.call('coc#ui#open_url', [tempFile]); 906 | }; 907 | } 908 | 909 | export function viewCrateGraph(ctx: Ctx): Cmd { 910 | return crateGraph(ctx, false); 911 | } 912 | 913 | export function viewFullCrateGraph(ctx: Ctx): Cmd { 914 | return crateGraph(ctx, true); 915 | } 916 | 917 | export function shuffleCrateGraph(ctx: Ctx): Cmd { 918 | return async () => { 919 | const { document } = await workspace.getCurrentState(); 920 | if (!isRustDocument(document)) return; 921 | 922 | await ctx.client.sendRequest(ra.shuffleCrateGraph); 923 | }; 924 | } 925 | 926 | export function viewItemTree(ctx: Ctx): Cmd { 927 | return async () => { 928 | const { document } = await workspace.getCurrentState(); 929 | if (!isRustDocument(document)) return; 930 | 931 | const param: ra.ViewItemTreeParams = { 932 | textDocument: { uri: document.uri }, 933 | }; 934 | const ret = await ctx.client.sendRequest(ra.viewItemTree, param); 935 | if (!ret) return; 936 | const nvim = workspace.nvim; 937 | nvim.pauseNotification(); 938 | nvim.command('edit +setl\\ buftype=nofile [ItemTree]', true); 939 | nvim.command('setl nobuflisted bufhidden=wipe', true); 940 | nvim.call('append', [0, ret.split('\n')], true); 941 | nvim.command('exe 1', true); 942 | await nvim.resumeNotification(true); 943 | }; 944 | } 945 | 946 | export function rebuildProcMacros(ctx: Ctx): Cmd { 947 | return async () => { 948 | const { document } = await workspace.getCurrentState(); 949 | if (!isRustDocument(document)) return; 950 | 951 | await ctx.client.sendRequest(ra.rebuildProcMacros); 952 | }; 953 | } 954 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import { commands, type ConfigurationChangeEvent, window, workspace, type WorkspaceConfiguration } from 'coc.nvim'; 2 | 3 | export type UpdatesChannel = 'stable' | 'nightly'; 4 | 5 | export interface Env { 6 | [name: string]: string; 7 | } 8 | 9 | export class Config { 10 | private readonly rootSection = 'rust-analyzer'; 11 | private readonly requiresReloadOpts = ['server', 'cargo', 'procMacro', 'files', 'updates', 'lens', 'inlayHints'].map( 12 | (opt) => `${this.rootSection}.${opt}`, 13 | ); 14 | private cfg: WorkspaceConfiguration; 15 | 16 | constructor() { 17 | workspace.onDidChangeConfiguration((event) => this.onConfigChange(event)); 18 | this.cfg = workspace.getConfiguration(this.rootSection); 19 | } 20 | 21 | private async onConfigChange(event: ConfigurationChangeEvent) { 22 | this.cfg = workspace.getConfiguration(this.rootSection); 23 | 24 | const requiresReloadOpt = this.requiresReloadOpts.find((opt) => event.affectsConfiguration(opt)); 25 | if (!requiresReloadOpt) return; 26 | 27 | let reload = !!this.restartServerOnConfigChange; 28 | if (!reload) { 29 | const msg = `Changing "${requiresReloadOpt}" requires a reload`; 30 | reload = await window.showPrompt(`${msg}. Reload now?`); 31 | } 32 | if (reload) { 33 | await commands.executeCommand('rust-analyzer.reload'); 34 | } 35 | } 36 | 37 | get serverPath() { 38 | return this.cfg.get('server.path') ?? this.cfg.get('serverPath'); 39 | } 40 | 41 | get serverExtraEnv() { 42 | return this.cfg.get('server.extraEnv') ?? {}; 43 | } 44 | 45 | get restartServerOnConfigChange() { 46 | return this.cfg.get('restartServerOnConfigChange'); 47 | } 48 | 49 | get inlayHint() { 50 | return { 51 | enable: workspace.getConfiguration('inlayHint').get('enable', true), 52 | }; 53 | } 54 | 55 | get debug() { 56 | return { 57 | runtime: this.cfg.get('debug.runtime'), 58 | vimspectorConfiguration: { 59 | name: this.cfg.get('debug.vimspector.configuration.name'), 60 | }, 61 | nvimdapConfiguration: { 62 | template: this.cfg.get('debug.nvimdap.configuration.template'), 63 | }, 64 | }; 65 | } 66 | 67 | get prompt() { 68 | return this.cfg.get('updates.prompt', true); 69 | } 70 | 71 | get channel() { 72 | return this.cfg.get('updates.channel')!; 73 | } 74 | 75 | get checkOnStartup() { 76 | return this.cfg.get('updates.checkOnStartup'); 77 | } 78 | 79 | get terminal() { 80 | return { 81 | startinsert: this.cfg.get('terminal.startinsert'), 82 | }; 83 | } 84 | 85 | get enable() { 86 | return this.cfg.get('enable'); 87 | } 88 | 89 | get disableProgressNotifications() { 90 | return this.cfg.get('disableProgressNotifications'); 91 | } 92 | 93 | get disablePullDiagnostic() { 94 | return this.cfg.get('disablePullDiagnostic'); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/ctx.ts: -------------------------------------------------------------------------------- 1 | import { 2 | commands, 3 | type Disposable, 4 | type ExtensionContext, 5 | type LanguageClient, 6 | services, 7 | type TextDocument, 8 | Uri, 9 | window, 10 | workspace, 11 | } from 'coc.nvim'; 12 | import { spawnSync } from 'node:child_process'; 13 | import { existsSync } from 'node:fs'; 14 | import { join } from 'node:path'; 15 | import which from 'which'; 16 | import { createClient } from './client'; 17 | import { Config } from './config'; 18 | import { downloadServer, getLatestRelease } from './downloader'; 19 | import * as ra from './lsp_ext'; 20 | 21 | export type RustDocument = TextDocument & { languageId: 'rust' }; 22 | export function isRustDocument(document: TextDocument): document is RustDocument { 23 | return document.languageId === 'rust'; 24 | } 25 | 26 | export function isCargoTomlDocument(document: TextDocument): document is RustDocument { 27 | const u = Uri.parse(document.uri); 28 | return u.scheme === 'file' && u.fsPath.endsWith('Cargo.toml'); 29 | } 30 | 31 | export type Cmd = (...args: any[]) => unknown; 32 | 33 | export class Ctx { 34 | client!: LanguageClient; 35 | public readonly config = new Config(); 36 | private usingSystemServer = false; 37 | 38 | constructor(private readonly extCtx: ExtensionContext) { 39 | const statusBar = window.createStatusBarItem(0); 40 | statusBar.text = 'rust-analyzer'; 41 | statusBar.show(); 42 | this.extCtx.subscriptions.push(statusBar); 43 | 44 | window.onDidChangeActiveTextEditor((editor) => { 45 | if (editor && editor.document.languageId === 'rust') { 46 | statusBar.show(); 47 | } else { 48 | statusBar.hide(); 49 | } 50 | }); 51 | } 52 | 53 | registerCommand(name: string, factory: (ctx: Ctx) => Cmd, internal = false) { 54 | const fullName = `rust-analyzer.${name}`; 55 | const cmd = factory(this); 56 | const d = commands.registerCommand(fullName, cmd, null, internal); 57 | this.extCtx.subscriptions.push(d); 58 | } 59 | 60 | async startServer() { 61 | const bin = this.resolveBin(); 62 | if (!bin) { 63 | return; 64 | } 65 | 66 | const client = createClient(bin, this.config); 67 | this.extCtx.subscriptions.push(services.registLanguageClient(client)); 68 | const watcher = workspace.createFileSystemWatcher('**/Cargo.toml'); 69 | this.extCtx.subscriptions.push(watcher); 70 | watcher.onDidChange(async () => await commands.executeCommand('rust-analyzer.reloadWorkspace')); 71 | await client.onReady(); 72 | 73 | client.onNotification(ra.serverStatus, async (status) => { 74 | if (status.health !== 'ok' && status.message?.length) { 75 | // https://github.com/fannheyward/coc-rust-analyzer/issues/763 76 | if (status.message.startsWith('cargo check failed')) return; 77 | window.showNotification({ content: status.message }); 78 | window.showWarningMessage( 79 | `rust-analyzer failed to start, run ':CocCommand rust-analyzer.reloadWorkspace' to reload`, 80 | ); 81 | } 82 | }); 83 | 84 | this.client = client; 85 | } 86 | 87 | async stopServer() { 88 | if (this.client) { 89 | await this.client.stop(); 90 | } 91 | } 92 | 93 | get subscriptions(): Disposable[] { 94 | return this.extCtx.subscriptions; 95 | } 96 | 97 | resolveBin(): string | undefined { 98 | // 1. from config, custom server path 99 | // 2. bundled, coc-rust-analyzer can handle updating 100 | // 3. fallback to system installed server 101 | const executableName = process.platform === 'win32' ? 'rust-analyzer.exe' : 'rust-analyzer'; 102 | let bin = join(this.extCtx.storagePath, executableName); 103 | if (this.config.serverPath) { 104 | bin = which.sync(workspace.expand(this.config.serverPath), { nothrow: true }) || bin; 105 | } 106 | 107 | if (existsSync(bin)) { 108 | return bin; 109 | } 110 | 111 | const systemBin = which.sync(executableName, { nothrow: true }); 112 | if (systemBin) { 113 | const { stderr } = spawnSync(systemBin, ['--version'], { encoding: 'utf8' }); 114 | if (stderr.trim().length > 0) { 115 | return; 116 | } 117 | 118 | this.usingSystemServer = true; 119 | return systemBin; 120 | } 121 | 122 | return; 123 | } 124 | 125 | async installServerFromGitHub() { 126 | const latest = await getLatestRelease(this.config.channel); 127 | if (!latest) { 128 | return; 129 | } 130 | try { 131 | if (process.platform === 'win32') { 132 | await this.client.stop(); 133 | } 134 | 135 | await downloadServer(this.extCtx, latest); 136 | } catch (e) { 137 | console.error(e); 138 | let msg = 'Install rust-analyzer failed, please try again'; 139 | // @ts-expect-error 140 | if (e.code === 'EBUSY' || e.code === 'ETXTBSY' || e.code === 'EPERM') { 141 | msg = 142 | 'Install rust-analyzer failed, other Vim instances might be using it, you should close them and try again'; 143 | } 144 | window.showInformationMessage(msg, 'error'); 145 | return; 146 | } 147 | await this.client.stop(); 148 | this.client.start(); 149 | 150 | this.extCtx.globalState.update('release', latest.tag); 151 | } 152 | 153 | async checkUpdate(auto = true) { 154 | if (this.config.serverPath || this.usingSystemServer) { 155 | // no update checking if using custom or system server 156 | return; 157 | } 158 | if (auto && !this.config.checkOnStartup) { 159 | return; 160 | } 161 | 162 | const latest = await getLatestRelease(this.config.channel); 163 | if (!latest) { 164 | return; 165 | } 166 | 167 | const old = this.extCtx.globalState.get('release') || 'unknown release'; 168 | if (old === latest.tag) { 169 | if (!auto) { 170 | window.showInformationMessage('Your Rust Analyzer release is updated'); 171 | } 172 | console.info(`Rust Analyzer is up to date: ${latest.tag}`); 173 | return; 174 | } 175 | 176 | const msg = `Rust Analyzer has a new release: ${latest.tag}, you're using ${old}. Would you like to download from GitHub`; 177 | let ret = 0; 178 | if (this.config.prompt === true) { 179 | ret = await window.showQuickpick( 180 | ['Yes, download the latest rust-analyzer', 'Check GitHub releases', 'Cancel'], 181 | msg, 182 | ); 183 | } 184 | if (ret === 0) { 185 | if (process.platform === 'win32') { 186 | await this.client.stop(); 187 | } 188 | try { 189 | await downloadServer(this.extCtx, latest); 190 | } catch (e) { 191 | console.error(e); 192 | let msg = 'Upgrade rust-analyzer failed, please try again'; 193 | // @ts-expect-error 194 | if (e.code === 'EBUSY' || e.code === 'ETXTBSY' || e.code === 'EPERM') { 195 | msg = 196 | 'Upgrade rust-analyzer failed, other Vim instances might be using it, you should close them and try again'; 197 | } 198 | window.showInformationMessage(msg, 'error'); 199 | return; 200 | } 201 | await this.client.stop(); 202 | this.client.start(); 203 | 204 | this.extCtx.globalState.update('release', latest.tag); 205 | } else if (ret === 1) { 206 | await commands 207 | .executeCommand('vscode.open', 'https://github.com/rust-analyzer/rust-analyzer/releases') 208 | .catch(() => {}); 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/downloader.ts: -------------------------------------------------------------------------------- 1 | import { exec, spawnSync } from 'node:child_process'; 2 | import { type ExtensionContext, window, workspace } from 'coc.nvim'; 3 | import { randomBytes } from 'node:crypto'; 4 | import { createWriteStream, type PathLike, promises as fs } from 'node:fs'; 5 | import { HttpsProxyAgent } from 'https-proxy-agent'; 6 | import AdmZip from 'adm-zip'; 7 | import fetch from 'node-fetch'; 8 | import * as zlib from 'node:zlib'; 9 | import path from 'node:path'; 10 | import stream from 'node:stream'; 11 | import util from 'node:util'; 12 | import type { UpdatesChannel } from './config'; 13 | 14 | const pipeline = util.promisify(stream.pipeline); 15 | const rejectUnauthorized = workspace.getConfiguration('http').get('proxyStrictSSL', true); 16 | const proxy = process.env.https_proxy || process.env.HTTPS_PROXY; 17 | const agent = proxy ? new HttpsProxyAgent(proxy, { rejectUnauthorized }) : null; 18 | 19 | async function patchelf(dest: PathLike): Promise { 20 | const expression = ` 21 | {src, pkgs ? import {}}: 22 | pkgs.stdenv.mkDerivation { 23 | name = "rust-analyzer"; 24 | inherit src; 25 | phases = [ "installPhase" "fixupPhase" ]; 26 | installPhase = "cp $src $out"; 27 | fixupPhase = '' 28 | chmod 755 $out 29 | patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out 30 | ''; 31 | } 32 | `; 33 | const origFile = `${dest}-orig`; 34 | await fs.rename(dest, origFile); 35 | 36 | await new Promise((resolve, reject) => { 37 | const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`, (err, stdout, stderr) => { 38 | if (err != null) { 39 | reject(Error(stderr)); 40 | } else { 41 | resolve(stdout); 42 | } 43 | }); 44 | handle.stdin?.write(expression); 45 | handle.stdin?.end(); 46 | }); 47 | 48 | await fs.unlink(origFile); 49 | } 50 | 51 | interface Asset { 52 | name: string; 53 | browser_download_url: string; 54 | } 55 | 56 | interface GithubRelease { 57 | tag_name: string; 58 | published_at: string; 59 | assets: Array; 60 | } 61 | 62 | export interface ReleaseTag { 63 | tag: string; 64 | url: string; 65 | name: string; 66 | asset?: Asset; 67 | } 68 | 69 | function isMusl(): boolean { 70 | // We can detect Alpine by checking `/etc/os-release` but not Void Linux musl. 71 | // Instead, we run `ldd` since it advertises the libc which it belongs to. 72 | const res = spawnSync('ldd', ['--version']); 73 | return res.stderr != null && res.stderr.indexOf('musl libc') >= 0; 74 | } 75 | 76 | function getPlatform(): string | undefined { 77 | const platforms: { [key: string]: string } = { 78 | 'ia32 win32': 'x86_64-pc-windows-msvc', 79 | 'x64 win32': 'x86_64-pc-windows-msvc', 80 | 'x64 linux': 'x86_64-unknown-linux-gnu', 81 | 'x64 darwin': 'x86_64-apple-darwin', 82 | 'arm linux': 'arm-unknown-linux-gnueabihf', 83 | 'arm64 win32': 'aarch64-pc-windows-msvc', 84 | 'arm64 linux': 'aarch64-unknown-linux-gnu', 85 | 'arm64 darwin': 'aarch64-apple-darwin', 86 | }; 87 | 88 | let platform = platforms[`${process.arch} ${process.platform}`]; 89 | if (platform === 'x86_64-unknown-linux-gnu' && isMusl()) { 90 | platform = 'x86_64-unknown-linux-musl'; 91 | } 92 | return platform; 93 | } 94 | 95 | export async function getLatestRelease(updatesChannel: UpdatesChannel): Promise { 96 | console.info(`Fetching ${updatesChannel} release...`); 97 | let releaseURL = 'https://api.github.com/repos/rust-analyzer/rust-analyzer/releases/latest'; 98 | if (updatesChannel === 'nightly') { 99 | releaseURL = 'https://api.github.com/repos/rust-analyzer/rust-analyzer/releases/tags/nightly'; 100 | } 101 | // @ts-expect-error 102 | const response = await fetch(releaseURL, { agent }); 103 | if (!response.ok) { 104 | console.error(await response.text()); 105 | return; 106 | } 107 | 108 | const release: GithubRelease = await response.json(); 109 | const platform = getPlatform(); 110 | if (!platform) { 111 | console.error(`Unfortunately we don't ship binaries for your platform yet.`); 112 | return; 113 | } 114 | const suffix = process.platform === 'win32' ? 'zip' : 'gz'; 115 | const asset = release.assets.find((val) => val.browser_download_url.endsWith(`${platform}.${suffix}`)); 116 | if (!asset) { 117 | console.error(`getLatestRelease failed: ${JSON.stringify(release)}`); 118 | return; 119 | } 120 | 121 | let tag = release.tag_name; 122 | if (updatesChannel === 'nightly') { 123 | tag = `${release.tag_name} ${release.published_at.slice(0, 10)}`; 124 | } 125 | const name = process.platform === 'win32' ? 'rust-analyzer.exe' : 'rust-analyzer'; 126 | 127 | console.info(`Latest release tag: ${tag}`); 128 | return { asset, tag, url: asset.browser_download_url, name: name }; 129 | } 130 | 131 | export async function downloadServer(context: ExtensionContext, release: ReleaseTag): Promise { 132 | console.info(`Downloading rust-analyzer ${release.tag}`); 133 | const statusItem = window.createStatusBarItem(0, { progress: true }); 134 | statusItem.text = `Downloading rust-analyzer ${release.tag}`; 135 | statusItem.show(); 136 | 137 | // @ts-expect-error 138 | const resp = await fetch(release.url, { agent }); 139 | // const resp = await fetch('http://devd.io/rust-analyzer'); 140 | if (!resp.ok) { 141 | statusItem.hide(); 142 | throw new Error('Download failed'); 143 | } 144 | 145 | let cur = 0; 146 | const len = Number(resp.headers.get('content-length')); 147 | resp.body.on('data', (chunk: Buffer) => { 148 | cur += chunk.length; 149 | const p = ((cur / len) * 100).toFixed(2); 150 | statusItem.text = `${p}% Downloading rust-analyzer ${release.tag}`; 151 | console.info(`${p}% Downloading rust-analyzer ${release.tag}`); 152 | }); 153 | 154 | const _path = path.join(context.storagePath, release.name); 155 | const randomHex = randomBytes(5).toString('hex'); 156 | const tempFile = path.join(context.storagePath, `${release.name}${randomHex}`); 157 | 158 | if (process.platform === 'win32') { 159 | await fs.writeFile(tempFile, await resp.buffer()); 160 | 161 | new AdmZip(tempFile).extractAllTo(context.storagePath, true, true); 162 | await fs.unlink(tempFile).catch((err) => { 163 | console.error(err); 164 | }); 165 | statusItem.hide(); 166 | return; 167 | } 168 | 169 | const destFileStream = createWriteStream(tempFile, { mode: 0o755 }); 170 | await pipeline(resp.body.pipe(zlib.createGunzip()), destFileStream); 171 | await new Promise((resolve) => { 172 | destFileStream.on('close', resolve); 173 | destFileStream.destroy(); 174 | setTimeout(resolve, 1000); 175 | }); 176 | 177 | await fs.unlink(_path).catch((err) => { 178 | if (err.code !== 'ENOENT') throw err; 179 | }); 180 | await fs.rename(tempFile, _path); 181 | 182 | await context.globalState.update('release', release.tag); 183 | 184 | try { 185 | if (await fs.stat('/etc/nixos')) { 186 | statusItem.text = 'Patching rust-analyzer executable...'; 187 | await patchelf(_path); 188 | } 189 | } catch (_e) {} 190 | 191 | console.info(`rust-analyzer has been upgrade to ${release.tag}`); 192 | statusItem.hide(); 193 | } 194 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { type ExtensionContext, window } from 'coc.nvim'; 2 | import { existsSync, mkdirSync } from 'node:fs'; 3 | import * as cmds from './commands'; 4 | import { Ctx } from './ctx'; 5 | import { downloadServer, getLatestRelease } from './downloader'; 6 | 7 | export async function activate(context: ExtensionContext): Promise { 8 | const ctx = new Ctx(context); 9 | if (!ctx.config.enable) { 10 | return; 11 | } 12 | 13 | const serverRoot = context.storagePath; 14 | if (!existsSync(serverRoot)) { 15 | mkdirSync(serverRoot); 16 | } 17 | 18 | const bin = ctx.resolveBin(); 19 | if (!bin) { 20 | let msg = 'Rust Analyzer is not found, download from GitHub release?'; 21 | let ret = ctx.config.prompt === 'neverDownload' ? -1 : 0; 22 | if (ctx.config.prompt === true) { 23 | ret = await window.showQuickpick(['Yes', 'Cancel'], msg); 24 | } 25 | if (ret === 0) { 26 | try { 27 | const latest = await getLatestRelease(ctx.config.channel); 28 | if (!latest) throw new Error('Failed to get latest release'); 29 | await downloadServer(context, latest); 30 | } catch (e) { 31 | console.error(e); 32 | msg = 'Download rust-analyzer failed, you can get it from https://github.com/rust-analyzer/rust-analyzer'; 33 | window.showErrorMessage(msg); 34 | return; 35 | } 36 | } else { 37 | return; 38 | } 39 | } 40 | 41 | // internal commands that are invoked by server 42 | ctx.registerCommand('runSingle', cmds.runSingle, true); 43 | ctx.registerCommand('debugSingle', cmds.debugSingle, true); 44 | ctx.registerCommand('showReferences', cmds.showReferences, true); 45 | ctx.registerCommand('resolveCodeAction', cmds.resolveCodeAction, true); 46 | ctx.registerCommand('applySnippetWorkspaceEdit', cmds.applySnippetWorkspaceEditCommand, true); 47 | 48 | // common commands 49 | ctx.registerCommand('run', cmds.run); 50 | ctx.registerCommand('ssr', cmds.ssr); 51 | ctx.registerCommand('debug', cmds.debug); 52 | ctx.registerCommand('reload', cmds.reload); 53 | ctx.registerCommand('install', cmds.install); 54 | ctx.registerCommand('upgrade', cmds.upgrade); 55 | ctx.registerCommand('viewHir', cmds.viewHir); 56 | ctx.registerCommand('viewMir', cmds.viewMir); 57 | ctx.registerCommand('openDocs', cmds.openDocs); 58 | ctx.registerCommand('joinLines', cmds.joinLines); 59 | ctx.registerCommand('peekTests', cmds.peekTests); 60 | ctx.registerCommand('viewSyntaxTree', cmds.viewSyntaxTree); 61 | ctx.registerCommand('moveItemUp', cmds.moveItemUp); 62 | ctx.registerCommand('testCurrent', cmds.testCurrent); 63 | ctx.registerCommand('memoryUsage', cmds.memoryUsage); 64 | ctx.registerCommand('expandMacro', cmds.expandMacro); 65 | ctx.registerCommand('moveItemDown', cmds.moveItemDown); 66 | ctx.registerCommand('viewFileText', cmds.viewFileText); 67 | ctx.registerCommand('viewItemTree', cmds.viewItemTree); 68 | ctx.registerCommand('explainError', cmds.explainError); 69 | ctx.registerCommand('parentModule', cmds.parentModule); 70 | ctx.registerCommand('matchingBrace', cmds.matchingBrace); 71 | ctx.registerCommand('openCargoToml', cmds.openCargoToml); 72 | ctx.registerCommand('serverVersion', cmds.serverVersion); 73 | ctx.registerCommand('runFlycheck', cmds.runFlycheck); 74 | ctx.registerCommand('cancelFlycheck', cmds.cancelFlycheck); 75 | ctx.registerCommand('clearFlycheck', cmds.clearFlycheck); 76 | ctx.registerCommand('analyzerStatus', cmds.analyzerStatus); 77 | ctx.registerCommand('viewCrateGraph', cmds.viewCrateGraph); 78 | ctx.registerCommand('interpretFunction', cmds.interpretFunction); 79 | ctx.registerCommand('rebuildProcMacros', cmds.rebuildProcMacros); 80 | ctx.registerCommand('shuffleCrateGraph', cmds.shuffleCrateGraph); 81 | ctx.registerCommand('viewFullCrateGraph', cmds.viewFullCrateGraph); 82 | ctx.registerCommand('reloadWorkspace', cmds.reloadWorkspace); 83 | ctx.registerCommand('echoRunCommandLine', cmds.echoRunCommandLine); 84 | 85 | await ctx.startServer(); 86 | if (bin) await ctx.checkUpdate(); 87 | } 88 | -------------------------------------------------------------------------------- /src/lsp_ext.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file mirrors `crates/rust-analyzer/src/lsp_ext.rs` declarations. 3 | */ 4 | 5 | import * as lc from "coc.nvim"; 6 | 7 | // rust-analyzer overrides 8 | 9 | export const hover = new lc.RequestType< 10 | HoverParams, 11 | (lc.Hover & { actions: CommandLinkGroup[] }) | null, 12 | void 13 | >('textDocument/hover'); 14 | export type HoverParams = { 15 | workDoneToken?: lc.ProgressToken; 16 | textDocument: lc.TextDocumentIdentifier; 17 | position: lc.Range | lc.Position; 18 | }; 19 | export type CommandLink = { 20 | /** 21 | * A tooltip for the command, when represented in the UI. 22 | */ 23 | tooltip?: string; 24 | } & lc.Command; 25 | export type CommandLinkGroup = { 26 | title?: string; 27 | commands: CommandLink[]; 28 | }; 29 | 30 | // rust-analyzer extensions 31 | 32 | export const analyzerStatus = new lc.RequestType( 33 | "rust-analyzer/analyzerStatus", 34 | ); 35 | export const cancelFlycheck = new lc.NotificationType0("rust-analyzer/cancelFlycheck"); 36 | export const clearFlycheck = new lc.NotificationType0("rust-analyzer/clearFlycheck"); 37 | export const expandMacro = new lc.RequestType( 38 | "rust-analyzer/expandMacro", 39 | ); 40 | export const memoryUsage = new lc.RequestType0("rust-analyzer/memoryUsage"); 41 | export const openServerLogs = new lc.NotificationType0("rust-analyzer/openServerLogs"); 42 | export const relatedTests = new lc.RequestType( 43 | "rust-analyzer/relatedTests", 44 | ); 45 | export const reloadWorkspace = new lc.RequestType0("rust-analyzer/reloadWorkspace"); 46 | export const rebuildProcMacros = new lc.RequestType0("rust-analyzer/rebuildProcMacros"); 47 | 48 | export const runFlycheck = new lc.NotificationType<{ 49 | textDocument: lc.TextDocumentIdentifier | null; 50 | }>("rust-analyzer/runFlycheck"); 51 | export const shuffleCrateGraph = new lc.RequestType0("rust-analyzer/shuffleCrateGraph"); 52 | export const viewSyntaxTree = new lc.RequestType( 53 | "rust-analyzer/viewSyntaxTree", 54 | ); 55 | export const viewCrateGraph = new lc.RequestType( 56 | "rust-analyzer/viewCrateGraph", 57 | ); 58 | export const viewFileText = new lc.RequestType( 59 | "rust-analyzer/viewFileText", 60 | ); 61 | export const viewHir = new lc.RequestType( 62 | "rust-analyzer/viewHir", 63 | ); 64 | export const viewMir = new lc.RequestType( 65 | "rust-analyzer/viewMir", 66 | ); 67 | export const interpretFunction = new lc.RequestType( 68 | "rust-analyzer/interpretFunction", 69 | ); 70 | export const viewItemTree = new lc.RequestType( 71 | "rust-analyzer/viewItemTree", 72 | ); 73 | 74 | export type DiscoverTestParams = { testId?: string | undefined }; 75 | export type RunTestParams = { 76 | include?: string[] | undefined; 77 | exclude?: string[] | undefined; 78 | }; 79 | export type TestItem = { 80 | id: string; 81 | label: string; 82 | kind: "package" | "module" | "test"; 83 | canResolveChildren: boolean; 84 | parent?: string | undefined; 85 | textDocument?: lc.TextDocumentIdentifier | undefined; 86 | range?: lc.Range | undefined; 87 | runnable?: Runnable | undefined; 88 | }; 89 | export type DiscoverTestResults = { 90 | tests: TestItem[]; 91 | scope: string[] | undefined; 92 | scopeFile: lc.TextDocumentIdentifier[] | undefined; 93 | }; 94 | export type TestState = 95 | | { tag: "failed"; message: string } 96 | | { tag: "passed" } 97 | | { tag: "started" } 98 | | { tag: "enqueued" } 99 | | { tag: "skipped" }; 100 | export type ChangeTestStateParams = { testId: string; state: TestState }; 101 | export const discoverTest = new lc.RequestType( 102 | "experimental/discoverTest", 103 | ); 104 | export const discoveredTests = new lc.NotificationType( 105 | "experimental/discoveredTests", 106 | ); 107 | export const runTest = new lc.RequestType("experimental/runTest"); 108 | export const abortRunTest = new lc.NotificationType0("experimental/abortRunTest"); 109 | export const endRunTest = new lc.NotificationType0("experimental/endRunTest"); 110 | export const appendOutputToRunTest = new lc.NotificationType( 111 | "experimental/appendOutputToRunTest", 112 | ); 113 | export const changeTestState = new lc.NotificationType( 114 | "experimental/changeTestState", 115 | ); 116 | 117 | export type AnalyzerStatusParams = { textDocument?: lc.TextDocumentIdentifier }; 118 | 119 | export interface FetchDependencyListParams {} 120 | 121 | export interface FetchDependencyListResult { 122 | crates: { 123 | name?: string; 124 | version?: string; 125 | path: string; 126 | }[]; 127 | } 128 | 129 | export const fetchDependencyList = new lc.RequestType< 130 | FetchDependencyListParams, 131 | FetchDependencyListResult, 132 | void 133 | >("rust-analyzer/fetchDependencyList"); 134 | 135 | export interface FetchDependencyGraphParams {} 136 | 137 | export interface FetchDependencyGraphResult { 138 | crates: { 139 | name: string; 140 | version: string; 141 | path: string; 142 | }[]; 143 | } 144 | 145 | export const fetchDependencyGraph = new lc.RequestType< 146 | FetchDependencyGraphParams, 147 | FetchDependencyGraphResult, 148 | void 149 | >("rust-analyzer/fetchDependencyGraph"); 150 | 151 | export type ExpandMacroParams = { 152 | textDocument: lc.TextDocumentIdentifier; 153 | position: lc.Position; 154 | }; 155 | export type ExpandedMacro = { 156 | name: string; 157 | expansion: string; 158 | }; 159 | export type TestInfo = { runnable: Runnable }; 160 | export type SyntaxTreeParams = { 161 | textDocument: lc.TextDocumentIdentifier; 162 | range: lc.Range | null; 163 | }; 164 | export type ViewCrateGraphParams = { full: boolean }; 165 | export type ViewItemTreeParams = { textDocument: lc.TextDocumentIdentifier }; 166 | 167 | // experimental extensions 168 | 169 | export const joinLines = new lc.RequestType( 170 | "experimental/joinLines", 171 | ); 172 | export const matchingBrace = new lc.RequestType( 173 | "experimental/matchingBrace", 174 | ); 175 | export const moveItem = new lc.RequestType( 176 | "experimental/moveItem", 177 | ); 178 | export const onEnter = new lc.RequestType( 179 | "experimental/onEnter", 180 | ); 181 | export const openCargoToml = new lc.RequestType( 182 | "experimental/openCargoToml", 183 | ); 184 | export interface DocsUrls { 185 | local?: string; 186 | web?: string; 187 | } 188 | export const openDocs = new lc.RequestType( 189 | "experimental/externalDocs", 190 | ); 191 | export const parentModule = new lc.RequestType< 192 | lc.TextDocumentPositionParams, 193 | lc.LocationLink[] | null, 194 | void 195 | >("experimental/parentModule"); 196 | export const runnables = new lc.RequestType( 197 | "experimental/runnables", 198 | ); 199 | export const serverStatus = new lc.NotificationType( 200 | "experimental/serverStatus", 201 | ); 202 | export const ssr = new lc.RequestType("experimental/ssr"); 203 | export const viewRecursiveMemoryLayout = new lc.RequestType< 204 | lc.TextDocumentPositionParams, 205 | RecursiveMemoryLayout | null, 206 | void 207 | >("rust-analyzer/viewRecursiveMemoryLayout"); 208 | 209 | export type JoinLinesParams = { 210 | textDocument: lc.TextDocumentIdentifier; 211 | ranges: lc.Range[]; 212 | }; 213 | export type MatchingBraceParams = { 214 | textDocument: lc.TextDocumentIdentifier; 215 | positions: lc.Position[]; 216 | }; 217 | export type MoveItemParams = { 218 | textDocument: lc.TextDocumentIdentifier; 219 | range: lc.Range; 220 | direction: Direction; 221 | }; 222 | export type Direction = "Up" | "Down"; 223 | export type OpenCargoTomlParams = { 224 | textDocument: lc.TextDocumentIdentifier; 225 | }; 226 | export type Runnable = { 227 | label: string; 228 | location?: lc.LocationLink; 229 | } & (RunnableCargo | RunnableShell); 230 | 231 | type RunnableCargo = { 232 | kind: "cargo"; 233 | args: CargoRunnableArgs; 234 | }; 235 | 236 | type RunnableShell = { 237 | kind: "shell"; 238 | args: ShellRunnableArgs; 239 | }; 240 | 241 | export type CommonRunnableArgs = { 242 | /** 243 | * Environment variables to set before running the command. 244 | */ 245 | environment?: Record; 246 | /** 247 | * The working directory to run the command in. 248 | */ 249 | cwd: string; 250 | }; 251 | 252 | export type ShellRunnableArgs = { 253 | kind: string; 254 | program: string; 255 | args: string[]; 256 | } & CommonRunnableArgs; 257 | 258 | export type CargoRunnableArgs = { 259 | /** 260 | * The workspace root directory of the cargo project. 261 | */ 262 | workspaceRoot?: string; 263 | /** 264 | * Arguments to pass to the executable, these will be passed to the command after a `--` argument. 265 | */ 266 | executableArgs: string[]; 267 | /** 268 | * Arguments to pass to cargo. 269 | */ 270 | cargoArgs: string[]; 271 | /** 272 | * Command to execute instead of `cargo`. 273 | */ 274 | // This is supplied by the user via config. We could pull this through the client config in the 275 | // extension directly, but that would prevent us from honoring the rust-analyzer.toml for it. 276 | overrideCargo?: string; 277 | } & CommonRunnableArgs; 278 | 279 | export type RunnablesParams = { 280 | textDocument: lc.TextDocumentIdentifier; 281 | position: lc.Position | null; 282 | }; 283 | export type ServerStatusParams = { 284 | health: "ok" | "warning" | "error"; 285 | quiescent: boolean; 286 | message?: string; 287 | }; 288 | export type SsrParams = { 289 | query: string; 290 | parseOnly: boolean; 291 | textDocument: lc.TextDocumentIdentifier; 292 | position: lc.Position; 293 | selections: readonly lc.Range[]; 294 | }; 295 | 296 | export type RecursiveMemoryLayoutNode = { 297 | item_name: string; 298 | typename: string; 299 | size: number; 300 | alignment: number; 301 | offset: number; 302 | parent_idx: number; 303 | children_start: number; 304 | children_len: number; 305 | }; 306 | export type RecursiveMemoryLayout = { 307 | nodes: RecursiveMemoryLayoutNode[]; 308 | }; 309 | 310 | export const unindexedProject = new lc.NotificationType( 311 | "rust-analyzer/unindexedProject", 312 | ); 313 | 314 | export type UnindexedProjectParams = { textDocuments: lc.TextDocumentIdentifier[] }; 315 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "target": "ES2021", 5 | "module": "commonjs", 6 | "declaration": false, 7 | "sourceMap": true, 8 | "outDir": "lib", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "noImplicitAny": false, 12 | "esModuleInterop": true 13 | }, 14 | "include": ["src"] 15 | } 16 | --------------------------------------------------------------------------------