Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bundle of fixes/improvements to extension #12

Merged
merged 13 commits into from
May 28, 2024
9 changes: 9 additions & 0 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Documentation for Extension Developers

This document is intended for developers who want to contribute to the Chapel extension for Visual Studio Code.

## Building locally

To build and test the extension locally in debug mode, you can use the Run/Debug tab to launch the extension in a new VSCode window (or press `F5`).

For some debugging purposes, it may be useful to build a local binary of the extension using `vsce`. To do this, run `vsce package -o bin/chapel.vsix` from the root of the repository. This can then be installed in VSCode by selecting "Install from VSIX" in the Extensions view, or by running `code --install-extension bin/chapel.vsix`.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- Generic Instantiations: inspect generic code with helpful annotations
- Dead Code: highlight dead code that will never execute

> **_:warning: CAUTION:_**
> **_CAUTION:_**
> These features use a work-in-progress resolver for Chapel called Dyno to further
> inspect your code. To enable these features, use Dyno by setting
> `chapel.chpl-language-server.resolver` to `true`. Enabling the Dyno resolver
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 13 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,8 @@
],
"commands": [
{
"command": "chapel.findChpl",
"title": "Find Chapel",
"category": "chapel"
},
{
"command": "chapel.buildTools",
"title": "Build chpl-language-server and chplcheck",
"command": "chapel.findChplHome",
"title": "Find CHPL_HOME",
"category": "chapel"
},
{
Expand All @@ -114,7 +109,7 @@
"chapel.CHPL_HOME": {
"scope": "window",
"type": "string",
"description": "CHPL_HOME"
"description": "The path to CHPL_HOME. If not provided, the extension may be able to find it automatically if `chpl`, `chplcheck`, and `chpl-language-server` are in PATH."
},
"chapel.CHPL_DEVELOPER": {
"scope": "window",
Expand All @@ -128,6 +123,11 @@
"default": true,
"description": "Enable chplcheck"
},
"chapel.chplcheck.path": {
"scope": "window",
"type": "string",
"description": "An explicit path to the chplcheck executable. If not provided, the extension will look for chplcheck in PATH and in CHPL_HOME"
},
"chapel.chplcheck.args": {
"scope": "window",
"type": "array",
Expand All @@ -143,6 +143,11 @@
"default": true,
"description": "Enable chpl-language-server"
},
"chapel.chpl-language-server.path": {
"scope": "window",
"type": "string",
"description": "An explicit path to the chpl-language-server executable. If not provided, the extension will look for chpl-language-server in PATH and in CHPL_HOME"
},
"chapel.chpl-language-server.resolver": {
"scope": "window",
"type": "boolean",
Expand Down
94 changes: 65 additions & 29 deletions src/ChapelLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@
* limitations under the License.
*/

import { ToolConfig, getChplDeveloper } from "./configuration";
import { ToolConfig, getChplDeveloper, getChplHome } from "./configuration";
import * as fs from "fs";
import * as vscode from "vscode";
import * as vlc from "vscode-languageclient/node";
import { checkToolPath, checkChplHome, cloneEnv } from "./ChplPaths";
import {
checkToolPath,
checkChplHome,
cloneEnv,
findToolPath,
findPossibleChplHomes,
getWorkspaceFolder,
} from "./ChplPaths";
import { showChplHomeMissingError } from "./extension";
import * as path from "path";

export enum LanguageClientState {
Expand Down Expand Up @@ -62,21 +70,19 @@ class ErrorHandlingClient extends vlc.LanguageClient {
}

export abstract class ChapelLanguageClient {
chplhome: string;
protected config_: ToolConfig;
name: string;
state: LanguageClientState;
tool_path: string;
client: ErrorHandlingClient | undefined;
logger: vscode.LogOutputChannel;
statusBarItem: vscode.StatusBarItem;

constructor(
chplhome: string,
config: ToolConfig,
name: string,
logger: vscode.LogOutputChannel
) {
this.chplhome = chplhome;
this.config_ = config;
this.name = name;
this.state = this.config_.enable
Expand All @@ -85,16 +91,30 @@ export abstract class ChapelLanguageClient {
this.tool_path = this.getToolPath();
this.client = undefined;
this.logger = logger;
this.statusBarItem = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Right,
1000
);
// render the text using vscode codicons
this.statusBarItem.text = `$(error) ${this.name}`;
this.statusBarItem.tooltip = `${this.name} is stopped. Click to restart.`;
this.statusBarItem.color = new vscode.ThemeColor(
"statusBarItem.errorForeground"
);
this.statusBarItem.backgroundColor = new vscode.ThemeColor(
"statusBarItem.errorBackground"
);
this.statusBarItem.command = `${this.name}.restart`;
this.statusBarItem.hide();
}

protected abstract getToolPath(): string;

get config(): ToolConfig {
return this.config_;
}
async resetConfig(chplhome: string, config: ToolConfig) {
async resetConfig(config: ToolConfig) {
await this.stop();
this.chplhome = chplhome;
this.config_ = config;
this.state = this.config_.enable
? LanguageClientState.STOPPED
Expand All @@ -105,36 +125,41 @@ export abstract class ChapelLanguageClient {

setErrorState() {
this.state = LanguageClientState.ERRORED;
this.statusBarItem.show();
}

clearError(): void {
this.state = LanguageClientState.STOPPED;
}

private errorFindTools() {
this.setErrorState();
// if invalid chplhome, prompt user to set it
// if missing tool path, warn user that we can't find it, tell them to not override the path or upgrade their chapel version
// otherwise, its likely the tools arent built, so prompt the user to build them

if (checkChplHome(this.chplhome) !== undefined) {
if (this.tool_path === "") {
vscode.window
.showErrorMessage(
"CHPL_HOME is either missing or incorrect, make sure the path is correct",
"Find CHPL_HOME",
`Could not determine the path for ${this.name}. Make sure it is installed. If it is, you may need to set the path manually.`,
`Set ${this.name} Path`,
"Set CHPL_HOME",
"Show Log",
"Ok"
)
.then((value) => {
if (value === "Find CHPL_HOME") {
vscode.commands.executeCommand("chapel.findChpl");
if (value === `Set ${this.name} Path`) {
// TODO
} else if (value === "Set CHPL_HOME") {
vscode.commands.executeCommand("chapel.findChplHome");
} else if (value === "Show Log") {
this.logger.show();
}
});
} else if (checkToolPath(this.tool_path) !== undefined) {
vscode.window
.showErrorMessage(
`${this.name} does not exist in the CHPL_HOME directory, make sure you are using the correct version of Chapel`,
`${this.name} is missing at the path '${this.tool_path}'. If you set the path manually, make sure it is correct. If it is, you may need to upgrade your Chapel version.`,
"Show Log",
"Ok"
)
Expand All @@ -146,15 +171,12 @@ export abstract class ChapelLanguageClient {
} else {
vscode.window
.showErrorMessage(
`${this.name} encountered an error, this is likely because ${this.name} is not installed. Double check that ${this.name} is built.`,
"Build Tools",
`${this.name} encountered an error. You may need to rebuild ${this.name}.`,
"Show Log",
"Ok"
)
.then((value) => {
if (value === "Build Tools") {
vscode.commands.executeCommand(`chapel.buildTools`, this.chplhome);
} else if (value === "Show Log") {
if (value === "Show Log") {
this.logger.show();
}
});
Expand All @@ -168,16 +190,25 @@ export abstract class ChapelLanguageClient {
return Promise.resolve();
}
this.state = LanguageClientState.STARTING;
this.statusBarItem.hide();
let toolPathError = checkToolPath(this.tool_path);
if (toolPathError !== undefined) {
this.logger.error(toolPathError);
this.errorFindTools();
this.state = LanguageClientState.STOPPED;
return Promise.reject();
}

let env = cloneEnv();
env.CHPL_HOME = this.chplhome;
const chplhome = getChplHome();
if (chplhome !== undefined && chplhome !== "") {
this.logger.info(`Using CHPL_HOME: ${chplhome}`);
const chplHomeError = checkChplHome(chplhome);
if (chplHomeError !== undefined) {
showChplHomeMissingError(chplHomeError);
} else {
env.CHPL_HOME = chplhome;
}
}
env.CHPL_DEVELOPER = getChplDeveloper() ? "1" : "0";

let args = this.alwaysArguments();
Expand All @@ -190,7 +221,7 @@ export abstract class ChapelLanguageClient {
command: this.tool_path,
args: args,
options: {
cwd: this.chplhome,
cwd: getWorkspaceFolder()?.uri.fsPath,
env: env,
},
};
Expand Down Expand Up @@ -238,7 +269,7 @@ export abstract class ChapelLanguageClient {
}

this.stop().finally(() => {
this.state = LanguageClientState.ERRORED;
this.setErrorState();

vscode.window
.showErrorMessage(
Expand Down Expand Up @@ -337,20 +368,25 @@ export abstract class ChapelLanguageClient {

export class ChplCheckClient extends ChapelLanguageClient {
getToolPath(): string {
return path.join(this.chplhome, "tools", "chplcheck", "chplcheck");
const path = findToolPath("chplcheck", getChplHome());
if (path === undefined) {
this.setErrorState();
return "";
}
return path;
}
alwaysArguments(): Array<string> {
return ["--lsp"];
}
}
export class CLSClient extends ChapelLanguageClient {
getToolPath(): string {
return path.join(
this.chplhome,
"tools",
"chpl-language-server",
"chpl-language-server"
);
const path = findToolPath("chpl-language-server", getChplHome());
if (path === undefined) {
this.setErrorState();
return "";
}
return path;
}
alwaysArguments(): Array<string> {
let args = [];
Expand Down
Loading