2019-12-30 13:42:59 +00:00
import * as vscode from 'vscode' ;
import * as lc from 'vscode-languageclient' ;
import { Server } from './server' ;
2019-12-30 19:46:14 +00:00
import { Config } from './config' ;
2019-12-30 13:42:59 +00:00
export class Ctx {
2019-12-31 16:28:01 +00:00
readonly config = new Config ( ) ;
2019-12-30 14:11:30 +00:00
private extCtx : vscode.ExtensionContext ;
2019-12-30 13:42:59 +00:00
constructor ( extCtx : vscode.ExtensionContext ) {
2019-12-30 14:11:30 +00:00
this . extCtx = extCtx ;
2019-12-30 13:42:59 +00:00
}
get client ( ) : lc . LanguageClient {
2019-12-30 14:11:30 +00:00
return Server . client ;
2019-12-30 13:42:59 +00:00
}
2019-12-30 14:20:13 +00:00
get activeRustEditor ( ) : vscode . TextEditor | undefined {
const editor = vscode . window . activeTextEditor ;
return editor && editor . document . languageId === 'rust'
? editor
: undefined ;
}
2019-12-30 14:11:30 +00:00
registerCommand ( name : string , factory : ( ctx : Ctx ) = > Cmd ) {
const fullName = ` rust-analyzer. ${ name } ` ;
2019-12-30 13:42:59 +00:00
const cmd = factory ( this ) ;
const d = vscode . commands . registerCommand ( fullName , cmd ) ;
this . pushCleanup ( d ) ;
}
2019-12-30 15:43:34 +00: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 18:05:41 +00:00
get subscriptions ( ) : { dispose ( ) : any } [ ] {
return this . extCtx . subscriptions ;
}
2019-12-30 13:42:59 +00:00
pushCleanup ( d : { dispose ( ) : any } ) {
2019-12-30 14:11:30 +00:00
this . extCtx . subscriptions . push ( d ) ;
2019-12-30 13:42:59 +00:00
}
2019-12-30 21:18:16 +00:00
2019-12-30 22:12:33 +00:00
async sendRequestWithRetry < R > (
method : string ,
param : any ,
2019-12-31 01:17:50 +00:00
token? : vscode.CancellationToken ,
2019-12-30 22:12:33 +00:00
) : Promise < R > {
2019-12-30 21:18:16 +00:00
await this . client . onReady ( ) ;
2019-12-30 21:53:21 +00:00
for ( const delay of [ 2 , 4 , 6 , 8 , 10 , null ] ) {
2019-12-30 21:18:16 +00:00
try {
2019-12-31 10:44:52 +00:00
return await ( token ? this . client . sendRequest ( method , param , token ) : this . client . sendRequest ( method , param ) ) ;
2019-12-30 21:18:16 +00:00
} catch ( e ) {
2019-12-30 22:12:33 +00:00
if (
e . code === lc . ErrorCodes . ContentModified &&
delay !== null
) {
await sleep ( 10 * ( 1 << delay ) ) ;
2019-12-30 21:18:16 +00:00
continue ;
}
throw e ;
}
}
2019-12-30 22:12:33 +00:00
throw 'unreachable' ;
2019-12-30 21:18:16 +00:00
}
2019-12-31 16:22:43 +00:00
onNotification ( method : string , handler : lc.GenericNotificationHandler ) {
this . client . onReady ( )
. then ( ( ) = > this . client . onNotification ( method , handler ) )
}
2019-12-30 13:42:59 +00:00
}
2019-12-30 13:53:43 +00:00
export type Cmd = ( . . . args : any [ ] ) = > any ;
2019-12-30 21:53:21 +00:00
2019-12-30 22:12:33 +00:00
const sleep = ( ms : number ) = > new Promise ( resolve = > setTimeout ( resolve , ms ) ) ;