88 * you may not use this file except in compliance with the License.
99 * You may obtain a copy of the License at
1010 *
11- * http: // www.apache.org/licenses/LICENSE-2.0
11+ * http: // www.apache.org/licenses/LICENSE-2.0
1212 *
1313 * Unless required by applicable law or agreed to in writing, software
1414 * distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,10 +25,10 @@ import * as vscode from "vscode";
2525import which from "which" ;
2626
2727import {
28- LanguageClient ,
29- LanguageClientOptions ,
30- ServerOptions ,
31- State ,
28+ LanguageClient ,
29+ LanguageClientOptions ,
30+ ServerOptions ,
31+ State ,
3232} from "vscode-languageclient/node" ;
3333
3434let client : LanguageClient ;
@@ -40,39 +40,41 @@ let logger: vscode.LogOutputChannel
4040 * Called when vscode first activates the extension
4141 */
4242export async function activate ( context : vscode . ExtensionContext ) {
43- logger = vscode . window . createOutputChannel ( 'LFortran Language Server' , {
44- log : true
45- } ) ;
43+ logger = vscode . window . createOutputChannel ( 'LFortran Language Server' , {
44+ log : true
45+ } ) ;
4646
47- logger . info ( "Extension activated." ) ;
48- await startLangServer ( ) ;
47+ logger . info ( "Extension activated." ) ;
48+ await startLangServer ( ) ;
4949}
5050
5151async function checkPathExistsAndIsExecutable ( path : string ) : Promise < boolean > {
52- let pathExistsAndIsExecutable : boolean = false ;
53-
54- try {
55- const stats = await fs . promises . stat ( path ) ;
56- pathExistsAndIsExecutable = stats . isFile ( ) && ( stats . mode & 0o111 ) !== 0 ;
57- } catch ( err : any ) {
58- if ( err . code !== 'ENOENT' ) {
59- throw err ; // Other errors
52+ let pathExistsAndIsExecutable : boolean = false ;
53+
54+ try {
55+ const stats = await fs . promises . stat ( path ) ;
56+ pathExistsAndIsExecutable = stats . isFile ( ) && ( stats . mode & 0o111 ) !== 0 ;
57+ } catch ( err : any ) {
58+ if ( err . code !== 'ENOENT' ) {
59+ throw err ; // Other errors
60+ }
6061 }
61- }
6262
63- return pathExistsAndIsExecutable ;
63+ return pathExistsAndIsExecutable ;
6464}
6565
66- async function getLFortranPath ( ) : Promise < string | null | undefined > {
67- const compilerSettings =
68- vscode . workspace . getConfiguration ( "LFortranLanguageServer.compiler" ) ;
69- let lfortranPath = compilerSettings . get < string > ( "lfortranPath" ) ;
70- if ( lfortranPath === "lfortran"
71- || ! ( await checkPathExistsAndIsExecutable ( lfortranPath ) ) ) {
72- lfortranPath = await which ( "lfortran" , { nothrow : true } ) ;
73- }
74- logger . info ( `lfortranPath = ${ lfortranPath } ` ) ;
75- return lfortranPath ;
66+ async function getConfig ( ) : Promise < vscode . WorkspaceConfiguration > {
67+ return vscode . workspace . getConfiguration ( "LFortranLanguageServer" ) ;
68+ }
69+
70+ async function getLFortranPath ( config : vscode . WorkspaceConfiguration ) : Promise < string | null | undefined > {
71+ let lfortranPath = config . get < string > ( "compiler.lfortranPath" ) ;
72+ if ( lfortranPath === "lfortran"
73+ || ! ( await checkPathExistsAndIsExecutable ( lfortranPath ) ) ) {
74+ lfortranPath = await which ( "lfortran" , { nothrow : true } ) ;
75+ }
76+ logger . info ( `lfortranPath = ${ lfortranPath } ` ) ;
77+ return lfortranPath ;
7678}
7779
7880/**
@@ -84,81 +86,110 @@ async function getLFortranPath(): Promise<string | null | undefined> {
8486 */
8587async function startLangServer ( ) {
8688
87- // Don't interfere if we are already in the process of launching the server.
88- if ( clientStarting ) {
89- logger . info ( "clientStarting, returning ..." ) ;
90- return ;
91- }
92-
93- clientStarting = true ;
94- if ( client ) {
95- await stopLangServer ( ) ;
96- }
97-
98- const lfortranPath = await getLFortranPath ( ) ;
99- if ( ! lfortranPath ) {
100- logger . warn ( "lfortran command not found." ) ;
101- clientStarting = false ;
102- return ;
103- }
104-
105- const serverOptions : ServerOptions = {
106- command : lfortranPath ,
107- args : [
108- "server" ,
109- ] ,
110- options : {
111- env : process . env ,
112- } ,
113- } ;
114-
115- const clientOptions : LanguageClientOptions = {
116- documentSelector : [
117- {
118- scheme : "file" ,
119- language : "fortran"
120- } ,
121- ] ,
122- outputChannel : logger ,
123- connectionOptions : {
124- maxRestartCount : 0 // don't restart on server failure.
125- } ,
126- } ;
127-
128- client = new LanguageClient (
129- "LFortranLanguageServer" ,
130- "LFortran Language Server" ,
131- serverOptions ,
132- clientOptions ) ;
133-
134- const promises = [ client . start ( ) ]
135-
136- const results = await Promise . allSettled ( promises )
137- clientStarting = false
138-
139- for ( const result of results ) {
140- if ( result . status === "rejected" ) {
141- logger . error ( `There was a error starting the server: ${ result . reason } ` )
89+ // Don't interfere if we are already in the process of launching the server.
90+ if ( clientStarting ) {
91+ logger . info ( "clientStarting, returning ..." ) ;
92+ return ;
93+ }
94+
95+ clientStarting = true ;
96+ if ( client ) {
97+ await stopLangServer ( ) ;
98+ }
99+
100+ const config = await getConfig ( ) ;
101+ const lfortranPath = await getLFortranPath ( config ) ;
102+ if ( ! lfortranPath ) {
103+ logger . warn ( "lfortran command not found." ) ;
104+ clientStarting = false ;
105+ return ;
106+ }
107+
108+ const prettyPrint : boolean = config . get < boolean > ( "log.prettyPrint" ) ;
109+ const indentSize : number = config . get < number > ( "log.indentSize" ) ;
110+
111+ const serverArgs : string [ ] = [
112+ "server" ,
113+ "--open-issue-reporter-on-error" , config . get < boolean > ( "openIssueReporterOnError" ) . toString ( ) ,
114+ "--max-number-of-problems" , config . get < number > ( "maxNumberOfProblems" ) . toString ( 10 ) ,
115+ "--trace-server" , config . get < string > ( "trace.server" ) ,
116+ // "--compiler-path", config.get<string>("compiler.path"),
117+ "--compiler-path" , lfortranPath ,
118+ "--log-path" , config . get < string > ( "log.path" ) ,
119+ "--log-level" , config . get < string > ( "log.level" ) ,
120+ "--log-pretty-print" , prettyPrint . toString ( ) ,
121+ "--log-indent-size" , indentSize . toString ( 10 ) ,
122+ ] ;
123+
124+ const compilerFlags = config . get < string [ ] > ( "compiler.flags" ) ;
125+ if ( compilerFlags . length > 0 ) {
126+ serverArgs . push ( "--" )
127+ for ( const compilerFlag of compilerFlags ) {
128+ serverArgs . push ( compilerFlag )
129+ }
130+ }
131+
132+ const serverOptions : ServerOptions = {
133+ command : lfortranPath ,
134+ args : serverArgs ,
135+ options : {
136+ env : process . env ,
137+ } ,
138+ } ;
139+
140+ if ( prettyPrint ) {
141+ logger . debug ( `Executing lfortran: ${ JSON . stringify ( serverOptions , undefined , indentSize ) } ` )
142+ } else {
143+ logger . debug ( `Executing lfortran: ${ JSON . stringify ( serverOptions ) } ` )
144+ }
145+
146+ const clientOptions : LanguageClientOptions = {
147+ documentSelector : [
148+ {
149+ scheme : "file" ,
150+ language : "fortran"
151+ } ,
152+ ] ,
153+ outputChannel : logger ,
154+ connectionOptions : {
155+ maxRestartCount : Number . MAX_SAFE_INTEGER
156+ } ,
157+ } ;
158+
159+ client = new LanguageClient (
160+ "LFortranLanguageServer" ,
161+ "LFortran Language Server" ,
162+ serverOptions ,
163+ clientOptions ) ;
164+
165+ const promises = [ client . start ( ) ]
166+
167+ const results = await Promise . allSettled ( promises )
168+ clientStarting = false
169+
170+ for ( const result of results ) {
171+ if ( result . status === "rejected" ) {
172+ logger . error ( `There was a error starting the server: ${ result . reason } ` )
173+ }
142174 }
143- }
144175}
145176
146177export function deactivate ( ) : Thenable < void > {
147- return stopLangServer ( ) ;
178+ return stopLangServer ( ) ;
148179}
149180
150181async function stopLangServer ( ) : Promise < void > {
151- logger . info ( "Stopping lang server ..." ) ;
152- if ( ! client ) {
153- logger . info ( "No client to stop, returning..." ) ;
154- return
155- }
156-
157- if ( client . state === State . Running ) {
158- await client . stop ( ) ;
159- logger . info ( "Client stopped ..." ) ;
160- }
161-
162- client . dispose ( )
163- client = undefined
182+ logger . info ( "Stopping lang server ..." ) ;
183+ if ( ! client ) {
184+ logger . info ( "No client to stop, returning..." ) ;
185+ return
186+ }
187+
188+ if ( client . state === State . Running ) {
189+ await client . stop ( ) ;
190+ logger . info ( "Client stopped ..." ) ;
191+ }
192+
193+ client . dispose ( )
194+ client = undefined
164195}
0 commit comments