Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support (Neo)Vim by coc.nvim #439

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions coc-nix/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Ignore everything
/*

# Whitelist what you need
!dist/
!images/*
!snippets.json
*.map
28 changes: 28 additions & 0 deletions coc-nix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# nix-ide

Ported from [vscode-nix-ide](https://github.com/nix-community/vscode-nix-ide).

Because some APIs of [vscode](github.com/microsoft/vscode) are missing in
[coc.nvim](https://github.com/neoclide/coc.nvim), disable some features
temporarily:

- validate range: miss `vscode.document.validateRange()`
- rerun linter only when document is dirty: miss `vscode.document.isDirty`
- open URL of language server: miss `vscode.env.openExternal()`

## Install

- [coc-marketplace](https://github.com/fannheyward/coc-marketplace)
- [npm](https://www.npmjs.com/package/coc-nix)
- vim:

```vim
" command line
CocInstall coc-nix
" or add the following code to your vimrc
let g:coc_global_extensions = ['coc-nix', 'other coc-plugins']
```

## Usage

Refer [vscode-nix-ide](https://github.com/nix-community/vscode-nix-ide).
168 changes: 168 additions & 0 deletions coc-nix/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
{
"name": "coc-nix",
"displayName": "Nix IDE",
"description": "Nix language support - syntax highlighting, formatting, and error reporting.",
"version": "0.3.1",
"publisher": "jnoortheen",
"icon": "images/icon.png",
"license": "MIT",
"engines": {
"coc": "^0.0.82"
},
"categories": [
"Programming Languages",
"Formatters",
"Snippets"
],
"keywords": [
"coc.nvim",
"nix",
"IDE"
],
"bugs": {
"url": "https://github.com/nix-community/vscode-nix-ide/issues"
},
"homepage": "https://github.com/nix-community/vscode-nix-ide",
"repository": {
"type": "git",
"url": "https://github.com/nix-community/vscode-nix-ide"
},
"main": "dist/extension.js",
"activationEvents": [
"onLanguage:nix"
],
"contributes": {
"languages": [
{
"id": "nix",
"aliases": [
"Nix",
"nix"
],
"extensions": [
".nix"
],
"icon": {
"dark": "images/icon.png",
"light": "images/icon.png"
},
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "nix",
"scopeName": "source.nix",
"path": "./syntaxes/nix.tmLanguage.json"
},
{
"scopeName": "markdown.nix.codeblock",
"path": "./syntaxes/injection.json",
"injectTo": [
"text.html.markdown"
],
"embeddedLanguages": {
"meta.embedded.block.nix": "nix"
}
}
],
"snippets": [
{
"language": "nix",
"path": "./snippets.json"
}
],
"configuration": {
"title": "NixIDE",
"properties": {
"nix.formatterPath": {
"type": [
"string",
"array"
],
"default": "nixpkgs-fmt",
"description": "Location of the nix formatter command."
},
"nix.serverPath": {
"type": "string",
"default": "nil",
"description": "Location of the nix language server command."
},
"nix.enableLanguageServer": {
"type": "boolean",
"default": false,
"description": "Use LSP instead of nix-instantiate and nixpkgs-fmt."
},
"nix.serverSettings": {
"type": "object",
"default": {},
"description": "Settings passed to the language server on configuration requests."
},
"nix.hiddenLanguageServerErrors": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Error notifications from the language server for these request types will be suppressed.",
"examples": [
[
"textDocument/definition",
"textDocument/documentSymbol"
]
]
}
}
},
"configurationDefaults": {
"[nix]": {
"editor.insertSpaces": true,
"editor.tabSize": 2
}
},
"commands": [
{
"title": "Restart Language Server",
"category": "Nix IDE",
"command": "nix-ide.restartLanguageServer"
}
]
},
"devDependencies": {
"@commitlint/cli": "^19.6.1",
"@commitlint/config-conventional": "^19.6.0",
"@types/bun": "latest",
"@types/command-exists": "^1.2.3",
"@types/node": "^22.10.3",
"coc.nvim": "^0.0.83-next.18",
"esbuild": "^0.24.2",
"globals": "^15.14.0",
"husky": "^9.1.7",
"js-yaml": "^4.1.0",
"ovsx": "^0.10.1",
"standard-version": "^9.5.0",
"typescript": "^5.7.2"
},
"scripts": {
"patch": "scripts/patch.sh ../src/*.ts",
"prebuild": "bun run patch",
"build-base": "esbuild ./src/extension.ts --bundle --outfile=dist/extension.js --external:coc.nvim --format=cjs --platform=node",
"build": "bun run build-base --sourcemap --minify",
"watch": "bun run build-base --sourcemap --watch",
"postinstall": "husky",
"clean": "rm -rd dist",
"prerelease": "bun install && bun run lint && bun run clean && bun run build",
"release": "standard-version",
"postrelease": "git push --follow-tags",
"package": "bun run build && bunx vsce package",
"publish:ovsx": "bunx ovsx publish *.vsix --pat '$OVS_PAT'",
"publish:vsce": "bunx vsce publish",
"publish": "bun run package && bun run publish:vsce && bun run publish:ovsx",
"lint": "bun x biome check --write src"
},
"dependencies": {
"command-exists": "^1.2.9",
"coc-variables": "^0.0.1"
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
2 changes: 2 additions & 0 deletions coc-nix/scripts/patch.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env -S perl -p
s=//#==;
7 changes: 7 additions & 0 deletions coc-nix/scripts/patch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$(dirname "$(readlink -f "$0")")")"

for file; do
scripts/patch.pl "$file" | cpp -DHAVE_COC_NVIM -xassembler-with-cpp -nostdinc -P -C -o"${file#*/}"
done
2 changes: 2 additions & 0 deletions coc-nix/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/*
!/.gitignore
9 changes: 9 additions & 0 deletions coc-nix/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"allowSyntheticDefaultImports": true,
"noImplicitAny": false
}
}
34 changes: 31 additions & 3 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,40 @@ import {
type Disposable,
type ExtensionContext,
Uri,
env,
window,
workspace,
//# #if HAVE_VSCODE
env,
} from "vscode";
//# #elif HAVE_COC_NVIM
//# } from "coc.nvim";
//# #endif
import type {
CancellationToken,
ConfigurationParams,
LSPArray,
LanguageClientOptions,
MessageSignature,
//# #if HAVE_VSCODE
} from "vscode-languageclient";
//# #elif HAVE_COC_NVIM
//# } from "coc.nvim";
//# #endif
import {
type Executable,
LanguageClient,
type ServerOptions,
//# #if HAVE_VSCODE
} from "vscode-languageclient/node";
//# #elif HAVE_COC_NVIM
//# } from "coc.nvim";
//# #endif
import { type UriMessageItem, config } from "./configuration";

class Client extends LanguageClient {
disposables: Disposable[] = [];

//# #if HAVE_VSCODE
override handleFailedRequest<T>(
type: MessageSignature,
token: CancellationToken | undefined,
Expand Down Expand Up @@ -67,11 +80,13 @@ class Client extends LanguageClient {

return Promise.resolve();
}
//# #endif
}

let client: Client;

export async function activate(context: ExtensionContext): Promise<void> {
//# #if HAVE_VSCODE
if (!commandExistsSync(config.serverPath)) {
const selection = await window.showErrorMessage<UriMessageItem>(
`Command ${config.serverPath} not found in $PATH`,
Expand All @@ -87,8 +102,9 @@ export async function activate(context: ExtensionContext): Promise<void> {
return;
}
}
//# #endif
const serverExecutable: Executable = {
command: config.serverPath,
command: await config.serverPath,
};
const serverOptions: ServerOptions = serverExecutable;

Expand Down Expand Up @@ -128,7 +144,9 @@ export async function activate(context: ExtensionContext): Promise<void> {

client = new Client("nix", "Nix", serverOptions, clientOptions);
client.disposables.push(outputChannel, fileEvents);
//# #if HAVE_VSCODE
client.registerProposedFeatures();
//# #endif
await client.start();

context.subscriptions.push(client);
Expand All @@ -138,20 +156,30 @@ export async function deactivate(): Promise<void> {
if (client?.needsStop()) {
await client.stop();
}
//# #if HAVE_VSCODE
await client.dispose();
//# #endif
}

export async function restart(context: ExtensionContext): Promise<void> {
//# #if HAVE_VSCODE
const restartingMsg = window.setStatusBarMessage(
"$(loading~spin) Restarting Nix language server",
);
//# #endif

try {
await deactivate();
await activate(context);
} catch (error) {
client?.error("Failed to restart Nix language server", error, "force");
client?.error("Failed to restart Nix language server", error
//# #if HAVE_VSCODE
, "force"
//# #endif
);
} finally {
//# #if HAVE_VSCODE
restartingMsg.dispose();
//# #endif
}
}
8 changes: 7 additions & 1 deletion src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ import {
type ConfigurationChangeEvent,
type WorkspaceConfiguration,
workspace,
//# #if HAVE_VSCODE
} from "vscode";
import type { LSPObject } from "vscode-languageclient";

import type { MessageItem, Uri } from "vscode";
//# #elif HAVE_COC_NVIM
//# } from "coc.nvim";
//# import type { LSPObject } from "coc.nvim";
//# import type { MessageItem, Uri } from "coc.nvim";
//# #endif

import { transformConfigValueByVscodeVariables } from "./utils";

export interface UriMessageItem extends MessageItem {
Expand Down
10 changes: 10 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
//# #if HAVE_VSCODE
import * as vscode from "vscode";
import type { ExtensionContext } from "vscode";
//# #elif HAVE_COC_NVIM
//# import * as vscode from "coc.nvim";
//# import type { ExtensionContext } from "coc.nvim";
//# #endif
import * as client from "./client";
import { config } from "./configuration";
import { formattingProviders } from "./formatter";
Expand Down Expand Up @@ -27,8 +32,13 @@ export async function activate(context: ExtensionContext): Promise<void> {
} else {
await startLinting(context);
const subs = [
//# #if HAVE_VSCODE
vscode.languages.registerDocumentFormattingEditProvider,
vscode.languages.registerDocumentRangeFormattingEditProvider,
//# #elif HAVE_COC_NVIM
//# vscode.languages.registerDocumentFormatProvider,
//# vscode.languages.registerDocumentRangeFormatProvider,
//# #endif
].map((func) => func("nix", formattingProviders));
context.subscriptions.concat(subs);
}
Expand Down
Loading
Loading