Skip to content

Commit

Permalink
Add support to view inherited members #2342
Browse files Browse the repository at this point in the history
The reference view API is used to show the document outline with inherited
symbols using the new java.ls extension method.

Signed-off-by: Gayan Perera <[email protected]>
  • Loading branch information
gayanper committed Jul 22, 2022
1 parent fb12b59 commit 5033b82
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 1 deletion.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,11 @@
"command": "java.action.changeBaseType",
"title": "%java.action.changeBaseType%",
"category": "Java"
},
{
"command": "java.action.showExtendedOutline",
"title": "%java.action.showExtendedOutline%",
"category": "Java"
}
],
"keybindings": [
Expand Down
3 changes: 2 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@
"java.action.showClassHierarchy": "Show Class Hierarchy",
"java.action.showSupertypeHierarchy": "Show Supertype Hierarchy",
"java.action.showSubtypeHierarchy": "Show Subtype Hierarchy",
"java.action.changeBaseType": "Base on this Type"
"java.action.changeBaseType": "Base on this Type",
"java.action.showExtendedOutline": "Open Extended Outline"
}
6 changes: 6 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,10 @@ export namespace Commands {
export const UPGRADE_GRADLE_WRAPPER = '_java.gradle.upgradeWrapper';

export const LOMBOK_CONFIGURE = "java.lombokConfigure";

/**
* Show Extended Outline for current document.
*/
export const SHOW_EXTEND_OUTLINE = 'java.action.showExtendedOutline';

}
40 changes: 40 additions & 0 deletions src/outline/extendedOutlineTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { LanguageClient } from "vscode-languageclient/node";
import { SymbolTree } from "../typeHierarchy/references-view";
import * as vscode from "vscode";
import { getActiveLanguageClient } from "../extension";
import { ExtendedOutlineTreeInput } from "./model";

export class ExtendedOutlineTree {
private api: SymbolTree;
private client: LanguageClient;
public initialized: boolean;

constructor() {
this.initialized = false;
}

async initialize() {
// It uses a new publisher id in June 2022 Update, check both old/new id for compatibility
// See https://github.com/microsoft/vscode/pull/152213
const referencesViewExt = vscode.extensions.getExtension<SymbolTree>('vscode.references-view')
?? vscode.extensions.getExtension<SymbolTree>('ms-vscode.references-view');
this.api = await referencesViewExt?.activate();
this.client = await getActiveLanguageClient();
this.initialized = true;
}

async open(uri: vscode.Uri) {
if (!this.initialized) {
await this.initialize();
}

if (!this.api) {
return;
}
const input: ExtendedOutlineTreeInput = new ExtendedOutlineTreeInput(new vscode.Location(uri, new vscode.Position(0, 0)));
this.api.setInput(input);
}
}

export const extendedOutlineTree: ExtendedOutlineTree = new ExtendedOutlineTree();

92 changes: 92 additions & 0 deletions src/outline/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { DocumentSymbol, Event, Location, Position, ProviderResult, Range, SymbolKind, TextDocumentShowOptions, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri } from "vscode";
import { DocumentSymbolParams, LanguageClient, TextDocumentIdentifier } from "vscode-languageclient/node";
import { getActiveLanguageClient } from "../extension";
import { getThemeIcon } from "../themeUtils";
import { SymbolItemNavigation, SymbolTreeInput, SymbolTreeModel } from "../typeHierarchy/references-view";
import { ExtendedDocumentSymbol, ExtendedDocumentSymbolsRequest } from "./protocol";

export class ExtendedOutlineTreeInput implements SymbolTreeInput<ExtendedDocumentSymbol> {
readonly contextValue: string = "javaExtendedOutline";
readonly title: string = "Extended Outline";
client: LanguageClient;

constructor(readonly location: Location) {
}

async resolve(): Promise<SymbolTreeModel<ExtendedDocumentSymbol>> {
if (!this.client) {
this.client = await getActiveLanguageClient();
}

const params: DocumentSymbolParams = {
textDocument: TextDocumentIdentifier.create(this.location.uri.toString())
};
const symbols = await this.client.sendRequest(ExtendedDocumentSymbolsRequest.type, params);
const treeModel: SymbolTreeModel<ExtendedDocumentSymbol> = {
provider: new ExtendedOutlineProvider(symbols, this.client),
message: undefined,
navigation: new ExtendedOutlineModel()
};
return Promise.resolve(treeModel);
}

with(location: Location): SymbolTreeInput<ExtendedDocumentSymbol> {
return new ExtendedOutlineTreeInput(location);
}
}

