2018-08-10 07:07:43 -05:00
import * as vscode from 'vscode' ;
2018-10-08 13:55:22 -05:00
import * as lc from 'vscode-languageclient' ;
2018-08-10 07:07:43 -05:00
2018-10-07 15:59:02 -05:00
import * as commands from './commands' ;
2019-11-19 11:06:10 -06:00
import { ExpandMacroContentProvider } from './commands/expand_macro' ;
2019-07-23 08:38:21 -05:00
import { HintsUpdater } from './commands/inlay_hints' ;
2019-03-03 13:54:51 -06:00
import { SyntaxTreeContentProvider } from './commands/syntaxTree' ;
2019-12-25 12:10:30 -06:00
import { StatusDisplay } from './commands/watch_status' ;
2018-10-07 15:59:02 -05:00
import * as events from './events' ;
2018-10-08 13:55:22 -05:00
import * as notifications from './notifications' ;
2018-10-07 15:59:02 -05:00
import { Server } from './server' ;
2019-12-30 08:11:30 -06:00
import { Ctx } from './ctx' ;
2019-12-30 07:42:59 -06:00
let ctx ! : Ctx ;
2018-08-10 07:07:43 -05:00
2019-12-08 06:41:44 -06:00
export async function activate ( context : vscode.ExtensionContext ) {
2019-12-30 07:42:59 -06:00
ctx = new Ctx ( context ) ;
2019-12-30 07:53:43 -06:00
ctx . registerCommand ( 'analyzerStatus' , commands . analyzerStatus ) ;
ctx . registerCommand ( 'collectGarbage' , commands . collectGarbage ) ;
2019-12-30 08:20:13 -06:00
ctx . registerCommand ( 'matchingBrace' , commands . matchingBrace ) ;
2019-12-30 07:42:59 -06:00
2018-10-07 15:44:25 -05:00
function disposeOnDeactivation ( disposable : vscode.Disposable ) {
2018-08-10 07:07:43 -05:00
context . subscriptions . push ( disposable ) ;
}
2018-08-22 02:18:58 -05:00
2018-10-07 15:44:25 -05:00
function registerCommand ( name : string , f : any ) {
2018-10-07 15:59:02 -05:00
disposeOnDeactivation ( vscode . commands . registerCommand ( name , f ) ) ;
2018-10-07 15:44:25 -05:00
}
2018-10-09 08:00:20 -05:00
function overrideCommand (
name : string ,
2019-12-09 12:57:55 -06:00
f : ( . . . args : any [ ] ) = > Promise < boolean > ,
2018-10-09 08:00:20 -05:00
) {
const defaultCmd = ` default: ${ name } ` ;
2018-10-12 01:59:12 -05:00
const original = ( . . . args : any [ ] ) = >
vscode . commands . executeCommand ( defaultCmd , . . . args ) ;
2018-10-09 15:56:15 -05:00
2018-12-22 07:26:18 -06:00
try {
registerCommand ( name , async ( . . . args : any [ ] ) = > {
const editor = vscode . window . activeTextEditor ;
if (
! editor ||
! editor . document ||
editor . document . languageId !== 'rust'
) {
return await original ( . . . args ) ;
}
if ( ! ( await f ( . . . args ) ) ) {
return await original ( . . . args ) ;
}
} ) ;
2019-01-12 17:49:07 -06:00
} catch ( _ ) {
vscode . window . showWarningMessage (
2019-12-09 12:57:55 -06:00
'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-01-12 17:49:07 -06:00
) ;
2018-12-22 07:26:18 -06:00
}
2018-10-09 08:00:20 -05:00
}
2018-08-27 12:58:38 -05:00
2018-10-08 13:55:22 -05:00
// Commands are requests from vscode to the language server
2019-01-28 05:43:07 -06:00
registerCommand ( 'rust-analyzer.joinLines' , commands . joinLines . handle ) ;
registerCommand ( 'rust-analyzer.parentModule' , commands . parentModule . handle ) ;
registerCommand ( 'rust-analyzer.run' , commands . runnables . handle ) ;
// Unlike the above this does not send requests to the language server
registerCommand ( 'rust-analyzer.runSingle' , commands . runnables . handleSingle ) ;
registerCommand (
'rust-analyzer.applySourceChange' ,
2019-12-09 12:57:55 -06:00
commands . applySourceChange . handle ,
2018-10-08 16:38:33 -05:00
) ;
2019-02-01 07:44:23 -06:00
registerCommand (
'rust-analyzer.showReferences' ,
( uri : string , position : lc.Position , locations : lc.Location [ ] ) = > {
vscode . commands . executeCommand (
'editor.action.showReferences' ,
vscode . Uri . parse ( uri ) ,
Server . client . protocol2CodeConverter . asPosition ( position ) ,
2019-12-09 12:57:55 -06:00
locations . map ( Server . client . protocol2CodeConverter . asLocation ) ,
2019-02-01 07:44:23 -06:00
) ;
2019-12-09 12:57:55 -06:00
} ,
2019-02-01 07:44:23 -06:00
) ;
2019-02-07 04:37:36 -06:00
if ( Server . config . enableEnhancedTyping ) {
overrideCommand ( 'type' , commands . onEnter . handle ) ;
}
2018-08-10 13:13:39 -05:00
2019-12-25 12:10:30 -06:00
const watchStatus = new StatusDisplay (
2019-12-25 13:23:44 -06:00
Server . config . cargoWatchOptions . command ,
2019-12-25 12:10:30 -06:00
) ;
2019-12-25 12:08:44 -06:00
disposeOnDeactivation ( watchStatus ) ;
2018-10-08 13:55:22 -05:00
// Notifications are events triggered by the language server
2019-12-08 12:27:50 -06:00
const allNotifications : Iterable < [
string ,
2019-12-09 12:57:55 -06:00
lc . GenericNotificationHandler ,
2019-12-08 12:27:50 -06:00
] > = [
2019-12-30 08:11:30 -06:00
[
'rust-analyzer/publishDecorations' ,
notifications . publishDecorations . handle ,
] ,
[
'$/progress' ,
params = > watchStatus . handleProgressNotification ( params ) ,
] ,
] ;
2019-03-03 14:03:37 -06:00
const syntaxTreeContentProvider = new SyntaxTreeContentProvider ( ) ;
2019-11-19 11:06:10 -06:00
const expandMacroContentProvider = new ExpandMacroContentProvider ( ) ;
2018-10-08 13:55:22 -05:00
// The events below are plain old javascript events, triggered and handled by vscode
2018-10-08 16:38:33 -05:00
vscode . window . onDidChangeActiveTextEditor (
2019-12-09 12:57:55 -06:00
events . changeActiveTextEditor . makeHandler ( syntaxTreeContentProvider ) ,
2018-10-08 16:38:33 -05:00
) ;
2018-10-08 13:55:22 -05:00
2018-10-08 16:38:33 -05:00
disposeOnDeactivation (
vscode . workspace . registerTextDocumentContentProvider (
2019-01-28 05:43:07 -06:00
'rust-analyzer' ,
2019-12-09 12:57:55 -06:00
syntaxTreeContentProvider ,
) ,
2018-10-08 16:38:33 -05:00
) ;
2019-11-19 11:06:10 -06:00
disposeOnDeactivation (
vscode . workspace . registerTextDocumentContentProvider (
'rust-analyzer' ,
2019-12-09 12:57:55 -06:00
expandMacroContentProvider ,
) ,
2019-11-19 11:06:10 -06:00
) ;
2018-08-10 07:07:43 -05:00
2019-03-03 13:21:40 -06:00
registerCommand (
'rust-analyzer.syntaxTree' ,
2019-12-09 12:57:55 -06:00
commands . syntaxTree . createHandle ( syntaxTreeContentProvider ) ,
2019-03-03 13:21:40 -06:00
) ;
2019-11-19 11:06:10 -06:00
registerCommand (
'rust-analyzer.expandMacro' ,
2019-12-09 12:57:55 -06:00
commands . expandMacro . createHandle ( expandMacroContentProvider ) ,
2019-11-19 11:06:10 -06:00
) ;
2019-03-03 13:21:40 -06:00
2018-10-07 15:44:25 -05:00
vscode . workspace . onDidChangeTextDocument (
2019-03-03 13:54:51 -06:00
events . changeTextDocument . createHandler ( syntaxTreeContentProvider ) ,
2018-10-07 15:44:25 -05:00
null ,
2019-12-09 12:57:55 -06:00
context . subscriptions ,
2018-10-08 16:38:33 -05:00
) ;
2018-10-08 13:55:22 -05:00
2019-04-15 14:41:27 -05:00
const startServer = ( ) = > Server . start ( allNotifications ) ;
const reloadCommand = ( ) = > reloadServer ( startServer ) ;
vscode . commands . registerCommand ( 'rust-analyzer.reload' , reloadCommand ) ;
2018-10-08 13:55:22 -05:00
// Start the language server, finally!
2019-12-08 06:41:44 -06:00
try {
await startServer ( ) ;
} catch ( e ) {
vscode . window . showErrorMessage ( e . message ) ;
}
2019-07-23 08:38:21 -05:00
if ( Server . config . displayInlayHints ) {
const hintsUpdater = new HintsUpdater ( ) ;
2019-08-05 14:31:12 -05:00
hintsUpdater . refreshHintsForVisibleEditors ( ) . then ( ( ) = > {
// vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
// so update the hints once when the focus changes to guarantee their presence
let editorChangeDisposable : vscode.Disposable | null = null ;
editorChangeDisposable = vscode . window . onDidChangeActiveTextEditor (
_ = > {
if ( editorChangeDisposable !== null ) {
editorChangeDisposable . dispose ( ) ;
}
return hintsUpdater . refreshHintsForVisibleEditors ( ) ;
2019-12-09 12:57:55 -06:00
} ,
2019-08-05 14:31:12 -05:00
) ;
2019-07-25 07:54:20 -05:00
disposeOnDeactivation (
2019-08-05 14:31:12 -05:00
vscode . window . onDidChangeVisibleTextEditors ( _ = >
2019-12-09 12:57:55 -06:00
hintsUpdater . refreshHintsForVisibleEditors ( ) ,
) ,
2019-07-25 07:54:20 -05:00
) ;
disposeOnDeactivation (
vscode . workspace . onDidChangeTextDocument ( e = >
2019-12-09 12:57:55 -06:00
hintsUpdater . refreshHintsForVisibleEditors ( e ) ,
) ,
2019-07-25 07:54:20 -05:00
) ;
disposeOnDeactivation (
vscode . workspace . onDidChangeConfiguration ( _ = >
hintsUpdater . toggleHintsDisplay (
2019-12-09 12:57:55 -06:00
Server . config . displayInlayHints ,
) ,
) ,
2019-07-25 07:54:20 -05:00
) ;
2019-07-23 08:38:21 -05:00
} ) ;
}
2018-08-17 11:54:08 -05:00
}
2018-08-10 07:07:43 -05:00
export function deactivate ( ) : Thenable < void > {
2018-10-07 15:44:25 -05:00
if ( ! Server . client ) {
2018-08-27 14:52:43 -05:00
return Promise . resolve ( ) ;
2018-08-10 07:07:43 -05:00
}
2018-10-07 15:44:25 -05:00
return Server . client . stop ( ) ;
2018-08-29 10:03:14 -05:00
}
2019-04-15 14:41:27 -05:00
2019-12-08 06:41:44 -06:00
async function reloadServer ( startServer : ( ) = > Promise < void > ) {
2019-04-15 14:41:27 -05:00
if ( Server . client != null ) {
vscode . window . showInformationMessage ( 'Reloading rust-analyzer...' ) ;
await Server . client . stop ( ) ;
2019-12-08 06:41:44 -06:00
await startServer ( ) ;
2019-04-15 14:41:27 -05:00
}
2019-04-16 15:11:50 -05:00
}