Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"amodio.tsl-problem-matcher"
"amodio.tsl-problem-matcher",
"yaozheng.vscode-pde"
]
}
Binary file added icons/icon24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions icons/java-svgrepo-com.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 36 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1752,7 +1752,21 @@
"command": "java.action.showExtendedOutline",
"title": "%java.action.showExtendedOutline%",
"category": "Java"
}
},
{
"command": "java.dashboard.refresh",
"category": "Java",
"title": "Refresh",
"icon": "$(refresh)",
"when": "java:dashboard == true"
},
{
"command": "java.dashboard.dumpState",
"category": "Java",
"title": "Dump State",
"icon": "$(json)",
"when": "java:dashboard == true"
}
],
"keybindings": [
{
Expand Down Expand Up @@ -1928,6 +1942,16 @@
"command": "java.action.showSubtypeHierarchy",
"group": "navigation@1",
"when": "view == references-view.tree && reference-list.hasResult && reference-list.source == javaTypeHierarchy"
},
{
"command": "java.dashboard.refresh",
"group": "navigation",
"when": "view == java.dashboard"
},
{
"command": "java.dashboard.dumpState",
"group": "navigation",
"when": "view == java.dashboard"
}
],
"view/item/context": [
Expand All @@ -1937,6 +1961,16 @@
"when": "view == references-view.tree && reference-list.hasResult && reference-list.source == javaTypeHierarchy && viewItem != 'false'"
}
]
},
"views": {
"explorer": [
{
"type": "webview",
"id": "java.dashboard",
"name": "Java Dashboard",
"icon": "icons/java-svgrepo-com.svg"
}
]
}
},
"scripts": {
Expand All @@ -1946,7 +1980,7 @@
"pretest": "npm run compile",
"test": "node ./out/test/runtest.js",
"build-server": "./node_modules/.bin/gulp build_server",
"build": "./node_modules/.bin/gulp build_or_download",
"build": "node_modules\\.bin\\gulp build_or_download",
"fast-build-server": "./node_modules/.bin/gulp dev_server",
"watch-server": "./node_modules/.bin/gulp watch_server",
"eslint": "eslint --ignore-path .eslintignore --ext .js,.ts,.tsx .",
Expand Down
4 changes: 4 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,10 @@ export namespace Commands {
*/
export const SHOW_EXTEND_OUTLINE = 'java.action.showExtendedOutline';

/**
* Get diagnostic info command in jdt.ls
*/
export const GET_TROUBLESHOOTING_INFO = 'java.getTroubleshootingInfo';
}

/**
Expand Down
156 changes: 156 additions & 0 deletions src/dashboard/dashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { prepareExecutable } from '../javaServerStarter';
import { getComputedJavaConfig, getExecutable, getWorkspacePath } from '../extension';
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { getNonce, getUri } from '../webviewUtils';
import { DashboardState, DiagnosticInfo, JVM, UpdateMessage } from '../webviewProtocol/toDashboard';
import { isLombokSupportEnabled, Lombok } from '../lombokSupport';
import { Commands } from '../commands';
import { apiManager } from '../apiManager';

const currentState: DashboardState = {
};

export namespace Dashboard {
export function initialize(context: vscode.ExtensionContext): void {
console.log('registering dashboard webview provider');
let webview: vscode.Webview;

context.subscriptions.push(vscode.window.registerWebviewViewProvider('java.dashboard', {
resolveWebviewView: async function (webviewView: vscode.WebviewView, webviewContext: vscode.WebviewViewResolveContext, token: vscode.CancellationToken): Promise<void> {
vscode.commands.executeCommand('setContext', 'java:dashboard', true);
webview = webviewView.webview;
webviewView.webview.options = {
enableScripts: true,
enableCommandUris: true,
localResourceRoots: [context.extensionUri]
};

webviewView.webview.html = await getWebviewContent(webviewView.webview, context);
webviewView.onDidDispose(() => {
vscode.commands.executeCommand('setContext', 'java:dashboard', false);
});
}
}));

context.subscriptions.push(vscode.commands.registerCommand('java.dashboard.refresh', async () => {
refreshLSInfo(webview);
}));

context.subscriptions.push(vscode.commands.registerCommand('java.dashboard.revealFileInOS', async (arg: { path: string }) => {
await vscode.commands.executeCommand('revealFileInOS', vscode.Uri.file(arg.path));
}));

context.subscriptions.push(vscode.commands.registerCommand('java.dashboard.dumpState', async () => {
await vscode.workspace.openTextDocument({
language: 'json',
content: JSON.stringify(currentState, null, 2)
});
}));

console.log('registered dashboard webview provider');
}
}

async function getJvms(): Promise<JVM[]> {
const config = await getComputedJavaConfig();
const jres: JVM[] = config.configuration.runtimes.map(jre => ({
name: jre.name,
version: jre.version,
path: jre.path,
}));
return jres;

}

function getWebviewContent(webview: vscode.Webview, context: vscode.ExtensionContext) {
setWebviewMessageListener(webview);

const scriptUri = getUri(webview, context.extensionUri, [
"dist",
"dashboard.js",
]);

const nonce = getNonce();

return /* html*/ `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>Dashboard</title>
</head>
<body>
<div id="root"></div>
<script nonce="${nonce}" src="${scriptUri}"></script>
</body>
</html>
`;
}
async function refreshLSInfo(webview: vscode.Webview): Promise<void> {
try {
vscode.commands.executeCommand<DiagnosticInfo>(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.GET_TROUBLESHOOTING_INFO).then(info => {
currentState.diagnosticInfo = info;
const msg: UpdateMessage = {
type: "update",
diagnosticInfo: info
};
webview.postMessage(msg);
});
} catch (e) {
console.error('Failed to get diagnostic info', e);
}
}

