Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make tree sitter viewport colorization sync #240511

Merged
merged 1 commit into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,17 @@ export class TreeSitterTextModelService extends Disposable implements ITreeSitte
return undefined;
}

getTreeSync(content: string, languageId: string): Parser.Tree | undefined {
const language = this.getOrInitLanguage(languageId);
const Parser = this._treeSitterImporter.parserClass;
if (language && Parser) {
const parser = new Parser();
parser.setLanguage(language);
return parser.parse(content) ?? undefined;
}
return undefined;
}

/**
* For testing
*/
Expand Down
6 changes: 6 additions & 0 deletions src/vs/editor/common/services/treeSitterParserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface ITreeSitterParserService {
getOrInitLanguage(languageId: string): Parser.Language | undefined;
getParseResult(textModel: ITextModel): ITreeSitterParseResult | undefined;
getTree(content: string, languageId: string): Promise<Parser.Tree | undefined>;
getTreeSync(content: string, languageId: string): Parser.Tree | undefined;
onDidUpdateTree: Event<TreeUpdateEvent>;
/**
* For testing purposes so that the time to parse can be measured.
Expand All @@ -64,6 +65,7 @@ export const ITreeSitterImporter = createDecorator<ITreeSitterImporter>('treeSit
export interface ITreeSitterImporter {
readonly _serviceBrand: undefined;
getParserClass(): Promise<typeof Parser.Parser>;
readonly parserClass: typeof Parser.Parser | undefined;
getLanguageClass(): Promise<typeof Parser.Language>;
getQueryClass(): Promise<typeof Parser.Query>;
}
Expand All @@ -81,6 +83,10 @@ export class TreeSitterImporter implements ITreeSitterImporter {
return this._treeSitterImport;
}

get parserClass() {
return this._parserClass;
}

private _parserClass: typeof Parser.Parser | undefined;
public async getParserClass() {
if (!this._parserClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import { ITextModelTreeSitter, ITreeSitterParseResult, ITreeSitterParserService,

/**
* The monaco build doesn't like the dynamic import of tree sitter in the real service.
* We use a dummy sertive here to make the build happy.
* We use a dummy service here to make the build happy.
*/
export class StandaloneTreeSitterParserService implements ITreeSitterParserService {
getTreeSync(content: string, languageId: string): Parser.Tree | undefined {
return undefined;
}
async getTextModelTreeSitter(model: ITextModel, parseImmediately?: boolean): Promise<ITextModelTreeSitter | undefined> {
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ class MockParser implements Parser.Parser {

class MockTreeSitterImporter implements ITreeSitterImporter {
_serviceBrand: undefined;
getParserClass(): Promise<typeof Parser.Parser> {
async getParserClass(): Promise<typeof Parser.Parser> {
return MockParser as any;
}
getLanguageClass(): Promise<typeof Parser.Language> {
async getLanguageClass(): Promise<typeof Parser.Language> {
return MockLanguage as any;
}
getQueryClass(): Promise<typeof Parser.Query> {
async getQueryClass(): Promise<typeof Parser.Query> {
throw new Error('Method not implemented.');
}

parserClass = MockParser as any;
}

class MockTree implements Parser.Tree {
Expand Down
3 changes: 3 additions & 0 deletions src/vs/editor/test/common/services/testTreeSitterService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { ITextModel } from '../../../common/model.js';
import { ITreeSitterParserService, ITreeSitterParseResult, ITextModelTreeSitter, TreeUpdateEvent } from '../../../common/services/treeSitterParserService.js';

export class TestTreeSitterParserService implements ITreeSitterParserService {
getTreeSync(content: string, languageId: string): Parser.Tree | undefined {
throw new Error('Method not implemented.');
}
async getTextModelTreeSitter(model: ITextModel, parseImmediately?: boolean): Promise<ITextModelTreeSitter> {
throw new Error('Method not implemented.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { ITextModel } from '../../../../editor/common/model.js';
import { PLAINTEXT_LANGUAGE_ID } from '../../../../editor/common/languages/modesRegistry.js';
import { debounce } from '../../../../base/common/decorators.js';
import { Range } from '../../../../editor/common/core/range.js';

export interface IViewPortChangeEvent {
Expand Down Expand Up @@ -61,7 +60,6 @@ export class TreeSitterCodeEditors extends Disposable {
this._onViewportChange(editor);
}

@debounce(200)
private async _onViewportChange(editor: ICodeEditor): Promise<void> {
const ranges = this._nonIntersectingViewPortRanges(editor);
this._onDidChangeViewport.fire({ model: editor.getModel()!, ranges });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,11 @@ export class TreeSitterTokenizationSupport extends Disposable implements ITreeSi
this._tokenizationStoreService.setTokens(textModel, tokens, TokenQuality.None);
}

private async _parseAndTokenizeViewPortRange(model: ITextModel, range: Range, languageId: LanguageId, startOffsetOfRangeInDocument: number, endOffsetOfRangeInDocument: number) {
private _parseAndTokenizeViewPortRange(model: ITextModel, range: Range, languageId: LanguageId, startOffsetOfRangeInDocument: number, endOffsetOfRangeInDocument: number) {
const content = model.getValueInRange(range);
const likelyRelevantLines = findLikelyRelevantLines(model, range.startLineNumber).likelyRelevantLines;
const likelyRelevantPrefix = likelyRelevantLines.join(model.getEOL());
const tree = await this._treeSitterService.getTree(`${likelyRelevantPrefix}${content}`, this._languageId);
const tree = this._treeSitterService.getTreeSync(`${likelyRelevantPrefix}${content}`, this._languageId);
if (!tree) {
return;
}
Expand Down
Loading