1- import * as path from "path" ;
2- import * as fs from 'fs' ;
1+ import * as fs from "fs"
2+ import * as path from "path"
33
44import {
55 commands ,
99 ExtensionContext ,
1010 MarkdownString ,
1111 StatusBarAlignment ,
12+ StatusBarItem ,
1213 TextEditor ,
1314 ThemeColor ,
1415} from 'vscode'
@@ -20,62 +21,21 @@ import {
2021 TransportKind ,
2122} from 'vscode-languageclient/node'
2223
23- const logger = window . createOutputChannel ( "Roughly Extension" , { log : true } ) ;
24+ const logger = window . createOutputChannel ( "Roughly Extension" , { log : true } )
25+ const outputChannel = window . createOutputChannel ( "Roughly" )
2426
2527const EXTENSION_ROOT_DIR = path . dirname ( __dirname )
2628const ROUGHLY_BINARY_NAME = process . platform === "win32" ? "roughly.exe" : "roughly"
2729const BUNDLED_ROUGHLY_EXECUTABLE = path . join ( EXTENSION_ROOT_DIR , "bin" , ROUGHLY_BINARY_NAME )
2830
29- let client : LanguageClient
30- let statusBar
31+ let client : LanguageClient | null = null
32+ let statusBar : StatusBarItem
3133let status = { health : "started" }
32- let version
34+ let version : string | undefined
3335
34- export function activate ( { subscriptions, extension } : ExtensionContext ) {
36+ export async function activate ( { subscriptions, extension, } : ExtensionContext ) : Promise < void > {
3537 version = extension . packageJSON . version ?? "<unknown>"
3638
37- const config = workspace . getConfiguration ( "roughly" )
38-
39- const command = process . env . SERVER_PATH
40- ?? config . get < string > ( "path" )
41- ?? (
42- fs . existsSync ( BUNDLED_ROUGHLY_EXECUTABLE )
43- ? BUNDLED_ROUGHLY_EXECUTABLE
44- : "roughly"
45- )
46-
47- const args = config . get < string [ ] > ( "args" , [ "server" ] )
48-
49- logger . info ( "using server command:" , [ command , ...args ] . join ( " " ) )
50-
51- const outputChannel = window . createOutputChannel ( "Roughly" ) ;
52-
53- client = ( ( ) => {
54- const serverOptions : ServerOptions = {
55- command,
56- args,
57- transport : TransportKind . stdio ,
58- options : {
59- env : {
60- ...process . env ,
61- RUST_LOG : "debug" ,
62- } ,
63- } ,
64- }
65-
66- const clientOptions : LanguageClientOptions = {
67- documentSelector : [ { scheme : "file" , language : "r" } ] ,
68- outputChannel,
69- }
70-
71- return new LanguageClient (
72- 'roughly' ,
73- 'Roughly' ,
74- serverOptions ,
75- clientOptions
76- )
77- } ) ( )
78-
7939 subscriptions . push (
8040 workspace . onDidChangeConfiguration ( async ( change ) => {
8141 if (
@@ -85,43 +45,36 @@ export function activate({ subscriptions, extension }: ExtensionContext) {
8545 "Restart" ,
8646 )
8747 if ( choice === "Restart" ) {
88- await client . restart ( )
48+ await restartClient ( )
8949 setTimeout ( ( ) => {
90- client . outputChannel . show ( )
50+ client ? .outputChannel . show ( )
9151 } , 1500 )
9252 }
9353 }
9454 } ) ,
9555 commands . registerCommand (
9656 "roughly.restartServer" ,
9757 async ( ) => {
98- if ( client . isRunning ) {
99- await client . restart ( )
100- } else {
101- await client . start ( )
102- }
103- setServerStatus ( { health : "started" } )
58+ await restartClient ( )
10459 }
10560 ) ,
10661 commands . registerCommand (
10762 "roughly.startServer" ,
10863 async ( ) => {
109- await client . start ( )
110- setServerStatus ( { health : "started" } )
64+ await restartClient ( )
11165 }
11266 ) ,
11367 commands . registerCommand (
11468 "roughly.stopServer" ,
11569 async ( ) => {
116- await client . stop ( )
117- setServerStatus ( { health : "stopped" } )
70+ await stopClient ( )
11871 }
11972 ) ,
12073 commands . registerCommand (
12174 "roughly.openLogs" ,
12275 async ( ) => {
123- if ( client . outputChannel ) {
124- client . outputChannel . show ( ) ;
76+ if ( client ? .outputChannel ) {
77+ client . outputChannel . show ( )
12578 }
12679 }
12780 )
@@ -133,16 +86,100 @@ export function activate({ subscriptions, extension }: ExtensionContext) {
13386 updateStatusBarVisibility ( window . activeTextEditor )
13487 window . onDidChangeActiveTextEditor ( ( editor ) => updateStatusBarVisibility ( editor ) )
13588
136- client . start ( ) // this also launches the server
89+ restartClient ( )
90+ }
91+
92+ export async function deactivate ( ) : Promise < void > {
93+ await stopClient ( )
13794}
13895
96+ //
97+ // SERVER
98+ //
99+
100+ async function restartClient ( ) : Promise < void > {
101+ const newClient = createClient ( )
102+ try {
103+ await newClient . start ( )
104+ void stopClient ( )
105+ client = newClient
106+ setServerStatus ( { health : "started" } )
107+ } catch ( reason ) {
108+ void window . showWarningMessage ( "Failed to start Roughly language server." )
109+ setServerStatus ( { health : "stopped" } )
110+ }
111+ }
112+
113+ function createClient ( ) : LanguageClient {
114+ const config = workspace . getConfiguration ( "roughly" )
115+
116+ const command = process . env . SERVER_PATH
117+ ?? config . get < string > ( "path" )
118+ ?? (
119+ fs . existsSync ( BUNDLED_ROUGHLY_EXECUTABLE )
120+ ? BUNDLED_ROUGHLY_EXECUTABLE
121+ : "roughly"
122+ )
123+
124+ const args = config . get < string [ ] > ( "args" , [ "server" ] )
125+
126+ logger . info ( "using server command:" , [ command , ...args ] . join ( " " ) )
127+
128+ const serverOptions : ServerOptions = {
129+ command,
130+ args,
131+ transport : TransportKind . stdio ,
132+ options : {
133+ env : {
134+ ...process . env ,
135+ RUST_LOG : "debug" ,
136+ } ,
137+ } ,
138+ }
139+
140+ const clientOptions : LanguageClientOptions = {
141+ documentSelector : [ { scheme : "file" , language : "r" } ] ,
142+ outputChannel,
143+ }
144+
145+ const client = new LanguageClient (
146+ 'roughly' ,
147+ 'Roughly' ,
148+ serverOptions ,
149+ clientOptions
150+ )
151+
152+ return client
153+ }
154+
155+
156+ async function stopClient ( ) : Promise < void > {
157+ if ( ! client ) {
158+ return
159+ }
160+
161+ logger . info ( "stopping server ..." )
162+
163+ const oldClient = client
164+ client = null
165+
166+ // The `stop` call will send the "shutdown" notification to the LSP
167+ await oldClient . stop ( )
168+ // The `dipose` call will send the "exit" request to the LSP which actually tells the child process to exit
169+ await oldClient . dispose ( )
170+ }
171+
172+ //
173+ // STATUS BAR
174+ //
175+
139176type ServerStatus = {
140177 health : "started" | "stopped"
141178}
142179
143180function setServerStatus ( newStatus : ServerStatus ) {
144- status = newStatus ;
145- updateStatusBarItem ( ) ;
181+ status = newStatus
182+ updateStatusBarItem ( )
146183}
147184
148185function updateStatusBarVisibility ( editor : TextEditor | undefined ) {
@@ -188,11 +225,3 @@ function updateStatusBarItem() {
188225 // if (true) icon = "$(loading~spin) "
189226 statusBar . text = `${ icon } Roughly`
190227}
191-
192-
193- export function deactivate ( ) : Thenable < void > | undefined {
194- if ( ! client ) {
195- return undefined
196- }
197- return client . stop ( )
198- }
0 commit comments