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-04-13 20:13:21 +00:00
import { CargoWatchProvider } from './commands/cargo_watch' ;
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-04-19 16:28:14 +00:00
import {
interactivelyStartCargoWatch ,
startCargoWatch
} from './commands/runnables' ;
2019-03-03 19:54:51 +00:00
import { SyntaxTreeContentProvider } from './commands/syntaxTree' ;
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' ;
2018-08-10 12:07:43 +00:00
export function activate ( context : vscode.ExtensionContext ) {
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 ,
2018-10-09 20:56:15 +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-10-30 20:44:06 +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-25 13:10:34 +00:00
registerCommand (
2019-01-28 11:43:07 +00:00
'rust-analyzer.analyzerStatus' ,
2019-01-25 13:10:34 +00:00
commands . analyzerStatus . makeCommand ( context )
) ;
2019-01-28 11:43:07 +00:00
registerCommand ( 'rust-analyzer.collectGarbage' , ( ) = >
Server . client . sendRequest < null > ( 'rust-analyzer/collectGarbage' , null )
2019-01-25 16:11:58 +00:00
) ;
2019-01-28 11:43:07 +00:00
registerCommand (
'rust-analyzer.matchingBrace' ,
commands . matchingBrace . handle
) ;
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' ,
2018-10-08 21:38:33 +00:00
commands . applySourceChange . handle
) ;
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 ) ,
locations . map ( Server . client . protocol2CodeConverter . asLocation )
) ;
}
) ;
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
2018-10-08 18:55:22 +00:00
// Notifications are events triggered by the language server
2018-10-08 21:38:33 +00:00
const allNotifications : Iterable <
[ string , lc . GenericNotificationHandler ]
2019-01-28 11:43:07 +00:00
> = [
2019-11-17 19:39:11 +00:00
[
'rust-analyzer/publishDecorations' ,
notifications . publishDecorations . handle
]
] ;
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-03-03 20:03:37 +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-03-03 19:54:51 +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' ,
expandMacroContentProvider
)
) ;
2018-08-10 12:07:43 +00:00
2019-03-03 19:21:40 +00:00
registerCommand (
'rust-analyzer.syntaxTree' ,
2019-03-03 19:54:51 +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' ,
commands . expandMacro . createHandle ( expandMacroContentProvider )
) ;
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 ,
2018-10-08 21:38:33 +00:00
context . subscriptions
) ;
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 ) ;
2019-03-18 21:30:23 +00:00
// Executing `cargo watch` provides us with inline diagnostics on save
2019-04-13 20:13:21 +00:00
let provider : CargoWatchProvider | undefined ;
interactivelyStartCargoWatch ( context ) . then ( p = > {
provider = p ;
} ) ;
registerCommand ( 'rust-analyzer.startCargoWatch' , ( ) = > {
if ( provider ) {
provider . start ( ) ;
2019-04-19 16:28:14 +00:00
} else {
startCargoWatch ( context ) . then ( p = > {
provider = p ;
} ) ;
2019-04-13 20:13:21 +00:00
}
} ) ;
registerCommand ( 'rust-analyzer.stopCargoWatch' , ( ) = > {
if ( provider ) {
provider . stop ( ) ;
}
} ) ;
2019-03-18 19:50:52 +00:00
2018-10-08 18:55:22 +00:00
// Start the language server, finally!
2019-04-15 19:41:27 +00:00
startServer ( ) ;
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-07-25 12:54:20 +00:00
disposeOnDeactivation (
2019-08-05 19:31:12 +00:00
vscode . window . onDidChangeVisibleTextEditors ( _ = >
hintsUpdater . refreshHintsForVisibleEditors ( )
2019-07-25 12:54:20 +00:00
)
) ;
disposeOnDeactivation (
vscode . workspace . onDidChangeTextDocument ( e = >
2019-08-05 19:31:12 +00:00
hintsUpdater . refreshHintsForVisibleEditors ( e )
2019-07-25 12:54:20 +00:00
)
) ;
disposeOnDeactivation (
vscode . workspace . onDidChangeConfiguration ( _ = >
hintsUpdater . toggleHintsDisplay (
Server . config . displayInlayHints
)
)
) ;
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
async function reloadServer ( startServer : ( ) = > void ) {
if ( Server . client != null ) {
vscode . window . showInformationMessage ( 'Reloading rust-analyzer...' ) ;
await Server . client . stop ( ) ;
startServer ( ) ;
}
2019-04-16 20:11:50 +00:00
}