@@ -15,6 +15,7 @@ import {
15
15
ExecutableOptions ,
16
16
LanguageClient ,
17
17
LanguageClientOptions ,
18
+ Logger ,
18
19
RevealOutputChannelOn ,
19
20
ServerOptions ,
20
21
TransportKind ,
@@ -23,7 +24,7 @@ import { CommandNames } from './commands/constants';
23
24
import { ImportIdentifier } from './commands/importIdentifier' ;
24
25
import { DocsBrowser } from './docsBrowser' ;
25
26
import { downloadHaskellLanguageServer } from './hlsBinaries' ;
26
- import { executableExists } from './utils' ;
27
+ import { executableExists , ExtensionLogger } from './utils' ;
27
28
28
29
// The current map of documents & folders to language servers.
29
30
// It may be null to indicate that we are in the process of launching a server,
@@ -45,7 +46,11 @@ export async function activate(context: ExtensionContext) {
45
46
for ( const folder of event . removed ) {
46
47
const client = clients . get ( folder . uri . toString ( ) ) ;
47
48
if ( client ) {
48
- clients . delete ( folder . uri . toString ( ) ) ;
49
+ const uri = folder . uri . toString ( ) ;
50
+ client . info ( 'Deleting folder for clients: ${uri}' ) ;
51
+ clients . delete ( uri ) ;
52
+ client . info ;
53
+ client . info ( 'Stopping the client' ) ;
49
54
client . stop ( ) ;
50
55
}
51
56
}
@@ -54,10 +59,13 @@ export async function activate(context: ExtensionContext) {
54
59
// Register editor commands for HIE, but only register the commands once at activation.
55
60
const restartCmd = commands . registerCommand ( CommandNames . RestartServerCommandName , async ( ) => {
56
61
for ( const langClient of clients . values ( ) ) {
62
+ langClient ?. info ( 'Stopping the client' ) ;
57
63
await langClient ?. stop ( ) ;
64
+ langClient ?. info ( 'Starting the client' ) ;
58
65
langClient ?. start ( ) ;
59
66
}
60
67
} ) ;
68
+
61
69
context . subscriptions . push ( restartCmd ) ;
62
70
63
71
context . subscriptions . push ( ImportIdentifier . registerCommand ( ) ) ;
@@ -70,30 +78,31 @@ export async function activate(context: ExtensionContext) {
70
78
context . subscriptions . push ( openOnHackageDisposable ) ;
71
79
}
72
80
73
- function findManualExecutable ( uri : Uri , folder ?: WorkspaceFolder ) : string | null {
81
+ function findManualExecutable ( logger : Logger , uri : Uri , folder ?: WorkspaceFolder ) : string | null {
74
82
let exePath = workspace . getConfiguration ( 'haskell' , uri ) . serverExecutablePath ;
75
83
if ( exePath === '' ) {
76
84
return null ;
77
85
}
78
-
86
+ logger . info ( 'Trying to find the server executable in: ${exePath}' ) ;
79
87
// Substitute path variables with their corresponding locations.
80
88
exePath = exePath . replace ( '${HOME}' , os . homedir ) . replace ( '${home}' , os . homedir ) . replace ( / ^ ~ / , os . homedir ) ;
81
89
if ( folder ) {
82
90
exePath = exePath . replace ( '${workspaceFolder}' , folder . uri . path ) . replace ( '${workspaceRoot}' , folder . uri . path ) ;
83
91
}
84
-
92
+ logger . info ( 'Location after path variables subsitution: ${exePath}' ) ;
85
93
if ( ! executableExists ( exePath ) ) {
86
94
throw new Error ( `serverExecutablePath is set to ${ exePath } but it doesn't exist and is not on the PATH` ) ;
87
95
}
88
96
return exePath ;
89
97
}
90
98
91
99
/** Searches the PATH for whatever is set in serverVariant */
92
- function findLocalServer ( context : ExtensionContext , uri : Uri , folder ?: WorkspaceFolder ) : string | null {
100
+ function findLocalServer ( context : ExtensionContext , logger : Logger , uri : Uri , folder ?: WorkspaceFolder ) : string | null {
93
101
const exes : string [ ] = [ 'haskell-language-server-wrapper' , 'haskell-language-server' ] ;
94
-
102
+ logger . info ( 'Searching for server executables ${exes} in PATH' ) ;
95
103
for ( const exe of exes ) {
96
104
if ( executableExists ( exe ) ) {
105
+ logger . info ( 'Found server executable in PATH: ${exe}' ) ;
97
106
return exe ;
98
107
}
99
108
}
@@ -120,6 +129,9 @@ async function activeServer(context: ExtensionContext, document: TextDocument) {
120
129
121
130
async function activateServerForFolder ( context : ExtensionContext , uri : Uri , folder ?: WorkspaceFolder ) {
122
131
const clientsKey = folder ? folder . uri . toString ( ) : uri . toString ( ) ;
132
+ // Set a unique name per workspace folder (useful for multi-root workspaces).
133
+ const langName = 'Haskell' + ( folder ? ` (${ folder . name } )` : '' ) ;
134
+ const outputChannel : OutputChannel = window . createOutputChannel ( langName ) ;
123
135
124
136
// If the client already has an LSP server for this uri/folder, then don't start a new one.
125
137
if ( clients . has ( clientsKey ) ) {
@@ -129,21 +141,25 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold
129
141
clients . set ( clientsKey , null ) ;
130
142
131
143
const logLevel = workspace . getConfiguration ( 'haskell' , uri ) . trace . server ;
144
+ const clientLogLevel = workspace . getConfiguration ( 'haskell' , uri ) . trace . client ;
132
145
const logFile = workspace . getConfiguration ( 'haskell' , uri ) . logFile ;
133
146
147
+ const logger : Logger = new ExtensionLogger ( 'client' , clientLogLevel , outputChannel ) ;
148
+
134
149
let serverExecutable ;
135
150
try {
136
151
// Try and find local installations first
137
- serverExecutable = findManualExecutable ( uri , folder ) ?? findLocalServer ( context , uri , folder ) ;
152
+ serverExecutable = findManualExecutable ( logger , uri , folder ) ?? findLocalServer ( context , logger , uri , folder ) ;
138
153
if ( serverExecutable === null ) {
139
154
// If not, then try to download haskell-language-server binaries if it's selected
140
- serverExecutable = await downloadHaskellLanguageServer ( context , uri , folder ) ;
155
+ serverExecutable = await downloadHaskellLanguageServer ( context , logger , uri , folder ) ;
141
156
if ( ! serverExecutable ) {
142
157
return ;
143
158
}
144
159
}
145
160
} catch ( e ) {
146
161
if ( e instanceof Error ) {
162
+ logger . error ( 'Error getting the server executable: ${e.message}' ) ;
147
163
window . showErrorMessage ( e . message ) ;
148
164
}
149
165
return ;
@@ -173,13 +189,9 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold
173
189
debug : { command : serverExecutable , transport : TransportKind . stdio , args, options : exeOptions } ,
174
190
} ;
175
191
176
- // Set a unique name per workspace folder (useful for multi-root workspaces).
177
- const langName = 'Haskell' + ( folder ? ` (${ folder . name } )` : '' ) ;
178
- const outputChannel : OutputChannel = window . createOutputChannel ( langName ) ;
179
- outputChannel . appendLine ( '[client] run command: "' + serverExecutable + ' ' + args . join ( ' ' ) + '"' ) ;
180
- outputChannel . appendLine ( '[client] debug command: "' + serverExecutable + ' ' + args . join ( ' ' ) + '"' ) ;
181
-
182
- outputChannel . appendLine ( `[client] server cwd: ${ exeOptions . cwd } ` ) ;
192
+ logger . info ( 'run command: "' + serverExecutable + ' ' + args . join ( ' ' ) + '"' ) ;
193
+ logger . info ( 'debug command: "' + serverExecutable + ' ' + args . join ( ' ' ) + '"' ) ;
194
+ logger . info ( `server cwd: ${ exeOptions . cwd } ` ) ;
183
195
184
196
const pat = folder ? `${ folder . uri . fsPath } /**/*` : '**/*' ;
185
197
const clientOptions : LanguageClientOptions = {
@@ -213,6 +225,7 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold
213
225
langClient . registerProposedFeatures ( ) ;
214
226
215
227
// Finally start the client and add it to the list of clients.
228
+ logger . info ( 'Starting language client' ) ;
216
229
langClient . start ( ) ;
217
230
clients . set ( clientsKey , langClient ) ;
218
231
}
0 commit comments