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