-
Notifications
You must be signed in to change notification settings - Fork 96
/
Copy pathmacroDefinitionProvider.ts
executable file
·113 lines (106 loc) · 3.16 KB
/
macroDefinitionProvider.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import {
Definition,
DefinitionLink,
DefinitionProvider,
Disposable,
Location,
Position,
ProviderResult,
TextDocument,
Uri,
} from "vscode";
import { MacroMetaMap } from "../domain";
import { DBTProjectContainer } from "../manifest/dbtProjectContainer";
import { ManifestCacheChangedEvent } from "../manifest/event/manifestCacheChangedEvent";
import { isEnclosedWithinCodeBlock, provideSingleton } from "../utils";
import { TelemetryService } from "../telemetry";
@provideSingleton(MacroDefinitionProvider)
export class MacroDefinitionProvider implements DefinitionProvider, Disposable {
private macroToLocationMap: Map<string, MacroMetaMap> = new Map();
private static readonly IS_MACRO = /\w+\.?\w+/;
private disposables: Disposable[] = [];
constructor(
private dbtProjectContainer: DBTProjectContainer,
private telemetry: TelemetryService,
) {
this.disposables.push(
dbtProjectContainer.onManifestChanged((event) =>
this.onManifestCacheChanged(event),
),
);
}
dispose() {
while (this.disposables.length) {
const x = this.disposables.pop();
if (x) {
x.dispose();
}
}
}
provideDefinition(
document: TextDocument,
position: Position,
): ProviderResult<Definition | DefinitionLink[]> {
return new Promise((resolve) => {
const textLine = document.lineAt(position).text;
const range = document.getWordRangeAtPosition(
position,
MacroDefinitionProvider.IS_MACRO,
);
const word = document.getText(range);
if (
range &&
textLine[range.end.character] === "(" &&
isEnclosedWithinCodeBlock(document, range)
) {
const packageName = this.dbtProjectContainer.getPackageName(
document.uri,
);
const macroName =
packageName !== undefined && !word.includes(".")
? `${packageName}.${word}`
: word;
const definition = this.getMacroDefinition(macroName, document.uri);
if (definition !== undefined) {
resolve(definition);
this.telemetry.sendTelemetryEvent("provideMacroDefinition");
return;
}
}
resolve(undefined);
});
}
private onManifestCacheChanged(event: ManifestCacheChangedEvent): void {
event.added?.forEach((added) => {
this.macroToLocationMap.set(
added.project.projectRoot.fsPath,
added.macroMetaMap,
);
});
event.removed?.forEach((removed) => {
this.macroToLocationMap.delete(removed.projectRoot.fsPath);
});
}
private getMacroDefinition(
macroName: string,
currentFilePath: Uri,
): Definition | undefined {
const projectRootpath =
this.dbtProjectContainer.getProjectRootpath(currentFilePath);
if (projectRootpath === undefined) {
return;
}
const macroMap = this.macroToLocationMap.get(projectRootpath.fsPath);
if (macroMap === undefined) {
return;
}
const location = macroMap.get(macroName);
if (location && location.path) {
return new Location(
Uri.file(location.path),
new Position(location.line, location.character),
);
}
return undefined;
}
}