├── .gitignore ├── src ├── constants.ts ├── lsp_extensions.ts ├── types.d.ts ├── commands.ts └── extension.ts ├── .npmignore ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── codeql-analysis.yml ├── tsconfig.json ├── esbuild.js ├── LICENSE ├── LICENSE.deno ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | out 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. 2 | 3 | export const EXTENSION_NS = "deno"; 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | node_modules 3 | tsconfig.json 4 | *.map 5 | .tags 6 | .DS_Store 7 | .github 8 | diff.sh 9 | esbuild.js 10 | webpack.config.js 11 | package-lock.json 12 | yarn.lock 13 | yarn-error.log 14 | .vim 15 | .vscode 16 | -------------------------------------------------------------------------------- /.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-semver: 10 | patterns: 11 | - "@types/semver" 12 | - "semver" 13 | reviewers: 14 | - fannheyward 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "noEmit": true, 5 | "module": "commonjs", 6 | "target": "es2019", 7 | "lib": [ 8 | "ES2019" 9 | ], 10 | "outDir": "lib", 11 | "rootDir": "src", 12 | "sourceMap": true, 13 | "strict": true 14 | }, 15 | "include": [ 16 | "src" 17 | ], 18 | "exclude": [ 19 | "node_modules", 20 | ".vscode-test" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.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 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: denoland/setup-deno@v2 18 | with: 19 | deno-version: v2.x 20 | - name: deno lint 21 | run: | 22 | deno lint src 23 | -------------------------------------------------------------------------------- /esbuild.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | async function start() { 3 | await require("esbuild").build({ 4 | entryPoints: ["./src/extension.ts"], 5 | bundle: true, 6 | minify: process.env.NODE_ENV === "production", 7 | sourcemap: process.env.NODE_ENV === "development", 8 | mainFields: ["module", "main"], 9 | external: ["coc.nvim"], 10 | platform: "node", 11 | target: "node14.14", 12 | outfile: "lib/index.js", 13 | }); 14 | } 15 | 16 | start().catch((e) => { 17 | console.error(e); 18 | }); 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE.deno: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2020 the Deno authors 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 | -------------------------------------------------------------------------------- /src/lsp_extensions.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. 2 | 3 | /** Contains extensions to the Language Server Protocol that are supported by 4 | * the Deno Language Server. 5 | * 6 | * The requests and notifications types should mirror the Deno's CLI 7 | * `cli/lsp/language_server.rs` under the method `request_else`. 8 | */ 9 | 10 | import { 11 | NotificationType, 12 | RequestType, 13 | RequestType0, 14 | TextDocumentIdentifier, 15 | } from "coc.nvim"; 16 | 17 | export interface RegistryStateParams { 18 | origin: string; 19 | suggestions: boolean; 20 | } 21 | 22 | export const registryState = new NotificationType( 23 | "deno/registryState", 24 | ); 25 | 26 | export interface TaskRequestResponse { 27 | name: string; 28 | detail: string; 29 | } 30 | 31 | /** Requests any tasks from the language server that the language server is 32 | * aware of, which are defined in a Deno configuration file. */ 33 | export const task = new RequestType0< 34 | TaskRequestResponse[] | undefined, 35 | void 36 | >( 37 | "deno/task", 38 | ); 39 | 40 | export interface VirtualTextDocumentParams { 41 | textDocument: TextDocumentIdentifier; 42 | } 43 | 44 | export const virtualTextDocument = new RequestType< 45 | VirtualTextDocumentParams, 46 | string, 47 | void 48 | >("deno/virtualTextDocument"); 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coc-deno 2 | 3 | 4 | 5 | GitHub Sponsors 6 | Patreon donate button 7 | PayPal donate button 8 | 9 | Deno extension for coc.nvim, forked from 10 | [vscode_deno](https://github.com/denoland/vscode_deno). 11 | 12 | ## Install 13 | 14 | `:CocInstall coc-deno` 15 | 16 | ## Usage 17 | 18 | 1. make sure you have Deno v1.7+ installed `deno --version` 19 | 2. run `:CocCommand deno.initializeWorkspace` in your project 20 | 21 | ## Commands 22 | 23 | - `deno.cacheActiveDocument`: Cache Dependencies 24 | - `deno.status`: Display language server status 25 | - `deno.task`: List/Run Deno tasks 26 | - `deno.initializeWorkspace`: Initialize workspace configuration for Deno 27 | 28 | ## Configurations 29 | 30 | You can configure `coc-deno` through `:CocConfig`, same configurations as 31 | [vscode_deno](https://github.com/denoland/vscode_deno#configuration). 32 | 33 | ## License 34 | 35 | MIT 36 | 37 | --- 38 | 39 | > This extension is built with 40 | > [create-coc-extension](https://github.com/fannheyward/create-coc-extension) 41 | -------------------------------------------------------------------------------- /.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@v2 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@v1 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@v1 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@v1 50 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. 2 | 3 | /** When `vscode.WorkspaceSettings` get serialized, they keys of the 4 | * configuration are available. This interface should mirror the configuration 5 | * contributions made by the extension. 6 | */ 7 | export interface Settings { 8 | /** Specify an explicit path to the `deno` cache instead of using DENO_DIR 9 | * or the OS default. */ 10 | cache: string | null; 11 | /** Controls if the extension should cache the active document's dependencies on save. */ 12 | cacheOnSave: boolean; 13 | /** Settings related to code lens. */ 14 | codeLens: { 15 | implementations: boolean; 16 | references: boolean; 17 | referencesAllFunctions: boolean; 18 | test: boolean; 19 | testArgs: string[]; 20 | } | null; 21 | /** A path to a `tsconfig.json` that should be applied. */ 22 | config: string | null; 23 | /** Is the extension enabled or not. */ 24 | enable: boolean; 25 | /** A path to an import map that should be applied. */ 26 | importMap: string | null; 27 | /** Options related to the display of inlay hints. */ 28 | inlayHints: { 29 | parameterNames: { 30 | /** Enable/disable inlay hints for parameter names. */ 31 | enabled: "none" | "literals" | "all"; 32 | /** Do not display an inlay hint when the argument name matches the parameter. */ 33 | suppressWhenArgumentMatchesName: boolean; 34 | } | null; 35 | /** Enable/disable inlay hints for implicit parameter types. */ 36 | parameterTypes: { enabled: boolean } | null; 37 | variableTypes: { 38 | /** Enable/disable inlay hints for implicit variable types. */ 39 | enabled: boolean; 40 | /** Suppress type hints where the variable name matches the implicit type. */ 41 | suppressWhenTypeMatchesName: boolean; 42 | } | null; 43 | /** Enable/disable inlay hints for implicit property declarations. */ 44 | propertyDeclarationTypes: { enabled: boolean } | null; 45 | /** Enable/disable inlay hints for implicit function return types. */ 46 | functionLikeReturnTypes: { enabled: boolean } | null; 47 | /** Enable/disable inlay hints for enum values. */ 48 | enumMemberValues: { enabled: boolean } | null; 49 | } | null; 50 | /** A flag that enables additional internal debug information to be printed 51 | * to the _Deno Language Server_ output. */ 52 | internalDebug: boolean; 53 | /** Determine if the extension should be providing linting diagnostics. */ 54 | lint: boolean; 55 | /** Specify an explicit path to the `deno` binary. */ 56 | path: string | null; 57 | suggest: { 58 | autoImports: boolean; 59 | completeFunctionCalls: boolean; 60 | names: boolean; 61 | paths: boolean; 62 | imports: { 63 | autoDiscover: boolean; 64 | hosts: Record; 65 | } | null; 66 | } | null; 67 | /** Determine if the extension should be type checking against the unstable 68 | * APIs. */ 69 | unstable: boolean; 70 | } 71 | -------------------------------------------------------------------------------- /src/commands.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. 2 | 3 | /** Contains handlers for commands that are enabled in Visual Studio Code for 4 | * the extension. */ 5 | 6 | import { 7 | commands, 8 | ExtensionContext, 9 | extensions, 10 | LanguageClient, 11 | Location, 12 | Position, 13 | State, 14 | Terminal, 15 | Uri, 16 | window, 17 | workspace, 18 | } from "coc.nvim"; 19 | import { EXTENSION_NS } from "./constants"; 20 | import { task as taskReq, virtualTextDocument } from "./lsp_extensions"; 21 | 22 | let terminal: Terminal | undefined; 23 | 24 | // deno-lint-ignore no-explicit-any 25 | export type Callback = (...args: any[]) => unknown; 26 | export type Factory = ( 27 | context: ExtensionContext, 28 | client: LanguageClient, 29 | ) => Callback; 30 | 31 | export function cacheActiveDocument(): Callback { 32 | return async () => { 33 | const { document } = await workspace.getCurrentState(); 34 | return window.withProgress({ 35 | title: "caching", 36 | }, () => { 37 | return commands.executeCommand( 38 | "deno.cache", 39 | [document.uri.toString()], 40 | document.uri.toString(), 41 | ); 42 | }); 43 | }; 44 | } 45 | 46 | export async function doInitialize() { 47 | const title = "Initialize Deno Project"; 48 | const linting = "Enable Deno linting?"; 49 | const unstable = "Enable Deno unstable APIs?"; 50 | const prettier = "Disable coc-prettier for current project?"; 51 | const items = [linting, unstable]; 52 | if (extensions.all.find((e) => e.id === "coc-prettier")) { 53 | items.push(prettier); 54 | } 55 | const settings = await window.showPickerDialog(items, title); 56 | if (!settings) return; 57 | 58 | const config = workspace.getConfiguration(EXTENSION_NS); 59 | config.update("enable", true); 60 | config.update("lint", settings.includes(linting)); 61 | config.update("unstable", settings.includes(unstable)); 62 | 63 | if (settings.includes(prettier)) { 64 | const prettierConfig = workspace.getConfiguration("prettier"); 65 | prettierConfig.update("disableLanguages", ["typescript", "javascript"]); 66 | } 67 | window.showInformationMessage("Deno is now setup in this workspace."); 68 | } 69 | 70 | export function initializeWorkspace(): Callback { 71 | return async () => { 72 | await doInitialize(); 73 | await checkTSServer(); 74 | }; 75 | } 76 | 77 | export function showReferences( 78 | uri: string, 79 | position: Position, 80 | locations: Location[], 81 | ) { 82 | if (!uri) return; 83 | commands.executeCommand( 84 | "editor.action.showReferences", 85 | Uri.parse(uri), 86 | position, 87 | locations, 88 | ); 89 | } 90 | 91 | /** Open and display the "virtual document" which provides the status of the 92 | * Deno Language Server. */ 93 | export function status( 94 | _context: ExtensionContext, 95 | client: LanguageClient, 96 | ): Callback { 97 | return async () => { 98 | const content = await client.sendRequest(virtualTextDocument, { 99 | textDocument: { uri: "deno:/status.md" }, 100 | }); 101 | if (!content) return; 102 | 103 | const nvim = workspace.nvim; 104 | nvim.pauseNotification(); 105 | nvim.command( 106 | `edit +setl\\ buftype=nofile [Deno Language Server Status]`, 107 | true, 108 | ); 109 | nvim.command("setl nobuflisted bufhidden=wipe", true); 110 | nvim.command("setl filetype=markdown", true); 111 | nvim.call("append", [0, content.split("\n")], true); 112 | nvim.command(`exe 1`, true); 113 | await nvim.resumeNotification(); 114 | }; 115 | } 116 | 117 | export function task( 118 | _context: ExtensionContext, 119 | client: LanguageClient, 120 | ): Callback { 121 | return async () => { 122 | const tasks = await client.sendRequest(taskReq); 123 | if (!tasks || tasks.length === 0) return; 124 | 125 | const items = [...tasks.map((task) => ({ text: task.detail }))]; 126 | const idx = await window.showMenuPicker(items, { 127 | title: "Select a task to run", 128 | position: "center", 129 | }); 130 | if (idx === -1) return; 131 | 132 | if (terminal) { 133 | terminal.dispose(); 134 | terminal = undefined; 135 | } 136 | 137 | const task = tasks[idx]; 138 | terminal = await window.createTerminal({ 139 | name: task.name, 140 | cwd: workspace.root, 141 | }); 142 | terminal.sendText(task.detail); 143 | }; 144 | } 145 | 146 | export async function test(uri: string, name: string) { 147 | const config = workspace.getConfiguration(EXTENSION_NS); 148 | const testArgs = [...config.get("codeLens.testArgs", [])]; 149 | if (config.has("unstable")) { 150 | testArgs.push("--unstable"); 151 | } 152 | if (!testArgs.includes("--import-map")) { 153 | const importMap = config.get("importMap"); 154 | if (importMap?.trim()) { 155 | testArgs.push("--import-map", importMap.trim()); 156 | } 157 | } 158 | const env = config.has("cache") 159 | ? { "DENO_DIR": config.get("cache") } as Record 160 | : undefined; 161 | const bin = config.get("path", "deno"); 162 | const filter = new RegExp( 163 | "^" + name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$", 164 | ); 165 | const args = [ 166 | "test", 167 | ...testArgs, 168 | "--filter", 169 | `"${filter}"`, 170 | Uri.parse(uri).fsPath, 171 | ]; 172 | 173 | if (terminal) { 174 | terminal.dispose(); 175 | terminal = undefined; 176 | } 177 | terminal = await window.createTerminal({ name, cwd: workspace.root, env }); 178 | terminal.sendText(`${bin} ${args.join(" ")}`); 179 | } 180 | 181 | export function welcome( 182 | _context: ExtensionContext, 183 | _client: LanguageClient, 184 | ): Callback { 185 | return () => { 186 | // TODO 187 | }; 188 | } 189 | 190 | export function restart( 191 | _context: ExtensionContext, 192 | client: LanguageClient, 193 | ): Callback { 194 | return () => { 195 | if (client.getPublicState() === State.Running) { 196 | client.restart(); 197 | } 198 | }; 199 | } 200 | 201 | // deno-lint-ignore require-await 202 | export async function checkTSServer(): Promise { 203 | const tsserverConfig = workspace.getConfiguration("tsserver"); 204 | const enable = tsserverConfig.get("enable"); 205 | if (enable) { 206 | tsserverConfig.update("enable", false); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. 2 | 3 | import { 4 | CancellationToken, 5 | commands, 6 | Executable, 7 | ExtensionContext, 8 | LanguageClient, 9 | LanguageClientOptions, 10 | ProviderResult, 11 | services, 12 | TextDocumentContentProvider, 13 | Thenable, 14 | Uri, 15 | window, 16 | workspace, 17 | } from "coc.nvim"; 18 | import process from "node:process"; 19 | import * as cmds from "./commands"; 20 | import { EXTENSION_NS } from "./constants"; 21 | import { 22 | registryState, 23 | RegistryStateParams, 24 | virtualTextDocument, 25 | } from "./lsp_extensions"; 26 | import { Settings } from "./types"; 27 | 28 | /** Assert that the condition is "truthy", otherwise throw. */ 29 | function assert(cond: unknown, msg = "Assertion failed."): asserts cond { 30 | if (!cond) { 31 | throw new Error(msg); 32 | } 33 | } 34 | 35 | const settingsKeys: Array = [ 36 | "cache", 37 | "cacheOnSave", 38 | "codeLens", 39 | "config", 40 | "enable", 41 | "importMap", 42 | "inlayHints", 43 | "internalDebug", 44 | "lint", 45 | "suggest", 46 | "unstable", 47 | ]; 48 | 49 | function getSettings(): Settings { 50 | const settings = workspace.getConfiguration(EXTENSION_NS); 51 | const result = Object.create(null); 52 | for (const key of settingsKeys) { 53 | const value = settings.inspect(key); 54 | assert(value); 55 | result[key] = value.workspaceFolderValue ?? value.workspaceValue ?? 56 | value.globalValue ?? value.defaultValue; 57 | } 58 | return result; 59 | } 60 | 61 | let client: LanguageClient; 62 | let serverVersion = ""; 63 | 64 | class DenoTextDocumentContentProvider implements TextDocumentContentProvider { 65 | constructor(private client: LanguageClient) {} 66 | 67 | provideTextDocumentContent( 68 | uri: Uri, 69 | token: CancellationToken, 70 | ): ProviderResult { 71 | return this.client.sendRequest( 72 | virtualTextDocument, 73 | { textDocument: { uri: uri.toString() } }, 74 | token, 75 | ); 76 | } 77 | } 78 | 79 | async function tryActivate(context: ExtensionContext): Promise { 80 | await cmds.checkTSServer(); 81 | 82 | const command = workspace.getConfiguration(EXTENSION_NS).get("path", "deno"); 83 | const run: Executable = { 84 | command, 85 | args: ["lsp"], 86 | options: { env: { ...process.env, "NO_COLOR": true } }, 87 | }; 88 | 89 | const clientOptions: LanguageClientOptions = { 90 | documentSelector: [ 91 | { scheme: "file", language: "json" }, 92 | { scheme: "file", language: "jsonc" }, 93 | { scheme: "file", language: "markdown" }, 94 | { scheme: "file", language: "javascript" }, 95 | { scheme: "file", language: "javascriptreact" }, 96 | { scheme: "file", language: "typescript" }, 97 | { scheme: "file", language: "typescriptreact" }, 98 | { scheme: "deno", language: "javascript" }, 99 | { scheme: "deno", language: "javascriptreact" }, 100 | { scheme: "deno", language: "typescript" }, 101 | { scheme: "deno", language: "typescriptreact" }, 102 | ], 103 | diagnosticCollectionName: EXTENSION_NS, 104 | initializationOptions: getSettings(), 105 | middleware: { 106 | didOpen: async (data, next) => { 107 | const fsPath = Uri.parse(data.uri).fsPath; 108 | if (fsPath.includes("deno:asset") || fsPath.includes("deno:/asset")) { 109 | return; 110 | } 111 | if (fsPath.includes("deno:/https")) { 112 | const pwd = process.cwd() + "/"; 113 | // @ts-ignore force set 114 | data.uri = Uri.parse(fsPath.replace(pwd, "")).toString(); 115 | } 116 | await next(data); 117 | }, 118 | }, 119 | }; 120 | 121 | client = new LanguageClient( 122 | EXTENSION_NS, 123 | run, 124 | clientOptions, 125 | ); 126 | context.subscriptions.push(services.registLanguageClient(client)); 127 | 128 | const statusBarItem = window.createStatusBarItem(0); 129 | context.subscriptions.push(statusBarItem); 130 | 131 | context.subscriptions.push( 132 | workspace.onDidChangeConfiguration((evt) => { 133 | if (evt.affectsConfiguration(EXTENSION_NS)) { 134 | client.sendNotification( 135 | "workspace/didChangeConfiguration", 136 | // We actually set this to empty because the language server will 137 | // call back and get the configuration. There can be issues with the 138 | // information on the event not being reliable. 139 | { settings: null }, 140 | ); 141 | } 142 | }), 143 | // Register a content provider for Deno resolved read-only files. 144 | workspace.registerTextDocumentContentProvider( 145 | EXTENSION_NS, 146 | new DenoTextDocumentContentProvider(client), 147 | ), 148 | ); 149 | 150 | const registerCommand = createRegisterCommand(context); 151 | registerCommand("task", cmds.task); 152 | registerCommand("status", cmds.status); 153 | registerCommand("restart", cmds.restart); 154 | registerCommand("cacheActiveDocument", cmds.cacheActiveDocument); 155 | registerCommand("initializeWorkspace", cmds.initializeWorkspace); 156 | commands.registerCommand(`${EXTENSION_NS}.test`, cmds.test, null, true); 157 | commands.registerCommand( 158 | `${EXTENSION_NS}.showReferences`, 159 | cmds.showReferences, 160 | null, 161 | true, 162 | ); 163 | 164 | await client.onReady(); 165 | client.onNotification(registryState, createRegistryStateHandler()); 166 | 167 | serverVersion = 168 | (client.initializeResult?.serverInfo?.version ?? "").split(" ")[0]; 169 | if (serverVersion) { 170 | statusBarItem.text = `Deno ${serverVersion}`; 171 | statusBarItem.show(); 172 | } 173 | } 174 | 175 | export async function activate(context: ExtensionContext): Promise { 176 | const enable = workspace.getConfiguration(EXTENSION_NS).get("enable", false); 177 | if (!enable) { 178 | context.subscriptions.push( 179 | commands.registerCommand( 180 | `${EXTENSION_NS}.initializeWorkspace`, 181 | async () => { 182 | await cmds.doInitialize(); 183 | await tryActivate(context); 184 | }, 185 | ), 186 | ); 187 | return; 188 | } 189 | 190 | await tryActivate(context); 191 | } 192 | 193 | export function deactivate(): Thenable | undefined { 194 | return client?.stop(); 195 | } 196 | 197 | /** Internal function factory that returns a registerCommand function that is 198 | * bound to the extension context. */ 199 | function createRegisterCommand( 200 | context: ExtensionContext, 201 | ): (name: string, factory: cmds.Factory) => void { 202 | return function registerCommand( 203 | name: string, 204 | factory: ( 205 | context: ExtensionContext, 206 | client: LanguageClient, 207 | ) => cmds.Callback, 208 | ): void { 209 | const fullName = `${EXTENSION_NS}.${name}`; 210 | const command = factory(context, client); 211 | context.subscriptions.push(commands.registerCommand(fullName, command)); 212 | }; 213 | } 214 | 215 | export interface NotificationHandler

{ 216 | (params: P): void; 217 | } 218 | 219 | function createRegistryStateHandler(): NotificationHandler< 220 | RegistryStateParams 221 | > { 222 | return async function handler(p) { 223 | if (p.suggestions) { 224 | const selection = await window.showInformationMessage( 225 | `The server "${p.origin}" supports completion suggestions for imports. Do you wish to enable this? (Only do this if you trust "${p.origin}") [Learn More](https://github.com/denoland/vscode_deno/blob/main/docs/ImportCompletions.md)`, 226 | "No", 227 | "Enable", 228 | ); 229 | const enable = selection === "Enable"; 230 | const config = workspace.getConfiguration("deno.suggest.imports"); 231 | const hosts: Record = config.get("hosts", {}); 232 | hosts[p.origin] = enable; 233 | config.update("hosts", hosts); 234 | } 235 | }; 236 | } 237 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coc-deno", 3 | "version": "3.15.0", 4 | "description": "Deno extension for coc.nvim, forked from vscode_deno", 5 | "author": "Heyward Fann ", 6 | "license": "MIT", 7 | "main": "./lib/index.js", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/fannheyward/coc-deno.git" 11 | }, 12 | "keywords": [ 13 | "coc.nvim", 14 | "deno" 15 | ], 16 | "engines": { 17 | "coc": "^0.0.80" 18 | }, 19 | "scripts": { 20 | "prepare": "node esbuild.js", 21 | "build": "node esbuild.js", 22 | "watch": "node esbuild.js --watch", 23 | "fmt": "deno fmt src README.md", 24 | "lint": "deno lint src" 25 | }, 26 | "devDependencies": { 27 | "@types/node": "16", 28 | "coc.nvim": "^0.0.83-next.18", 29 | "esbuild": "^0.27.0", 30 | "typescript": "^5.0.4" 31 | }, 32 | "activationEvents": [ 33 | "onCommand:deno.initializeWorkspace", 34 | "onLanguage:typescript", 35 | "onLanguage:typescriptreact", 36 | "onLanguage:javascript", 37 | "onLanguage:javascriptreact" 38 | ], 39 | "contributes": { 40 | "commands": [ 41 | { 42 | "command": "deno.cacheActiveDocument", 43 | "title": "Cache Dependencies", 44 | "category": "Deno", 45 | "description": "Cache the active workspace document and its dependencies." 46 | }, 47 | { 48 | "command": "deno.status", 49 | "title": "Language Server Status", 50 | "category": "Deno", 51 | "description": "Provide a status document of the language server." 52 | }, 53 | { 54 | "command": "deno.restart", 55 | "title": "Restart Language Server", 56 | "category": "Deno", 57 | "description": "Restart the Deno language server" 58 | }, 59 | { 60 | "command": "deno.task", 61 | "title": "List/Run Deno task", 62 | "category": "Deno", 63 | "description": "List/Run Deno tasks" 64 | }, 65 | { 66 | "command": "deno.initializeWorkspace", 67 | "title": "Initialize Workspace Configuration", 68 | "category": "Deno", 69 | "description": "Initialize the workspace configuration for Deno." 70 | } 71 | ], 72 | "configuration": { 73 | "type": "object", 74 | "title": "coc-deno configuration", 75 | "properties": { 76 | "deno.enable": { 77 | "type": "boolean", 78 | "default": false, 79 | "markdownDescription": "Controls if the Deno Language Server is enabled. When enabled, the extension will disable the built-in VSCode JavaScript and TypeScript language services, and will use the Deno Language Server (`deno lsp`) instead.\n\n**Not recommended to be enabled globally.**", 80 | "scope": "window", 81 | "examples": [ 82 | true, 83 | false 84 | ] 85 | }, 86 | "deno.trace.server": { 87 | "type": "string", 88 | "scope": "window", 89 | "enum": [ 90 | "off", 91 | "messages", 92 | "verbose" 93 | ], 94 | "enumDescriptions": [ 95 | "No traces", 96 | "Error only", 97 | "Full log" 98 | ], 99 | "default": "off", 100 | "description": "Trace requests to Deno" 101 | }, 102 | "deno.path": { 103 | "type": "string", 104 | "default": null, 105 | "markdownDescription": "A path to the `deno` CLI executable. By default, the extension looks for `deno` in the `PATH`, but if set, will use the path specified instead.", 106 | "scope": "window", 107 | "examples": [ 108 | "/usr/bin/deno", 109 | "C:\\Program Files\\deno\\deno.exe" 110 | ] 111 | }, 112 | "deno.cache": { 113 | "type": "string", 114 | "default": null, 115 | "markdownDescription": "A path to the cache directory for Deno. By default, the operating system's cache path plus `deno` is used, or the `DENO_DIR` environment variable, but if set, this path will be used instead.", 116 | "scope": "window" 117 | }, 118 | "deno.cacheOnSave": { 119 | "type": "boolean", 120 | "default": true, 121 | "markdownDescription": "Controls if the extension should cache the active document's dependencies on save.", 122 | "scope": "window" 123 | }, 124 | "deno.codeLens.implementations": { 125 | "type": "boolean", 126 | "default": false, 127 | "markdownDescription": "Enables or disables the display of code lens information for implementations of items in the code.", 128 | "scope": "window", 129 | "examples": [ 130 | true, 131 | false 132 | ] 133 | }, 134 | "deno.codeLens.references": { 135 | "type": "boolean", 136 | "default": false, 137 | "markdownDescription": "Enables or disables the display of code lens information for references of items in the code.", 138 | "scope": "window", 139 | "examples": [ 140 | true, 141 | false 142 | ] 143 | }, 144 | "deno.codeLens.referencesAllFunctions": { 145 | "type": "boolean", 146 | "default": false, 147 | "markdownDescription": "Enables or disables the display of code lens information for all functions in the code.", 148 | "scope": "window", 149 | "examples": [ 150 | true, 151 | false 152 | ] 153 | }, 154 | "deno.codeLens.test": { 155 | "type": "boolean", 156 | "default": true, 157 | "markdownDescription": "Enables or disables the display of code lenses that allow running of individual tests in the code.", 158 | "scope": "resource" 159 | }, 160 | "deno.codeLens.testArgs": { 161 | "type": "array", 162 | "items": { 163 | "type": "string" 164 | }, 165 | "default": [ 166 | "--allow-all", 167 | "--no-check" 168 | ], 169 | "markdownDescription": "Additional arguments to use with the run test code lens. Defaults to `[ \"--allow-all\", \"--no-check\" ]`.", 170 | "scope": "resource" 171 | }, 172 | "deno.config": { 173 | "type": "string", 174 | "default": null, 175 | "markdownDescription": "The file path to a configuration file. This is the equivalent to using `--config` on the command line. The path can be either be relative to the workspace, or an absolute path.\n\nIt is recommend you name it `deno.json` or `deno.jsonc`.\n\n**Not recommended to be set globally.**", 176 | "scope": "window", 177 | "examples": [ 178 | "./deno.jsonc", 179 | "/path/to/deno.jsonc", 180 | "C:\\path\\to\\deno.jsonc" 181 | ] 182 | }, 183 | "deno.inlayHints.parameterNames.enabled": { 184 | "type": "string", 185 | "enum": [ 186 | "none", 187 | "literals", 188 | "all" 189 | ], 190 | "enumDescriptions": [ 191 | "Disable inlay hints for parameters.", 192 | "Display inlay hints for literal arguments.", 193 | "Display inlay hints for all literal and non-literal arguments." 194 | ], 195 | "default": "none", 196 | "markdownDescription": "Enable/disable inlay hints for parameter names.", 197 | "scope": "resource" 198 | }, 199 | "deno.inlayHints.parameterNames.suppressWhenArgumentMatchesName": { 200 | "type": "boolean", 201 | "default": true, 202 | "markdownDescription": "Do not display an inlay hint when the argument name matches the parameter.", 203 | "scope": "resource" 204 | }, 205 | "deno.inlayHints.parameterTypes.enabled": { 206 | "type": "boolean", 207 | "default": false, 208 | "markdownDescription": "Enable/disable inlay hints for implicit parameter types.", 209 | "scope": "resource" 210 | }, 211 | "deno.inlayHints.variableTypes.enabled": { 212 | "type": "boolean", 213 | "default": false, 214 | "markdownDescription": "Enable/disable inlay hints for implicit variable types.", 215 | "scope": "resource" 216 | }, 217 | "deno.inlayHints.variableTypes.suppressWhenTypeMatchesName": { 218 | "type": "boolean", 219 | "default": true, 220 | "markdownDescription": "Suppress type hints where the variable name matches the implicit type.", 221 | "scope": "resource" 222 | }, 223 | "deno.inlayHints.propertyDeclarationTypes.enabled": { 224 | "type": "boolean", 225 | "default": false, 226 | "markdownDescription": "Enable/disable inlay hints for implicit property declarations.", 227 | "scope": "resource" 228 | }, 229 | "deno.inlayHints.functionLikeReturnTypes.enabled": { 230 | "type": "boolean", 231 | "default": false, 232 | "markdownDescription": "Enable/disable inlay hints for implicit function return types.", 233 | "scope": "resource" 234 | }, 235 | "deno.inlayHints.enumMemberValues.enabled": { 236 | "type": "boolean", 237 | "default": false, 238 | "markdownDescription": "Enable/disable inlay hints for enum values.", 239 | "scope": "resource" 240 | }, 241 | "deno.documentPreloadLimit": { 242 | "type": "number", 243 | "markdownDescription": "Maximum number of file system entries to traverse when finding scripts to preload into TypeScript on startup. Set this to 0 to disable document preloading.", 244 | "default": 1000, 245 | "scope": "resource", 246 | "examples": [ 247 | 0, 248 | 100, 249 | 1000 250 | ] 251 | }, 252 | "deno.importMap": { 253 | "type": "string", 254 | "default": null, 255 | "markdownDescription": "The file path to an import map. This is the equivalent to using `--import-map` on the command line.\n\n[Import maps](https://deno.land/manual@v1.6.0/linking_to_external_code/import_maps) provide a way to \"relocate\" modules based on their specifiers. The path can either be relative to the workspace, or an absolute path.\n\n**Not recommended to be set globally.**", 256 | "scope": "window", 257 | "examples": [ 258 | "./import_map.json", 259 | "/path/to/import_map.json", 260 | "C:\\path\\to\\import_map.json" 261 | ] 262 | }, 263 | "deno.suggest.autoImports": { 264 | "type": "boolean", 265 | "default": true, 266 | "scope": "window" 267 | }, 268 | "deno.suggest.completeFunctionCalls": { 269 | "type": "boolean", 270 | "default": false, 271 | "scope": "window" 272 | }, 273 | "deno.suggest.names": { 274 | "type": "boolean", 275 | "default": true, 276 | "scope": "window" 277 | }, 278 | "deno.suggest.paths": { 279 | "type": "boolean", 280 | "default": true, 281 | "scope": "window" 282 | }, 283 | "deno.suggest.imports.autoDiscover": { 284 | "type": "boolean", 285 | "default": true, 286 | "markdownDescription": "If enabled, when new hosts/origins are encountered that support import suggestions, you will be prompted to enable or disable it. Defaults to `true`.", 287 | "scope": "window" 288 | }, 289 | "deno.suggest.imports.hosts": { 290 | "type": "object", 291 | "default": { 292 | "https://deno.land": true 293 | }, 294 | "markdownDescription": "Controls which hosts are enabled for import suggestions.", 295 | "scope": "window", 296 | "examples": { 297 | "https://deno.land": true 298 | } 299 | }, 300 | "deno.testing.args": { 301 | "type": "array", 302 | "items": { 303 | "type": "string" 304 | }, 305 | "default": [ 306 | "--allow-all", 307 | "--no-check" 308 | ], 309 | "markdownDescription": "Arguments to use when running tests via the Test Explorer. Defaults to `[ \"--allow-all\" ]`.", 310 | "scope": "window" 311 | }, 312 | "deno.unstable": { 313 | "type": "boolean", 314 | "default": false, 315 | "markdownDescription": "Controls if code will be type checked with Deno's unstable APIs. This is the equivalent to using `--unstable` on the command line.\n\n**Not recommended to be enabled globally.**", 316 | "scope": "window", 317 | "examples": [ 318 | true, 319 | false 320 | ] 321 | }, 322 | "deno.internalDebug": { 323 | "type": "boolean", 324 | "default": false, 325 | "markdownDescription": "Determines if the internal debugging information for the Deno language server will be logged to the _Deno Language Server_ console.", 326 | "scope": "window", 327 | "examples": [ 328 | true, 329 | false 330 | ] 331 | }, 332 | "deno.lint": { 333 | "type": "boolean", 334 | "default": true, 335 | "markdownDescription": "Controls if linting information will be provided by the Deno Language Server.\n\n**Not recommended to be enabled globally.**", 336 | "scope": "window", 337 | "examples": [ 338 | true, 339 | false 340 | ] 341 | } 342 | } 343 | }, 344 | "jsonValidation": [ 345 | { 346 | "fileMatch": "deno-import-intellisense.json", 347 | "url": "https://raw.githubusercontent.com/denoland/vscode_deno/main/schemas/registry-completions.schema.json" 348 | }, 349 | { 350 | "fileMatch": [ 351 | "deno.json", 352 | "deno.jsonc" 353 | ], 354 | "url": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json" 355 | }, 356 | { 357 | "fileMatch": "deno.lock", 358 | "url": "https://raw.githubusercontent.com/denoland/vscode_deno/main/schemas/lockfile.schema.json" 359 | }, 360 | { 361 | "fileMatch": [ 362 | "import*map*.json", 363 | "importMap*.json" 364 | ], 365 | "url": "https://raw.githubusercontent.com/denoland/vscode_deno/main/schemas/import_map.schema.json" 366 | } 367 | ] 368 | } 369 | } 370 | --------------------------------------------------------------------------------