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",
|
"command": "opengoal.switchFile",
|
||||||
"title": "OpenGOAL - Switch File"
|
"title": "OpenGOAL - Switch File"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.openLogs",
|
||||||
|
"title": "OpenGOAL - Open Logs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.decomp.openLogs",
|
||||||
|
"title": "OpenGOAL - Open Decompiler Logs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "opengoal.decomp.openMostRecentIRFile",
|
"command": "opengoal.decomp.openMostRecentIRFile",
|
||||||
"title": "OpenGOAL - Open Recent IR2 File"
|
"title": "OpenGOAL - Open Recent IR2 File"
|
||||||
|
@ -159,6 +167,10 @@
|
||||||
"command": "opengoal.lsp.restart",
|
"command": "opengoal.lsp.restart",
|
||||||
"title": "OpenGOAL - LSP - Restart"
|
"title": "OpenGOAL - LSP - Restart"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.lsp.openLogs",
|
||||||
|
"title": "OpenGOAL - LSP - Open Logs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "opengoal.nrepl.jackin",
|
"command": "opengoal.nrepl.jackin",
|
||||||
"title": "OpenGOAL - nREPL - Jack-In"
|
"title": "OpenGOAL - nREPL - Jack-In"
|
||||||
|
@ -216,6 +228,11 @@
|
||||||
"id": "opengoal-decomp",
|
"id": "opengoal-decomp",
|
||||||
"title": "Decompilation",
|
"title": "Decompilation",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"opengoal.autoDecompilation": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Automatically active IR2 files"
|
||||||
|
},
|
||||||
"opengoal.eeManPagePath": {
|
"opengoal.eeManPagePath": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
|
|
|
@ -16,7 +16,6 @@ export function getConfig() {
|
||||||
formatDecompilationOutput: configOptions.get<boolean>(
|
formatDecompilationOutput: configOptions.get<boolean>(
|
||||||
"formatDecompilationOutput",
|
"formatDecompilationOutput",
|
||||||
),
|
),
|
||||||
|
|
||||||
eeManPagePath: configOptions.get<string>("eeManPagePath"),
|
eeManPagePath: configOptions.get<string>("eeManPagePath"),
|
||||||
vuManPagePath: configOptions.get<string>("vuManPagePath"),
|
vuManPagePath: configOptions.get<string>("vuManPagePath"),
|
||||||
decompilerPath: configOptions.get<string>("decompilerPath"),
|
decompilerPath: configOptions.get<string>("decompilerPath"),
|
||||||
|
@ -34,6 +33,7 @@ export function getConfig() {
|
||||||
"decompilerJak3ConfigVersion",
|
"decompilerJak3ConfigVersion",
|
||||||
"ntsc_v1",
|
"ntsc_v1",
|
||||||
),
|
),
|
||||||
|
autoDecompilation: configOptions.get<boolean>("autoDecompilation"),
|
||||||
colorsGoalGlobals: configOptions.get<string>("colors.goal.entity.global"),
|
colorsGoalGlobals: configOptions.get<string>("colors.goal.entity.global"),
|
||||||
colorsGoalStorageControl: configOptions.get<string>(
|
colorsGoalStorageControl: configOptions.get<string>(
|
||||||
"colors.goal.storage.control",
|
"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) {
|
export async function updateEeManPagePath(path: string) {
|
||||||
const userConfig = vscode.workspace.getConfiguration();
|
const userConfig = vscode.workspace.getConfiguration();
|
||||||
await userConfig.update(
|
await userConfig.update(
|
||||||
|
|
102
src/context.ts
102
src/context.ts
|
@ -3,19 +3,35 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { RecentFiles } from "./RecentFiles";
|
import { RecentFiles } from "./RecentFiles";
|
||||||
import { getWorkspaceFolderByName } from "./utils/workspace";
|
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");
|
const channel = vscode.window.createOutputChannel("OpenGOAL");
|
||||||
let extensionContext: vscode.ExtensionContext;
|
let extensionContext: vscode.ExtensionContext;
|
||||||
let recentFiles: RecentFiles;
|
let recentFiles: RecentFiles;
|
||||||
let projectRoot: vscode.Uri | undefined = undefined;
|
let projectRoot: vscode.Uri | undefined = undefined;
|
||||||
|
let extensionStatus: vscode.StatusBarItem;
|
||||||
|
|
||||||
export function initContext(extContext: vscode.ExtensionContext) {
|
export function initContext(extContext: vscode.ExtensionContext) {
|
||||||
extensionContext = extContext;
|
extensionContext = extContext;
|
||||||
|
extensionStatus = vscode.window.createStatusBarItem(
|
||||||
|
vscode.StatusBarAlignment.Left,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
updateStatusBar(false, false);
|
||||||
|
|
||||||
recentFiles = new RecentFiles(extensionContext);
|
recentFiles = new RecentFiles(extensionContext);
|
||||||
if (vscode.window.activeTextEditor?.document != undefined) {
|
if (vscode.window.activeTextEditor?.document != undefined) {
|
||||||
recentFiles.addFile(vscode.window.activeTextEditor?.document.fileName);
|
recentFiles.addFile(vscode.window.activeTextEditor?.document.fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
extensionContext.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand("opengoal.openLogs", () => {
|
||||||
|
channel.show();
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRecentFiles() {
|
export function getRecentFiles() {
|
||||||
|
@ -43,3 +59,89 @@ export function getProjectRoot(): vscode.Uri {
|
||||||
}
|
}
|
||||||
return projectRoot;
|
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 * as util from "util";
|
||||||
import {
|
import {
|
||||||
getConfig,
|
getConfig,
|
||||||
|
updateAutoDecompilation,
|
||||||
updateDecompilerPath,
|
updateDecompilerPath,
|
||||||
updateFormatterPath,
|
updateFormatterPath,
|
||||||
} from "../config/config";
|
} from "../config/config";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { getExtensionContext, getProjectRoot } from "../context";
|
import {
|
||||||
|
getExtensionContext,
|
||||||
|
getProjectRoot,
|
||||||
|
updateStatusBar,
|
||||||
|
} from "../context";
|
||||||
import {
|
import {
|
||||||
getFileNamesFromUris,
|
getFileNamesFromUris,
|
||||||
getUrisFromTabs,
|
getUrisFromTabs,
|
||||||
|
@ -31,14 +36,9 @@ const execAsync = util.promisify(exec);
|
||||||
let channel: vscode.OutputChannel;
|
let channel: vscode.OutputChannel;
|
||||||
let fsWatcher: vscode.FileSystemWatcher | undefined;
|
let fsWatcher: vscode.FileSystemWatcher | undefined;
|
||||||
|
|
||||||
const decompStatusItem = vscode.window.createStatusBarItem(
|
|
||||||
vscode.StatusBarAlignment.Left,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
enum DecompStatus {
|
enum DecompStatus {
|
||||||
Idle,
|
Idle,
|
||||||
Running,
|
Decompiling,
|
||||||
Errored,
|
Errored,
|
||||||
Formatting,
|
Formatting,
|
||||||
FormattingError,
|
FormattingError,
|
||||||
|
@ -48,40 +48,12 @@ function updateStatus(status: DecompStatus, metadata?: any) {
|
||||||
let subText = "";
|
let subText = "";
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case DecompStatus.Errored:
|
case DecompStatus.Errored:
|
||||||
decompStatusItem.tooltip = "Toggle Auto-Decomp";
|
updateStatusBar(false, true, "Decomp Failed");
|
||||||
decompStatusItem.command = "opengoal.decomp.toggleAutoDecompilation";
|
|
||||||
decompStatusItem.text = "$(testing-error-icon) Decomp Failed";
|
|
||||||
break;
|
break;
|
||||||
case DecompStatus.FormattingError:
|
case DecompStatus.FormattingError:
|
||||||
decompStatusItem.tooltip = "Toggle Auto-Decomp";
|
updateStatusBar(false, true, "Formatting Failed");
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
|
case DecompStatus.Decompiling:
|
||||||
case DecompStatus.Formatting:
|
case DecompStatus.Formatting:
|
||||||
if (metadata.objectNames.length > 0) {
|
if (metadata.objectNames.length > 0) {
|
||||||
if (metadata.objectNames.length <= 5) {
|
if (metadata.objectNames.length <= 5) {
|
||||||
|
@ -92,11 +64,14 @@ function updateStatus(status: DecompStatus, metadata?: any) {
|
||||||
} more`;
|
} more`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decompStatusItem.text = `$(loading~spin) Formatting - ${subText} - [ ${metadata.decompConfig} ]`;
|
updateStatusBar(
|
||||||
decompStatusItem.tooltip = "Formatting...";
|
true,
|
||||||
decompStatusItem.command = undefined;
|
false,
|
||||||
|
`${status == DecompStatus.Decompiling ? "Decompiling" : "Formatting"} - ${subText} - [ ${metadata.decompConfig} ]`,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
updateStatusBar(false, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,7 +222,7 @@ async function decompFiles(
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowed_objects = fileNames.map((name) => `"${name}"`).join(",");
|
const allowed_objects = fileNames.map((name) => `"${name}"`).join(",");
|
||||||
updateStatus(DecompStatus.Running, {
|
updateStatus(DecompStatus.Decompiling, {
|
||||||
objectNames: fileNames,
|
objectNames: fileNames,
|
||||||
decompConfig: path.parse(decompConfig).name,
|
decompConfig: path.parse(decompConfig).name,
|
||||||
});
|
});
|
||||||
|
@ -375,7 +350,7 @@ async function decompSpecificFile() {
|
||||||
gameName = GameName.Jak1;
|
gameName = GameName.Jak1;
|
||||||
} else if (gameNameSelection == "jak2") {
|
} else if (gameNameSelection == "jak2") {
|
||||||
gameName = GameName.Jak2;
|
gameName = GameName.Jak2;
|
||||||
} else if (gameNameSelection == "jak3") {
|
} else {
|
||||||
gameName = GameName.Jak3;
|
gameName = GameName.Jak3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,8 +471,9 @@ function openManPage() {
|
||||||
open_in_pdf(word);
|
open_in_pdf(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAutoDecompilation() {
|
function setupAutoDecompilation() {
|
||||||
if (fsWatcher === undefined) {
|
const isEnabled = getConfig().autoDecompilation;
|
||||||
|
if (isEnabled && fsWatcher === undefined) {
|
||||||
fsWatcher = vscode.workspace.createFileSystemWatcher(
|
fsWatcher = vscode.workspace.createFileSystemWatcher(
|
||||||
"**/decompiler/config/**/*.{jsonc,json,gc}",
|
"**/decompiler/config/**/*.{jsonc,json,gc}",
|
||||||
);
|
);
|
||||||
|
@ -511,11 +487,19 @@ function toggleAutoDecompilation() {
|
||||||
});
|
});
|
||||||
fsWatcher.onDidCreate(() => decompAllActiveFiles());
|
fsWatcher.onDidCreate(() => decompAllActiveFiles());
|
||||||
fsWatcher.onDidDelete(() => decompAllActiveFiles());
|
fsWatcher.onDidDelete(() => decompAllActiveFiles());
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function toggleAutoDecompilation() {
|
||||||
|
const isEnabled = getConfig().autoDecompilation;
|
||||||
|
await updateAutoDecompilation(!isEnabled);
|
||||||
|
if (!getConfig().autoDecompilation && fsWatcher !== undefined) {
|
||||||
fsWatcher.dispose();
|
fsWatcher.dispose();
|
||||||
fsWatcher = undefined;
|
fsWatcher = undefined;
|
||||||
|
} else if (getConfig().autoDecompilation) {
|
||||||
|
setupAutoDecompilation();
|
||||||
}
|
}
|
||||||
updateStatus(DecompStatus.Idle);
|
updateStatusBar(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateSourceFile() {
|
async function updateSourceFile() {
|
||||||
|
@ -737,12 +721,15 @@ export async function activateDecompTools() {
|
||||||
"opengoal-ir",
|
"opengoal-ir",
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleAutoDecompilation();
|
setupAutoDecompilation();
|
||||||
|
|
||||||
updateStatus(DecompStatus.Idle);
|
updateStatus(DecompStatus.Idle);
|
||||||
decompStatusItem.show();
|
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
|
getExtensionContext().subscriptions.push(
|
||||||
|
vscode.commands.registerCommand("opengoal.decomp.openLogs", () => {
|
||||||
|
channel.show();
|
||||||
|
}),
|
||||||
|
);
|
||||||
getExtensionContext().subscriptions.push(
|
getExtensionContext().subscriptions.push(
|
||||||
vscode.commands.registerCommand("opengoal.decomp.openManPage", openManPage),
|
vscode.commands.registerCommand("opengoal.decomp.openManPage", openManPage),
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as vscode from "vscode";
|
||||||
import { integer } from "vscode-languageclient";
|
import { integer } from "vscode-languageclient";
|
||||||
import { getConfig, updateOpengoalParinferMode } from "../../config/config";
|
import { getConfig, updateOpengoalParinferMode } from "../../config/config";
|
||||||
import { getEditorRange } from "../../utils/editor-utils";
|
import { getEditorRange } from "../../utils/editor-utils";
|
||||||
|
import { updateStatusBar } from "../../context";
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - iron out some quirks around undoing
|
// - iron out some quirks around undoing
|
||||||
|
@ -72,45 +73,9 @@ const eventQueue: EventQueueItem[] = [];
|
||||||
const maxEventQueueSize = 10;
|
const maxEventQueueSize = 10;
|
||||||
let currentParinferMode = ParinferMode.DISABLED;
|
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) {
|
async function changeParinferMode(mode: ParinferMode) {
|
||||||
currentParinferMode = mode;
|
currentParinferMode = mode;
|
||||||
await updateOpengoalParinferMode(mode);
|
await updateOpengoalParinferMode(mode);
|
||||||
updateStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanUpEventQueue() {
|
function cleanUpEventQueue() {
|
||||||
|
@ -333,6 +298,7 @@ function showChangeModeMenu() {
|
||||||
.then((v) => {
|
.then((v) => {
|
||||||
if (v !== undefined) {
|
if (v !== undefined) {
|
||||||
changeParinferMode(v.label as ParinferMode);
|
changeParinferMode(v.label as ParinferMode);
|
||||||
|
updateStatusBar(false, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -343,8 +309,6 @@ export function registerParinferCommands(
|
||||||
changeParinferMode(
|
changeParinferMode(
|
||||||
(getConfig().opengoalParinferMode as ParinferMode) ?? ParinferMode.DISABLED,
|
(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(
|
context.subscriptions.push(
|
||||||
vscode.commands.registerCommand(
|
vscode.commands.registerCommand(
|
||||||
"opengoal.parinfer.changeMode",
|
"opengoal.parinfer.changeMode",
|
||||||
|
|
163
src/lsp/main.ts
163
src/lsp/main.ts
|
@ -1,101 +1,55 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import {
|
import {
|
||||||
BaseLanguageClient,
|
|
||||||
ClientCapabilities,
|
|
||||||
DocumentSelector,
|
|
||||||
FeatureState,
|
|
||||||
InitializeParams,
|
|
||||||
LanguageClient,
|
LanguageClient,
|
||||||
LanguageClientOptions,
|
LanguageClientOptions,
|
||||||
ServerCapabilities,
|
|
||||||
ServerOptions,
|
ServerOptions,
|
||||||
StaticFeature,
|
|
||||||
TransportKind,
|
TransportKind,
|
||||||
WorkDoneProgress,
|
|
||||||
WorkDoneProgressCreateRequest,
|
|
||||||
} from "vscode-languageclient/node";
|
} from "vscode-languageclient/node";
|
||||||
import { getConfig } from "../config/config";
|
import { getConfig } from "../config/config";
|
||||||
import { downloadLsp } from "./download";
|
import { downloadLsp } from "./download";
|
||||||
import { getLatestVersion, getLspPath, getVersionFromMetaFile } from "./util";
|
import { getLatestVersion, getLspPath, getVersionFromMetaFile } from "./util";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { disposeAll } from "../vendor/vscode-pdfviewer/disposable";
|
import { updateStatusBar } from "../context";
|
||||||
|
|
||||||
let extensionContext: vscode.ExtensionContext;
|
let extensionContext: vscode.ExtensionContext;
|
||||||
let opengoalLspPath: string | undefined;
|
let opengoalLspPath: string | undefined;
|
||||||
let activeClient: LanguageClient | undefined;
|
let activeClient: LanguageClient | undefined;
|
||||||
|
|
||||||
type LspStatus =
|
export type LspStatus =
|
||||||
| "stopped"
|
| "stopped"
|
||||||
| "starting"
|
| "starting"
|
||||||
| "started"
|
| "started"
|
||||||
| "downloading"
|
| "downloading"
|
||||||
| "error"
|
| "error";
|
||||||
| "serverProgressBegin"
|
|
||||||
| "serverProgressEnd";
|
|
||||||
|
|
||||||
// TODO - rust analyzer's context menu on hover is nice
|
let currentStatus: LspStatus = "stopped";
|
||||||
class LSPStatusItem {
|
function updateStatus(status: LspStatus, extraInfo?: string) {
|
||||||
private currentStatus: LspStatus = "stopped";
|
currentStatus = status;
|
||||||
|
switch (currentStatus) {
|
||||||
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":
|
case "starting":
|
||||||
this.statusItem.text = "$(loading~spin) OpenGOAL LSP Starting";
|
updateStatusBar(true, false, "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;
|
break;
|
||||||
case "downloading":
|
case "downloading":
|
||||||
this.statusItem.text = `$(sync~spin) OpenGOAL LSP Downloading - ${extraInfo}`;
|
updateStatusBar(true, false, `LSP Downloading - ${extraInfo}`);
|
||||||
this.statusItem.tooltip = `Downloading version - ${extraInfo}`;
|
|
||||||
this.statusItem.command = undefined;
|
|
||||||
break;
|
break;
|
||||||
case "error":
|
case "error":
|
||||||
this.statusItem.text = "$(error) OpenGOAL LSP Error";
|
updateStatusBar(false, true, "LSP Startup 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;
|
break;
|
||||||
default:
|
default:
|
||||||
|
updateStatusBar(false, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public hide() {
|
/**
|
||||||
this.statusItem.hide();
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public show() {
|
|
||||||
this.statusItem.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusItem = new LSPStatusItem(
|
|
||||||
vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0),
|
|
||||||
);
|
|
||||||
|
|
||||||
async function ensureServerDownloaded(): Promise<string | undefined> {
|
async function ensureServerDownloaded(): Promise<string | undefined> {
|
||||||
const installedVersion = getVersionFromMetaFile(
|
const installedVersion = getVersionFromMetaFile(
|
||||||
extensionContext.extensionPath,
|
extensionContext.extensionPath,
|
||||||
|
@ -130,15 +84,15 @@ async function ensureServerDownloaded(): Promise<string | undefined> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install the LSP and update the version metadata file
|
// Install the LSP and update the version metadata file
|
||||||
statusItem.updateStatus("downloading", versionToDownload);
|
updateStatus("downloading", versionToDownload);
|
||||||
const newLspPath = await downloadLsp(
|
const newLspPath = await downloadLsp(
|
||||||
extensionContext.extensionPath,
|
extensionContext.extensionPath,
|
||||||
versionToDownload,
|
versionToDownload,
|
||||||
);
|
);
|
||||||
if (newLspPath === undefined) {
|
if (newLspPath === undefined) {
|
||||||
statusItem.updateStatus("error");
|
updateStatus("error");
|
||||||
} else {
|
} else {
|
||||||
statusItem.updateStatus("stopped");
|
updateStatus("stopped");
|
||||||
}
|
}
|
||||||
return newLspPath;
|
return newLspPath;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +175,7 @@ function createClient(lspPath: string): LanguageClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stopClient() {
|
async function stopClient() {
|
||||||
statusItem.updateStatus("stopped");
|
updateStatus("stopped");
|
||||||
if (activeClient !== undefined) {
|
if (activeClient !== undefined) {
|
||||||
console.log("Stopping opengoal-lsp");
|
console.log("Stopping opengoal-lsp");
|
||||||
return await activeClient
|
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> {
|
async function startClient(): Promise<void> {
|
||||||
if (opengoalLspPath === undefined) {
|
if (opengoalLspPath === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const client = createClient(opengoalLspPath);
|
const client = createClient(opengoalLspPath);
|
||||||
client.registerFeature(new StatusBarFeature(client));
|
|
||||||
console.log("Starting opengoal-lsp at", opengoalLspPath);
|
console.log("Starting opengoal-lsp at", opengoalLspPath);
|
||||||
|
|
||||||
// TODO - some form of startup test would be nice
|
// TODO - some form of startup test would be nice
|
||||||
try {
|
try {
|
||||||
statusItem.updateStatus("starting");
|
updateStatus("starting");
|
||||||
await client.start();
|
await client.start();
|
||||||
activeClient = client;
|
activeClient = client;
|
||||||
statusItem.updateStatus("started", path.basename(opengoalLspPath));
|
updateStatus("started", path.basename(opengoalLspPath));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("opengoal-lsp:", error);
|
console.error("opengoal-lsp:", error);
|
||||||
statusItem.updateStatus("error");
|
updateStatus("error");
|
||||||
statusItem.hide();
|
|
||||||
await stopClient();
|
await stopClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startClientCommand() {
|
export async function startClientCommand() {
|
||||||
statusItem.show();
|
|
||||||
await maybeDownloadLspServer();
|
await maybeDownloadLspServer();
|
||||||
if (opengoalLspPath !== undefined) {
|
if (opengoalLspPath !== undefined) {
|
||||||
await startClient();
|
await startClient();
|
||||||
|
@ -359,7 +260,15 @@ function startedMenuCommand() {
|
||||||
showMenu(items, commands);
|
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(
|
context.subscriptions.push(
|
||||||
vscode.commands.registerCommand("opengoal.lsp.start", startClientCommand),
|
vscode.commands.registerCommand("opengoal.lsp.start", startClientCommand),
|
||||||
);
|
);
|
||||||
|
@ -381,11 +290,7 @@ export async function activate(
|
||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
extensionContext = context;
|
extensionContext = context;
|
||||||
registerLifeCycleCommands(context);
|
registerCommands(context);
|
||||||
// TODO - add info and open log file options
|
|
||||||
// registerDiagnosticsCommands(context);
|
|
||||||
statusItem.updateStatus("stopped");
|
|
||||||
statusItem.show();
|
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
if (config.launchLspOnStartup) {
|
if (config.launchLspOnStartup) {
|
||||||
await startClientCommand();
|
await startClientCommand();
|
||||||
|
|
|
@ -3,34 +3,21 @@ import * as path from "path";
|
||||||
import PromiseSocket from "promise-socket";
|
import PromiseSocket from "promise-socket";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { getConfig } from "../../../config/config";
|
import { getConfig } from "../../../config/config";
|
||||||
|
import { updateStatusBar } from "../../../context";
|
||||||
|
|
||||||
let jackedIn = false;
|
let jackedIn = false;
|
||||||
let socket: PromiseSocket<Socket> | undefined = undefined;
|
let socket: PromiseSocket<Socket> | undefined = undefined;
|
||||||
|
|
||||||
const nreplStatusItem = vscode.window.createStatusBarItem(
|
// TODO - status bar updates for errors and such
|
||||||
vscode.StatusBarAlignment.Left,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
function updateStatus() {
|
export function isJackedIn() {
|
||||||
// TODO - show errors
|
return jackedIn;
|
||||||
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 async function jackIn() {
|
export async function jackIn() {
|
||||||
if (socket !== undefined) {
|
if (socket !== undefined) {
|
||||||
jackedIn = true;
|
jackedIn = true;
|
||||||
updateStatus();
|
updateStatusBar(false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -46,13 +33,13 @@ export async function jackIn() {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
socket = undefined;
|
socket = undefined;
|
||||||
}
|
}
|
||||||
updateStatus();
|
updateStatusBar(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function unJack() {
|
export async function unJack() {
|
||||||
if (socket === undefined) {
|
if (socket === undefined) {
|
||||||
jackedIn = false;
|
jackedIn = false;
|
||||||
updateStatus();
|
updateStatusBar(false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -62,7 +49,7 @@ export async function unJack() {
|
||||||
}
|
}
|
||||||
socket = undefined;
|
socket = undefined;
|
||||||
jackedIn = false;
|
jackedIn = false;
|
||||||
updateStatus();
|
updateStatusBar(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function reloadFile(fileName: string) {
|
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.jackin", jackIn),
|
||||||
vscode.commands.registerCommand("opengoal.nrepl.unjack", unJack),
|
vscode.commands.registerCommand("opengoal.nrepl.unjack", unJack),
|
||||||
);
|
);
|
||||||
updateStatus();
|
|
||||||
nreplStatusItem.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nreplOnFileSaveHandler(e: vscode.TextDocument) {
|
export function nreplOnFileSaveHandler(e: vscode.TextDocument) {
|
||||||
|
@ -110,6 +95,5 @@ export function nreplOnFileSaveHandler(e: vscode.TextDocument) {
|
||||||
}
|
}
|
||||||
// Get the name
|
// Get the name
|
||||||
const fileName = path.basename(e.fileName).replace(".gc", "");
|
const fileName = path.basename(e.fileName).replace(".gc", "");
|
||||||
console.log(fileName);
|
|
||||||
reloadFile(fileName);
|
reloadFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue