diff --git a/src/commands.ts b/src/commands.ts index 5ad0a8085..ebf8eae3d 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -350,4 +350,18 @@ export namespace Commands { */ export const RESOLVE_PASTED_TEXT = "java.project.resolveText"; + /** + * The command when clicking the server status bar item. + */ + export const OPEN_STATUS_SHORTCUT = "_java.openShortcuts"; + +} + +/** + * Command titles used to render in the UI + */ +export namespace CommandTitle { + export const OPEN_JAVA_SETTINGS = "$(settings-gear) Open Java Settings"; + export const OPEN_LOGS = "$(output) Open Logs..."; + export const CLEAN_WORKSPACE_CACHE = "$(trash) Clean Workspace Cache"; } diff --git a/src/extension.ts b/src/extension.ts index 398b6a00f..4e5854cd0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,12 +5,12 @@ import * as fs from 'fs'; import * as fse from 'fs-extra'; import * as os from 'os'; import * as path from 'path'; -import { CodeActionContext, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, RelativePattern, TextDocument, UIKind, Uri, ViewColumn, window, workspace, WorkspaceConfiguration } from 'vscode'; +import { CodeActionContext, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, QuickPickItemKind, RelativePattern, TextDocument, UIKind, Uri, ViewColumn, window, workspace, WorkspaceConfiguration } from 'vscode'; import { CancellationToken, CodeActionParams, CodeActionRequest, Command, CompletionRequest, DidChangeConfigurationNotification, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn } from 'vscode-languageclient'; import { LanguageClient } from 'vscode-languageclient/node'; import { apiManager } from './apiManager'; import { ClientErrorHandler } from './clientErrorHandler'; -import { Commands } from './commands'; +import { Commands, CommandTitle } from './commands'; import { ClientStatus, ExtensionAPI, TraceEvent } from './extension.api'; import * as fileEventHandler from './fileEventHandler'; import { getSharedIndexCache, HEAP_DUMP_LOCATION, prepareExecutable } from './javaServerStarter'; @@ -23,7 +23,7 @@ import { registerClientProviders } from './providerDispatcher'; import { initialize as initializeRecommendation } from './recommendation'; import * as requirements from './requirements'; import { languageStatusBarProvider } from './runtimeStatusBarProvider'; -import { serverStatusBarProvider } from './serverStatusBarProvider'; +import { serverStatusBarProvider, ShortcutQuickPickItem } from './serverStatusBarProvider'; import { ACTIVE_BUILD_TOOL_STATE, cleanWorkspaceFileName, getJavaServerMode, handleTextDocumentChanges, getImportMode, onConfigurationChange, ServerMode, ImportMode } from './settings'; import { snippetCompletionProvider } from './snippetCompletionProvider'; import { JavaClassEditorProvider } from './javaClassEditor'; @@ -38,6 +38,7 @@ import { activationProgressNotification } from "./serverTaskPresenter"; import { loadSupportedJreNames } from './jdkUtils'; import { BuildFileSelector, PICKED_BUILD_FILES, cleanupProjectPickerCache } from './buildFilesSelector'; import { pasteFile } from './pasteAction'; +import { ServerStatusKind } from './serverStatus'; const syntaxClient: SyntaxLanguageClient = new SyntaxLanguageClient(); const standardClient: StandardLanguageClient = new StandardLanguageClient(); @@ -343,6 +344,50 @@ export async function activate(context: ExtensionContext): Promise } // Register commands here to make it available even when the language client fails + context.subscriptions.push(commands.registerCommand(Commands.OPEN_STATUS_SHORTCUT, async (status: string) => { + const items: ShortcutQuickPickItem[] = []; + let statusCommand: string; + if (status === ServerStatusKind.error || status === ServerStatusKind.warning) { + statusCommand = "workbench.panel.markers.view.focus"; + } else { + statusCommand = Commands.SHOW_SERVER_TASK_STATUS; + } + + items.push({ + label: `$(coffee) Java Status: ${status}`, + command: statusCommand, + }, { + label: "", + kind: QuickPickItemKind.Separator, + command: "", + }, { + label: CommandTitle.OPEN_JAVA_SETTINGS, + command: "workbench.action.openSettings", + args: ["java"], + }, { + label: CommandTitle.OPEN_LOGS, + command: Commands.OPEN_LOGS, + }, { + label: CommandTitle.CLEAN_WORKSPACE_CACHE, + command: Commands.CLEAN_WORKSPACE + }); + + const choice = await window.showQuickPick(items); + if (!choice) { + return; + } + + apiManager.fireTraceEvent({ + name: "triggerShortcutCommand", + properties: { + message: choice.command, + }, + }); + + if (choice.command) { + commands.executeCommand(choice.command, ...(choice.args || [])); + } + })); context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_LOG, (column: ViewColumn) => openServerLogFile(storagePath, column))); context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_STDOUT_LOG, (column: ViewColumn) => openRollingServerLogFile(storagePath, '.out-jdt.ls', column))); context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_STDERR_LOG, (column: ViewColumn) => openRollingServerLogFile(storagePath, '.error-jdt.ls', column))); @@ -510,7 +555,7 @@ async function startStandardServer(context: ExtensionContext, requirements: requ standardClient.start().then(async () => { standardClient.registerLanguageClientActions(context, await fse.pathExists(path.join(workspacePath, ".metadata", ".plugins")), jdtEventEmitter); }); - serverStatusBarProvider.showStandardStatus(); + serverStatusBarProvider.setBusy("Activating..."); } async function workspaceContainsBuildFiles(): Promise { diff --git a/src/serverStatus.ts b/src/serverStatus.ts index a7fd2eac8..28c51990a 100644 --- a/src/serverStatus.ts +++ b/src/serverStatus.ts @@ -2,7 +2,7 @@ import { EventEmitter } from "vscode"; import { serverTasks } from "./serverTasks"; -import { ProgressKind } from "./protocol"; +import { serverStatusBarProvider } from "./serverStatusBarProvider"; export enum ServerStatusKind { ready = "Ready", @@ -32,7 +32,11 @@ export namespace serverStatus { export function initialize() { serverTasks.onDidUpdateServerTask(tasks => { - isBusy = tasks.some(task => !(task.complete)); + const busyTask = tasks.find(task => !task.complete); + isBusy = !!busyTask; + if (isBusy) { + serverStatusBarProvider.setBusy(busyTask.value.message); + } fireEvent(); }); } diff --git a/src/serverStatusBarProvider.ts b/src/serverStatusBarProvider.ts index 4bff57ed8..a410c65ce 100644 --- a/src/serverStatusBarProvider.ts +++ b/src/serverStatusBarProvider.ts @@ -1,64 +1,75 @@ 'use strict'; -import { StatusBarItem, window, StatusBarAlignment } from "vscode"; -import { Commands } from "./commands"; +import { StatusBarItem, window, StatusBarAlignment, ThemeColor, commands, QuickPickItem, QuickPickItemKind } from "vscode"; import { Disposable } from "vscode-languageclient"; import { StatusCommands } from "./languageStatusItemFactory"; +import { Commands } from "./commands"; +import { ServerStatusKind } from "./serverStatus"; class ServerStatusBarProvider implements Disposable { private statusBarItem: StatusBarItem; constructor() { - this.statusBarItem = window.createStatusBarItem("java.serverStatus", StatusBarAlignment.Right, Number.MIN_VALUE); + this.statusBarItem = window.createStatusBarItem("java.serverStatus", StatusBarAlignment.Left); + this.statusBarItem.show(); } public showLightWeightStatus(): void { this.statusBarItem.name = "Java Server Mode"; - this.statusBarItem.text = StatusIcon.lightWeight; + this.statusBarItem.text = `${StatusIcon.lightWeight} Java: Lightweight Mode`; this.statusBarItem.command = StatusCommands.switchToStandardCommand; this.statusBarItem.tooltip = "Java language server is running in LightWeight mode, click to switch to Standard mode"; - this.statusBarItem.show(); } public showNotImportedStatus(): void { this.statusBarItem.name = "No projects are imported"; - this.statusBarItem.text = StatusIcon.notImported; + this.statusBarItem.text = `${StatusIcon.notImported} Java: No Projects Imported`; this.statusBarItem.command = StatusCommands.startStandardServerCommand; this.statusBarItem.tooltip = "No projects are imported, click to load projects"; - this.statusBarItem.show(); - } - - public showStandardStatus(): void { - this.statusBarItem.name = "Java Server Status"; - this.statusBarItem.text = StatusIcon.busy; - this.statusBarItem.command = Commands.SHOW_SERVER_TASK_STATUS; - this.statusBarItem.tooltip = ""; - this.statusBarItem.show(); } - public setBusy(): void { - this.statusBarItem.text = StatusIcon.busy; + public setBusy(process: string): void { + this.statusBarItem.text = `${StatusIcon.busy} Java: ${process}`; + this.statusBarItem.tooltip = process; + this.statusBarItem.command = { + title: "Show Java status menu", + command: Commands.OPEN_STATUS_SHORTCUT, + tooltip: "Show Java status menu", + arguments: [ServerStatusKind.busy], + }; } public setError(): void { - this.statusBarItem.text = StatusIcon.error; - this.statusBarItem.command = Commands.OPEN_LOGS; + this.statusBarItem.text = `${StatusIcon.java} Java: Error`; + this.statusBarItem.tooltip = "Show Java status menu"; + this.statusBarItem.command = { + title: "Show Java status menu", + command: Commands.OPEN_STATUS_SHORTCUT, + tooltip: "Show Java status menu", + arguments: [ServerStatusKind.error], + }; } public setWarning(): void { - this.statusBarItem.text = StatusIcon.warning; - this.statusBarItem.command = "workbench.panel.markers.view.focus"; - this.statusBarItem.tooltip = "Errors occurred in project configurations, click to show the PROBLEMS panel"; + this.statusBarItem.text = `${StatusIcon.java} Java: Warning`; + this.statusBarItem.tooltip = "Show Java status menu"; + this.statusBarItem.command = { + title: "Show Java status menu", + command: Commands.OPEN_STATUS_SHORTCUT, + tooltip: "Show Java status menu", + arguments: [ServerStatusKind.warning], + }; } public setReady(): void { - this.statusBarItem.text = StatusIcon.ready; - this.statusBarItem.command = Commands.SHOW_SERVER_TASK_STATUS; - this.statusBarItem.tooltip = "ServiceReady"; - } - - public updateTooltip(tooltip: string): void { - this.statusBarItem.tooltip = tooltip; + this.statusBarItem.text = `${StatusIcon.java} Java: Ready`; + this.statusBarItem.tooltip = "Show Java status menu"; + this.statusBarItem.command = { + title: "Show Java status menu", + command: Commands.OPEN_STATUS_SHORTCUT, + tooltip: "Show Java status menu", + arguments: ["Ready"], + }; } public dispose(): void { @@ -68,11 +79,14 @@ class ServerStatusBarProvider implements Disposable { export enum StatusIcon { lightWeight = "$(rocket)", + notImported = "$(info)", busy = "$(sync~spin)", - ready = "$(thumbsup)", - warning = "$(thumbsdown)", - error = "$(thumbsdown)", - notImported = "$(info)" + java = "$(coffee)", +} + +export interface ShortcutQuickPickItem extends QuickPickItem { + command: string; + args?: any[]; } export const serverStatusBarProvider: ServerStatusBarProvider = new ServerStatusBarProvider(); diff --git a/src/standardLanguageClient.ts b/src/standardLanguageClient.ts index b98c184e7..8183bc57d 100644 --- a/src/standardLanguageClient.ts +++ b/src/standardLanguageClient.ts @@ -75,13 +75,11 @@ export class StandardLanguageClient { serverStatus.initialize(); serverStatus.onServerStatusChanged(status => { - if (status === ServerStatusKind.busy) { - serverStatusBarProvider.setBusy(); - } else if (status === ServerStatusKind.error) { + if (status === ServerStatusKind.error) { serverStatusBarProvider.setError(); } else if (status === ServerStatusKind.warning) { serverStatusBarProvider.setWarning(); - } else { + } else if (status === ServerStatusKind.ready) { serverStatusBarProvider.setReady(); } }); @@ -181,9 +179,6 @@ export class StandardLanguageClient { // message goes to progress report instead break; } - if (!serverStatus.hasErrors()) { - serverStatusBarProvider.updateTooltip(report.message); - } }); this.languageClient.onNotification(ProgressNotification.type, (progress) => {