Skip to content

Commit bab9747

Browse files
Make get tree synchronous again
1 parent 6a3e299 commit bab9747

3 files changed

Lines changed: 83 additions & 42 deletions

File tree

src/errors.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Uri } from "vscode";
2+
13
export class UnsupportedLanguageError extends Error {
24
constructor(language: string) {
35
super(
@@ -7,10 +9,10 @@ export class UnsupportedLanguageError extends Error {
79
}
810
}
911

10-
export class LanguageFailedToLoad extends Error {
12+
export class LanguageStillLoadingError extends Error {
1113
constructor(language: string) {
12-
super(`Language '${language}' failed to load`);
13-
this.name = "LanguageFailedToLoad";
14+
super(`Language '${language}' is still loading; please wait and try again`);
15+
this.name = "LanguageStillLoadingError";
1416
}
1517
}
1618

@@ -20,3 +22,17 @@ export class DeprecatedError extends Error {
2022
this.name = "DeprecatedError";
2123
}
2224
}
25+
26+
export class FailedToParseError extends Error {
27+
constructor(uri: Uri) {
28+
super(`Failed to parse document: ${uri.toString()}`);
29+
this.name = "FailedToParseError";
30+
}
31+
}
32+
33+
export class DocumentNotOpenError extends Error {
34+
constructor(uri: Uri) {
35+
super(`Document not open: ${uri.toString()}`);
36+
this.name = "DocumentNotOpenError";
37+
}
38+
}

src/extension.ts

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ import {
1414
} from "./disabledLanguages";
1515
import {
1616
DeprecatedError,
17-
LanguageFailedToLoad,
17+
LanguageStillLoadingError,
1818
UnsupportedLanguageError,
1919
} from "./errors";
2020
import { languages } from "./languages";
2121
import { Trees } from "./Trees";
22-
import { getWasmPath, isDocumentVisible } from "./utils";
22+
import {
23+
getOpenDocument,
24+
getWasmPath,
25+
isDocumentVisible,
26+
parseDocument,
27+
} from "./utils";
2328

2429
// For some reason this crashes if we put it inside activate
2530
// Fix: this isn't a field, suppress package member coloring like Go
@@ -92,65 +97,60 @@ export function activate(context: ExtensionContext) {
9297
throw new Error(`No parser for language ${document.languageId}`);
9398
}
9499

95-
tree = language.parser?.parse(document.getText()) ?? undefined;
96-
97-
if (tree == null) {
98-
throw Error(`Failed to parse ${uriString}`);
99-
}
100+
tree = parseDocument(language.parser, document);
100101

101102
trees.set(uriString, tree);
102103

103104
return tree;
104105
}
105106

106-
/**
107-
* Create a tree-sitter query for a given language and query source
108-
* @param languageId the vscode language id of the language to create the query for
109-
* @param source the source of the query
110-
* @returns the created query, or undefined if the language couldn't be loaded
111-
*/
112-
function createQuery(languageId: string, source: string): Query | undefined {
113-
const language = languages[languageId]?.parser?.language;
114-
if (language == null) {
115-
throwIfLanguageIsDisabled(languageId);
116-
return undefined;
117-
}
118-
return new Query(language, source);
119-
}
120-
121107
/**
122108
* Get the parse tree for a given document, parsing it if necessary
123109
* @param document the document to get the tree for
124110
* @returns the parse tree for the document
125111
*/
126-
async function getTreeForUri(uri: Uri): Promise<Tree> {
112+
function getTreeForUri(uri: Uri): Tree {
127113
const uriString = uri.toString();
128114
let tree = trees.get(uriString);
129115

116+
// Document is already opened
130117
if (tree != null) {
131118
return tree;
132119
}
133120

134-
const document = workspace.textDocuments.find(
135-
(textDocument) => textDocument.uri.toString() === uri.toString(),
136-
);
137-
138-
if (document == null) {
139-
throw new Error(`Document ${uriString} is not open`);
140-
}
141-
142-
tree = await openDocument(document);
121+
const document = getOpenDocument(uri);
122+
const language = languages[document.languageId];
143123

144-
if (tree != null) {
145-
return tree;
124+
// Language without a parser, e.g. plaintext
125+
if (language == null) {
126+
throw new UnsupportedLanguageError(document.languageId);
146127
}
147128

148-
if (document.languageId in languages) {
129+
// Language definition exists, but the parser is not loaded. Could be a race
130+
// condition or a disabled language.
131+
if (language.parser == null) {
149132
throwIfLanguageIsDisabled(document.languageId);
150-
throw new LanguageFailedToLoad(document.languageId);
133+
throw new LanguageStillLoadingError(document.languageId);
151134
}
152135

153-
throw new UnsupportedLanguageError(document.languageId);
136+
tree = parseDocument(language.parser, document);
137+
trees.set(uriString, tree);
138+
return tree;
139+
}
140+
141+
/**
142+
* Create a tree-sitter query for a given language and query source
143+
* @param languageId the vscode language id of the language to create the query for
144+
* @param source the source of the query
145+
* @returns the created query, or undefined if the language couldn't be loaded
146+
*/
147+
function createQuery(languageId: string, source: string): Query | undefined {
148+
const language = languages[languageId]?.parser?.language;
149+
if (language == null) {
150+
throwIfLanguageIsDisabled(languageId);
151+
return undefined;
152+
}
153+
return new Query(language, source);
154154
}
155155

156156
// NOTE: if you make this an async function, it seems to cause edit anomalies

src/utils.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import * as fs from "node:fs";
22
import * as path from "node:path";
3-
import type { TextDocument } from "vscode";
4-
import { window } from "vscode";
3+
import type { TextDocument, Uri } from "vscode";
4+
import { window, workspace } from "vscode";
5+
import type { Parser, Tree } from "web-tree-sitter";
6+
import { DocumentNotOpenError, FailedToParseError } from "./errors";
57

68
export function isDocumentVisible(document: TextDocument): boolean {
79
const uriString = document.uri.toString();
@@ -10,6 +12,19 @@ export function isDocumentVisible(document: TextDocument): boolean {
1012
);
1113
}
1214

15+
export function getOpenDocument(uri: Uri): TextDocument {
16+
const uriString = uri.toString();
17+
const document = workspace.textDocuments.find(
18+
(doc) => doc.uri.toString() === uriString,
19+
);
20+
21+
if (document == null) {
22+
throw new DocumentNotOpenError(uri);
23+
}
24+
25+
return document;
26+
}
27+
1328
export function getWasmPath(extensionPath: string, moduleName: string): string {
1429
const absolute = path.join(extensionPath, "parsers", moduleName + ".wasm");
1530

@@ -19,3 +34,13 @@ export function getWasmPath(extensionPath: string, moduleName: string): string {
1934

2035
return absolute;
2136
}
37+
38+
export function parseDocument(parser: Parser, document: TextDocument): Tree {
39+
const tree = parser.parse(document.getText());
40+
41+
if (tree == null) {
42+
throw new FailedToParseError(document.uri);
43+
}
44+
45+
return tree;
46+
}

0 commit comments

Comments
 (0)