Skip to content

Commit

Permalink
Adds config option for log path; removes config options for benchmark…
Browse files Browse the repository at this point in the history
…ing and filtering logs since they are no longer needed; passes config options to lfortran when the server is initialized
  • Loading branch information
dylon committed Feb 28, 2025
1 parent fd21699 commit d37c233
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 248 deletions.
231 changes: 131 additions & 100 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: // www.apache.org/licenses/LICENSE-2.0
* http: // www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -25,10 +25,10 @@ import * as vscode from "vscode";
import which from "which";

import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
State,
LanguageClient,
LanguageClientOptions,
ServerOptions,
State,
} from "vscode-languageclient/node";

let client: LanguageClient;
Expand All @@ -40,39 +40,41 @@ let logger: vscode.LogOutputChannel
* Called when vscode first activates the extension
*/
export async function activate(context: vscode.ExtensionContext) {
logger = vscode.window.createOutputChannel('LFortran Language Server', {
log: true
});
logger = vscode.window.createOutputChannel('LFortran Language Server', {
log: true
});

logger.info("Extension activated.");
await startLangServer();
logger.info("Extension activated.");
await startLangServer();
}

async function checkPathExistsAndIsExecutable(path: string): Promise<boolean> {
let pathExistsAndIsExecutable: boolean = false;

try {
const stats = await fs.promises.stat(path);
pathExistsAndIsExecutable = stats.isFile() && (stats.mode & 0o111) !== 0;
} catch (err: any) {
if (err.code !== 'ENOENT') {
throw err; // Other errors
let pathExistsAndIsExecutable: boolean = false;

try {
const stats = await fs.promises.stat(path);
pathExistsAndIsExecutable = stats.isFile() && (stats.mode & 0o111) !== 0;
} catch (err: any) {
if (err.code !== 'ENOENT') {
throw err; // Other errors
}
}
}

return pathExistsAndIsExecutable;
return pathExistsAndIsExecutable;
}

async function getLFortranPath(): Promise<string | null | undefined> {
const compilerSettings =
vscode.workspace.getConfiguration("LFortranLanguageServer.compiler");
let lfortranPath = compilerSettings.get<string>("lfortranPath");
if (lfortranPath === "lfortran"
|| !(await checkPathExistsAndIsExecutable(lfortranPath))) {
lfortranPath = await which("lfortran", { nothrow: true });
}
logger.info(`lfortranPath = ${lfortranPath}`);
return lfortranPath;
async function getConfig(): Promise<vscode.WorkspaceConfiguration> {
return vscode.workspace.getConfiguration("LFortranLanguageServer");
}

async function getLFortranPath(config: vscode.WorkspaceConfiguration): Promise<string | null | undefined> {
let lfortranPath = config.get<string>("compiler.lfortranPath");
if (lfortranPath === "lfortran"
|| !(await checkPathExistsAndIsExecutable(lfortranPath))) {
lfortranPath = await which("lfortran", { nothrow: true });
}
logger.info(`lfortranPath = ${lfortranPath}`);
return lfortranPath;
}

/**
Expand All @@ -84,81 +86,110 @@ async function getLFortranPath(): Promise<string | null | undefined> {
*/
async function startLangServer() {

// Don't interfere if we are already in the process of launching the server.
if (clientStarting) {
logger.info("clientStarting, returning ...");
return;
}

clientStarting = true;
if (client) {
await stopLangServer();
}

const lfortranPath = await getLFortranPath();
if (!lfortranPath) {
logger.warn("lfortran command not found.");
clientStarting = false;
return;
}

const serverOptions: ServerOptions = {
command: lfortranPath,
args: [
"server",
],
options: {
env: process.env,
},
};

const clientOptions: LanguageClientOptions = {
documentSelector: [
{
scheme: "file",
language: "fortran"
},
],
outputChannel: logger,
connectionOptions: {
maxRestartCount: 0 // don't restart on server failure.
},
};

client = new LanguageClient(
"LFortranLanguageServer",
"LFortran Language Server",
serverOptions,
clientOptions);

const promises = [client.start()]

const results = await Promise.allSettled(promises)
clientStarting = false

for (const result of results) {
if (result.status === "rejected") {
logger.error(`There was a error starting the server: ${result.reason}`)
// Don't interfere if we are already in the process of launching the server.
if (clientStarting) {
logger.info("clientStarting, returning ...");
return;
}

clientStarting = true;
if (client) {
await stopLangServer();
}

const config = await getConfig();
const lfortranPath = await getLFortranPath(config);
if (!lfortranPath) {
logger.warn("lfortran command not found.");
clientStarting = false;
return;
}

const prettyPrint: boolean = config.get<boolean>("log.prettyPrint");
const indentSize: number = config.get<number>("log.indentSize");

const serverArgs: string[] = [
"server",
"--open-issue-reporter-on-error", config.get<boolean>("openIssueReporterOnError").toString(),
"--max-number-of-problems", config.get<number>("maxNumberOfProblems").toString(10),
"--trace-server", config.get<string>("trace.server"),
// "--compiler-path", config.get<string>("compiler.path"),
"--compiler-path", lfortranPath,
"--log-path", config.get<string>("log.path"),
"--log-level", config.get<string>("log.level"),
"--log-pretty-print", prettyPrint.toString(),
"--log-indent-size", indentSize.toString(10),
];

const compilerFlags = config.get<string[]>("compiler.flags");
if (compilerFlags.length > 0) {
serverArgs.push("--")
for (const compilerFlag of compilerFlags) {
serverArgs.push(compilerFlag)
}
}

const serverOptions: ServerOptions = {
command: lfortranPath,
args: serverArgs,
options: {
env: process.env,
},
};

if (prettyPrint) {
logger.debug(`Executing lfortran: ${JSON.stringify(serverOptions, undefined, indentSize)}`)
} else {
logger.debug(`Executing lfortran: ${JSON.stringify(serverOptions)}`)
}

const clientOptions: LanguageClientOptions = {
documentSelector: [
{
scheme: "file",
language: "fortran"
},
],
outputChannel: logger,
connectionOptions: {
maxRestartCount: Number.MAX_SAFE_INTEGER
},
};

client = new LanguageClient(
"LFortranLanguageServer",
"LFortran Language Server",
serverOptions,
clientOptions);

const promises = [client.start()]

const results = await Promise.allSettled(promises)
clientStarting = false

for (const result of results) {
if (result.status === "rejected") {
logger.error(`There was a error starting the server: ${result.reason}`)
}
}
}
}

export function deactivate(): Thenable<void> {
return stopLangServer();
return stopLangServer();
}

async function stopLangServer(): Promise<void> {
logger.info("Stopping lang server ...");
if (!client) {
logger.info("No client to stop, returning...");
return
}

if (client.state === State.Running) {
await client.stop();
logger.info("Client stopped ...");
}

client.dispose()
client = undefined
logger.info("Stopping lang server ...");
if (!client) {
logger.info("No client to stop, returning...");
return
}

if (client.state === State.Running) {
await client.stop();
logger.info("Client stopped ...");
}

client.dispose()
client = undefined
}
2 changes: 1 addition & 1 deletion esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as esbuild from 'esbuild';
const watch = process.argv.includes('--watch');

let production = process.argv.includes('--production');
if (process.env.FORTLS_LFORTRAN_MODE === "debug") {
if (process.env.LFORTRAN_LSP_MODE === "debug") {
production = false;
}

Expand Down
Loading

0 comments on commit d37c233

Please sign in to comment.