11import {
22 CancellationToken ,
33 Connection ,
4- TextDocuments ,
5- TextDocumentSyncKind
4+ DidChangeWatchedFilesParams ,
5+ FileChangeType ,
6+ TextDocumentSyncKind ,
67} 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" ;
816import { URI } from "vscode-uri" ;
917import { Processor } from "../../util" ;
1018import { ExtensionContext } from "../extension" ;
@@ -19,45 +27,40 @@ import { identifyDocument } from "./languageId";
1927import { TextDocument } from "./text-document" ;
2028
2129import * 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" ;
2233
2334export 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 > {
3538 public readonly name : string = "documents" ;
36- private _documents : TextDocuments < TextDocument > ;
39+ private _cachedDocuments : CacheDocuments ;
3740 private _factory : TextDocumentFactory ;
41+ private _onDeleted : Emitter < DocumentEvent > ;
42+ private _onCreated : Emitter < DocumentEvent > ;
43+ private _onChanged : Emitter < DocumentEvent > ;
3844
3945 constructor ( logger : IExtendedLogger , extension : ExtensionContext ) {
4046 super ( logger . withPrefix ( "[documents]" ) , extension ) ;
4147
4248 this . _factory = new TextDocumentFactory ( logger , extension ) ;
43- this . _documents = new TextDocuments ( this . _factory ) ;
44- }
49+ this . _cachedDocuments = new CacheDocuments ( ) ;
4550
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 ( ) ;
4954 }
50- /** @inheritdoc */
51- get onDidChangeContent ( ) {
52- return this . _documents . onDidChangeContent ;
55+
56+ get onDeleted ( ) {
57+ return this . _onDeleted . event ;
5358 }
54- /** @inheritdoc */
55- get onDidClose ( ) {
56- return this . _documents . onDidClose ;
59+ get onCreated ( ) {
60+ return this . _onCreated . event ;
5761 }
58- /** @inheritdoc */
59- get onDidSave ( ) {
60- return this . _documents . onDidSave ;
62+ get onChanged ( ) {
63+ return this . _onChanged . event ;
6164 }
6265
6366 onInitialize ( capabilities : CapabilityBuilder ) : void {
@@ -82,7 +85,69 @@ export class DocumentManager
8285 }
8386
8487 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 ) ;
86151 }
87152
88153 get ( uri : string ) : TextDocument | undefined ;
@@ -106,7 +171,7 @@ export class DocumentManager
106171 return this . _factory . extend ( content ) ;
107172 }
108173
109- const doc = this . _documents . get ( u . toString ( ) ) ;
174+ const doc = this . _cachedDocuments . get ( u . toString ( ) ) || this . _cachedDocuments . get ( uri ) ;
110175 if ( doc ) return this . _factory . extend ( doc ) ;
111176
112177 const text = readDocument ( u , this . logger ) ;
0 commit comments