Skip to content

Commit 0c8b556

Browse files
authored
Merge pull request #10 from joshraphael/refactor
Refactor
2 parents 6968929 + b78e72e commit 0c8b556

6 files changed

Lines changed: 152 additions & 141 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515

1616
- Syntax highlighting to use upstream [rascript-syntax](https://github.com/joshraphael/rascript-syntax) repo
1717
- Bug involving incorrect comment bounds detected for hover, definition and completion data
18+
- Unify document parser to align with language server
1819

1920
### Removed
2021

src/clients/shared/completionItemsProvider.ts

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,23 @@
11
import * as vscode from "vscode";
22
import * as parser from "./parser";
3-
import { builtinFunctionDefinitions } from "./functionDefinitions";
43

54
export function completionItemsProvider(
65
document: vscode.TextDocument,
76
position: vscode.Position
87
) {
9-
let completionFunctions = [];
10-
let completionVariables = [];
11-
let completionClasses = [];
8+
let parsedDocument = parser.parseDocument(document);
129
let completionItems: vscode.CompletionItem[] = [];
13-
for (let i = 0; i < builtinFunctionDefinitions.length; i++) {
14-
let fn = builtinFunctionDefinitions[i];
15-
completionFunctions.push(fn.key);
16-
}
17-
let text = document.getText();
18-
let commentBounds = parser.getCommentBoundsList(document);
19-
let classes = parser.getClassData(text, commentBounds);
20-
let m: RegExpExecArray | null;
21-
while ((m = parser.G_FUNCTION_DEFINITION.exec(text))) {
22-
// dont parse if its in a comment
23-
if (parser.inCommentBound(m.index, commentBounds)) {
24-
continue;
25-
}
26-
completionFunctions.push(m[2]);
27-
}
28-
let functionSet: Set<string> = new Set(completionFunctions);
10+
let functionSet: Set<string> = new Set(parsedDocument.completionFunctions);
2911
functionSet.forEach((fnName: string) => {
3012
completionItems.push(parser.newBuiltInFunction(fnName));
3113
});
32-
while ((m = parser.G_VARIABLES.exec(text))) {
33-
// dont parse if its in a comment
34-
if (parser.inCommentBound(m.index, commentBounds)) {
35-
continue;
36-
}
37-
completionVariables.push(m[1]);
38-
}
39-
let variableSet: Set<string> = new Set(completionVariables);
14+
let variableSet: Set<string> = new Set(parsedDocument.completionVariables);
4015
variableSet.forEach((varName: string) => {
4116
completionItems.push(
4217
parser.newCompletion(varName, vscode.CompletionItemKind.Variable)
4318
);
4419
});
45-
for (const [className, classScope] of classes) {
46-
completionClasses.push(className);
47-
}
48-
let classSet: Set<string> = new Set(completionClasses);
20+
let classSet: Set<string> = new Set(parsedDocument.completionClasses);
4921
classSet.forEach((className: string) => {
5022
completionItems.push(
5123
parser.newCompletion(className, vscode.CompletionItemKind.Class)

src/clients/shared/definitionProvider.ts

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,13 @@ export function definitionProvider(
1010
let text = document.getText();
1111
const range = document.getWordRangeAtPosition(position);
1212
const word = document.getText(range);
13+
let parsedDocument = parser.parseDocument(document);
1314
const origWordOffset = document.offsetAt(position);
14-
let commentBounds = parser.getCommentBoundsList(document);
15-
let classes = parser.getClassData(text, commentBounds);
16-
let m: RegExpExecArray | null;
17-
let functionDefinitions = new Map<string, models.ClassFunction[]>();
18-
while ((m = parser.G_FUNCTION_DEFINITION.exec(text))) {
19-
// dont parse if its in a comment
20-
if (parser.inCommentBound(m.index, commentBounds)) {
21-
continue;
22-
}
23-
let pos = document.positionAt(m.index);
24-
let list = functionDefinitions.get(m[2]);
25-
let a = m[3].split(",").map((s) => s.trim());
26-
var args = a.filter(function (el) {
27-
return el !== null && el !== "" && el !== undefined;
28-
});
29-
let item = parser.createClassFunction(
30-
parser.detectClass(m.index, classes),
31-
m[2],
32-
pos,
33-
...args
34-
);
35-
if (list !== undefined) {
36-
list.push(item);
37-
} else {
38-
functionDefinitions.set(m[2], [item]);
39-
}
40-
}
41-
if (functionDefinitions.has(word)) {
15+
if (parsedDocument.functionDefinitions.has(word)) {
4216
if (range !== undefined) {
4317
let endOffset = document.offsetAt(range.end);
4418
if (text[endOffset] !== "(") {
45-
return null; // not a function
19+
return null; // not a function (maybe comment, or just varaible named the same)
4620
}
4721
}
4822
let origOffset = document.offsetAt(position);
@@ -51,12 +25,12 @@ export function definitionProvider(
5125
}
5226
let offset = origOffset - 1;
5327
const [global, usingThis] = parser.getScope(document, origOffset);
54-
let list = functionDefinitions.get(word) || [];
28+
let list = parsedDocument.functionDefinitions.get(word) || [];
5529
let filteredList = list.filter(
5630
parser.classFilter(
5731
global,
5832
usingThis,
59-
parser.detectClass(origWordOffset, classes)
33+
parser.detectClass(origWordOffset, parsedDocument.classes)
6034
)
6135
);
6236
// can only link to one location, so anything that has multiple definitions wont work for code jumping

src/clients/shared/hoverProvider.ts

Lines changed: 4 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,11 @@
11
import * as vscode from "vscode";
22
import * as parser from "./parser";
3-
import * as models from "./models";
4-
import { builtinFunctionDefinitions } from "./functionDefinitions";
53

64
export function hoverProvider(
75
document: vscode.TextDocument,
86
position: vscode.Position
97
) {
10-
let words = new Map<string, models.HoverData[]>();
11-
for (let i = 0; i < builtinFunctionDefinitions.length; i++) {
12-
let fn = builtinFunctionDefinitions[i];
13-
let comment = fn.commentDoc.join("\n");
14-
let hover = parser.newHoverText(
15-
fn.key,
16-
-1,
17-
parser.G_FUNTION,
18-
"",
19-
comment,
20-
fn.url,
21-
...fn.args
22-
);
23-
let definitions = words.get(fn.key);
24-
if (definitions !== undefined) {
25-
definitions.push(hover);
26-
} else {
27-
words.set(fn.key, [hover]);
28-
}
29-
}
30-
let text = document.getText();
31-
let m: RegExpExecArray | null;
32-
// get bounds of single line comments
33-
let commentBounds = parser.getCommentBoundsList(document);
34-
let classes = parser.getClassData(text, commentBounds);
35-
for (const [className, classScope] of classes) {
36-
let pos = document.positionAt(classScope.start);
37-
let comment = parser.getCommentText(document, pos);
38-
let hover = parser.newHoverText(
39-
className,
40-
classScope.start,
41-
parser.G_CLASS,
42-
"",
43-
comment,
44-
"",
45-
...classScope.constructorArgs
46-
);
47-
let definitions = words.get(className);
48-
if (definitions !== undefined) {
49-
definitions.push(hover);
50-
} else {
51-
words.set(className, [hover]);
52-
}
53-
}
54-
while ((m = parser.G_FUNCTION_DEFINITION.exec(text))) {
55-
// dont parse if its in a comment
56-
if (parser.inCommentBound(m.index, commentBounds)) {
57-
continue;
58-
}
59-
let className = parser.detectClass(m.index, classes);
60-
let pos = document.positionAt(m.index);
61-
let comment = parser.getCommentText(document, pos);
62-
let a = m[3].split(",").map((s) => s.trim());
63-
var args = a.filter(function (el) {
64-
return el !== null && el !== "" && el !== undefined;
65-
});
66-
let hover = parser.newHoverText(
67-
m[2],
68-
m.index,
69-
parser.G_FUNTION,
70-
className,
71-
comment,
72-
"",
73-
...args
74-
);
75-
let definitions = words.get(m[2]);
76-
if (definitions !== undefined) {
77-
definitions.push(hover);
78-
} else {
79-
words.set(m[2], [hover]);
80-
}
81-
}
8+
let parsedDocument = parser.parseDocument(document);
829
const range = document.getWordRangeAtPosition(position);
8310
let startingPos = position;
8411
if (range?.start !== undefined) {
@@ -91,12 +18,12 @@ export function hoverProvider(
9118
const startingOffset = document.offsetAt(startingPos);
9219
const endingOffset = document.offsetAt(endingPos);
9320
const word = document.getText(range);
94-
const hoverClass = parser.detectClass(startingOffset, classes);
21+
const hoverClass = parser.detectClass(startingOffset, parsedDocument.classes);
9522
let offset = startingOffset - 1; // get character just before the function name position
9623

9724
// Special case: this keyword should show the class hover info
9825
if (word === "this") {
99-
let definitions = words.get(hoverClass);
26+
let definitions = parsedDocument.hoverData.get(hoverClass);
10027
if (definitions !== undefined) {
10128
for (let i = 0; i < definitions.length; i++) {
10229
let definition = definitions[i];
@@ -108,7 +35,7 @@ export function hoverProvider(
10835
}
10936
const [global, usingThis] = parser.getScope(document, startingOffset);
11037

111-
let definitions = words.get(word);
38+
let definitions = parsedDocument.hoverData.get(word);
11239
if (definitions !== undefined) {
11340
const [fn, cls] = parser.getWordType(
11441
document,

src/clients/shared/models.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,12 @@ export interface HoverData {
3535
args: string[];
3636
lines: string[];
3737
}
38+
39+
export interface ParsedDocument {
40+
classes: Map<string, ClassScope>;
41+
functionDefinitions: Map<string, ClassFunction[]>;
42+
hoverData: Map<string, HoverData[]>;
43+
completionFunctions: string[];
44+
completionVariables: string[];
45+
completionClasses: string[];
46+
}

src/clients/shared/parser.ts

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as vscode from "vscode";
22
import * as models from "./models";
3+
import { builtinFunctionDefinitions } from "./functionDefinitions";
34

45
export const G_FUNCTION_DEFINITION =
56
/(\bfunction\b)[\t ]*([a-zA-Z_][\w]*)[\t ]*\(([^\(\)]*)\)/g; // keep in sync with syntax file rascript.tmLanguage.json #function-definitions regex
@@ -348,7 +349,7 @@ export function detectClass(
348349
export function getClassData(
349350
text: string,
350351
commentBounds: models.CommentBounds[]
351-
) {
352+
): Map<string, models.ClassScope> {
352353
let classes = new Map<string, models.ClassScope>();
353354
let m: RegExpExecArray | null;
354355
while ((m = G_CLASS_DEFINITION.exec(text))) {
@@ -506,3 +507,130 @@ export function newHoverText(
506507
lines: lines,
507508
};
508509
}
510+
511+
export function parseDocument(
512+
document: vscode.TextDocument
513+
): models.ParsedDocument {
514+
let text = document.getText();
515+
let commentBounds = getCommentBoundsList(document);
516+
let classes = getClassData(text, commentBounds);
517+
let functionDefinitions = new Map<string, models.ClassFunction[]>();
518+
let words = new Map<string, models.HoverData[]>(); // should be renamed to hoverData or something
519+
let completionFunctions: string[] = [];
520+
let completionVariables: string[] = [];
521+
let completionClasses: string[] = [];
522+
// Parse each build in function in the document
523+
for (let i = 0; i < builtinFunctionDefinitions.length; i++) {
524+
let fn = builtinFunctionDefinitions[i];
525+
526+
// Add hover data
527+
let comment = fn.commentDoc.join("\n");
528+
let hover = newHoverText(
529+
fn.key,
530+
-1,
531+
G_FUNTION,
532+
"",
533+
comment,
534+
fn.url,
535+
...fn.args
536+
);
537+
let definitions = words.get(fn.key);
538+
if (definitions !== undefined) {
539+
definitions.push(hover);
540+
} else {
541+
words.set(fn.key, [hover]);
542+
}
543+
544+
// Add completion data
545+
completionFunctions.push(fn.key);
546+
}
547+
548+
// Parse each class in the document
549+
for (const [className, classScope] of classes) {
550+
// add hover info
551+
let pos = document.positionAt(classScope.start);
552+
let comment = getCommentText(document, pos);
553+
let hover = newHoverText(
554+
className,
555+
classScope.start,
556+
G_CLASS,
557+
"",
558+
comment,
559+
"",
560+
...classScope.constructorArgs
561+
);
562+
let definitions = words.get(className);
563+
if (definitions !== undefined) {
564+
definitions.push(hover);
565+
} else {
566+
words.set(className, [hover]);
567+
}
568+
569+
// add completion info
570+
completionClasses.push(className);
571+
}
572+
573+
// Parse each function in the document
574+
let m: RegExpExecArray | null;
575+
while ((m = G_FUNCTION_DEFINITION.exec(text))) {
576+
// dont parse if its in a comment
577+
if (inCommentBound(m.index, commentBounds)) {
578+
continue;
579+
}
580+
let className = detectClass(m.index, classes);
581+
let pos = document.positionAt(m.index);
582+
let comment = getCommentText(document, pos);
583+
let list = functionDefinitions.get(m[2]);
584+
let a = m[3].split(",").map((s) => s.trim());
585+
var args = a.filter(function (el) {
586+
return el !== null && el !== "" && el !== undefined;
587+
});
588+
589+
// add definition info
590+
let item = createClassFunction(className, m[2], pos, ...args);
591+
if (list !== undefined) {
592+
list.push(item);
593+
} else {
594+
functionDefinitions.set(m[2], [item]);
595+
}
596+
597+
// add hover info
598+
let hover = newHoverText(
599+
m[2],
600+
m.index,
601+
G_FUNTION,
602+
className,
603+
comment,
604+
"",
605+
...args
606+
);
607+
let definitions = words.get(m[2]);
608+
if (definitions !== undefined) {
609+
definitions.push(hover);
610+
} else {
611+
words.set(m[2], [hover]);
612+
}
613+
614+
// add completion info
615+
completionFunctions.push(m[2]);
616+
}
617+
618+
// Parse each variable in the document
619+
while ((m = G_VARIABLES.exec(text))) {
620+
// dont parse if its in a comment
621+
if (inCommentBound(m.index, commentBounds)) {
622+
continue;
623+
}
624+
625+
// add completion info
626+
completionVariables.push(m[1]);
627+
}
628+
return {
629+
classes: classes,
630+
functionDefinitions: functionDefinitions,
631+
hoverData: words,
632+
completionFunctions: completionFunctions,
633+
completionVariables: completionVariables,
634+
completionClasses: completionClasses,
635+
};
636+
}

0 commit comments

Comments
 (0)