-
Notifications
You must be signed in to change notification settings - Fork 61
/
position-tracker.ts
85 lines (64 loc) · 3.15 KB
/
position-tracker.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
/******************************************************************************
* Copyright 2023 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import type { LangiumDocument, MaybePromise } from 'langium';
import type { Position } from 'vscode-languageserver';
import type { DocumentHighlight, DocumentHighlightParams } from 'vscode-languageserver';
import type { LangiumSprottyServices } from './sprotty-services.js';
import { DefaultDocumentHighlightProvider } from 'langium/lsp';
/**
* This service provides access to the user's current cursor position.
*/
export interface PositionTracker {
firePositionChanged(document: LangiumDocument, position: Position): void;
onPositionChanged(listener: PositionChangeListener): void;
removePositionChangeListener(listener: PositionChangeListener): void;
getOffset(document: LangiumDocument): number | undefined;
}
export type PositionChangeListener = (document: LangiumDocument, position: Position) => void;
export class DefaultPositionTracker {
protected readonly positionMap = new Map<string, Position>();
protected readonly positionChangeListeners: PositionChangeListener[] = [];
constructor(services: LangiumSprottyServices) {
services.shared.workspace.TextDocuments.onDidClose(event => {
this.positionMap.delete(event.document.uri.toString());
});
}
firePositionChanged(document: LangiumDocument, position: Position): void {
this.positionMap.set(document.uri.toString(), position);
this.positionChangeListeners.forEach(listener => listener(document, position));
}
onPositionChanged(listener: PositionChangeListener): void {
this.positionChangeListeners.push(listener);
}
removePositionChangeListener(listener: PositionChangeListener): void {
const index = this.positionChangeListeners.indexOf(listener);
if (index >= 0) {
this.positionChangeListeners.splice(index, 1);
}
}
getOffset(document: LangiumDocument): number | undefined {
const position = this.positionMap.get(document.uri.toString());
if (!position) {
return undefined;
}
return document.textDocument.offsetAt(position);
}
}
/**
* Exploit the client's document highlight requests to track cursor positions.
* Known limitation: document highlight requests are not sent when the cursor is surrounded by whitespace.
*/
export class TrackingDocumentHighlightProvider extends DefaultDocumentHighlightProvider {
private readonly positionTracker: PositionTracker;
constructor(services: LangiumSprottyServices) {
super(services);
this.positionTracker = services.diagram.PositionTracker;
}
override getDocumentHighlight(document: LangiumDocument, params: DocumentHighlightParams): MaybePromise<DocumentHighlight[] | undefined> {
this.positionTracker.firePositionChanged(document, params.position);
return super.getDocumentHighlight(document, params);
}
}