mirror of
https://github.com/open-goal/opengoal-vscode.git
synced 2024-10-19 20:47:37 -04:00
consolidate and cleanup statusbar items (#345)
This commit is contained in:
parent
31d22058f0
commit
92d168700e
17
package.json
17
package.json
|
@ -55,6 +55,14 @@
|
|||
"command": "opengoal.switchFile",
|
||||
"title": "OpenGOAL - Switch File"
|
||||
},
|
||||
{
|
||||
"command": "opengoal.openLogs",
|
||||
"title": "OpenGOAL - Open Logs"
|
||||
},
|
||||
{
|
||||
"command": "opengoal.decomp.openLogs",
|
||||
"title": "OpenGOAL - Open Decompiler Logs"
|
||||
},
|
||||
{
|
||||
"command": "opengoal.decomp.openMostRecentIRFile",
|
||||
"title": "OpenGOAL - Open Recent IR2 File"
|
||||
|
@ -159,6 +167,10 @@
|
|||
"command": "opengoal.lsp.restart",
|
||||
"title": "OpenGOAL - LSP - Restart"
|
||||
},
|
||||
{
|
||||
"command": "opengoal.lsp.openLogs",
|
||||
"title": "OpenGOAL - LSP - Open Logs"
|
||||
},
|
||||
{
|
||||
"command": "opengoal.nrepl.jackin",
|
||||
"title": "OpenGOAL - nREPL - Jack-In"
|
||||
|
@ -216,6 +228,11 @@
|
|||
"id": "opengoal-decomp",
|
||||
"title": "Decompilation",
|
||||
"properties": {
|
||||
"opengoal.autoDecompilation": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Automatically active IR2 files"
|
||||
},
|
||||
"opengoal.eeManPagePath": {
|
||||
"type": [
|
||||
"string",
|
||||
|
|
|
@ -16,7 +16,6 @@ export function getConfig() {
|
|||
formatDecompilationOutput: configOptions.get<boolean>(
|
||||
"formatDecompilationOutput",
|
||||
),
|
||||
|
||||
eeManPagePath: configOptions.get<string>("eeManPagePath"),
|
||||
vuManPagePath: configOptions.get<string>("vuManPagePath"),
|
||||
decompilerPath: configOptions.get<string>("decompilerPath"),
|
||||
|
@ -34,6 +33,7 @@ export function getConfig() {
|
|||
"decompilerJak3ConfigVersion",
|
||||
"ntsc_v1",
|
||||
),
|
||||
autoDecompilation: configOptions.get<boolean>("autoDecompilation"),
|
||||
colorsGoalGlobals: configOptions.get<string>("colors.goal.entity.global"),
|
||||
colorsGoalStorageControl: configOptions.get<string>(
|
||||
"colors.goal.storage.control",
|
||||
|
@ -60,6 +60,15 @@ export function getConfig() {
|
|||
};
|
||||
}
|
||||
|
||||
export async function updateAutoDecompilation(val: boolean) {
|
||||
const userConfig = vscode.workspace.getConfiguration();
|
||||
await userConfig.update(
|
||||
"opengoal.autoDecompilation",
|
||||
val,
|
||||
vscode.ConfigurationTarget.Global,
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateEeManPagePath(path: string) {
|
||||
const userConfig = vscode.workspace.getConfiguration();
|
||||
await userConfig.update(
|
||||
|
|
102
src/context.ts
102
src/context.ts
|
@ -3,19 +3,35 @@
|
|||
import * as vscode from "vscode";
|
||||
import { RecentFiles } from "./RecentFiles";
|
||||
import { getWorkspaceFolderByName } from "./utils/workspace";
|
||||
import { getConfig } from "./config/config";
|
||||
import { isJackedIn } from "./tools/opengoal/nrepl/opengoal-nrepl";
|
||||
import { getLspStatus } from "./lsp/main";
|
||||
|
||||
const channel = vscode.window.createOutputChannel("OpenGOAL");
|
||||
let extensionContext: vscode.ExtensionContext;
|
||||
let recentFiles: RecentFiles;
|
||||
let projectRoot: vscode.Uri | undefined = undefined;
|
||||
let extensionStatus: vscode.StatusBarItem;
|
||||
|
||||
export function initContext(extContext: vscode.ExtensionContext) {
|
||||
extensionContext = extContext;
|
||||
extensionStatus = vscode.window.createStatusBarItem(
|
||||
vscode.StatusBarAlignment.Left,
|
||||
0,
|
||||
);
|
||||
updateStatusBar(false, false);
|
||||
|
||||
recentFiles = new RecentFiles(extensionContext);
|
||||
if (vscode.window.activeTextEditor?.document != undefined) {
|
||||
recentFiles.addFile(vscode.window.activeTextEditor?.document.fileName);
|
||||
}
|
||||
|
||||
// Commands
|
||||
extensionContext.subscriptions.push(
|
||||
vscode.commands.registerCommand("opengoal.openLogs", () => {
|
||||
channel.show();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function getRecentFiles() {
|
||||
|
@ -43,3 +59,89 @@ export function getProjectRoot(): vscode.Uri {
|
|||
}
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
export function updateStatusBar(
|
||||
workInProgress: boolean,
|
||||
errorOccurred: boolean,
|
||||
text?: string,
|
||||
): void {
|
||||
let statusIcon = "";
|
||||
const statusItem = extensionStatus;
|
||||
statusItem.show();
|
||||
statusItem.tooltip = new vscode.MarkdownString("", true);
|
||||
statusItem.tooltip.isTrusted = true;
|
||||
if (errorOccurred) {
|
||||
statusIcon = "$(testing-error-icon) ";
|
||||
} else if (workInProgress) {
|
||||
statusIcon = "$(loading~spin) ";
|
||||
}
|
||||
if (errorOccurred) {
|
||||
statusItem.backgroundColor = new vscode.ThemeColor(
|
||||
"statusBarItem.errorForeground",
|
||||
);
|
||||
} else {
|
||||
statusItem.backgroundColor = undefined;
|
||||
}
|
||||
statusItem.command = "opengoal.openLogs";
|
||||
if (text) {
|
||||
statusItem.text = `${statusIcon}${text}`;
|
||||
} else {
|
||||
statusItem.text = `${statusIcon}OpenGOAL`;
|
||||
}
|
||||
// tooltip
|
||||
statusItem.tooltip.appendMarkdown("**General**");
|
||||
statusItem.tooltip.appendMarkdown("\n\n---\n\n");
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Open Extension Logs](command:opengoal.openLogs)`,
|
||||
);
|
||||
if (isJackedIn()) {
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[nREPL Un-jack](command:opengoal.nrepl.unjack)`,
|
||||
);
|
||||
} else {
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[nREPL Jack-in](command:opengoal.nrepl.jackin)`,
|
||||
);
|
||||
}
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Change Parinfer Mode](command:opengoal.parinfer.changeMode): ${
|
||||
getConfig().opengoalParinferMode
|
||||
}`,
|
||||
);
|
||||
statusItem.tooltip.appendMarkdown("\n\n**LSP**");
|
||||
statusItem.tooltip.appendMarkdown("\n\n---\n\n");
|
||||
if (getLspStatus() === "started" || getLspStatus() === "error") {
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Restart Server](command:opengoal.lsp.restart)`,
|
||||
);
|
||||
} else if (getLspStatus() === "stopped") {
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Start Server](command:opengoal.lsp.start)`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
getLspStatus() !== "stopped" &&
|
||||
getLspStatus() !== "downloading" &&
|
||||
getLspStatus() !== "error"
|
||||
) {
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Stop Server](command:opengoal.lsp.stop)`,
|
||||
);
|
||||
}
|
||||
|
||||
if (getConfig().opengoalLspLogPath !== undefined) {
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Open LSP Logs](command:opengoal.lsp.openLogs)`,
|
||||
);
|
||||
}
|
||||
statusItem.tooltip.appendMarkdown("\n\n**Decompiling**");
|
||||
statusItem.tooltip.appendMarkdown("\n\n---\n\n");
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[Open Decompiler Logs](command:opengoal.decomp.openLogs)`,
|
||||
);
|
||||
statusItem.tooltip.appendMarkdown(
|
||||
`\n\n[${
|
||||
getConfig().autoDecompilation ? "Disable" : "Enable"
|
||||
} Auto-Decompilation](command:opengoal.decomp.toggleAutoDecompilation)`,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,16 @@ import { open_in_pdf } from "./man-page";
|
|||
import * as util from "util";
|
||||
import {
|
||||
getConfig,
|
||||
updateAutoDecompilation,
|
||||
updateDecompilerPath,
|
||||
updateFormatterPath,
|
||||
} from "../config/config";
|
||||
import * as path from "path";
|
||||
import { getExtensionContext, getProjectRoot } from "../context";
|
||||
import {
|
||||
getExtensionContext,
|
||||
getProjectRoot,
|
||||
updateStatusBar,
|
||||
} from "../context";
|
||||
import {
|
||||
getFileNamesFromUris,
|
||||
getUrisFromTabs,
|
||||
|
@ -31,14 +36,9 @@ const execAsync = util.promisify(exec);
|
|||
let channel: vscode.OutputChannel;
|
||||
let fsWatcher: vscode.FileSystemWatcher | undefined;
|
||||
|
||||
const decompStatusItem = vscode.window.createStatusBarItem(
|
||||
vscode.StatusBarAlignment.Left,
|
||||
0,
|
||||
);
|
||||
|
||||
enum DecompStatus {
|
||||
Idle,
|
||||
Running,
|
||||
Decompiling,
|
||||
Errored,
|
||||
Formatting,
|
||||
FormattingError,
|
||||
|
@ -48,40 +48,12 @@ function updateStatus(status: DecompStatus, metadata?: any) {
|
|||
let subText = "";
|
||||
switch (status) {
|
||||
case DecompStatus.Errored:
|
||||
decompStatusItem.tooltip = "Toggle Auto-Decomp";
|
||||
decompStatusItem.command = "opengoal.decomp.toggleAutoDecompilation";
|
||||
decompStatusItem.text = "$(testing-error-icon) Decomp Failed";
|
||||
updateStatusBar(false, true, "Decomp Failed");
|
||||
break;
|
||||
case DecompStatus.FormattingError:
|
||||
decompStatusItem.tooltip = "Toggle Auto-Decomp";
|
||||
decompStatusItem.command = "opengoal.decomp.toggleAutoDecompilation";
|
||||
decompStatusItem.text = "$(testing-error-icon) Formatting Failed";
|
||||
break;
|
||||
case DecompStatus.Idle:
|
||||
decompStatusItem.tooltip = "Toggle Auto-Decomp";
|
||||
decompStatusItem.command = "opengoal.decomp.toggleAutoDecompilation";
|
||||
if (fsWatcher === undefined) {
|
||||
decompStatusItem.text =
|
||||
"$(extensions-sync-ignored) Auto-Decomp Disabled";
|
||||
} else {
|
||||
decompStatusItem.text =
|
||||
"$(extensions-sync-enabled) Auto-Decomp Enabled";
|
||||
}
|
||||
break;
|
||||
case DecompStatus.Running:
|
||||
if (metadata.objectNames.length > 0) {
|
||||
if (metadata.objectNames.length <= 5) {
|
||||
subText = metadata.objectNames.join(", ");
|
||||
} else {
|
||||
subText = `${metadata.objectNames.slice(0, 5).join(", ")}, and ${
|
||||
metadata.objectNames.length - 5
|
||||
} more`;
|
||||
}
|
||||
}
|
||||
decompStatusItem.text = `$(loading~spin) Decompiling - ${subText} - [ ${metadata.decompConfig} ]`;
|
||||
decompStatusItem.tooltip = "Decompiling...";
|
||||
decompStatusItem.command = undefined;
|
||||
updateStatusBar(false, true, "Formatting Failed");
|
||||
break;
|
||||
case DecompStatus.Decompiling:
|
||||
case DecompStatus.Formatting:
|
||||
if (metadata.objectNames.length > 0) {
|
||||
if (metadata.objectNames.length <= 5) {
|
||||
|
@ -92,11 +64,14 @@ function updateStatus(status: DecompStatus, metadata?: any) {
|
|||
} more`;
|
||||
}
|
||||
}
|
||||
decompStatusItem.text = `$(loading~spin) Formatting - ${subText} - [ ${metadata.decompConfig} ]`;
|
||||
decompStatusItem.tooltip = "Formatting...";
|
||||
decompStatusItem.command = undefined;
|
||||
updateStatusBar(
|
||||
true,
|
||||
false,
|
||||
`${status == DecompStatus.Decompiling ? "Decompiling" : "Formatting"} - ${subText} - [ ${metadata.decompConfig} ]`,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
updateStatusBar(false, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -247,7 +222,7 @@ async function decompFiles(
|
|||
}
|
||||
|
||||
const allowed_objects = fileNames.map((name) => `"${name}"`).join(",");
|
||||
updateStatus(DecompStatus.Running, {
|
||||
updateStatus(DecompStatus.Decompiling, {
|
||||
objectNames: fileNames,
|
||||
decompConfig: path.parse(decompConfig).name,
|
||||
});
|
||||
|
@ -375,7 +350,7 @@ async function decompSpecificFile() {
|
|||
gameName = GameName.Jak1;
|
||||
} else if (gameNameSelection == "jak2") {
|
||||
gameName = GameName.Jak2;
|
||||
} else if (gameNameSelection == "jak3") {
|
||||
} else {
|
||||
gameName = GameName.Jak3;
|
||||
}
|
||||
}
|
||||
|
@ -496,8 +471,9 @@ function openManPage() {
|
|||
open_in_pdf(word);
|
||||
}
|
||||
|
||||
function toggleAutoDecompilation() {
|
||||
if (fsWatcher === undefined) {
|
||||
function setupAutoDecompilation() {
|
||||
const isEnabled = getConfig().autoDecompilation;
|
||||
if (isEnabled && fsWatcher === undefined) {
|
||||
fsWatcher = vscode.workspace.createFileSystemWatcher(
|
||||
"**/decompiler/config/**/*.{jsonc,json,gc}",
|
||||
);
|
||||
|
@ -511,11 +487,19 @@ function toggleAutoDecompilation() {
|
|||
});
|
||||
fsWatcher.onDidCreate(() => decompAllActiveFiles());
|
||||
fsWatcher.onDidDelete(() => decompAllActiveFiles());
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleAutoDecompilation() {
|
||||
const isEnabled = getConfig().autoDecompilation;
|
||||
await updateAutoDecompilation(!isEnabled);
|
||||
if (!getConfig().autoDecompilation && fsWatcher !== undefined) {
|
||||
fsWatcher.dispose();
|
||||
fsWatcher = undefined;
|
||||
} else if (getConfig().autoDecompilation) {
|
||||
setupAutoDecompilation();
|
||||
}
|
||||
updateStatus(DecompStatus.Idle);
|
||||
updateStatusBar(false, false);
|
||||
}
|
||||
|
||||
async function updateSourceFile() {
|
||||
|
@ -737,12 +721,15 @@ export async function activateDecompTools() {
|
|||
"opengoal-ir",
|
||||
);
|
||||
|
||||
toggleAutoDecompilation();
|
||||
|
||||
setupAutoDecompilation();
|
||||
updateStatus(DecompStatus.Idle);
|
||||
decompStatusItem.show();
|
||||
|
||||
// Commands
|
||||
getExtensionContext().subscriptions.push(
|
||||
vscode.commands.registerCommand("opengoal.decomp.openLogs", () => {
|
||||
channel.show();
|
||||
}),
|
||||
);
|
||||
getExtensionContext().subscriptions.push(
|
||||
vscode.commands.registerCommand("opengoal.decomp.openManPage", openManPage),
|
||||
);
|
||||
|
|
|
@ -3,6 +3,7 @@ import * as vscode from "vscode";
|
|||
import { integer } from "vscode-languageclient";
|
||||
import { getConfig, updateOpengoalParinferMode } from "../../config/config";
|
||||
import { getEditorRange } from "../../utils/editor-utils";
|
||||
import { updateStatusBar } from "../../context";
|
||||
|
||||
// TODO:
|
||||
// - iron out some quirks around undoing
|
||||
|
@ -72,45 +73,9 @@ const eventQueue: EventQueueItem[] = [];
|
|||
const maxEventQueueSize = 10;
|
||||
let currentParinferMode = ParinferMode.DISABLED;
|
||||
|
||||
const parinferStatusItem = vscode.window.createStatusBarItem(
|
||||
vscode.StatusBarAlignment.Left,
|
||||
0,
|
||||
);
|
||||
|
||||
function updateStatus() {
|
||||
switch (currentParinferMode) {
|
||||
case ParinferMode.DISABLED:
|
||||
parinferStatusItem.text = "$(json) Parinfer Disabled";
|
||||
parinferStatusItem.tooltip = "Currently doing nothing! - Change Mode";
|
||||
parinferStatusItem.command = "opengoal.parinfer.changeMode";
|
||||
break;
|
||||
case ParinferMode.SMART:
|
||||
parinferStatusItem.text = "$(json) Smart Parinfer";
|
||||
parinferStatusItem.tooltip =
|
||||
"Automatically runs in Paren or Indent mode - Change Mode";
|
||||
parinferStatusItem.command = "opengoal.parinfer.changeMode";
|
||||
break;
|
||||
case ParinferMode.PAREN:
|
||||
parinferStatusItem.text = "$(json) Paren Parinfer";
|
||||
parinferStatusItem.tooltip =
|
||||
"You handle the parens while parinfer handles indentation! - Change Mode";
|
||||
parinferStatusItem.command = "opengoal.parinfer.changeMode";
|
||||
break;
|
||||
case ParinferMode.INDENT:
|
||||
parinferStatusItem.text = "$(json) Parinfer Disabled";
|
||||
parinferStatusItem.tooltip =
|
||||
"You handle the indentation while parinfer handles the parens! - Change Mode";
|
||||
parinferStatusItem.command = "opengoal.parinfer.changeMode";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async function changeParinferMode(mode: ParinferMode) {
|
||||
currentParinferMode = mode;
|
||||
await updateOpengoalParinferMode(mode);
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
function cleanUpEventQueue() {
|
||||
|
@ -333,6 +298,7 @@ function showChangeModeMenu() {
|
|||
.then((v) => {
|
||||
if (v !== undefined) {
|
||||
changeParinferMode(v.label as ParinferMode);
|
||||
updateStatusBar(false, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -343,8 +309,6 @@ export function registerParinferCommands(
|
|||
changeParinferMode(
|
||||
(getConfig().opengoalParinferMode as ParinferMode) ?? ParinferMode.DISABLED,
|
||||
);
|
||||
updateStatus();
|
||||
parinferStatusItem.hide(); // TODO - consolidate menu https://github.com/rust-lang/rust-analyzer/blob/9c03aa1ac2e67051db83a85baf3cfee902e4dd84/editors/code/src/ctx.ts#L406
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(
|
||||
"opengoal.parinfer.changeMode",
|
||||
|
|
181
src/lsp/main.ts
181
src/lsp/main.ts
|
@ -1,100 +1,54 @@
|
|||
import * as vscode from "vscode";
|
||||
import * as path from "path";
|
||||
import {
|
||||
BaseLanguageClient,
|
||||
ClientCapabilities,
|
||||
DocumentSelector,
|
||||
FeatureState,
|
||||
InitializeParams,
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerCapabilities,
|
||||
ServerOptions,
|
||||
StaticFeature,
|
||||
TransportKind,
|
||||
WorkDoneProgress,
|
||||
WorkDoneProgressCreateRequest,
|
||||
} from "vscode-languageclient/node";
|
||||
import { getConfig } from "../config/config";
|
||||
import { downloadLsp } from "./download";
|
||||
import { getLatestVersion, getLspPath, getVersionFromMetaFile } from "./util";
|
||||
import * as fs from "fs";
|
||||
import { disposeAll } from "../vendor/vscode-pdfviewer/disposable";
|
||||
import { updateStatusBar } from "../context";
|
||||
|
||||
let extensionContext: vscode.ExtensionContext;
|
||||
let opengoalLspPath: string | undefined;
|
||||
let activeClient: LanguageClient | undefined;
|
||||
|
||||
type LspStatus =
|
||||
export type LspStatus =
|
||||
| "stopped"
|
||||
| "starting"
|
||||
| "started"
|
||||
| "downloading"
|
||||
| "error"
|
||||
| "serverProgressBegin"
|
||||
| "serverProgressEnd";
|
||||
| "error";
|
||||
|
||||
// TODO - rust analyzer's context menu on hover is nice
|
||||
class LSPStatusItem {
|
||||
private currentStatus: LspStatus = "stopped";
|
||||
|
||||
constructor(private readonly statusItem: vscode.StatusBarItem) {}
|
||||
|
||||
public updateStatus(status: LspStatus, extraInfo?: string) {
|
||||
this.currentStatus = status;
|
||||
switch (this.currentStatus) {
|
||||
case "stopped":
|
||||
this.statusItem.text = "$(circle-outline) OpenGOAL LSP Stopped";
|
||||
this.statusItem.tooltip = "Launch LSP";
|
||||
this.statusItem.command = "opengoal.lsp.start";
|
||||
break;
|
||||
case "starting":
|
||||
this.statusItem.text = "$(loading~spin) OpenGOAL LSP Starting";
|
||||
this.statusItem.tooltip = "LSP Starting";
|
||||
this.statusItem.command = undefined;
|
||||
break;
|
||||
case "started":
|
||||
this.statusItem.text = "$(circle-filled) OpenGOAL LSP Ready";
|
||||
this.statusItem.tooltip = `LSP Active - ${extraInfo}`;
|
||||
this.statusItem.command = "opengoal.lsp.showLspStartedMenu";
|
||||
break;
|
||||
case "downloading":
|
||||
this.statusItem.text = `$(sync~spin) OpenGOAL LSP Downloading - ${extraInfo}`;
|
||||
this.statusItem.tooltip = `Downloading version - ${extraInfo}`;
|
||||
this.statusItem.command = undefined;
|
||||
break;
|
||||
case "error":
|
||||
this.statusItem.text = "$(error) OpenGOAL LSP Error";
|
||||
this.statusItem.tooltip = "LSP not running due to an error";
|
||||
this.statusItem.command = undefined;
|
||||
break;
|
||||
case "serverProgressBegin":
|
||||
this.statusItem.text = `$(loading~spin) ${extraInfo}`;
|
||||
this.statusItem.tooltip = extraInfo;
|
||||
this.statusItem.command = "opengoal.lsp.showLspStartedMenu";
|
||||
break;
|
||||
case "serverProgressEnd":
|
||||
this.statusItem.text = `$(circle-filled) ${extraInfo}`;
|
||||
this.statusItem.tooltip = extraInfo;
|
||||
this.statusItem.command = "opengoal.lsp.showLspStartedMenu";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public hide() {
|
||||
this.statusItem.hide();
|
||||
}
|
||||
|
||||
public show() {
|
||||
this.statusItem.show();
|
||||
let currentStatus: LspStatus = "stopped";
|
||||
function updateStatus(status: LspStatus, extraInfo?: string) {
|
||||
currentStatus = status;
|
||||
switch (currentStatus) {
|
||||
case "starting":
|
||||
updateStatusBar(true, false, "LSP Starting");
|
||||
break;
|
||||
case "downloading":
|
||||
updateStatusBar(true, false, `LSP Downloading - ${extraInfo}`);
|
||||
break;
|
||||
case "error":
|
||||
updateStatusBar(false, true, "LSP Startup Error");
|
||||
break;
|
||||
default:
|
||||
updateStatusBar(false, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const statusItem = new LSPStatusItem(
|
||||
vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0),
|
||||
);
|
||||
/**
|
||||
* Get the current status of the LSP.
|
||||
* @returns A string representing the current status of the LSP, one of "stopped", "starting", "started", "downloading", or "error".
|
||||
*/
|
||||
export function getLspStatus(): LspStatus {
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
async function ensureServerDownloaded(): Promise<string | undefined> {
|
||||
const installedVersion = getVersionFromMetaFile(
|
||||
|
@ -130,15 +84,15 @@ async function ensureServerDownloaded(): Promise<string | undefined> {
|
|||
}
|
||||
|
||||
// Install the LSP and update the version metadata file
|
||||
statusItem.updateStatus("downloading", versionToDownload);
|
||||
updateStatus("downloading", versionToDownload);
|
||||
const newLspPath = await downloadLsp(
|
||||
extensionContext.extensionPath,
|
||||
versionToDownload,
|
||||
);
|
||||
if (newLspPath === undefined) {
|
||||
statusItem.updateStatus("error");
|
||||
updateStatus("error");
|
||||
} else {
|
||||
statusItem.updateStatus("stopped");
|
||||
updateStatus("stopped");
|
||||
}
|
||||
return newLspPath;
|
||||
}
|
||||
|
@ -221,7 +175,7 @@ function createClient(lspPath: string): LanguageClient {
|
|||
}
|
||||
|
||||
async function stopClient() {
|
||||
statusItem.updateStatus("stopped");
|
||||
updateStatus("stopped");
|
||||
if (activeClient !== undefined) {
|
||||
console.log("Stopping opengoal-lsp");
|
||||
return await activeClient
|
||||
|
@ -235,80 +189,27 @@ async function stopClient() {
|
|||
}
|
||||
}
|
||||
|
||||
class StatusBarFeature implements StaticFeature {
|
||||
private requestHandlers: vscode.Disposable[] = [];
|
||||
public fillClientCapabilities(capabilities: ClientCapabilities): void {
|
||||
if (!capabilities.window) {
|
||||
capabilities.window = {};
|
||||
}
|
||||
capabilities.window.workDoneProgress = true;
|
||||
}
|
||||
|
||||
constructor(private readonly client: BaseLanguageClient) {}
|
||||
|
||||
fillInitializeParams?: ((params: InitializeParams) => void) | undefined;
|
||||
preInitialize?:
|
||||
| ((
|
||||
capabilities: ServerCapabilities<any>,
|
||||
documentSelector: DocumentSelector | undefined,
|
||||
) => void)
|
||||
| undefined;
|
||||
clear(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public getState(): FeatureState {
|
||||
return { kind: "static" };
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
// nothing to dispose here
|
||||
}
|
||||
|
||||
public initialize(): void {
|
||||
this.requestHandlers.push(
|
||||
this.client.onRequest(WorkDoneProgressCreateRequest.type, ({ token }) => {
|
||||
this.client.onProgress(WorkDoneProgress.type, token, (progress) => {
|
||||
if (progress.kind === "begin") {
|
||||
statusItem.updateStatus("serverProgressBegin", progress.title);
|
||||
}
|
||||
if (progress.kind === "report") {
|
||||
// do nothing right now, goalc provides no feedback on it's status
|
||||
}
|
||||
if (progress.kind === "end") {
|
||||
statusItem.updateStatus("serverProgressEnd", progress.message);
|
||||
disposeAll(this.requestHandlers);
|
||||
}
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function startClient(): Promise<void> {
|
||||
if (opengoalLspPath === undefined) {
|
||||
return;
|
||||
}
|
||||
const client = createClient(opengoalLspPath);
|
||||
client.registerFeature(new StatusBarFeature(client));
|
||||
console.log("Starting opengoal-lsp at", opengoalLspPath);
|
||||
|
||||
// TODO - some form of startup test would be nice
|
||||
try {
|
||||
statusItem.updateStatus("starting");
|
||||
updateStatus("starting");
|
||||
await client.start();
|
||||
activeClient = client;
|
||||
statusItem.updateStatus("started", path.basename(opengoalLspPath));
|
||||
updateStatus("started", path.basename(opengoalLspPath));
|
||||
} catch (error) {
|
||||
console.error("opengoal-lsp:", error);
|
||||
statusItem.updateStatus("error");
|
||||
statusItem.hide();
|
||||
updateStatus("error");
|
||||
await stopClient();
|
||||
}
|
||||
}
|
||||
|
||||
export async function startClientCommand() {
|
||||
statusItem.show();
|
||||
await maybeDownloadLspServer();
|
||||
if (opengoalLspPath !== undefined) {
|
||||
await startClient();
|
||||
|
@ -359,7 +260,15 @@ function startedMenuCommand() {
|
|||
showMenu(items, commands);
|
||||
}
|
||||
|
||||
function registerLifeCycleCommands(context: vscode.ExtensionContext): void {
|
||||
function registerCommands(context: vscode.ExtensionContext): void {
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("opengoal.lsp.openLogs", () => {
|
||||
const logPath = getConfig().opengoalLspLogPath;
|
||||
if (logPath !== undefined) {
|
||||
vscode.commands.executeCommand("vscode.open", vscode.Uri.file(logPath));
|
||||
}
|
||||
}),
|
||||
);
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("opengoal.lsp.start", startClientCommand),
|
||||
);
|
||||
|
@ -381,11 +290,7 @@ export async function activate(
|
|||
context: vscode.ExtensionContext,
|
||||
): Promise<void> {
|
||||
extensionContext = context;
|
||||
registerLifeCycleCommands(context);
|
||||
// TODO - add info and open log file options
|
||||
// registerDiagnosticsCommands(context);
|
||||
statusItem.updateStatus("stopped");
|
||||
statusItem.show();
|
||||
registerCommands(context);
|
||||
const config = getConfig();
|
||||
if (config.launchLspOnStartup) {
|
||||
await startClientCommand();
|
||||
|
|
|
@ -3,34 +3,21 @@ import * as path from "path";
|
|||
import PromiseSocket from "promise-socket";
|
||||
import * as vscode from "vscode";
|
||||
import { getConfig } from "../../../config/config";
|
||||
import { updateStatusBar } from "../../../context";
|
||||
|
||||
let jackedIn = false;
|
||||
let socket: PromiseSocket<Socket> | undefined = undefined;
|
||||
|
||||
const nreplStatusItem = vscode.window.createStatusBarItem(
|
||||
vscode.StatusBarAlignment.Left,
|
||||
0,
|
||||
);
|
||||
// TODO - status bar updates for errors and such
|
||||
|
||||
function updateStatus() {
|
||||
// TODO - show errors
|
||||
if (!jackedIn) {
|
||||
nreplStatusItem.text = "$(call-outgoing) nREPL";
|
||||
nreplStatusItem.tooltip =
|
||||
"Jack-in to a running OpenGOAL nREPL on port 8181";
|
||||
nreplStatusItem.command = "opengoal.nrepl.jackin";
|
||||
} else {
|
||||
nreplStatusItem.text = "$(debug-disconnect) nREPL";
|
||||
nreplStatusItem.tooltip =
|
||||
"Un-jack from a running OpenGOAL nREPL on port 8181";
|
||||
nreplStatusItem.command = "opengoal.nrepl.unjack";
|
||||
}
|
||||
export function isJackedIn() {
|
||||
return jackedIn;
|
||||
}
|
||||
|
||||
export async function jackIn() {
|
||||
if (socket !== undefined) {
|
||||
jackedIn = true;
|
||||
updateStatus();
|
||||
updateStatusBar(false, false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
@ -46,13 +33,13 @@ export async function jackIn() {
|
|||
console.error(e);
|
||||
socket = undefined;
|
||||
}
|
||||
updateStatus();
|
||||
updateStatusBar(false, false);
|
||||
}
|
||||
|
||||
export async function unJack() {
|
||||
if (socket === undefined) {
|
||||
jackedIn = false;
|
||||
updateStatus();
|
||||
updateStatusBar(false, false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
@ -62,7 +49,7 @@ export async function unJack() {
|
|||
}
|
||||
socket = undefined;
|
||||
jackedIn = false;
|
||||
updateStatus();
|
||||
updateStatusBar(false, false);
|
||||
}
|
||||
|
||||
export async function reloadFile(fileName: string) {
|
||||
|
@ -100,8 +87,6 @@ export function registerNReplCommands(context: vscode.ExtensionContext): void {
|
|||
vscode.commands.registerCommand("opengoal.nrepl.jackin", jackIn),
|
||||
vscode.commands.registerCommand("opengoal.nrepl.unjack", unJack),
|
||||
);
|
||||
updateStatus();
|
||||
nreplStatusItem.show();
|
||||
}
|
||||
|
||||
export function nreplOnFileSaveHandler(e: vscode.TextDocument) {
|
||||
|
@ -110,6 +95,5 @@ export function nreplOnFileSaveHandler(e: vscode.TextDocument) {
|
|||
}
|
||||
// Get the name
|
||||
const fileName = path.basename(e.fileName).replace(".gc", "");
|
||||
console.log(fileName);
|
||||
reloadFile(fileName);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue