4
4
* terms of the MIT License, which is available in the project root.
5
5
******************************************************************************/
6
6
7
+ import { LSPErrorCodes , ResponseError } from 'vscode-languageserver-protocol' ;
7
8
import { CancellationToken } from '../utils/cancellation.js' ;
8
9
import { Disposable } from '../utils/disposable.js' ;
9
10
import type { ServiceRegistry } from '../service-registry.js' ;
@@ -490,8 +491,8 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
490
491
}
491
492
492
493
waitUntil ( state : DocumentState , cancelToken ?: CancellationToken ) : Promise < void > ;
493
- waitUntil ( state : DocumentState , uri ?: URI , cancelToken ?: CancellationToken ) : Promise < URI | undefined > ;
494
- waitUntil ( state : DocumentState , uriOrToken ?: URI | CancellationToken , cancelToken ?: CancellationToken ) : Promise < URI | undefined | void > {
494
+ waitUntil ( state : DocumentState , uri ?: URI , cancelToken ?: CancellationToken ) : Promise < URI > ;
495
+ waitUntil ( state : DocumentState , uriOrToken ?: URI | CancellationToken , cancelToken ?: CancellationToken ) : Promise < URI | void > {
495
496
let uri : URI | undefined = undefined ;
496
497
if ( uriOrToken && 'path' in uriOrToken ) {
497
498
uri = uriOrToken ;
@@ -500,26 +501,67 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
500
501
}
501
502
cancelToken ??= CancellationToken . None ;
502
503
if ( uri ) {
503
- const document = this . langiumDocuments . getDocument ( uri ) ;
504
- if ( document && document . state >= state ) {
505
- return Promise . resolve ( uri ) ;
506
- }
504
+ return this . awaitDocumentState ( state , uri , cancelToken ) ;
505
+
506
+ } else {
507
+ return this . awaitBuilderState ( state , cancelToken ) ;
508
+ }
509
+ }
510
+
511
+ protected awaitDocumentState ( state : DocumentState , uri : URI , cancelToken : CancellationToken ) : Promise < URI > {
512
+ const document = this . langiumDocuments . getDocument ( uri ) ;
513
+ if ( ! document ) {
514
+ return Promise . reject (
515
+ new ResponseError (
516
+ LSPErrorCodes . ServerCancelled ,
517
+ `No document found for URI: ${ uri . toString ( ) } `
518
+ )
519
+ ) ;
520
+
521
+ } else if ( document . state >= state ) {
522
+ return Promise . resolve ( uri ) ;
523
+
524
+ } else if ( cancelToken . isCancellationRequested ) {
525
+ return Promise . reject ( OperationCancelled ) ;
526
+
527
+ } else if ( this . currentState >= state && state > document . state ) {
528
+ // this would imply that the document has been excluded from linking or validation, for example;
529
+ // this should never occur, the LS need to make sure that the affected document is properly built,
530
+ // alternatively, the build state requirement need to be relaxed.
531
+ return Promise . reject (
532
+ new ResponseError (
533
+ LSPErrorCodes . RequestFailed ,
534
+ `Document state of ${ uri . toString ( ) } is ${ DocumentState [ document . state ] } , requiring ${ DocumentState [ state ] } , but workspace state is already ${ DocumentState [ this . currentState ] } . Returning undefined.`
535
+ )
536
+ ) ;
507
537
}
538
+ return new Promise ( ( resolve , reject ) => {
539
+ const buildDisposable = this . onDocumentPhase ( state , ( doc ) => {
540
+ if ( doc . uri . toString ( ) === uri . toString ( ) ) {
541
+ buildDisposable . dispose ( ) ;
542
+ cancelDisposable . dispose ( ) ;
543
+ resolve ( doc . uri ) ;
544
+ }
545
+ } ) ;
546
+ const cancelDisposable = cancelToken ! . onCancellationRequested ( ( ) => {
547
+ buildDisposable . dispose ( ) ;
548
+ cancelDisposable . dispose ( ) ;
549
+ reject ( OperationCancelled ) ;
550
+ } ) ;
551
+ } ) ;
552
+ }
553
+
554
+ protected awaitBuilderState ( state : DocumentState , cancelToken : CancellationToken ) : Promise < void > {
508
555
if ( this . currentState >= state ) {
509
- return Promise . resolve ( undefined ) ;
556
+ return Promise . resolve ( ) ;
510
557
} else if ( cancelToken . isCancellationRequested ) {
511
558
return Promise . reject ( OperationCancelled ) ;
512
559
}
513
560
return new Promise ( ( resolve , reject ) => {
514
561
const buildDisposable = this . onBuildPhase ( state , ( ) => {
515
562
buildDisposable . dispose ( ) ;
516
563
cancelDisposable . dispose ( ) ;
517
- if ( uri ) {
518
- const document = this . langiumDocuments . getDocument ( uri ) ;
519
- resolve ( document ?. uri ) ;
520
- } else {
521
- resolve ( undefined ) ;
522
- }
564
+ resolve ( ) ;
523
565
} ) ;
524
566
const cancelDisposable = cancelToken ! . onCancellationRequested ( ( ) => {
525
567
buildDisposable . dispose ( ) ;
0 commit comments