1
1
import {
2
2
CancellationToken ,
3
3
Connection ,
4
- TextDocuments ,
5
- TextDocumentSyncKind
4
+ DidChangeWatchedFilesParams ,
5
+ FileChangeType ,
6
+ TextDocumentSyncKind ,
6
7
} from "vscode-languageserver" ;
7
- import { FileOperationFilter } from "vscode-languageserver-protocol/lib/common/protocol.fileOperations" ;
8
+ import {
9
+ DidChangeTextDocumentParams ,
10
+ DidCloseTextDocumentParams ,
11
+ DidOpenTextDocumentParams ,
12
+ DidSaveTextDocumentParams ,
13
+ Disposable ,
14
+ Emitter ,
15
+ } from "vscode-languageserver-protocol" ;
8
16
import { URI } from "vscode-uri" ;
9
17
import { Processor } from "../../util" ;
10
18
import { ExtensionContext } from "../extension" ;
@@ -19,45 +27,40 @@ import { identifyDocument } from "./languageId";
19
27
import { TextDocument } from "./text-document" ;
20
28
21
29
import * as vscode from "vscode-languageserver-textdocument" ;
30
+ import { FileOperationFilter } from "vscode-languageserver-protocol/lib/common/protocol.fileOperations" ;
31
+ import { DocumentEvent , LazyDocumentEvent } from "./event" ;
32
+ import { CacheDocuments } from "./cached" ;
22
33
23
34
export type ContentType = string | vscode . TextDocument | undefined ;
24
- export type IDocumentManager = Pick <
25
- DocumentManager ,
26
- "get" | "forEach" | "onDidChangeContent" | "onDidClose" | "onDidOpen" | "onDidSave"
27
- > ;
28
-
29
- export class DocumentManager
30
- extends BaseService
31
- implements
32
- Partial < IService > ,
33
- Pick < TextDocuments < TextDocument > , "onDidChangeContent" | "onDidClose" | "onDidOpen" | "onDidSave" >
34
- {
35
+ export type IDocumentManager = Pick < DocumentManager , "get" | "forEach" | "onDeleted" | "onCreated" | "onChanged" > ;
36
+
37
+ export class DocumentManager extends BaseService implements Partial < IService > {
35
38
public readonly name : string = "documents" ;
36
- private _documents : TextDocuments < TextDocument > ;
39
+ private _cachedDocuments : CacheDocuments ;
37
40
private _factory : TextDocumentFactory ;
41
+ private _onDeleted : Emitter < DocumentEvent > ;
42
+ private _onCreated : Emitter < DocumentEvent > ;
43
+ private _onChanged : Emitter < DocumentEvent > ;
38
44
39
45
constructor ( logger : IExtendedLogger , extension : ExtensionContext ) {
40
46
super ( logger . withPrefix ( "[documents]" ) , extension ) ;
41
47
42
48
this . _factory = new TextDocumentFactory ( logger , extension ) ;
43
- this . _documents = new TextDocuments ( this . _factory ) ;
44
- }
49
+ this . _cachedDocuments = new CacheDocuments ( ) ;
45
50
46
- /** @inheritdoc */
47
- get onDidOpen ( ) {
48
- return this . _documents . onDidOpen ;
51
+ this . _onDeleted = new Emitter ( ) ;
52
+ this . _onCreated = new Emitter ( ) ;
53
+ this . _onChanged = new Emitter ( ) ;
49
54
}
50
- /** @inheritdoc */
51
- get onDidChangeContent ( ) {
52
- return this . _documents . onDidChangeContent ;
55
+
56
+ get onDeleted ( ) {
57
+ return this . _onDeleted . event ;
53
58
}
54
- /** @inheritdoc */
55
- get onDidClose ( ) {
56
- return this . _documents . onDidClose ;
59
+ get onCreated ( ) {
60
+ return this . _onCreated . event ;
57
61
}
58
- /** @inheritdoc */
59
- get onDidSave ( ) {
60
- return this . _documents . onDidSave ;
62
+ get onChanged ( ) {
63
+ return this . _onChanged . event ;
61
64
}
62
65
63
66
onInitialize ( capabilities : CapabilityBuilder ) : void {
@@ -82,7 +85,69 @@ export class DocumentManager
82
85
}
83
86
84
87
setupHandlers ( connection : Connection ) : void {
85
- this . _documents . listen ( connection ) ;
88
+ this . addDisposable (
89
+ connection . onDidChangeWatchedFiles ( this . _onDidChangeWatchedFiles . bind ( this ) ) ,
90
+ connection . onDidSaveTextDocument ( this . _handleSave . bind ( this ) ) ,
91
+ connection . onDidCloseTextDocument ( this . _handleClose . bind ( this ) ) ,
92
+ connection . onDidOpenTextDocument ( this . _handleOpen . bind ( this ) ) ,
93
+ connection . onDidChangeTextDocument ( this . _handleChanged . bind ( this ) )
94
+ ) ;
95
+ }
96
+
97
+ private async _onDidChangeWatchedFiles ( params : DidChangeWatchedFilesParams ) {
98
+ const changes = params . changes . map ( ( m ) => new LazyDocumentEvent ( this , m . uri , m . type ) ) ;
99
+
100
+ // Delete, then create, finally changed
101
+ const disposables : Partial < Disposable > [ ] = [
102
+ ...changes . filter ( ( c ) => c . type === FileChangeType . Deleted ) . map ( ( c ) => this . _processDeleted ( c ) ) ,
103
+ ...changes . filter ( ( c ) => c . type === FileChangeType . Created ) . map ( ( c ) => this . _processCreated ( c ) ) ,
104
+ ...changes . filter ( ( c ) => c . type === FileChangeType . Changed ) . map ( ( c ) => this . _processChanged ( c ) ) ,
105
+ ] ;
106
+
107
+ // Cleanup
108
+ disposables . forEach ( ( d ) => d ?. dispose ?. call ( d ) ) ;
109
+ }
110
+
111
+ private _processDeleted ( event : LazyDocumentEvent ) {
112
+ this . logger . debug ( "received file watch delete event" , event ) ;
113
+
114
+ this . _cachedDocuments . delete ( event . uri ) ;
115
+ return this . _onDeleted . fire ( Object . freeze ( event ) ) ;
116
+ }
117
+ private _processCreated ( event : LazyDocumentEvent ) {
118
+ this . logger . debug ( "received file watch create event" , event ) ;
119
+
120
+ return this . _onCreated . fire ( Object . freeze ( event ) ) ;
121
+ }
122
+ private _processChanged ( event : LazyDocumentEvent ) {
123
+ this . logger . debug ( "received file watch change event" , event ) ;
124
+
125
+ return this . _onChanged . fire ( Object . freeze ( event ) ) ;
126
+ }
127
+ private _handleChanged ( params : DidChangeTextDocumentParams ) {
128
+ if ( params . contentChanges . length === 0 ) return ;
129
+ this . logger . debug ( "received changed event" , params ) ;
130
+
131
+ let doc = this . _cachedDocuments . get ( params . textDocument . uri ) ;
132
+ if ( doc ) {
133
+ doc = this . _factory . update ( doc , params . contentChanges , params . textDocument . version ) ;
134
+ this . _cachedDocuments . set ( doc . uri , doc ) ;
135
+ }
136
+ }
137
+ private _handleOpen ( params : DidOpenTextDocumentParams ) {
138
+ this . logger . debug ( "received open event" , params ) ;
139
+
140
+ const td = params . textDocument ;
141
+ const doc = this . _factory . create ( td . uri , td . languageId , td . version , td . text ) ;
142
+ this . _cachedDocuments . set ( doc . uri , doc ) ;
143
+ }
144
+ private _handleClose ( params : DidCloseTextDocumentParams ) {
145
+ this . logger . debug ( "received close event" , params ) ;
146
+
147
+ return this . _cachedDocuments . delete ( params . textDocument . uri ) ;
148
+ }
149
+ private _handleSave ( params : DidSaveTextDocumentParams ) {
150
+ this . logger . debug ( "received saved event" , params ) ;
86
151
}
87
152
88
153
get ( uri : string ) : TextDocument | undefined ;
@@ -106,7 +171,7 @@ export class DocumentManager
106
171
return this . _factory . extend ( content ) ;
107
172
}
108
173
109
- const doc = this . _documents . get ( u . toString ( ) ) ;
174
+ const doc = this . _cachedDocuments . get ( u . toString ( ) ) || this . _cachedDocuments . get ( uri ) ;
110
175
if ( doc ) return this . _factory . extend ( doc ) ;
111
176
112
177
const text = readDocument ( u , this . logger ) ;
0 commit comments