Skip to content

Commit

Permalink
perf(server): smarter tree-sitter parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
EmileRolley committed May 3, 2024
1 parent ddc45f4 commit 24e1cda
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 8 deletions.
3 changes: 3 additions & 0 deletions server/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export type FileInfos = {
// NOTE: It is stored to get more efficient parsing when the file is changed.
// NOTE: It's not used for now, because at first try, it was not working well.
tsTree: TSParser.Tree;
// Document version to check if the document has changed since the last parse.
// NOTE: for now, it's only used to skip the tree-sitter parsing if the document has not changed.
version?: number;
};

export type RuleDef = {
Expand Down
5 changes: 3 additions & 2 deletions server/src/publicodesRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Diagnostic, DiagnosticSeverity } from "vscode-languageserver/node.js";
import { getModelFromSource } from "@publicodes/tools/compilation";

import { FilePath, LSContext, RawPublicodes, RuleDef } from "./context";
import { tsParseText } from "./treeSitter";
import { getTSTree } from "./treeSitter";

const PUBLICODES_FILE_EXTENSION = ".publicodes";

Expand Down Expand Up @@ -46,7 +46,8 @@ export function parseDocument(
document?: TextDocument,
) {
const fileContent = document?.getText() ?? readFileSync(filePath).toString();
const tsTree = tsParseText(fileContent);
const fileInfos = ctx.fileInfos.get(filePath);
const tsTree = getTSTree(fileContent, fileInfos, document);
const { rawRules, errors } = parseRawRules(filePath);
const ruleDefs = collectRuleDefs(tsTree);

Expand Down
7 changes: 4 additions & 3 deletions server/src/semanticTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import {
} from "vscode-languageserver";
import { LSContext } from "./context";
import TSParser from "tree-sitter";
import { tsParseText } from "./treeSitter";
import { getTSTree } from "./treeSitter";
import { fileURLToPath } from "node:url";

export function semanticTokensFullProvider(ctx: LSContext) {
return ({ textDocument }: SemanticTokensParams): SemanticTokens => {
const document = ctx.documents.get(textDocument.uri);
const builder = new SemanticTokensBuilder();
const fileInfos = ctx.fileInfos.get(fileURLToPath(textDocument.uri));

if (document) {
// TODO: investigate to use cache or be smarter with the parseDocument function
const fileContent = document.getText();
const currentTree = tsParseText(fileContent);
const currentTree = getTSTree(fileContent, fileInfos, document);
collectTokens(ctx, builder, currentTree.rootNode);
}

Expand Down
22 changes: 19 additions & 3 deletions server/src/treeSitter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import TSParser from "tree-sitter";
import Publicodes from "tree-sitter-publicodes";
import { TextDocument } from "vscode-languageserver-textdocument";
import { FileInfos } from "./context";

const parser = new TSParser();
parser.setLanguage(Publicodes);

export function tsParseText(
/**
* Parse the content of the document with the tree-sitter parser if the
* document has changed since the last parse.
*
* @param content - The content of the document to parse
* @param fileInfos - The file infos to check if the document has changed
* @param document - The document to get the version from
*
* @returns The tree-sitter tree of the document
*/
export function getTSTree(
content: string,
currentTree?: TSParser.Tree | undefined,
fileInfos: FileInfos | undefined,
document: TextDocument | undefined,
): TSParser.Tree {
return parser.parse(content, currentTree);
if (fileInfos?.version && fileInfos.version === document?.version) {
return fileInfos.tsTree;
}
return parser.parse(content);
}

0 comments on commit 24e1cda

Please sign in to comment.