coc-codeql 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/docs/language-server.md +147 -0
- package/lib/index.js +134 -0
- package/lua/codeql.lua +93 -0
- package/package.json +95 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nitrocao
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# coc-codeql
|
|
2
|
+
|
|
3
|
+
[CodeQL](https://codeql.github.com/) language support for
|
|
4
|
+
[coc.nvim](https://github.com/neoclide/coc.nvim) — an editor companion
|
|
5
|
+
to the CodeQL CLI, following the editing experience of the official
|
|
6
|
+
[vscode-codeql](https://github.com/github/vscode-codeql) extension.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Language server integration** — diagnostics, completion, hover,
|
|
11
|
+
definition, references, document symbols, formatting, rename and
|
|
12
|
+
inlay hints, with pack resolution through the qlpack and the package
|
|
13
|
+
cache (`codeql pack install`)
|
|
14
|
+
- **Filetype detection** for `*.ql` / `*.qll`
|
|
15
|
+
- **Language configuration** — `//` line comments, block comment
|
|
16
|
+
continuation, comment-aware `formatoptions`
|
|
17
|
+
- **Tree-sitter highlighting & folding**
|
|
18
|
+
|
|
19
|
+
This extension is a pure editor integration: the language intelligence
|
|
20
|
+
lives in the CodeQL CLI, the parser and highlight queries are provided
|
|
21
|
+
by your editor's tree-sitter toolchain, and nothing is bundled here.
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- neovim ≥ 0.9 (developed and tested on 0.12)
|
|
26
|
+
- coc.nvim ≥ 0.0.82
|
|
27
|
+
- the CodeQL CLI ≥ 2.x on `PATH` (or set `codeql.cliPath`)
|
|
28
|
+
- the `ql` tree-sitter parser, installed through the tree-sitter
|
|
29
|
+
ecosystem:
|
|
30
|
+
|
|
31
|
+
```vim
|
|
32
|
+
:TSInstall ql
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> nvim-treesitter registers the
|
|
36
|
+
> [tree-sitter-ql](https://github.com/samlanning/tree-sitter-ql)
|
|
37
|
+
> grammar and ships its queries. The revision currently pinned in
|
|
38
|
+
> nvim-treesitter's lockfile mis-parses `true()`/`false()` (QL has no
|
|
39
|
+
> boolean literals); if that bites you, install a fixed parser build
|
|
40
|
+
> into your nvim site directory manually (`:h treesitter-parsers`).
|
|
41
|
+
> Without a parser, highlighting degrades gracefully with a warning;
|
|
42
|
+
> every other feature works.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```vim
|
|
47
|
+
:CocInstall coc-codeql
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
```jsonc
|
|
53
|
+
{
|
|
54
|
+
// Path to the CodeQL CLI executable: a name resolved on PATH
|
|
55
|
+
// (default "codeql") or an absolute path. Resolved once at
|
|
56
|
+
// activation; if it cannot be found, a warning is shown and the
|
|
57
|
+
// language-server features are disabled (editor features remain).
|
|
58
|
+
// Changing it requires :CocRestart.
|
|
59
|
+
"codeql.cliPath": "codeql",
|
|
60
|
+
|
|
61
|
+
// Start the CodeQL language server at all. When false, no client and
|
|
62
|
+
// no commands are registered; filetype detection, language
|
|
63
|
+
// configuration and highlighting are unaffected.
|
|
64
|
+
"codeql.languageServer.enable": true,
|
|
65
|
+
|
|
66
|
+
// How the server checks for QL errors — passed as --check-errors.
|
|
67
|
+
// "ON_CHANGE" (default): diagnostics are compiled and published
|
|
68
|
+
// in the background as you edit (live diagnostics).
|
|
69
|
+
// "EXPLICIT": the server runs no background checking and never
|
|
70
|
+
// publishes diagnostics; useful to silence diagnostics on slow
|
|
71
|
+
// machines or huge workspaces while keeping completion, hover
|
|
72
|
+
// and definition. Despite the name, there is no way to request
|
|
73
|
+
// checks on demand in the current protocol (verified against
|
|
74
|
+
// CLI 2.27.0).
|
|
75
|
+
// Re-read whenever the server starts (activation or restart).
|
|
76
|
+
"codeql.languageServer.checkErrors": "ON_CHANGE"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Commands:
|
|
81
|
+
|
|
82
|
+
| Command | Effect |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `:CocCommand codeql.restartLanguageServer` | Restart the language server (re-reads `checkErrors`). |
|
|
85
|
+
|
|
86
|
+
Protocol details and semantics:
|
|
87
|
+
[docs/language-server.md](docs/language-server.md).
|
|
88
|
+
|
|
89
|
+
## Development
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
pnpm build # esbuild → lib/index.js (also runs on pnpm install)
|
|
93
|
+
pnpm watch # rebuild on change
|
|
94
|
+
pnpm typecheck # tsc --noEmit for src and tests
|
|
95
|
+
pnpm lint # eslint — errors on any @deprecated API usage
|
|
96
|
+
pnpm lint:md # markdownlint over all markdown files
|
|
97
|
+
pnpm check # typecheck + lint + lint:md
|
|
98
|
+
pnpm test # test/*.test.ts — the feature suite (coc-test)
|
|
99
|
+
pnpm test:variants # test/variants/* — configuration-variant suites
|
|
100
|
+
pnpm test:all # check + both test suites
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The LSP suites skip when `codeql` is not on `PATH`. The highlighting
|
|
104
|
+
suites that need a real parser skip when none is found; point
|
|
105
|
+
`COC_CODEQL_PARSER_DIR` at a directory containing `parser/ql.so` and
|
|
106
|
+
`queries/ql/` to provide one. `test:variants` injects settings before
|
|
107
|
+
activation through `COC_CODEQL_SETTINGS`
|
|
108
|
+
(see `scripts/test-setup.mjs`).
|
|
109
|
+
|
|
110
|
+
## Roadmap
|
|
111
|
+
|
|
112
|
+
Measured against vscode-codeql's feature set (query execution,
|
|
113
|
+
database management, variant analysis, …), this extension currently
|
|
114
|
+
implements the language-editing foundation. Plans:
|
|
115
|
+
|
|
116
|
+
**Editing experience**
|
|
117
|
+
|
|
118
|
+
- [x] Language server: diagnostics, completion, hover, definition,
|
|
119
|
+
references, document symbols, formatting, rename
|
|
120
|
+
- [x] Syntax highlighting & folding (tree-sitter)
|
|
121
|
+
- [x] Filetype detection and language configuration
|
|
122
|
+
- [ ] Semantic tokens / richer highlighting from the server
|
|
123
|
+
- [ ] Inlay hints exposure (the server supports them; coc wiring needed)
|
|
124
|
+
|
|
125
|
+
**Query development**
|
|
126
|
+
|
|
127
|
+
- [ ] Run query against the current database
|
|
128
|
+
(`codeql query run` / the query server)
|
|
129
|
+
- [ ] Quick evaluation of the selected predicate/expressions
|
|
130
|
+
- [ ] Results viewing (export to CSV/SARIF, a results buffer)
|
|
131
|
+
- [ ] Query history
|
|
132
|
+
- [ ] `.qltest` test running and output comparison
|
|
133
|
+
|
|
134
|
+
**Database management**
|
|
135
|
+
|
|
136
|
+
- [ ] Database selection UI (`:CocList`-style picker)
|
|
137
|
+
- [ ] Database overview (language, upgrade hints)
|
|
138
|
+
|
|
139
|
+
**Workspace & packs**
|
|
140
|
+
|
|
141
|
+
- [ ] `codeql pack install` / dependency management commands
|
|
142
|
+
- [ ] qlpack-aware workspace features (smart workspace detection)
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# CodeQL language server integration
|
|
2
|
+
|
|
3
|
+
Reference for how coc-codeql drives `codeql execute language-server`.
|
|
4
|
+
Facts below were established against CLI **2.27.0** by raw stdio
|
|
5
|
+
JSON-RPC probing, by reading the shipped bytecode
|
|
6
|
+
(`com.semmle.frontend.server.*` in `tools/codeql.jar`), and by the
|
|
7
|
+
end-to-end tests in `test/`.
|
|
8
|
+
|
|
9
|
+
## Server
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
codeql execute language-server --check-errors ON_CHANGE|EXPLICIT
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- LSP over stdio (Content-Length framed JSON-RPC on stdin/stdout).
|
|
16
|
+
- Older CLI releases used the subcommand `executeLanguageServer`.
|
|
17
|
+
- `--search-path` exists but is not needed: the server discovers
|
|
18
|
+
qlpacks recursively under the workspace folders sent at
|
|
19
|
+
`initialize` and resolves dependencies through the pack cache
|
|
20
|
+
(`~/.codeql/packages`, populated by `codeql pack install`). Run
|
|
21
|
+
`codeql pack install` in your qlpack once.
|
|
22
|
+
- `--synchronous` exists for debugging; not used here.
|
|
23
|
+
|
|
24
|
+
### Capabilities (from `initialize`)
|
|
25
|
+
|
|
26
|
+
| Capability | Notes |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| diagnostics | pushed on change (ON_CHANGE mode); qlpack.yml files get published too |
|
|
29
|
+
| completion | trigger characters `.` and `,`; member + import completion |
|
|
30
|
+
| hover | markdown; predicate signature + doc comment |
|
|
31
|
+
| definition | jumps into the pack cache (`.qll` files) |
|
|
32
|
+
| references / documentHighlight / documentSymbol | |
|
|
33
|
+
| formatting (document + range) | |
|
|
34
|
+
| rename (+ prepareRename) | |
|
|
35
|
+
| inlayHint | |
|
|
36
|
+
| signatureHelp, codeAction, codeLens | |
|
|
37
|
+
| workspace folders | `supported: true, changeNotifications: true` |
|
|
38
|
+
| experimental | `checkErrorsProvider`, `guessLocationProvider` (both advertised unconditionally; see below) |
|
|
39
|
+
|
|
40
|
+
### Custom protocol surface
|
|
41
|
+
|
|
42
|
+
Beyond standard LSP, the server speaks:
|
|
43
|
+
|
|
44
|
+
- `textDocument/codeQLDidChangeVisibleFiles` (client → server,
|
|
45
|
+
notification) — sent by vscode-codeql when visible editors change.
|
|
46
|
+
**Not required**: diagnostics, completion, hover and definition all
|
|
47
|
+
work without it; not implemented here.
|
|
48
|
+
- `semmle/workspace/guessLocation` (client → server, request) — used
|
|
49
|
+
by upstream to "guess the qlpack for this file"; not implemented
|
|
50
|
+
here.
|
|
51
|
+
- `qlDidLoadConfiguration` (server → client, notification) — fired
|
|
52
|
+
after `workspace/didChangeConfiguration` is processed; carries
|
|
53
|
+
`ConfigurationLoadErrors`.
|
|
54
|
+
|
|
55
|
+
The server dynamically registers `workspace/didChangeWatchedFiles`
|
|
56
|
+
(requires the client to advertise the capability) and watches
|
|
57
|
+
`qlpack.yml`, `codeql-pack.yml`, `codeql-workspace.yml`,
|
|
58
|
+
`.codeqlmanifest.json`, `.dbscheme`, `*.ql`, `*.qll`.
|
|
59
|
+
|
|
60
|
+
### Protocol requirements
|
|
61
|
+
|
|
62
|
+
1. **`initialize.workspaceFolders` is mandatory.** With only `rootUri`,
|
|
63
|
+
every import fails with `could not resolve module …`. coc's
|
|
64
|
+
`LanguageClient` fills `workspaceFolders` from its workspace root
|
|
65
|
+
detection natively — nothing to do on our side.
|
|
66
|
+
2. `initialize` must not be followed by an unknown-option spawn: the
|
|
67
|
+
CLI rejects any extra arguments (see the `--stdio` pitfall below).
|
|
68
|
+
|
|
69
|
+
## Client wiring (src/lsp.ts)
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const serverOptions: ServerOptions = async () => {
|
|
73
|
+
serverProcess?.kill()
|
|
74
|
+
serverProcess = spawnChild(cli, serverArgs()) // re-reads configuration
|
|
75
|
+
return serverProcess
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const clientOptions: LanguageClientOptions = {
|
|
79
|
+
documentSelector: [
|
|
80
|
+
{ language: 'ql', scheme: 'file' },
|
|
81
|
+
{ language: 'yaml', scheme: 'file', pattern: '**/qlpack.yml' },
|
|
82
|
+
{ language: 'yaml', scheme: 'file', pattern: '**/codeql-pack.yml' },
|
|
83
|
+
{ language: 'yaml', scheme: 'file', pattern: '**/codeql-workspace.yml' },
|
|
84
|
+
],
|
|
85
|
+
outputChannelName: 'codeql',
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Design notes:
|
|
90
|
+
|
|
91
|
+
- **Function-form `ServerOptions`.** The extension spawns the server
|
|
92
|
+
itself on every start. The static `{ command, args }` form has two
|
|
93
|
+
problems: coc appends `--stdio` for explicit stdio transports, which
|
|
94
|
+
the codeql CLI rejects (`Unknown option: '--stdio'`, crash-looping
|
|
95
|
+
the client); and static args would be frozen at activation, so
|
|
96
|
+
`codeql.languageServer.checkErrors` could never take effect across a
|
|
97
|
+
restart. The function form avoids both; coc consumes the child's
|
|
98
|
+
stdin/stdout directly. The child is killed on disposal.
|
|
99
|
+
- **documentSelector** matches vscode-codeql's, plus
|
|
100
|
+
`**/codeql-workspace.yml` (upstream lists only qlpack.yml and
|
|
101
|
+
codeql-pack.yml).
|
|
102
|
+
- The server is spawned eagerly at activation. coc's service-wrapper
|
|
103
|
+
state shown in `:CocList services` still reads `initial` until the
|
|
104
|
+
first matching buffer opens — a display quirk of coc, not the actual
|
|
105
|
+
process state.
|
|
106
|
+
|
|
107
|
+
## Configuration semantics
|
|
108
|
+
|
|
109
|
+
- `codeql.cliPath` — `"codeql"` (default) or a path. Resolved via
|
|
110
|
+
`exepath` once at activation; if missing, a warning is shown and the
|
|
111
|
+
LSP features are disabled (editor features remain). Changing it
|
|
112
|
+
requires `:CocRestart`.
|
|
113
|
+
- `codeql.languageServer.enable` — `true` (default) / `false`. When
|
|
114
|
+
`false`, no client and no commands are registered; editor features
|
|
115
|
+
remain. Read at activation.
|
|
116
|
+
- `codeql.languageServer.checkErrors` — `"ON_CHANGE"` (default) /
|
|
117
|
+
`"EXPLICIT"`, passed as `--check-errors`. Re-read on every server
|
|
118
|
+
start (activation and `codeql.restartLanguageServer`); see below.
|
|
119
|
+
|
|
120
|
+
### `checkErrors` — what the values actually do
|
|
121
|
+
|
|
122
|
+
Established from the CLI bytecode and covered by
|
|
123
|
+
`test/explicit-mode.test.ts`:
|
|
124
|
+
|
|
125
|
+
- `ON_CHANGE` — the server constructs an `AsynchronousDiagnosticReporter`
|
|
126
|
+
that compiles changed QL files in the background and pushes
|
|
127
|
+
`textDocument/publishDiagnostics`. Live diagnostics.
|
|
128
|
+
- `EXPLICIT` — the reporter is never created, and **no diagnostics are
|
|
129
|
+
published at all**. Despite the advertised
|
|
130
|
+
`experimental.checkErrorsProvider: true` capability, this protocol
|
|
131
|
+
generation has no request that triggers checks on demand — the flag
|
|
132
|
+
is vestigial. Practical use: silence diagnostics on slow machines or
|
|
133
|
+
huge workspaces while keeping completion/hover/definition (those
|
|
134
|
+
still compile on demand).
|
|
135
|
+
|
|
136
|
+
## Commands
|
|
137
|
+
|
|
138
|
+
| Command | Effect |
|
|
139
|
+
| --- | --- |
|
|
140
|
+
| `codeql.restartLanguageServer` | Stop + start the server; re-reads `checkErrors`. |
|
|
141
|
+
|
|
142
|
+
## Out of scope
|
|
143
|
+
|
|
144
|
+
- Query execution, quick evaluation, results/BQRS inspection — the
|
|
145
|
+
*query server* (`codeql execute query-server2`), a separate JSON-RPC
|
|
146
|
+
protocol, not LSP.
|
|
147
|
+
- `.qltest` running and test-output acceptance.
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
activate: () => activate
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var import_node_path = __toESM(require("node:path"));
|
|
37
|
+
var import_coc2 = require("coc.nvim");
|
|
38
|
+
|
|
39
|
+
// src/lsp.ts
|
|
40
|
+
var import_node_child_process = require("node:child_process");
|
|
41
|
+
var import_coc = require("coc.nvim");
|
|
42
|
+
async function resolveCli() {
|
|
43
|
+
const config = import_coc.workspace.getConfiguration("codeql");
|
|
44
|
+
const cliPath = config.get("cliPath", "codeql");
|
|
45
|
+
const resolved = await import_coc.workspace.nvim.call("exepath", [cliPath]);
|
|
46
|
+
return resolved === "" ? void 0 : resolved;
|
|
47
|
+
}
|
|
48
|
+
function serverArgs() {
|
|
49
|
+
const config = import_coc.workspace.getConfiguration("codeql");
|
|
50
|
+
const checkErrors = config.get(
|
|
51
|
+
"languageServer.checkErrors",
|
|
52
|
+
"ON_CHANGE"
|
|
53
|
+
);
|
|
54
|
+
return ["execute", "language-server", "--check-errors", checkErrors];
|
|
55
|
+
}
|
|
56
|
+
async function registerLanguageServer(context) {
|
|
57
|
+
const cli = await resolveCli();
|
|
58
|
+
if (!cli) {
|
|
59
|
+
void import_coc.window.showWarningMessage(
|
|
60
|
+
'[coc-codeql] codeql CLI not found; set "codeql.cliPath". LSP features are disabled.'
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
let serverProcess;
|
|
65
|
+
const serverOptions = async () => {
|
|
66
|
+
serverProcess?.kill();
|
|
67
|
+
serverProcess = (0, import_node_child_process.spawn)(cli, serverArgs());
|
|
68
|
+
return serverProcess;
|
|
69
|
+
};
|
|
70
|
+
const clientOptions = {
|
|
71
|
+
documentSelector: [
|
|
72
|
+
{ language: "ql", scheme: "file" },
|
|
73
|
+
{ language: "yaml", scheme: "file", pattern: "**/qlpack.yml" },
|
|
74
|
+
{ language: "yaml", scheme: "file", pattern: "**/codeql-pack.yml" },
|
|
75
|
+
{ language: "yaml", scheme: "file", pattern: "**/codeql-workspace.yml" }
|
|
76
|
+
],
|
|
77
|
+
outputChannelName: "codeql"
|
|
78
|
+
};
|
|
79
|
+
const client = new import_coc.LanguageClient(
|
|
80
|
+
"codeql",
|
|
81
|
+
"CodeQL Language Server",
|
|
82
|
+
serverOptions,
|
|
83
|
+
clientOptions
|
|
84
|
+
);
|
|
85
|
+
context.subscriptions.push(import_coc.services.registerLanguageClient(client));
|
|
86
|
+
context.subscriptions.push({
|
|
87
|
+
dispose: () => serverProcess?.kill()
|
|
88
|
+
});
|
|
89
|
+
await client.start();
|
|
90
|
+
context.subscriptions.push(
|
|
91
|
+
import_coc.commands.registerCommand(
|
|
92
|
+
"codeql.restartLanguageServer",
|
|
93
|
+
async () => {
|
|
94
|
+
await client.stop();
|
|
95
|
+
await client.start();
|
|
96
|
+
void import_coc.window.showInformationMessage(
|
|
97
|
+
"[coc-codeql] language server restarted"
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/index.ts
|
|
105
|
+
async function activate(context) {
|
|
106
|
+
const { nvim } = import_coc2.workspace;
|
|
107
|
+
await nvim.call("nvim_set_var", [
|
|
108
|
+
"coc_codeql_lua_path",
|
|
109
|
+
import_node_path.default.join(context.extensionPath, "lua", "codeql.lua")
|
|
110
|
+
]);
|
|
111
|
+
await nvim.call("nvim_exec2", [
|
|
112
|
+
"lua local m = dofile(vim.g.coc_codeql_lua_path) ; _G.coc_codeql = m ; m.setup()",
|
|
113
|
+
{ output: false }
|
|
114
|
+
]);
|
|
115
|
+
const enabled = import_coc2.workspace.getConfiguration("codeql").get("languageServer.enable", true);
|
|
116
|
+
if (enabled) {
|
|
117
|
+
await registerLanguageServer(context);
|
|
118
|
+
}
|
|
119
|
+
const parserWarning = setTimeout(() => {
|
|
120
|
+
void import_coc2.workspace.nvim.getVar("coc_codeql_parser_error").then((error) => {
|
|
121
|
+
if (typeof error === "string" && error.length > 0) {
|
|
122
|
+
void import_coc2.window.showWarningMessage(
|
|
123
|
+
`[coc-codeql] tree-sitter parser for ql not available (${error}). Install it with \`:TSInstall ql\` (nvim-treesitter) or see :h treesitter-parsers.`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}).catch(() => {
|
|
127
|
+
});
|
|
128
|
+
}, 3e3);
|
|
129
|
+
context.subscriptions.push({ dispose: () => clearTimeout(parserWarning) });
|
|
130
|
+
}
|
|
131
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
132
|
+
0 && (module.exports = {
|
|
133
|
+
activate
|
|
134
|
+
});
|
package/lua/codeql.lua
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
--- CodeQL runtime support for coc-codeql.
|
|
2
|
+
---
|
|
3
|
+
--- This extension is pure editor integration: it provides filetype
|
|
4
|
+
--- detection, the language configuration and starts tree-sitter
|
|
5
|
+
--- highlighting. The parser itself is NOT bundled — that is the job of
|
|
6
|
+
--- the tree-sitter ecosystem:
|
|
7
|
+
---
|
|
8
|
+
--- :TSInstall ql (nvim-treesitter registers the tree-sitter-ql
|
|
9
|
+
--- grammar and ships its queries)
|
|
10
|
+
---
|
|
11
|
+
--- or a manual install, see :h treesitter-parsers.
|
|
12
|
+
---
|
|
13
|
+
--- Loaded by the coc extension through dofile() and exposed as the
|
|
14
|
+
--- global `coc_codeql` (setup() is idempotent, so it can be re-run).
|
|
15
|
+
|
|
16
|
+
local M = {}
|
|
17
|
+
|
|
18
|
+
local GROUP = 'coc_codeql'
|
|
19
|
+
|
|
20
|
+
local function start_highlight(buf)
|
|
21
|
+
-- nvim-treesitter's highlight module may already have started
|
|
22
|
+
if vim.treesitter.highlighter.active[buf] then
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
local ok, err = pcall(vim.treesitter.start, buf, 'ql')
|
|
26
|
+
if not ok then
|
|
27
|
+
-- No notifying from lua: vim.notify is hooked by coc.nvim into a
|
|
28
|
+
-- synchronous RPC handler, and any editor output from a scheduled
|
|
29
|
+
-- callback can wedge the RPC channel of embedded editors. Record the
|
|
30
|
+
-- failure; the extension's node side picks it up and warns through
|
|
31
|
+
-- coc's own message channel.
|
|
32
|
+
_G.coc_codeql_parser_error = tostring(err):gsub('\n.*', '')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
local function on_filetype(buf)
|
|
37
|
+
if vim.bo[buf].buftype ~= '' then
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
--- language configuration (was language-configuration.json in the
|
|
42
|
+
--- vscode extension): line comments, comment continuation, auto-wrap
|
|
43
|
+
vim.bo[buf].commentstring = '// %s'
|
|
44
|
+
vim.bo[buf].comments = 'sO:*. -,mO:*. ,exO:*/,s1:/*,mb:*,ex:*/,://'
|
|
45
|
+
local fo = vim.bo[buf].formatoptions:gsub('t', '')
|
|
46
|
+
for _, flag in ipairs({ 'c', 'r', 'o', 'q', 'l' }) do
|
|
47
|
+
if not fo:find(flag, 1, true) then
|
|
48
|
+
fo = fo .. flag
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
vim.bo[buf].formatoptions = fo
|
|
52
|
+
|
|
53
|
+
-- Started from a timer: launching the highlighter inside the
|
|
54
|
+
-- FileType autocmd wedges nvim's embed channel (see test notes).
|
|
55
|
+
vim.fn.timer_start(50, function() start_highlight(buf) end)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
function M.setup()
|
|
59
|
+
local group = vim.api.nvim_create_augroup(GROUP, { clear = true })
|
|
60
|
+
|
|
61
|
+
-- filetype detection: nvim has no built-in detection for CodeQL
|
|
62
|
+
vim.api.nvim_create_autocmd({ 'BufReadPost', 'BufNewFile' }, {
|
|
63
|
+
group = group,
|
|
64
|
+
pattern = { '*.ql', '*.qll' },
|
|
65
|
+
callback = function(args)
|
|
66
|
+
if vim.bo[args.buf].filetype == '' then
|
|
67
|
+
vim.bo[args.buf].filetype = 'ql' -- fires FileType below
|
|
68
|
+
end
|
|
69
|
+
end,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
vim.api.nvim_create_autocmd('FileType', {
|
|
73
|
+
group = group,
|
|
74
|
+
pattern = 'ql',
|
|
75
|
+
callback = function(args)
|
|
76
|
+
on_filetype(args.buf)
|
|
77
|
+
end,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
-- fix up buffers that were loaded before setup() ran
|
|
81
|
+
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
|
|
82
|
+
if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == '' then
|
|
83
|
+
local name = vim.api.nvim_buf_get_name(buf)
|
|
84
|
+
if vim.bo[buf].filetype == '' and name:match('%.qll?$') then
|
|
85
|
+
vim.bo[buf].filetype = 'ql'
|
|
86
|
+
elseif vim.bo[buf].filetype == 'ql' then
|
|
87
|
+
on_filetype(buf)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
return M
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "coc-codeql",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CodeQL language support for coc.nvim: language server integration, filetype detection and tree-sitter highlighting",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"coc",
|
|
8
|
+
"coc.nvim",
|
|
9
|
+
"codeql",
|
|
10
|
+
"ql",
|
|
11
|
+
"tree-sitter",
|
|
12
|
+
"highlight"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"coc": ">=0.0.82"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/NitroCao/coc-codeql.git"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/NitroCao/coc-codeql#readme",
|
|
22
|
+
"bugs": "https://github.com/NitroCao/coc-codeql/issues",
|
|
23
|
+
"packageManager": "pnpm@12.5.1",
|
|
24
|
+
"activationEvents": [
|
|
25
|
+
"*"
|
|
26
|
+
],
|
|
27
|
+
"coc-test": {
|
|
28
|
+
"entryFile": "src/index.ts",
|
|
29
|
+
"setup": "scripts/test-setup.mjs"
|
|
30
|
+
},
|
|
31
|
+
"contributes": {
|
|
32
|
+
"configuration": {
|
|
33
|
+
"title": "CodeQL",
|
|
34
|
+
"properties": {
|
|
35
|
+
"codeql.cliPath": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"default": "codeql",
|
|
38
|
+
"description": "Path to the CodeQL CLI executable."
|
|
39
|
+
},
|
|
40
|
+
"codeql.languageServer.enable": {
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"default": true,
|
|
43
|
+
"description": "Start the CodeQL language server (diagnostics, completion, hover, definition)."
|
|
44
|
+
},
|
|
45
|
+
"codeql.languageServer.checkErrors": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"enum": [
|
|
48
|
+
"ON_CHANGE",
|
|
49
|
+
"EXPLICIT"
|
|
50
|
+
],
|
|
51
|
+
"default": "ON_CHANGE",
|
|
52
|
+
"description": "When to check for QL errors."
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"commands": [
|
|
57
|
+
{
|
|
58
|
+
"title": "Restart the CodeQL language server",
|
|
59
|
+
"command": "codeql.restartLanguageServer"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "node esbuild.mjs",
|
|
65
|
+
"watch": "node esbuild.mjs --watch",
|
|
66
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.test.json",
|
|
67
|
+
"lint": "eslint .",
|
|
68
|
+
"lint:md": "markdownlint-cli2 '**/*.md' '#node_modules' '#.claude'",
|
|
69
|
+
"check": "pnpm typecheck && pnpm lint && pnpm lint:md",
|
|
70
|
+
"test": "coc-test 'test/*.test.ts'",
|
|
71
|
+
"test:variants": "COC_CODEQL_SETTINGS='{\"codeql\":{\"languageServer\":{\"enable\":false}}}' coc-test 'test/variants/no-language-server.test.ts' && COC_CODEQL_SETTINGS='{\"codeql\":{\"cliPath\":\"/nonexistent/codeql\"}}' coc-test 'test/variants/cli-not-found.test.ts'",
|
|
72
|
+
"test:all": "pnpm check && pnpm test && pnpm test:variants",
|
|
73
|
+
"clean": "node -e \"require('fs').rmSync('lib',{recursive:true,force:true})\"",
|
|
74
|
+
"prepare": "node esbuild.mjs"
|
|
75
|
+
},
|
|
76
|
+
"author": "nitrocao",
|
|
77
|
+
"license": "MIT",
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@types/node": "^22.10.2",
|
|
80
|
+
"coc-test": "^0.2.0",
|
|
81
|
+
"coc.nvim": "^0.0.83-next.9",
|
|
82
|
+
"esbuild": "^0.24.2",
|
|
83
|
+
"eslint": "^9.39.5",
|
|
84
|
+
"markdownlint-cli2": "^0.23.3",
|
|
85
|
+
"typescript": "^5.7.2",
|
|
86
|
+
"typescript-eslint": "^8.70.1"
|
|
87
|
+
},
|
|
88
|
+
"files": [
|
|
89
|
+
"lib",
|
|
90
|
+
"lua",
|
|
91
|
+
"docs",
|
|
92
|
+
"README.md",
|
|
93
|
+
"LICENSE"
|
|
94
|
+
]
|
|
95
|
+
}
|