@hydranium/core 1.0.0-next.105 → 1.0.0-next.107
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/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
- package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
- package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
- package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
- package/package.json +5 -5
- package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
|
-
import { type AstNodeDescription, type ReferenceInfo, type Stream } from '@hydranium/langium';
|
|
9
|
+
import { type AstNodeDescription, type LangiumDocument, type ReferenceInfo, type Stream } from '@hydranium/langium';
|
|
10
10
|
import { DefaultCompletionProvider, type CompletionContext, type CompletionValueItem } from '@hydranium/langium/lsp';
|
|
11
|
-
import type
|
|
11
|
+
import { CompletionList, type CancellationToken, type CompletionItem, type CompletionParams, type Position } from 'vscode-languageserver';
|
|
12
12
|
import { type ReferenceCandidateProvider } from '../../langium/scope/reference-candidate-provider.js';
|
|
13
13
|
import { type ServerLanguageServices } from '../../langium/language-module.js';
|
|
14
14
|
/**
|
|
@@ -50,10 +50,52 @@ import { type ServerLanguageServices } from '../../langium/language-module.js';
|
|
|
50
50
|
* elements. The provider owns that pipeline in one place, so the
|
|
51
51
|
* text-editor dropdown and the protocol candidate picker stay in sync; this
|
|
52
52
|
* class keeps only the LSP-specific {@link fillCompletionItem} upgrade.
|
|
53
|
+
*
|
|
54
|
+
* **A comment is not a completion site.** Langium's context builder reads the
|
|
55
|
+
* non-hidden token stream alone, so a cursor in a comment is indistinguishable
|
|
56
|
+
* from one in the whitespace between the tokens surrounding it: the grammar's
|
|
57
|
+
* follow-set goes out as keyword proposals, and none of them is filtered,
|
|
58
|
+
* because the characters the user typed belong to the hidden token and the
|
|
59
|
+
* prefix matched against is therefore empty. {@link isInsideComment} suppresses
|
|
60
|
+
* the request instead.
|
|
53
61
|
*/
|
|
54
62
|
export declare class HydraniumCompletionProvider extends DefaultCompletionProvider {
|
|
55
63
|
protected readonly candidateProvider: ReferenceCandidateProvider;
|
|
56
64
|
constructor(services: ServerLanguageServices);
|
|
65
|
+
/**
|
|
66
|
+
* Answer no proposals at all when the cursor is inside a comment.
|
|
67
|
+
*
|
|
68
|
+
* Suppressing the whole request is what makes the rule hold for every
|
|
69
|
+
* proposal kind at once. Filtering the built contexts instead has to catch
|
|
70
|
+
* each context kind the base builds separately, and a kind added upstream
|
|
71
|
+
* arrives unguarded.
|
|
72
|
+
*
|
|
73
|
+
* The list is marked incomplete so the client re-asks on the next keystroke
|
|
74
|
+
* and proposals resume the moment the cursor leaves the comment.
|
|
75
|
+
*/
|
|
76
|
+
getCompletion(document: LangiumDocument, params: CompletionParams, cancelToken?: CancellationToken): Promise<CompletionList | undefined>;
|
|
77
|
+
/**
|
|
78
|
+
* Whether `position` falls in text a comment terminal claims.
|
|
79
|
+
*
|
|
80
|
+
* The two comment kinds part company at their far edge. A single-line
|
|
81
|
+
* comment runs to the line break, so a cursor at its end offset is still in
|
|
82
|
+
* prose and that offset counts as inside. A multi-line comment is
|
|
83
|
+
* terminated, so a cursor at its end offset has passed the terminator and is
|
|
84
|
+
* back in code. A cursor ON the opening delimiter is outside either way,
|
|
85
|
+
* that offset being a legal position for whatever token the comment
|
|
86
|
+
* displaced.
|
|
87
|
+
*
|
|
88
|
+
* The hidden token stream decides rather than the CST. A leaf lookup by
|
|
89
|
+
* offset misses the position a cursor reaches by typing prose into a
|
|
90
|
+
* trailing comment, because that comment ends AT the line break and
|
|
91
|
+
* whitespace is discarded before a CST node is built over it — so the
|
|
92
|
+
* lookup answers nothing exactly where proposals are least wanted.
|
|
93
|
+
*
|
|
94
|
+
* An adopter whose comment syntax carries completable content — a
|
|
95
|
+
* documentation tag naming a type — narrows this to return `false` over that
|
|
96
|
+
* region rather than replacing {@link getCompletion}.
|
|
97
|
+
*/
|
|
98
|
+
protected isInsideComment(document: LangiumDocument, position: Position): boolean;
|
|
57
99
|
/**
|
|
58
100
|
* Delegate cross-reference candidate gathering to the candidate provider
|
|
59
101
|
* so the LSP completion dropdown applies the same filter / canonical
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydranium-completion-provider.d.ts","sourceRoot":"","sources":["../../../src/lsp/completion/hydranium-completion-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"hydranium-completion-provider.d.ts","sourceRoot":"","sources":["../../../src/lsp/completion/hydranium-completion-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACpH,OAAO,EAAE,yBAAyB,EAAE,KAAK,iBAAiB,EAAE,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACrH,OAAO,EACJ,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAErB,KAAK,QAAQ,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,qDAAqD,CAAC;AACtG,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,qBAAa,2BAA4B,SAAQ,yBAAyB;IACvE,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;gBAErD,QAAQ,EAAE,sBAAsB;IAK5C;;;;;;;;;;OAUG;IACY,aAAa,CACzB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,gBAAgB,EACxB,WAAW,CAAC,EAAE,iBAAiB,GAC/B,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAOtC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAsBjF;;;;;;;OAOG;cACgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAAC,kBAAkB,CAAC;cAIvG,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,mBAAmB,GAAG,cAAc,GAAG,SAAS;IAsBxH;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM;CAcnE"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
import { DefaultCompletionProvider } from '@hydranium/langium/lsp';
|
|
10
|
+
import { CompletionList } from 'vscode-languageserver';
|
|
10
11
|
/**
|
|
11
12
|
* Completion provider that upgrades Langium's default `TextEdit` to
|
|
12
13
|
* {@link InsertReplaceEdit} so accepting a suggestion over an existing token
|
|
@@ -46,6 +47,14 @@ import { DefaultCompletionProvider } from '@hydranium/langium/lsp';
|
|
|
46
47
|
* elements. The provider owns that pipeline in one place, so the
|
|
47
48
|
* text-editor dropdown and the protocol candidate picker stay in sync; this
|
|
48
49
|
* class keeps only the LSP-specific {@link fillCompletionItem} upgrade.
|
|
50
|
+
*
|
|
51
|
+
* **A comment is not a completion site.** Langium's context builder reads the
|
|
52
|
+
* non-hidden token stream alone, so a cursor in a comment is indistinguishable
|
|
53
|
+
* from one in the whitespace between the tokens surrounding it: the grammar's
|
|
54
|
+
* follow-set goes out as keyword proposals, and none of them is filtered,
|
|
55
|
+
* because the characters the user typed belong to the hidden token and the
|
|
56
|
+
* prefix matched against is therefore empty. {@link isInsideComment} suppresses
|
|
57
|
+
* the request instead.
|
|
49
58
|
*/
|
|
50
59
|
export class HydraniumCompletionProvider extends DefaultCompletionProvider {
|
|
51
60
|
candidateProvider;
|
|
@@ -53,6 +62,65 @@ export class HydraniumCompletionProvider extends DefaultCompletionProvider {
|
|
|
53
62
|
super(services);
|
|
54
63
|
this.candidateProvider = services.references.CandidateProvider;
|
|
55
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Answer no proposals at all when the cursor is inside a comment.
|
|
67
|
+
*
|
|
68
|
+
* Suppressing the whole request is what makes the rule hold for every
|
|
69
|
+
* proposal kind at once. Filtering the built contexts instead has to catch
|
|
70
|
+
* each context kind the base builds separately, and a kind added upstream
|
|
71
|
+
* arrives unguarded.
|
|
72
|
+
*
|
|
73
|
+
* The list is marked incomplete so the client re-asks on the next keystroke
|
|
74
|
+
* and proposals resume the moment the cursor leaves the comment.
|
|
75
|
+
*/
|
|
76
|
+
async getCompletion(document, params, cancelToken) {
|
|
77
|
+
if (this.isInsideComment(document, params.position)) {
|
|
78
|
+
return CompletionList.create([], true);
|
|
79
|
+
}
|
|
80
|
+
return super.getCompletion(document, params, cancelToken);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether `position` falls in text a comment terminal claims.
|
|
84
|
+
*
|
|
85
|
+
* The two comment kinds part company at their far edge. A single-line
|
|
86
|
+
* comment runs to the line break, so a cursor at its end offset is still in
|
|
87
|
+
* prose and that offset counts as inside. A multi-line comment is
|
|
88
|
+
* terminated, so a cursor at its end offset has passed the terminator and is
|
|
89
|
+
* back in code. A cursor ON the opening delimiter is outside either way,
|
|
90
|
+
* that offset being a legal position for whatever token the comment
|
|
91
|
+
* displaced.
|
|
92
|
+
*
|
|
93
|
+
* The hidden token stream decides rather than the CST. A leaf lookup by
|
|
94
|
+
* offset misses the position a cursor reaches by typing prose into a
|
|
95
|
+
* trailing comment, because that comment ends AT the line break and
|
|
96
|
+
* whitespace is discarded before a CST node is built over it — so the
|
|
97
|
+
* lookup answers nothing exactly where proposals are least wanted.
|
|
98
|
+
*
|
|
99
|
+
* An adopter whose comment syntax carries completable content — a
|
|
100
|
+
* documentation tag naming a type — narrows this to return `false` over that
|
|
101
|
+
* region rather than replacing {@link getCompletion}.
|
|
102
|
+
*/
|
|
103
|
+
isInsideComment(document, position) {
|
|
104
|
+
const text = document.textDocument.getText();
|
|
105
|
+
const offset = document.textDocument.offsetAt(position);
|
|
106
|
+
const multilineCommentRules = this.grammarConfig.multilineCommentRules;
|
|
107
|
+
for (const token of this.lexer.tokenize(text).hidden) {
|
|
108
|
+
if (token.startOffset >= offset) {
|
|
109
|
+
// Hidden tokens arrive in document order, so no later one reaches back over the cursor.
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
// `endOffset` is optional on the token type and the image is not, so
|
|
113
|
+
// the width comes from the image and needs no absent-value branch.
|
|
114
|
+
const endOffset = token.startOffset + token.image.length;
|
|
115
|
+
if (offset < endOffset) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
if (offset === endOffset && !multilineCommentRules.includes(token.tokenType.name)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
56
124
|
/**
|
|
57
125
|
* Delegate cross-reference candidate gathering to the candidate provider
|
|
58
126
|
* so the LSP completion dropdown applies the same filter / canonical
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydranium-completion-provider.js","sourceRoot":"","sources":["../../../src/lsp/completion/hydranium-completion-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,EAAE,yBAAyB,EAAoD,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"hydranium-completion-provider.js","sourceRoot":"","sources":["../../../src/lsp/completion/hydranium-completion-provider.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/core",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.107",
|
|
4
4
|
"description": "Foundational runtime of the hydranium framework: AST coordination layer (services, integrity, AST extension, serialization, multi-client documents) plus the LSP textual head at the /lsp subpath. Consumed by protocol-head packages (@hydranium/data-server, @hydranium/glsp-server).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hydranium",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"diff": "^5.2.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@hydranium/langium": "1.0.0-next.
|
|
108
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
107
|
+
"@hydranium/langium": "1.0.0-next.107",
|
|
108
|
+
"@hydranium/protocol": "1.0.0-next.107",
|
|
109
109
|
"@playwright/test": "^1.40.0",
|
|
110
110
|
"@types/diff": "^5.2.0",
|
|
111
111
|
"rimraf": "^5.0.0",
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
"vscode-languageserver-types": "^3.17.5"
|
|
118
118
|
},
|
|
119
119
|
"peerDependencies": {
|
|
120
|
-
"@hydranium/langium": "1.0.0-next.
|
|
121
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
120
|
+
"@hydranium/langium": "1.0.0-next.107",
|
|
121
|
+
"@hydranium/protocol": "1.0.0-next.107",
|
|
122
122
|
"@playwright/test": "^1.40.0",
|
|
123
123
|
"vscode-jsonrpc": "9.0.1",
|
|
124
124
|
"vscode-languageserver": "~10.0.1",
|
|
@@ -7,9 +7,16 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
|
-
import { type AstNodeDescription, type ReferenceInfo, type Stream } from '@hydranium/langium';
|
|
10
|
+
import { type AstNodeDescription, type LangiumDocument, type ReferenceInfo, type Stream } from '@hydranium/langium';
|
|
11
11
|
import { DefaultCompletionProvider, type CompletionContext, type CompletionValueItem } from '@hydranium/langium/lsp';
|
|
12
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
CompletionList,
|
|
14
|
+
type CancellationToken,
|
|
15
|
+
type CompletionItem,
|
|
16
|
+
type CompletionParams,
|
|
17
|
+
type InsertReplaceEdit,
|
|
18
|
+
type Position
|
|
19
|
+
} from 'vscode-languageserver';
|
|
13
20
|
import { type ReferenceCandidateProvider } from '../../langium/scope/reference-candidate-provider.js';
|
|
14
21
|
import { type ServerLanguageServices } from '../../langium/language-module.js';
|
|
15
22
|
|
|
@@ -52,6 +59,14 @@ import { type ServerLanguageServices } from '../../langium/language-module.js';
|
|
|
52
59
|
* elements. The provider owns that pipeline in one place, so the
|
|
53
60
|
* text-editor dropdown and the protocol candidate picker stay in sync; this
|
|
54
61
|
* class keeps only the LSP-specific {@link fillCompletionItem} upgrade.
|
|
62
|
+
*
|
|
63
|
+
* **A comment is not a completion site.** Langium's context builder reads the
|
|
64
|
+
* non-hidden token stream alone, so a cursor in a comment is indistinguishable
|
|
65
|
+
* from one in the whitespace between the tokens surrounding it: the grammar's
|
|
66
|
+
* follow-set goes out as keyword proposals, and none of them is filtered,
|
|
67
|
+
* because the characters the user typed belong to the hidden token and the
|
|
68
|
+
* prefix matched against is therefore empty. {@link isInsideComment} suppresses
|
|
69
|
+
* the request instead.
|
|
55
70
|
*/
|
|
56
71
|
export class HydraniumCompletionProvider extends DefaultCompletionProvider {
|
|
57
72
|
protected readonly candidateProvider: ReferenceCandidateProvider;
|
|
@@ -61,6 +76,71 @@ export class HydraniumCompletionProvider extends DefaultCompletionProvider {
|
|
|
61
76
|
this.candidateProvider = services.references.CandidateProvider;
|
|
62
77
|
}
|
|
63
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Answer no proposals at all when the cursor is inside a comment.
|
|
81
|
+
*
|
|
82
|
+
* Suppressing the whole request is what makes the rule hold for every
|
|
83
|
+
* proposal kind at once. Filtering the built contexts instead has to catch
|
|
84
|
+
* each context kind the base builds separately, and a kind added upstream
|
|
85
|
+
* arrives unguarded.
|
|
86
|
+
*
|
|
87
|
+
* The list is marked incomplete so the client re-asks on the next keystroke
|
|
88
|
+
* and proposals resume the moment the cursor leaves the comment.
|
|
89
|
+
*/
|
|
90
|
+
override async getCompletion(
|
|
91
|
+
document: LangiumDocument,
|
|
92
|
+
params: CompletionParams,
|
|
93
|
+
cancelToken?: CancellationToken
|
|
94
|
+
): Promise<CompletionList | undefined> {
|
|
95
|
+
if (this.isInsideComment(document, params.position)) {
|
|
96
|
+
return CompletionList.create([], true);
|
|
97
|
+
}
|
|
98
|
+
return super.getCompletion(document, params, cancelToken);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Whether `position` falls in text a comment terminal claims.
|
|
103
|
+
*
|
|
104
|
+
* The two comment kinds part company at their far edge. A single-line
|
|
105
|
+
* comment runs to the line break, so a cursor at its end offset is still in
|
|
106
|
+
* prose and that offset counts as inside. A multi-line comment is
|
|
107
|
+
* terminated, so a cursor at its end offset has passed the terminator and is
|
|
108
|
+
* back in code. A cursor ON the opening delimiter is outside either way,
|
|
109
|
+
* that offset being a legal position for whatever token the comment
|
|
110
|
+
* displaced.
|
|
111
|
+
*
|
|
112
|
+
* The hidden token stream decides rather than the CST. A leaf lookup by
|
|
113
|
+
* offset misses the position a cursor reaches by typing prose into a
|
|
114
|
+
* trailing comment, because that comment ends AT the line break and
|
|
115
|
+
* whitespace is discarded before a CST node is built over it — so the
|
|
116
|
+
* lookup answers nothing exactly where proposals are least wanted.
|
|
117
|
+
*
|
|
118
|
+
* An adopter whose comment syntax carries completable content — a
|
|
119
|
+
* documentation tag naming a type — narrows this to return `false` over that
|
|
120
|
+
* region rather than replacing {@link getCompletion}.
|
|
121
|
+
*/
|
|
122
|
+
protected isInsideComment(document: LangiumDocument, position: Position): boolean {
|
|
123
|
+
const text = document.textDocument.getText();
|
|
124
|
+
const offset = document.textDocument.offsetAt(position);
|
|
125
|
+
const multilineCommentRules = this.grammarConfig.multilineCommentRules;
|
|
126
|
+
for (const token of this.lexer.tokenize(text).hidden) {
|
|
127
|
+
if (token.startOffset >= offset) {
|
|
128
|
+
// Hidden tokens arrive in document order, so no later one reaches back over the cursor.
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
// `endOffset` is optional on the token type and the image is not, so
|
|
132
|
+
// the width comes from the image and needs no absent-value branch.
|
|
133
|
+
const endOffset = token.startOffset + token.image.length;
|
|
134
|
+
if (offset < endOffset) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (offset === endOffset && !multilineCommentRules.includes(token.tokenType.name)) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
|
|
64
144
|
/**
|
|
65
145
|
* Delegate cross-reference candidate gathering to the candidate provider
|
|
66
146
|
* so the LSP completion dropdown applies the same filter / canonical
|