function setWebviewMessageListener(webview: vscode.Webview) {

vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('java.jdt.ls.lombokSupport.enabled')) {
currentState.lombokEnabled = isLombokSupportEnabled();
const msg: UpdateMessage = {
type: "update",
lombokEnabled: isLombokSupportEnabled()
};
webview.postMessage(msg);
}
if (e.affectsConfiguration('java')) {
setTimeout(() => refreshLSInfo(webview), 1000); // wait for LS to pick up the config change
}
});

webview.onDidReceiveMessage(
async (message: any) => {
const command = message.command;
switch (command) {
case "webviewReady": {
await apiManager.getApiInstance().serverReady;
currentState.lombokEnabled = isLombokSupportEnabled();
currentState.activeLombokPath = Lombok.getActiveLombokPath();
currentState.workspacePath = getWorkspacePath();
const message: UpdateMessage = {
type: "update",
lombokEnabled: isLombokSupportEnabled(),
activeLombokPath: Lombok.getActiveLombokPath(),
workspacePath: getWorkspacePath(),
};
await webview.postMessage(message);
getJvms().then(jvms => {
currentState.jvms = jvms;
const msg: UpdateMessage = {
type: "update",
jvms: jvms
};

webview.postMessage(msg);
});

refreshLSInfo(webview);
break;
}
}
}
);
}
48 changes: 38 additions & 10 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import * as fse from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as semver from 'semver';
import { CodeActionContext, commands, CompletionItem, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, Location, MarkdownString, QuickPickItemKind, Range, RelativePattern, SnippetString, SnippetTextEdit, TextDocument, TextEditorRevealType, UIKind, Uri, version, ViewColumn, window, workspace, WorkspaceConfiguration, WorkspaceEdit } from 'vscode';
import { CodeActionContext, commands, CompletionItem, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions,
IndentAction, InputBoxOptions, languages, Location, MarkdownString, QuickPickItemKind, Range, RelativePattern,
SnippetString, SnippetTextEdit, TextDocument, TextEditorRevealType, UIKind, Uri, version, ViewColumn,
Webview,
WebviewView, WebviewViewResolveContext, window, workspace, WorkspaceConfiguration, WorkspaceEdit } from 'vscode';
import { CancellationToken, CodeActionParams, CodeActionRequest, CodeActionResolveRequest, Command, CompletionRequest, DidChangeConfigurationNotification, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn } from 'vscode-languageclient';
import { LanguageClient } from 'vscode-languageclient/node';
import { Executable, LanguageClient } from 'vscode-languageclient/node';
import { apiManager } from './apiManager';
import { ClientErrorHandler } from './clientErrorHandler';
import { Commands, CommandTitle } from './commands';
Expand Down Expand Up @@ -39,6 +43,8 @@ import { BuildFileSelector, PICKED_BUILD_FILES, cleanupWorkspaceState } from './
import { pasteFile } from './pasteAction';
import { ServerStatusKind } from './serverStatus';
import { TelemetryService } from '@redhat-developer/vscode-redhat-telemetry/lib/node';
import { Deferred } from './promiseUtil';
import { Dashboard } from './dashboard/dashboard';

const syntaxClient: SyntaxLanguageClient = new SyntaxLanguageClient();
const standardClient: StandardLanguageClient = new StandardLanguageClient();
Expand All @@ -47,6 +53,17 @@ const extensionName = 'Language Support for Java';
let storagePath: string;
let clientLogFile: string;

const excutable= new Deferred<Executable>();

export async function getExecutable(): Promise<Executable> {
return excutable.promise;
}

const javaConfigDeferred = new Deferred<any>();
export async function getComputedJavaConfig(): Promise<any> {
return javaConfigDeferred.promise;
}

