Skip to content

Commit d2c4961

Browse files
authored
Add symbols provider (#54)
* Add symbols provider * Fix comment * Complete symbols provider * Update REAME.md and CHANGELOG * Fix minor issue with completion items provider * Keep variable complex tokens inside function ones instead of keeping a parent id * Tweak
1 parent 796fcad commit d2c4961

18 files changed

+1264
-347
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,10 @@ I think we can consider the extension stable and out of beta. A big thank you to
8484

8585
## [2.0.2]
8686

87-
- Add back the initial indexing. Its removal caused performance issues.
87+
- Indexing added back. Its removal caused performances issues.
88+
89+
## [2.1.0]
90+
91+
- New provider: [Document Symbols](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-all-symbol-definitions-within-a-document).
92+
- Fixed a small issue with the `CompletionItemsProvider`.
93+
- Goto will now _really_ work with definitions from `nwscript.nss` if the file is in your project.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ NWScript: EE Language Server is a Visual Studio Code extension for the NWScript
1515
- Range formatting
1616
- Signature help
1717
- Diagnostics
18+
- Document Symbols
1819

1920
## Dependencies
2021

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"url": "https://github.com/PhilippeChab/nwscript-ee-language-server"
99
},
1010
"license": "MIT",
11-
"version": "2.0.2",
11+
"version": "2.1.0",
1212
"author": {
1313
"name": "Philippe Chabot"
1414
},

server/src/Documents/Document.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { STATIC_PREFIX } from "./DocumentsCollection";
33
import type { ComplexToken, StructComplexToken } from "../Tokenizer/types";
44
import type DocumentsCollection from "./DocumentsCollection";
55

6-
export type OwnedComplexTokens = { owner: string | null; tokens: ComplexToken[] };
7-
export type OwnedStructComplexTokens = { owner: string | null; tokens: StructComplexToken[] };
6+
export type OwnedComplexTokens = { owner?: string; tokens: ComplexToken[] };
7+
export type OwnedStructComplexTokens = { owner?: string; tokens: StructComplexToken[] };
88

