1- import { CancellationToken , CancellationTokenSource , CompletionItem , CompletionParams , DidChangeConfigurationNotification , DidChangeConfigurationParams , DidChangeWatchedFilesParams , DocumentSymbolParams , FoldingRange , FoldingRangeParams , Hover , HoverParams , PublishDiagnosticsParams , SemanticTokensParams , SemanticTokensRangeParams , SymbolInformation , TextDocuments , WorkspaceFoldersChangeEvent , _Connection } from 'vscode-languageserver' ;
1+ import { CancellationToken , CancellationTokenSource , CompletionItem , CompletionParams , DidChangeConfigurationNotification , DidChangeConfigurationParams , DidChangeWatchedFilesParams , DidOpenTextDocumentParams , DocumentSymbolParams , FoldingRange , FoldingRangeParams , Hover , HoverParams , PublishDiagnosticsParams , SemanticTokensParams , SemanticTokensRangeParams , SymbolInformation , TextDocuments , WorkspaceFoldersChangeEvent , _Connection } from 'vscode-languageserver' ;
22import { BaseProjectDocument } from './document' ;
33import { LanguageServerConfiguration } from '../server' ;
44import { hasConfigurationCapability } from '../capabilities/workspaceFolder' ;
55import { TextDocument } from 'vscode-languageserver-textdocument' ;
6+ import { sleep } from '../utils/helpers' ;
67
78
89/**
@@ -62,7 +63,7 @@ class WorkspaceEvents {
6263 private readonly _configuration : LanguageServerConfiguration ;
6364 private _parseCancellationToken ?: CancellationTokenSource ;
6465
65- activeDocument ?: BaseProjectDocument ;
66+ private _activeDocument ?: BaseProjectDocument ;
6667
6768 constructor ( params : { connection : _Connection , workspace : Workspace , configuration : LanguageServerConfiguration } ) {
6869 this . _connection = params . connection ;
@@ -74,8 +75,41 @@ class WorkspaceEvents {
7475 this . _documents . listen ( params . connection ) ;
7576 }
7677
78+ /**
79+ *
80+ * @param version the target document version (zero for any version).
81+ * @param token the cancellation token.
82+ * @returns the document when it is ready or undefined.
83+ */
84+ private async activeParsedDocument ( version : number , token : CancellationToken ) : Promise < BaseProjectDocument | undefined > {
85+ let document : BaseProjectDocument | undefined ;
86+ document = this . _activeDocument ;
87+
88+ // Sleep between attempting to grab the document.
89+ // Loop while we have undefined or an earlier version.
90+ while ( ! document || document . textDocument . version < version ) {
91+ if ( token . isCancellationRequested ) {
92+ return ;
93+ }
94+ await sleep ( 5 ) ;
95+ document = this . _activeDocument ;
96+ }
97+
98+ // Return if the version somehow outpaced us.
99+ if ( version > 0 && document . textDocument . version != version ) {
100+ return ;
101+ }
102+
103+ // Return the parsed document.
104+ while ( document . Busy ) {
105+ await sleep ( 5 ) ;
106+ }
107+ return document ;
108+ }
109+
77110 private initialiseConnectionEvents ( connection : _Connection ) {
78111 connection . onInitialized ( ( ) => this . _onInitialized ( ) ) ;
112+ connection . onDidOpenTextDocument ( params => this . _onDidOpenTextDocument ( params ) ) ;
79113 connection . onCompletion ( params => this . _onCompletion ( params ) ) ;
80114 connection . onCompletionResolve ( item => this . _onCompletionResolve ( item ) ) ;
81115 connection . onDidChangeConfiguration ( params => this . _onDidChangeConfiguration ( params ) ) ;
@@ -90,11 +124,11 @@ class WorkspaceEvents {
90124 connection . onRequest ( ( method : string , params : object | object [ ] | any ) => {
91125 switch ( method ) {
92126 case 'textDocument/semanticTokens/full' : {
93- return this . activeDocument ?. languageServerSemanticTokens ( ) ;
127+ return this . _activeDocument ?. languageServerSemanticTokens ( ) ;
94128 }
95129 case 'textDocument/semanticTokens/range' : {
96130 const rangeParams = params as SemanticTokensRangeParams ;
97- return this . activeDocument ?. languageServerSemanticTokens ( rangeParams . range ) ;
131+ return this . _activeDocument ?. languageServerSemanticTokens ( rangeParams . range ) ;
98132 }
99133 default :
100134 console . error ( `Unresolved request path: ${ method } ` ) ;
@@ -103,7 +137,7 @@ class WorkspaceEvents {
103137 }
104138
105139 private _sendDiagnostics ( ) {
106- this . _connection . sendDiagnostics ( this . activeDocument ?. getDiagnostics ( ) ?? { uri : "" , diagnostics : [ ] } ) ;
140+ this . _connection . sendDiagnostics ( this . _activeDocument ?. languageServerDiagnostics ( ) ?? { uri : "" , diagnostics : [ ] } ) ;
107141 }
108142
109143 private _initialiseDocumentsEvents ( ) {
@@ -134,11 +168,16 @@ class WorkspaceEvents {
134168 }
135169
136170 private async _onDocumentSymbolAsync ( params : DocumentSymbolParams , token : CancellationToken ) : Promise < SymbolInformation [ ] > {
137- return await this . activeDocument ?. languageServerSymbolInformationAsync ( token ) ?? [ ] ;
171+ const document = await this . activeParsedDocument ( 0 , token ) ;
172+ return document ?. languageServerSymbolInformation ( ) ?? [ ] ;
138173 }
139174
140175 private async _onFoldingRanges ( params : FoldingRangeParams , token : CancellationToken ) : Promise < FoldingRange [ ] > {
141- return await this . _workspace . activeDocument ?. getFoldingRanges ( token ) ?? [ ] ;
176+ // VSCode is an eager beaver and sends the folding range request before onDidChange or onDidOpen.
177+ await sleep ( 200 ) ;
178+ const document = await this . activeParsedDocument ( 0 , token ) ;
179+ const result = document ?. languageServerFoldingRanges ( ) ;
180+ return result ?? [ ] ;
142181 }
143182
144183 private _onHover ( params : HoverParams ) : Hover {
@@ -164,15 +203,28 @@ class WorkspaceEvents {
164203 * This event handler is called whenever a `TextDocuments<TextDocument>` is changed.
165204 * @param doc The document that changed.
166205 */
167- async onDidChangeContentAsync ( doc : TextDocument ) {
206+ async _onDidOpenTextDocument ( params : DidOpenTextDocumentParams ) {
207+ await this . _handleChangeOrOpenAsync ( TextDocument . create (
208+ params . textDocument . uri ,
209+ params . textDocument . languageId ,
210+ params . textDocument . version ,
211+ params . textDocument . text
212+ ) ) ;
213+ }
214+
215+ async onDidChangeContentAsync ( document : TextDocument ) {
216+ await this . _handleChangeOrOpenAsync ( document ) ;
168217 // this._parseCancellationToken?.cancel();
169218 // this._parseCancellationToken?.dispose();
219+ }
170220
171- this . activeDocument = BaseProjectDocument . create ( this . _workspace , doc ) ;
221+ protected async _handleChangeOrOpenAsync ( document : TextDocument ) {
222+ this . _activeDocument = BaseProjectDocument . create ( this . _workspace , document ) ;
172223 this . _parseCancellationToken = new CancellationTokenSource ( ) ;
173- await this . activeDocument . parseAsync ( this . _parseCancellationToken . token ) ;
224+ await this . _activeDocument . parseAsync ( this . _parseCancellationToken . token ) ;
174225 this . _sendDiagnostics ( ) ;
175226 this . _parseCancellationToken = undefined ;
176- this . _workspace . activateDocument ( this . activeDocument ) ;
227+ this . _workspace . activateDocument ( this . _activeDocument ) ;
177228 }
178229}
230+
0 commit comments