export class ExtendedOutlineModel implements SymbolItemNavigation<ExtendedDocumentSymbol> {
nearest(_uri: Uri, _position: Position): ExtendedDocumentSymbol | undefined {
return undefined;
}

next(from: ExtendedDocumentSymbol): ExtendedDocumentSymbol {
return from;
}
previous(from: ExtendedDocumentSymbol): ExtendedDocumentSymbol {
return from;
}
location(item: ExtendedDocumentSymbol): Location {
return new Location(Uri.parse(item.uri), new Range(item.range.start, item.range.end));
}

}

class ExtendedOutlineProvider implements TreeDataProvider<ExtendedDocumentSymbol> {
onDidChangeTreeData?: Event<void | ExtendedDocumentSymbol>;

constructor(readonly symbols: ExtendedDocumentSymbol[], readonly client: LanguageClient) { }

getTreeItem(element: ExtendedDocumentSymbol): TreeItem | Thenable<TreeItem> {
let state = TreeItemCollapsibleState.None;
if (element.children != null && element.children.length > 0)
state = TreeItemCollapsibleState.Collapsed;

const item: TreeItem = new TreeItem(element.name, state);
item.description = element.detail;
item.iconPath = getThemeIcon(element.kind - 1);
item.command = (element.uri) ? {
command: 'vscode.open',
title: 'Open Symbol Definition Location',
arguments: [
element.uri, <TextDocumentShowOptions>{ selection: element.selectionRange }
]
} : undefined;
return item;
}

getChildren(element?: ExtendedDocumentSymbol): ProviderResult<ExtendedDocumentSymbol[]> {
if (element == null) {
return Promise.resolve(this.symbols);
} else {
if (element.children != null) {
return Promise.resolve(element.children as ExtendedDocumentSymbol[]);
}
}
return undefined;
}

getParent?(_element: ExtendedDocumentSymbol): ProviderResult<ExtendedDocumentSymbol> {
return undefined;
}
}
9 changes: 9 additions & 0 deletions src/outline/protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DocumentSymbol, DocumentSymbolParams, RequestType } from "vscode-languageclient";

export namespace ExtendedDocumentSymbolsRequest {
export const type = new RequestType<DocumentSymbolParams, ExtendedDocumentSymbol[], void>('java/extendedDocumentSymbols');
}

export interface ExtendedDocumentSymbol extends DocumentSymbol {
uri: string;
}
12 changes: 12 additions & 0 deletions src/standardLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { snippetCompletionProvider } from "./snippetCompletionProvider";
import { JavaInlayHintsProvider } from "./inlayHintsProvider";
import { gradleCodeActionMetadata, GradleCodeActionProvider } from "./gradle/gradleCodeActionProvider";
import { checkLombokDependency } from "./lombokSupport";
import { extendedOutlineTree } from "./outline/extendedOutlineTree";

const extensionName = 'Language Support for Java';
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
Expand Down Expand Up @@ -533,6 +534,17 @@ export class StandardLanguageClient {
}
}));

context.subscriptions.push(commands.registerCommand(Commands.SHOW_EXTEND_OUTLINE, (location: any) => {
if (location instanceof Uri) {
extendedOutlineTree.open(location);
} else {
if (window.activeTextEditor?.document?.languageId !== "java") {
return;
}
extendedOutlineTree.open(window.activeTextEditor.document.uri);
}
}));

buildPath.registerCommands(context);
sourceAction.registerCommands(this.languageClient, context);
refactorAction.registerCommands(this.languageClient, context);
Expand Down
15 changes: 15 additions & 0 deletions src/themeUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SymbolKind, ThemeIcon } from "vscode";

const themeIconIds = [
'symbol-file', 'symbol-module', 'symbol-namespace', 'symbol-package', 'symbol-class', 'symbol-method',
'symbol-property', 'symbol-field', 'symbol-constructor', 'symbol-enum', 'symbol-interface',
'symbol-function', 'symbol-variable', 'symbol-constant', 'symbol-string', 'symbol-number', 'symbol-boolean',
'symbol-array', 'symbol-object', 'symbol-key', 'symbol-null', 'symbol-enum-member', 'symbol-struct',
'symbol-event', 'symbol-operator', 'symbol-type-parameter'
];

export function getThemeIcon(kind: SymbolKind): ThemeIcon | undefined {
const id = themeIconIds[kind];
return id ? new ThemeIcon(id) : undefined;
}

0 comments on commit 5033b82

Please sign in to comment.