/**
* Shows a message about the server crashing due to an out of memory issue
*/
Expand Down Expand Up @@ -113,6 +130,12 @@ export function fixJdtLinksInDocumentation(oldDocumentation: MarkdownString): Ma
}

export async function activate(context: ExtensionContext): Promise<ExtensionAPI> {
storagePath = context.storagePath;
if (!storagePath) {
storagePath = getTempWorkspace();
}
Dashboard.initialize(context);

await loadSupportedJreNames(context);
context.subscriptions.push(commands.registerCommand(Commands.FILESEXPLORER_ONPASTE, async () => {
const originalClipboard = await env.clipboard.readText();
Expand All @@ -130,16 +153,13 @@ export async function activate(context: ExtensionContext): Promise<ExtensionAPI>
markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `_java.notCoveredExecution.md`)), 'Not Covered Maven Plugin Execution', "", context);
}));

storagePath = context.storagePath;
context.subscriptions.push(commands.registerCommand(Commands.METADATA_FILES_GENERATION, async () => {
markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `_java.metadataFilesGeneration.md`)), 'Metadata Files Generation', "", context);
}));
context.subscriptions.push(commands.registerCommand(Commands.LEARN_MORE_ABOUT_CLEAN_UPS, async () => {
markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `${Commands.LEARN_MORE_ABOUT_CLEAN_UPS}.md`)), 'Java Clean Ups', "java-clean-ups", context);
}));
if (!storagePath) {
storagePath = getTempWorkspace();
}

const workspacePath = path.resolve(`${storagePath}/jdt_ws`);
clientLogFile = path.join(storagePath, 'client.log');
const cleanWorkspaceExists = fs.existsSync(path.join(workspacePath, cleanWorkspaceFileName));
Expand Down Expand Up @@ -196,6 +216,9 @@ export async function activate(context: ExtensionContext): Promise<ExtensionAPI>
let requireStandardServer = (serverMode !== ServerMode.lightWeight) && (!isDebugModeByClientPort || !!process.env['JDTLS_CLIENT_PORT']);
let initFailureReported: boolean = false;

const javaConfig = await getJavaConfig(requirements.java_home);
javaConfigDeferred.resolve(javaConfig);

// Options to control the language client
const clientOptions: LanguageClientOptions = {
// Register the server for java
Expand All @@ -210,7 +233,7 @@ export async function activate(context: ExtensionContext): Promise<ExtensionAPI>
initializationOptions: {
bundles: collectJavaExtensions(extensions.all),
workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null,
settings: { java: await getJavaConfig(requirements.java_home) },
settings: { java: javaConfig },
extendedClientCapabilities: {
classFileContentsSupport: true,
overrideMethodsPromptSupport: true,
Expand Down Expand Up @@ -394,6 +417,7 @@ export async function activate(context: ExtensionContext): Promise<ExtensionAPI>
// no need to pass `resolve` into any code past this point,
// since `resolve` is a no-op from now on
const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, context, true);
excutable.resolve(serverOptions);
if (requireSyntaxServer) {
if (process.env['SYNTAXLS_CLIENT_PORT']) {
syntaxClient.initialize(requirements, clientOptions);
Expand Down Expand Up @@ -859,18 +883,22 @@ async function cleanSharedIndexes(context: ExtensionContext) {
}

function openServerLogFile(storagePath, column: ViewColumn = ViewColumn.Active): Thenable<boolean> {
const workspacePath = getWorkspacePath(storagePath);
const workspacePath = computeWorkspacePath(storagePath);
const serverLogFile = path.join(workspacePath, '.metadata', '.log');
return openLogFile(serverLogFile, 'Could not open Java Language Server log file', column);
}

function getWorkspacePath(storagePath: any) {
function computeWorkspacePath(storagePath: any) {
return path.join(storagePath, apiManager.getApiInstance().serverMode === ServerMode.lightWeight ? 'ss_ws' : 'jdt_ws');
}

export function getWorkspacePath() {
return computeWorkspacePath(storagePath);
}

function openRollingServerLogFile(storagePath, filename, column: ViewColumn = ViewColumn.Active): Thenable<boolean> {
return new Promise((resolve) => {
const workspacePath = getWorkspacePath(storagePath);
const workspacePath = computeWorkspacePath(storagePath);
const dirname = path.join(workspacePath, '.metadata');

// find out the newest one
Expand Down
6 changes: 6 additions & 0 deletions src/lombokSupport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ let isLombokCommandInitialized: boolean = false;
let isExtensionLombok: boolean = false; // whether use extension's Lombok or not
let projectLombokPath: string = undefined; // the project's Lombok classpath

export namespace Lombok {

export function getActiveLombokPath(): string | undefined {
return activeLombokPath;
}
}
export function isLombokSupportEnabled(): boolean {
return vscode.workspace.getConfiguration().get("java.jdt.ls.lombokSupport.enabled");
}
Expand Down
Loading