Skip to content

Commit c9c37c8

Browse files
committed
Merge branch 'main' into feature/monitor_code_action
Signed-off-by: worksofliam <[email protected]>
2 parents 4b59507 + 90782ff commit c9c37c8

File tree

2 files changed

+75
-51
lines changed

2 files changed

+75
-51
lines changed

extension/server/src/providers/completionItem.ts

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import * as ileExports from './apis';
77
import skipRules from './linter/skipRules';
88
import * as Project from "./project";
99
import { getInterfaces } from './project/exportInterfaces';
10+
import Parser from '../../../../language/parser';
1011

1112
const completionKind = {
12-
function: CompletionItemKind.Function,
13-
struct: CompletionItemKind.Struct
13+
function: CompletionItemKind.Function,
14+
struct: CompletionItemKind.Struct
1415
};
1516

1617
const eol = `\n`;
@@ -29,10 +30,10 @@ export default async function completionItemProvider(handler: CompletionParams):
2930
const isFree = (document.getText(Range.create(0, 0, 0, 6)).toUpperCase() === `**FREE`);
3031

3132
// If they're typing inside of a procedure, let's get the stuff from there too
32-
const currentProcedure = doc.procedures.find((proc, index) =>
33+
const currentProcedure = doc.procedures.find((proc, index) =>
3334
proc.range.start && proc.range.end &&
34-
lineNumber >= proc.range.start &&
35-
(lineNumber <= proc.range.end+1 || index === doc.procedures.length-1) &&
35+
lineNumber >= proc.range.start &&
36+
(lineNumber <= proc.range.end + 1 || index === doc.procedures.length - 1) &&
3637
currentPath === proc.position.path
3738
);
3839

@@ -45,42 +46,61 @@ export default async function completionItemProvider(handler: CompletionParams):
4546

4647
// This means we're just looking for subfields in the struct
4748
if (trigger === `.`) {
48-
let currentPosition = Position.create(handler.position.line, handler.position.character - 2);
49-
let preWord = getWordRangeAtPosition(document, currentPosition);
49+
const tokens = Parser.lineTokens(isFree ? currentLine : currentLine.length >= 7 ? currentLine.substring(7) : ``, 0, 0, true);
5050

51-
// Uh oh! Maybe we found dim struct?
52-
if (preWord && preWord.includes(`)`)) {
53-
const startBracket = currentLine.lastIndexOf(`(`, currentPosition.character);
51+
if (tokens.length > 0) {
52+
const cursorIndex = handler.position.character;
53+
let tokenIndex = tokens.findIndex(token => cursorIndex > token.range.start && cursorIndex <= token.range.end);
54+
console.log(tokens);
55+
console.log({ cPos: handler.position.character, tokenIndex });
5456

55-
if (startBracket > -1) {
56-
currentPosition = Position.create(handler.position.line, startBracket - 1);
57-
preWord = getWordRangeAtPosition(document, currentPosition);
57+
while (tokens[tokenIndex] && [`block`, `word`, `dot`].includes(tokens[tokenIndex].type) && tokenIndex > 0) {
58+
tokenIndex--;
5859
}
59-
}
6060

61-
// Ok, we have a 'preWord' (the name of the struct?)
62-
if (preWord) {
63-
preWord = preWord.toUpperCase();
64-
65-
// Look at the parms or existing structs to find a possible reference
66-
const possibleStruct: Declaration | undefined = [
67-
// First we search the local procedure
68-
currentProcedure && currentProcedure.scope ? currentProcedure.scope.parameters.find(parm => parm.name.toUpperCase() === preWord && parm.subItems.length > 0) : undefined,
69-
currentProcedure && currentProcedure.scope ? currentProcedure.scope.structs.find(struct => struct.name.toUpperCase() === preWord) : undefined,
70-
currentProcedure && currentProcedure.scope ? currentProcedure.scope.constants.find(struct => struct.subItems.length > 0 && struct.name.toUpperCase() === preWord) : undefined,
71-
72-
// Then we search the globals
73-
doc.structs.find(struct => struct.name.toUpperCase() === preWord),
74-
doc.constants.find(struct => struct.subItems.length > 0 && struct.name.toUpperCase() === preWord)
75-
].find(x => x); // find the first non-undefined item
76-
77-
if (possibleStruct && possibleStruct.keyword[`QUALIFIED`]) {
78-
items.push(...possibleStruct.subItems.map(subItem => {
61+
let currentDef: Declaration | undefined;
62+
63+
for (tokenIndex; tokenIndex < tokens.length; tokenIndex++) {
64+
if ([`block`, `dot`, `newline`].includes(tokens[tokenIndex].type)) {
65+
continue;
66+
}
67+
68+
const word = tokens[tokenIndex].value?.toUpperCase();
69+
70+
if (!word) break;
71+
72+
if (currentDef) {
73+
if (currentDef.subItems && currentDef.subItems.length > 0) {
74+
currentDef = currentDef.subItems.find(subItem => subItem.name.toUpperCase() === word);
75+
}
76+
77+
} else {
78+
currentDef = [
79+
// First we search the local procedure
80+
currentProcedure && currentProcedure.scope ? currentProcedure.scope.parameters.find(parm => parm.name.toUpperCase() === word && parm.subItems.length > 0) : undefined,
81+
currentProcedure && currentProcedure.scope ? currentProcedure.scope.structs.find(struct => struct.name.toUpperCase() === word && struct.keyword[`QUALIFIED`]) : undefined,
82+
currentProcedure && currentProcedure.scope ? currentProcedure.scope.constants.find(struct => struct.subItems.length > 0 && struct.name.toUpperCase() === word) : undefined,
83+
84+
// Then we search the globals
85+
doc.structs.find(struct => struct.name.toUpperCase() === word && struct.keyword[`QUALIFIED`]),
86+
doc.constants.find(constants => constants.subItems.length > 0 && constants.name.toUpperCase() === word)
87+
].find(x => x); // find the first non-undefined item
88+
89+
if (currentDef && currentDef.subItems.length > 0) {
90+
// All good!
91+
} else {
92+
currentDef = undefined;
93+
}
94+
}
95+
}
96+
97+
if (currentDef && currentDef.subItems.length > 0) {
98+
items.push(...currentDef.subItems.map(subItem => {
7999
const item = CompletionItem.create(subItem.name);
80100
item.kind = CompletionItemKind.Property;
81101
item.insertText = subItem.name;
82102
item.detail = prettyKeywords(subItem.keyword);
83-
item.documentation = subItem.description + `${possibleStruct ? ` (${possibleStruct.name})` : ``}`;
103+
item.documentation = subItem.description + ` (${currentDef.name})`;
84104
return item;
85105
}));
86106
}
@@ -100,10 +120,10 @@ export default async function completionItemProvider(handler: CompletionParams):
100120
item.detail = file.relative;
101121
return item;
102122
}));
103-
123+
104124
} else if (currentLine.trimStart().startsWith(`//`)) {
105125
items.push(...skipRules);
106-
126+
107127
} else {
108128
const expandScope = (localCache: Cache) => {
109129
for (const subItem of localCache.parameters) {
@@ -266,7 +286,7 @@ export default async function completionItemProvider(handler: CompletionParams):
266286
kind: `markdown`,
267287
value: [
268288
currentExport.description,
269-
(currentExport.example ?
289+
(currentExport.example ?
270290
[`---`, '', '```rpgle', currentExport.example.join(eol), '```'].join(eol)
271291
: undefined)
272292
].filter(v => v).join(eol + eol)

language/parser.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ export type includeFilePromise = (baseFile: string, includeString: string) => Pr
1818
export type TableDetail = {[name: string]: {fetched: number, fetching?: boolean, recordFormats: Declaration[]}};
1919
export interface ParseOptions {withIncludes?: boolean, ignoreCache?: boolean, collectReferences?: boolean};
2020

21-
const lineTokens = (input: string, lineNumber: number, lineIndex: number): Token[] => {
22-
let tokens = tokenise(input, {
23-
baseIndex: lineIndex,
24-
lineNumber,
25-
ignoreTypes: [`tab`]
26-
});
27-
28-
return tokens;
29-
}
30-
3121
const PROGRAMPARMS_NAME = `PROGRAMPARMS`;
3222

3323
export default class Parser {
@@ -155,6 +145,20 @@ export default class Parser {
155145
}
156146
}
157147

148+
static lineTokens(input: string, lineNumber: number, lineIndex: number, withBlocks?: boolean): Token[] {
149+
let tokens = tokenise(input, {
150+
baseIndex: lineIndex,
151+
lineNumber,
152+
ignoreTypes: [`tab`]
153+
});
154+
155+
if (withBlocks) {
156+
tokens = createBlocks(tokens);
157+
}
158+
159+
return tokens;
160+
}
161+
158162
async getDocs(workingUri: string, baseContent?: string, options: ParseOptions = {withIncludes: true, collectReferences: true}): Promise<Cache|undefined> {
159163
const existingCache = this.getParsedCache(workingUri);
160164
if (options.ignoreCache !== true && existingCache) {
@@ -570,7 +574,7 @@ export default class Parser {
570574
};
571575

572576
const lineIsComment = line.trim().startsWith(`//`);
573-
tokens = lineTokens(getValidStatement(line), lineNumber, lineIndex);
577+
tokens = Parser.lineTokens(getValidStatement(line), lineNumber, lineIndex);
574578
partsLower = tokens.filter(piece => piece.value).map(piece => piece.value);
575579
parts = partsLower.map(piece => piece.toUpperCase());
576580

@@ -711,7 +715,7 @@ export default class Parser {
711715
// This means the line is just part of the end of the last statement as well.
712716
line = currentStmtStart.content + getValidStatement(baseLine);
713717

714-
tokens = lineTokens(line, currentStmtStart.line, currentStmtStart.index);
718+
tokens = Parser.lineTokens(line, currentStmtStart.line, currentStmtStart.index);
715719
partsLower = tokens.filter(piece => piece.value).map(piece => piece.value);
716720
parts = partsLower.map(piece => piece.toUpperCase());
717721

@@ -1368,7 +1372,7 @@ export default class Parser {
13681372
tokens = [cSpec.indicator, cSpec.ind1, cSpec.ind2, cSpec.ind3];
13691373

13701374
const fromToken = (token?: Token) => {
1371-
return token ? lineTokens(token.value, lineNumber, token.range.start) : [];
1375+
return token ? Parser.lineTokens(token.value, lineNumber, token.range.start) : [];
13721376
};
13731377

13741378
if (cSpec.opcode && ALLOWS_EXTENDED.includes(cSpec.opcode.value) && !cSpec.factor1 && cSpec.extended) {
@@ -1769,10 +1773,10 @@ export default class Parser {
17691773

17701774
static getTokens(content: string|string[]|Token[], lineNumber?: number, baseIndex?: number): Token[] {
17711775
if (Array.isArray(content) && typeof content[0] === `string`) {
1772-
return lineTokens(content.join(` `), lineNumber, baseIndex);
1776+
return Parser.lineTokens(content.join(` `), lineNumber, baseIndex);
17731777
} else
17741778
if (typeof content === `string`) {
1775-
return lineTokens(content, lineNumber, baseIndex);
1779+
return Parser.lineTokens(content, lineNumber, baseIndex);
17761780
} else {
17771781
return content as Token[];
17781782
}

0 commit comments

Comments
 (0)