Skip to content

Commit f764283

Browse files
authored
Support auto-completion for function properties, including documentation (#73)
Example: <img width="1111" alt="image" src="https://github.com/harrisont/fastbuild-vscode/assets/144260/fb0ccd56-5b12-41f5-9b29-4ca7f34027ee"> Fixes #13. Also fixes a bug with `parser.isPositionInRange` for multi-line ranges. There's still a future opportunity to add completion for other things, like accessible variables or function names, but that will be tracked in a future issue.
1 parent 1fd17d0 commit f764283

File tree

10 files changed

+3387
-229
lines changed

10 files changed

+3387
-229
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# v0.14.0
2+
3+
## New Features
4+
5+
* ([#13](https://github.com/harrisont/fastbuild-vscode/issues/13)) Support auto-completion for function properties, including both inline documentation and a link to the offical function's documentation.
6+
7+
Example:
8+
<img width="1111" alt="example" src="https://github.com/harrisont/fastbuild-vscode/assets/144260/fb0ccd56-5b12-41f5-9b29-4ca7f34027ee">
9+
110
# v0.13.4
211

312
## Bug Fixes

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "fastbuild-support",
33
"displayName": "FASTBuild Support",
44
"description": "FASTBuild language support. Includes go-to definition, find references, variable evaluation, syntax errors, etc.",
5-
"version": "0.13.4",
5+
"version": "0.14.0",
66
"preview": true,
77
"publisher": "HarrisonT",
88
"author": {

server/src/evaluator.ts

Lines changed: 39 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -12,223 +12,20 @@ import {
1212
RESERVED_SYMBOL_NAMES,
1313
SourcePosition,
1414
Statement,
15+
createRange,
1516
} from './parser';
1617

1718
import { IFileSystem } from './fileSystem';
1819

1920
import { ParseDataProvider, UriStr } from './parseDataProvider';
2021

22+
import { GENERIC_FUNCTION_METADATA_BY_NAME } from './genericFunctions';
23+
2124
// Used to manipulate URIs.
2225
import * as vscodeUri from 'vscode-uri';
2326

2427
const MAX_SCOPE_STACK_DEPTH = 128;
2528

26-
interface PropertyAttributes {
27-
isRequired: boolean;
28-
}
29-
30-
type PropertyName = string;
31-
32-
interface GenericFunctionMetadata {
33-
properties: Map<PropertyName, PropertyAttributes>;
34-
}
35-
36-
const GENERIC_FUNCTION_METADATA_BY_NAME = new Map<PropertyName, GenericFunctionMetadata>([
37-
[ 'Alias', {
38-
properties: new Map<PropertyName, PropertyAttributes>([
39-
['Targets', {
40-
isRequired: true,
41-
}],
42-
]),
43-
}],
44-
[ 'Compiler', {
45-
properties: new Map<PropertyName, PropertyAttributes>([
46-
['Executable', {
47-
isRequired: true,
48-
}],
49-
]),
50-
}],
51-
[ 'Copy', {
52-
properties: new Map<PropertyName, PropertyAttributes>([
53-
['Source', {
54-
isRequired: true,
55-
}],
56-
['Dest', {
57-
isRequired: true,
58-
}],
59-
]),
60-
}],
61-
[ 'CopyDir', {
62-
properties: new Map<PropertyName, PropertyAttributes>([
63-
['SourcePaths', {
64-
isRequired: true,
65-
}],
66-
['Dest', {
67-
isRequired: true,
68-
}],
69-
]),
70-
}],
71-
[ 'CSAssembly', {
72-
properties: new Map<PropertyName, PropertyAttributes>([
73-
['Compiler', {
74-
isRequired: true,
75-
}],
76-
['CompilerOptions', {
77-
isRequired: true,
78-
}],
79-
['CompilerOutput', {
80-
isRequired: true,
81-
}],
82-
]),
83-
}],
84-
[ 'DLL', {
85-
properties: new Map<PropertyName, PropertyAttributes>([
86-
['Linker', {
87-
isRequired: true,
88-
}],
89-
['LinkerOutput', {
90-
isRequired: true,
91-
}],
92-
['LinkerOptions', {
93-
isRequired: true,
94-
}],
95-
['Libraries', {
96-
isRequired: true,
97-
}],
98-
]),
99-
}],
100-
[ 'Exec', {
101-
properties: new Map<PropertyName, PropertyAttributes>([
102-
['ExecExecutable', {
103-
isRequired: true,
104-
}],
105-
['ExecOutput', {
106-
isRequired: true,
107-
}],
108-
]),
109-
}],
110-
[ 'Executable', {
111-
properties: new Map<PropertyName, PropertyAttributes>([
112-
['Linker', {
113-
isRequired: true,
114-
}],
115-
['LinkerOutput', {
116-
isRequired: true,
117-
}],
118-
['LinkerOptions', {
119-
isRequired: true,
120-
}],
121-
['Libraries', {
122-
isRequired: true,
123-
}],
124-
]),
125-
}],
126-
[ 'Library', {
127-
properties: new Map<PropertyName, PropertyAttributes>([
128-
['Compiler', {
129-
isRequired: true,
130-
}],
131-
['CompilerOptions', {
132-
isRequired: true,
133-
}],
134-
['Librarian', {
135-
isRequired: true,
136-
}],
137-
['LibrarianOptions', {
138-
isRequired: true,
139-
}],
140-
['LibrarianOutput', {
141-
isRequired: true,
142-
}],
143-
]),
144-
}],
145-
[ 'ListDependencies', {
146-
properties: new Map<PropertyName, PropertyAttributes>([
147-
['Source', {
148-
isRequired: true,
149-
}],
150-
['Dest', {
151-
isRequired: true,
152-
}],
153-
]),
154-
}],
155-
[ 'ObjectList', {
156-
properties: new Map<PropertyName, PropertyAttributes>([
157-
['Compiler', {
158-
isRequired: true,
159-
}],
160-
['CompilerOptions', {
161-
isRequired: true,
162-
}],
163-
]),
164-
}],
165-
[ 'RemoveDir', {
166-
properties: new Map<PropertyName, PropertyAttributes>([
167-
['RemovePaths', {
168-
isRequired: true,
169-
}],
170-
]),
171-
}],
172-
[ 'Test', {
173-
properties: new Map<PropertyName, PropertyAttributes>([
174-
['TestExecutable', {
175-
isRequired: true,
176-
}],
177-
['TestOutput', {
178-
isRequired: true,
179-
}],
180-
]),
181-
}],
182-
[ 'TextFile', {
183-
properties: new Map<PropertyName, PropertyAttributes>([
184-
['TextFileOutput', {
185-
isRequired: true,
186-
}],
187-
['TextFileInputStrings', {
188-
isRequired: true,
189-
}],
190-
]),
191-
}],
192-
[ 'Unity', {
193-
properties: new Map<PropertyName, PropertyAttributes>([
194-
['UnityOutputPath', {
195-
isRequired: true,
196-
}],
197-
]),
198-
}],
199-
[ 'VCXProject', {
200-
properties: new Map<PropertyName, PropertyAttributes>([
201-
['ProjectOutput', {
202-
isRequired: true,
203-
}],
204-
]),
205-
}],
206-
[ 'VSProjectExternal', {
207-
properties: new Map<PropertyName, PropertyAttributes>([
208-
['ExternalProjectPath', {
209-
isRequired: true,
210-
}],
211-
]),
212-
}],
213-
[ 'VSSolution', {
214-
properties: new Map<PropertyName, PropertyAttributes>([
215-
['SolutionOutput', {
216-
isRequired: true,
217-
}],
218-
]),
219-
}],
220-
[ 'XCodeProject', {
221-
properties: new Map<PropertyName, PropertyAttributes>([
222-
['ProjectOutput', {
223-
isRequired: true,
224-
}],
225-
['ProjectConfigs', {
226-
isRequired: true,
227-
}],
228-
]),
229-
}],
230-
]);
231-
23229
export interface ErrorRelatedInformation {
23330
range: SourceRange;
23431
message: string;
@@ -357,6 +154,13 @@ export interface IncludeReference {
357154
range: SourceRange;
358155
}
359156

157+
export interface GenericFunction {
158+
functionName: string;
159+
160+
// Range of the body, without the braces.
161+
bodyRangeWithoutBraces: SourceRange;
162+
}
163+
360164
export class EvaluatedData {
361165
evaluatedVariables: EvaluatedVariable[] = [];
362166

@@ -373,6 +177,9 @@ export class EvaluatedData {
373177

374178
includeReferences: IncludeReference[] = [];
375179

180+
// Maps a file URI to the functions called in that file.
181+
genericFunctions = new Map<UriStr, GenericFunction[]>();
182+
376183
nonFatalErrors: EvaluationError[] = [];
377184
}
378185

@@ -546,7 +353,10 @@ function isParsedStatementForEach(obj: Record<string, any>): obj is ParsedStatem
546353

547354
interface ParsedStatementGenericFunction {
548355
type: 'genericFunction';
356+
// Range of the function call, not including the body.
549357
range: ParseSourceRange;
358+
// Range of the function body, including the braces.
359+
bodyRange: ParseSourceRange;
550360
functionName: string;
551361
targetName: any;
552362
statements: Statement[];
@@ -1628,6 +1438,29 @@ function evaluateStatementGenericFunction(statement: ParsedStatementGenericFunct
16281438
context.evaluatedData.targetDefinitions.set(evaluatedTargetName.value, targetNameDefinition);
16291439
context.evaluatedData.targetReferences.push(targetNameReference);
16301440

1441+
// Create a new range for the body that excludes the braces.
1442+
const bodyRangeWithoutBraces = new SourceRange(
1443+
context.thisFbuildUri,
1444+
createRange(
1445+
statement.bodyRange.start.line,
1446+
statement.bodyRange.start.character + 1,
1447+
statement.bodyRange.end.line,
1448+
statement.bodyRange.end.character - 1,
1449+
),
1450+
);
1451+
1452+
const functionData: GenericFunction = {
1453+
functionName: statement.functionName,
1454+
bodyRangeWithoutBraces,
1455+
};
1456+
1457+
let functionsInFile = context.evaluatedData.genericFunctions.get(context.thisFbuildUri);
1458+
if (functionsInFile === undefined) {
1459+
functionsInFile = [];
1460+
context.evaluatedData.genericFunctions.set(context.thisFbuildUri, functionsInFile);
1461+
}
1462+
functionsInFile.push(functionData);
1463+
16311464
// Evaluate the function body.
16321465
let error: Error | null = null;
16331466
context.scopeStack.withScope(() => {

0 commit comments

Comments
 (0)