2019-12-30 07:42:59 -06:00
import * as vscode from 'vscode' ;
import * as lc from 'vscode-languageclient' ;
import { Server } from './server' ;
2019-12-30 13:46:14 -06:00
import { Config } from './config' ;
2019-12-30 07:42:59 -06:00
export class Ctx {
2019-12-31 10:28:01 -06:00
readonly config = new Config ( ) ;
2019-12-30 08:11:30 -06:00
private extCtx : vscode.ExtensionContext ;
2019-12-30 07:42:59 -06:00
constructor ( extCtx : vscode.ExtensionContext ) {
2019-12-30 08:11:30 -06:00
this . extCtx = extCtx ;
2019-12-30 07:42:59 -06:00
}
get client ( ) : lc . LanguageClient {
2019-12-30 08:11:30 -06:00
return Server . client ;
2019-12-30 07:42:59 -06:00
}
2019-12-30 08:20:13 -06:00
get activeRustEditor ( ) : vscode . TextEditor | undefined {
const editor = vscode . window . activeTextEditor ;
return editor && editor . document . languageId === 'rust'
? editor
: undefined ;
}
2019-12-30 08:11:30 -06:00
registerCommand ( name : string , factory : ( ctx : Ctx ) = > Cmd ) {
const fullName = ` rust-analyzer. ${ name } ` ;
2019-12-30 07:42:59 -06:00
const cmd = factory ( this ) ;
const d = vscode . commands . registerCommand ( fullName , cmd ) ;
this . pushCleanup ( d ) ;
}
2019-12-30 09:43:34 -06:00
overrideCommand ( name : string , factory : ( ctx : Ctx ) = > Cmd ) {
const defaultCmd = ` default: ${ name } ` ;
const override = factory ( this ) ;
const original = ( . . . args : any [ ] ) = >
vscode . commands . executeCommand ( defaultCmd , . . . args ) ;
try {
const d = vscode . commands . registerCommand (
name ,
async ( . . . args : any [ ] ) = > {
if ( ! ( await override ( . . . args ) ) ) {
return await original ( . . . args ) ;
}
} ,
) ;
this . pushCleanup ( d ) ;
} catch ( _ ) {
vscode . window . showWarningMessage (
'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings' ,
) ;
}
}
2019-12-30 12:05:41 -06:00
get subscriptions ( ) : { dispose ( ) : any } [ ] {
return this . extCtx . subscriptions ;
}
2019-12-30 07:42:59 -06:00
pushCleanup ( d : { dispose ( ) : any } ) {
2019-12-30 08:11:30 -06:00
this . extCtx . subscriptions . push ( d ) ;
2019-12-30 07:42:59 -06:00
}
2019-12-30 15:18:16 -06:00
2019-12-30 16:12:33 -06:00
async sendRequestWithRetry < R > (
method : string ,
param : any ,
2019-12-30 19:17:50 -06:00
token? : vscode.CancellationToken ,
2019-12-30 16:12:33 -06:00
) : Promise < R > {
2019-12-30 15:18:16 -06:00
await this . client . onReady ( ) ;
2019-12-30 15:53:21 -06:00
for ( const delay of [ 2 , 4 , 6 , 8 , 10 , null ] ) {
2019-12-30 15:18:16 -06:00
try {
2019-12-31 04:44:52 -06:00
return await ( token ? this . client . sendRequest ( method , param , token ) : this . client . sendRequest ( method , param ) ) ;
2019-12-30 15:18:16 -06:00
} catch ( e ) {
2019-12-30 16:12:33 -06:00
if (
e . code === lc . ErrorCodes . ContentModified &&
delay !== null
) {
await sleep ( 10 * ( 1 << delay ) ) ;
2019-12-30 15:18:16 -06:00
continue ;
}
throw e ;
}
}
2019-12-30 16:12:33 -06:00
throw 'unreachable' ;
2019-12-30 15:18:16 -06:00
}
2019-12-31 10:22:43 -06:00
onNotification ( method : string , handler : lc.GenericNotificationHandler ) {
this . client . onReady ( )
. then ( ( ) = > this . client . onNotification ( method , handler ) )
}
2019-12-30 07:42:59 -06:00
}
2019-12-30 07:53:43 -06:00
export type Cmd = ( . . . args : any [ ] ) = > any ;
2019-12-30 15:53:21 -06:00
2019-12-30 16:12:33 -06:00
const sleep = ( ms : number ) = > new Promise ( resolve = > setTimeout ( resolve , ms ) ) ;