99
export default class Document {
1010
constructor(
@@ -42,13 +42,7 @@ export default class Document {
4242
}
4343

4444
public getGlobalComplexTokensWithRef(computedChildren: string[] = []): OwnedComplexTokens[] {
45-
const localStandardLibDefinitions = this.collection.get("nwscript");
46-
return [
47-
{ owner: this.base ? null : this.uri, tokens: this.complexTokens },
48-
...(localStandardLibDefinitions
49-
? [{ owner: localStandardLibDefinitions.uri, tokens: localStandardLibDefinitions.complexTokens }]
50-
: []),
51-
].concat(
45+
return [{ owner: this.base ? undefined : this.uri, tokens: this.complexTokens } as OwnedComplexTokens].concat(
5246
this.children.flatMap((child) => {
5347
// Cycling children or/and duplicates
5448
if (computedChildren.includes(child)) {
@@ -92,7 +86,7 @@ export default class Document {
9286
}
9387

9488
public getGlobalStructComplexTokensWithRef(computedChildren: string[] = []): OwnedStructComplexTokens[] {
95-
return [{ owner: this.base ? null : this.uri, tokens: this.structComplexTokens }].concat(
89+
return [{ owner: this.base ? undefined : this.uri, tokens: this.structComplexTokens } as OwnedStructComplexTokens].concat(
9690
this.children.flatMap((child) => {
9791
// Cycling children or/and duplicates
9892
if (computedChildren.includes(child)) {
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { DocumentSymbol, SymbolKind } from "vscode-languageserver";
2+
3+
import type {
4+
ComplexToken,
5+
ConstantComplexToken,
6+
FunctionComplexToken,
7+
FunctionParamComplexToken,
8+
StructComplexToken,
9+
StructPropertyComplexToken,
10+
VariableComplexToken,
11+
} from "../../Tokenizer/types";
12+
import Builder from "./Builder";
13+
14+
export default class SymbolBuilder extends Builder {
15+
public static buildItem(token: ComplexToken): DocumentSymbol {
16+
if (this.isConstantToken(token)) {
17+
return this.buildConstantItem(token);
18+
} else if (this.isVariableToken(token)) {
19+
return this.buildVariableItem(token);
20+
} else if (this.isFunctionParameterToken(token)) {
21+
return this.buildFunctionParamItem(token);
22+
} else if (this.isFunctionToken(token)) {
23+
return this.buildFunctionItem(token);
24+
} else if (this.isStructPropertyToken(token)) {
25+
return this.buildStructPropertyItem(token);
26+
} else if (this.isStructToken(token)) {
27+
return this.buildStructItem(token);
28+
} else {
29+
throw new Error("Invalid complex token. Cannot build symbol.");
30+
}
31+
}
32+
33+
private static buildConstantItem(token: ConstantComplexToken) {
34+
return DocumentSymbol.create(
35+
token.identifier,
36+
undefined,
37+
SymbolKind.Constant,
38+
{ start: token.position, end: token.position },
39+
{ start: token.position, end: token.position },
40+
);
41+
}
42+
43+
private static buildVariableItem(token: VariableComplexToken) {
44+
return DocumentSymbol.create(
45+
token.identifier,
46+
undefined,
47+
SymbolKind.Variable,
48+
{ start: token.position, end: token.position },
49+
{ start: token.position, end: token.position },
50+
);
51+
}
52+
53+
private static buildFunctionParamItem(token: FunctionParamComplexToken) {
54+
return DocumentSymbol.create(
55+
token.identifier,
56+
undefined,
57+
SymbolKind.TypeParameter,
58+
{ start: token.position, end: token.position },
59+
{ start: token.position, end: token.position },
60+
);
61+
}
62+
63+
private static buildFunctionItem(token: FunctionComplexToken) {
64+
const paramSymbols = token.params.map((child) => SymbolBuilder.buildItem(child)) || [];
65+
const variableSymbols = token.variables?.map((child) => SymbolBuilder.buildItem(child)) || [];
66+
67+
return DocumentSymbol.create(
68+
token.identifier,
69+
undefined,
70+
SymbolKind.Function,
71+
{ start: token.position, end: token.position },
72+
{ start: token.position, end: token.position },
73+
paramSymbols.concat(variableSymbols),
74+
);
75+
}
76+
77+
private static buildStructPropertyItem(token: StructPropertyComplexToken) {
78+
return DocumentSymbol.create(
79+
token.identifier,
80+
undefined,
81+
SymbolKind.Property,
82+
{ start: token.position, end: token.position },
83+
{ start: token.position, end: token.position },
84+
);
85+
}
86+
87+
private static buildStructItem(token: StructComplexToken) {
88+
const symbols = token.properties?.map((child) => SymbolBuilder.buildItem(child));
89+
90+
return DocumentSymbol.create(
91+
token.identifier,
92+
undefined,
93+
SymbolKind.Struct,
94+
{ start: token.position, end: token.position },
95+
{ start: token.position, end: token.position },
96+
symbols,
97+
);
98+
}
99+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import CompletionItemBuilder from "./CompletionItemBuilder";
22
import HoverContentBuilder from "./HoverContentBuilder";
33
import SignatureHelpBuilder from "./SignatureHelpBuilder";
4+
import SymbolBuilder from "./SymbolBuilder";
45

5-
export { CompletionItemBuilder, HoverContentBuilder, SignatureHelpBuilder };
6+
export { CompletionItemBuilder, HoverContentBuilder, SignatureHelpBuilder, SymbolBuilder };

server/src/Providers/CompletionItemsProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default class CompletionItemsProvider extends Provider {
3737
const structVariableIdentifier = this.server.tokenizer?.findLineIdentiferFromPositionAt(
3838
liveDocument.getText(),
3939
position,
40-
-2,
40+
-1,
4141
);
4242

4343
const structIdentifer = localScope.functionVariablesComplexTokens.find(
@@ -53,7 +53,7 @@ export default class CompletionItemsProvider extends Provider {
5353
}
5454

5555
if (
56-
this.server.tokenizer?.findLineIdentiferFromPositionAt(liveDocument.getText(), position, -3) ===
56+
this.server.tokenizer?.findLineIdentiferFromPositionAt(liveDocument.getText(), position, -2) ===
5757
LanguageTypes.struct
5858
) {
5959
return document.getGlobalStructComplexTokens().map((token) => CompletionItemBuilder.buildItem(token));

server/src/Providers/GotoDefinitionProvider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,13 @@ export default class GotoDefinitionProvider extends Provider {
7474
}
7575

7676
if (!token && (tokenType === CompletionItemKind.Constant || tokenType === CompletionItemKind.Function)) {
77+
const localStandardLibDefinitions = this.server.documentsCollection.get("nwscript");
7778
const tokensWithRef = document.getGlobalComplexTokensWithRef();
79+
80+
if (localStandardLibDefinitions) {
81+
tokensWithRef.push({ owner: localStandardLibDefinitions?.uri, tokens: localStandardLibDefinitions?.complexTokens });
82+
}
83+
7884
for (let i = 0; i < tokensWithRef.length; i++) {
7985
ref = tokensWithRef[i];
8086

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { CompletionItemKind, DocumentSymbolParams } from "vscode-languageserver";
2+
3+
import type { ServerManager } from "../ServerManager";
4+
import { SymbolBuilder } from "./Builders";
5+
import { TokenizedScope } from "../Tokenizer/Tokenizer";
6+
import Provider from "./Provider";
7+
8+
export default class SymbolsProvider extends Provider {
9+
constructor(server: ServerManager) {
10+
super(server);
11+
12+
this.server.connection.onDocumentSymbol((params) => this.exceptionsWrapper(this.providerHandler(params)));
13+
}
14+
15+
private providerHandler(params: DocumentSymbolParams) {
16+
return () => {
17+
const {
18+
textDocument: { uri },
19+
} = params;
20+
21+
const liveDocument = this.server.liveDocumentsManager.get(uri);
22+
const document = this.server.documentsCollection.getFromUri(uri);
23+
24+
const constantSymbols =
25+
document?.complexTokens
26+
.filter((token) => token.tokenType === CompletionItemKind.Constant)
27+
.map((token) => SymbolBuilder.buildItem(token)) || [];
28+
29+
const structSymbols = document?.structComplexTokens.map((token) => SymbolBuilder.buildItem(token)) || [];
30+
31+
if (liveDocument) {
32+
const localScope = this.server.tokenizer?.tokenizeContent(liveDocument.getText(), TokenizedScope.local);
33+
34+
if (localScope) {
35+
return constantSymbols.concat(
36+
structSymbols.concat(localScope.functionsComplexTokens.map((token) => SymbolBuilder.buildItem(token))),
37+
);
38+
}
39+
}
40+
};
41+
}
42+
}

server/src/Providers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import SignatureHelpProvider from "./SignatureHelpProvider";
77
import DocumentFormatingProvider from "./DocumentFormattingProvider";
88
import DocumentRangeFormattingProvider from "./DocumentRangeFormattingProvider";
99
import DiagnosticsProvider from "./DiagnosticsProvider";
10+
import SymbolsProvider from "./SymbolsProvider";
1011

1112
export enum TriggerCharacters {
1213
dot = ".",
@@ -24,4 +25,5 @@ export {
2425
DocumentFormatingProvider,
2526
DocumentRangeFormattingProvider,
2627
DiagnosticsProvider,
28+
SymbolsProvider,
2729
};

0 commit comments

Comments
 (0)