diff --git a/package.json b/package.json index 86662ce..81ead5f 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,22 @@ "language": "nix", "path": "./snippets.json" } - ] + ], + "configuration": { + "title": "NixIDE", + "properties": { + "nix.serverPath": { + "type": "string", + "default": "", + "description": "Location of the rnix language server. By default rnix from $PATH is used (if enableLanguageServer is true.)" + }, + "nix.enableLanguageServer": { + "type": "boolean", + "default": false, + "description": "Setting this would disable nix-instantiate and nixpkgs-fmt" + } + } + } }, "devDependencies": { "@commitlint/cli": "^11.0.0", @@ -94,5 +109,8 @@ "release": "standard-version && git push --follow-tags", "pkg-release": "vsce publish && ovsx publish --pat $OVS_PAT", "lint": "eslint --ext ts src" + }, + "dependencies": { + "vscode-languageclient": "^7.0.0" } } diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 0000000..b0f19e6 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,53 @@ +// from PR of https://github.com/nix-community/vscode-nix-ide/pull/16/ + +import { env, ExtensionContext, Uri, window, workspace } from "vscode"; +import { + Executable, + LanguageClient, + LanguageClientOptions, + ServerOptions, +} from "vscode-languageclient"; +import { config, UriMessageItem } from "./configuration"; + +let client: LanguageClient; + +export async function activate(context: ExtensionContext): Promise { + if (config.serverPath === undefined || config.serverPath === "") { + const selection = await window.showErrorMessage( + "Unable to find Nix language server", + { + title: "Install language server", + uri: Uri.parse("https://github.com/nix-community/rnix-lsp"), + } + ); + if (selection?.uri !== undefined) { + await env.openExternal(selection?.uri); + return; + } + } + const serverExecutable: Executable = { + command: config.serverPath, + }; + const serverOptions: ServerOptions = serverExecutable; + + const nixDocumentSelector: { scheme: string; language: string }[] = [ + { scheme: "file", language: "nix" }, + { scheme: "untitled", language: "nix" }, + ]; + + const clientOptions: LanguageClientOptions = { + documentSelector: nixDocumentSelector, + synchronize: { + fileEvents: workspace.createFileSystemWatcher("**/*.nix"), + }, + outputChannel: window.createOutputChannel("Nix"), + }; + + client = new LanguageClient("nix", "Nix", serverOptions, clientOptions); + client.registerProposedFeatures(); + context.subscriptions.push(client.start()); +} + +export function deactivate(): Thenable | undefined { + return client ? client.stop() : undefined; +} diff --git a/src/configuration.ts b/src/configuration.ts new file mode 100644 index 0000000..6cd7648 --- /dev/null +++ b/src/configuration.ts @@ -0,0 +1,28 @@ +import * as vscode from "vscode"; + +import { MessageItem, Uri } from "vscode"; + +export interface UriMessageItem extends MessageItem { + uri: Uri; +} + +export class Config { + readonly rootSection = "nix"; + + private get cfg(): vscode.WorkspaceConfiguration { + return vscode.workspace.getConfiguration(this.rootSection); + } + + private get(path: string): T { + return this.cfg.get(path)!; + } + + get serverPath(): string { + return this.get("serverPath"); + } + + get LSPEnabled(): boolean { + return this.get("enableLanguageServer"); + } +} +export const config = new Config(); diff --git a/src/extension.ts b/src/extension.ts index 01f2332..3593cc9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,23 +2,36 @@ import * as vscode from "vscode"; import { ExtensionContext } from "vscode"; import { formattingProviders } from "./formatter"; import { startLinting } from "./linter"; +import { config } from "./configuration"; +import * as client from "./client"; /** * Activate this extension. * - * Format with nixpkgs-format - * validate with nix-instantiate + * If LSP is enabled + * then support IDE features with {@link https://github.com/nix-community/rnix-lsp|rnix-lsp} + * Else + * Format with nixpkgs-format + * validate with nix-instantiate * * @param context The context for this extension * @return A promise for the initialization */ export async function activate(context: ExtensionContext): Promise { - await startLinting(context); + if (config.LSPEnabled) { + await client.activate(context); + } else { + await startLinting(context); + const subs = [ + vscode.languages.registerDocumentFormattingEditProvider, + vscode.languages.registerDocumentRangeFormattingEditProvider, + ].map((func) => func("nix", formattingProviders)); + context.subscriptions.concat(subs); + } +} - const subs = [ - vscode.languages.registerDocumentFormattingEditProvider, - vscode.languages.registerDocumentRangeFormattingEditProvider, - ].map((func) => func("nix", formattingProviders)); - - context.subscriptions.concat(subs); -}; +export async function deactivate(): Promise { + if (config.LSPEnabled) { + await client.deactivate(); + } +} diff --git a/yarn.lock b/yarn.lock index 11051ff..e013293 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2065,6 +2065,13 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -2884,6 +2891,13 @@ semver@^6.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.4: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -3371,6 +3385,33 @@ vsce@^1.83.0: yauzl "^2.3.1" yazl "^2.2.2" +vscode-jsonrpc@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" + integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== + +vscode-languageclient@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz#b505c22c21ffcf96e167799757fca07a6bad0fb2" + integrity sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg== + dependencies: + minimatch "^3.0.4" + semver "^7.3.4" + vscode-languageserver-protocol "3.16.0" + +vscode-languageserver-protocol@3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" + integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== + dependencies: + vscode-jsonrpc "6.0.0" + vscode-languageserver-types "3.16.0" + +vscode-languageserver-types@3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" + integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== + vscode-test@^0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-0.4.3.tgz#461ebf25fc4bc93d77d982aed556658a2e2b90b8" @@ -3446,6 +3487,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"