Skip to content

Commit 907578a

Browse files
gayanperrgrunber
andcommitted
Support viewing inherited members through QuickPick UI.
- The QuickPick view API is used to show the document outline with inherited symbols using the new language server extension method, 'java/extendedDocumentSymbol'. - When ctrl+o is activated from the quick-pick menu (eg. the outline view is already active), the extended outline is then activated Co-Authored-by: Gayan Perera <[email protected]> Co-Authored-by: Roland Grunberg <[email protected]>
1 parent 03c4042 commit 907578a

File tree

8 files changed

+143
-17
lines changed

8 files changed

+143
-17
lines changed

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1727,7 +1727,11 @@
17271727
},
17281728
{
17291729
"command": "java.change.searchScope",
1730-
"title": "%java.change.searchScope%",
1730+
"title": "%java.change.searchScope%"
1731+
},
1732+
{
1733+
"command": "java.action.showExtendedOutline",
1734+
"title": "%java.action.showExtendedOutline%",
17311735
"category": "Java"
17321736
}
17331737
],
@@ -1757,6 +1761,11 @@
17571761
"command": "java.action.doCleanup",
17581762
"key": "ctrl+shift+alt+s",
17591763
"when": "javaLSReady && editorLangId == java"
1764+
},
1765+
{
1766+
"command": "java.action.showExtendedOutline",
1767+
"key": "ctrl+o",
1768+
"when": "javaLSReady && inQuickOpen"
17601769
}
17611770
],
17621771
"menus": {

package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
"java.edit.smartSemicolonDetection": "Java Smart Semicolon Detection",
2929
"java.action.filesExplorerPasteAction": "Paste Clipboard Text Into a File",
3030
"java.action.doCleanup": "Performs Cleanup Actions",
31-
"java.change.searchScope": "Change Search Scope"
31+
"java.change.searchScope": "Change Search Scope",
32+
"java.action.showExtendedOutline": "Open Extended Outline"
3233
}

src/commands.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,11 @@ export namespace Commands {
361361
*/
362362
export const CHANGE_JAVA_SEARCH_SCOPE = "java.change.searchScope";
363363

364+
/**
365+
* Show Extended Outline for current document.
366+
*/
367+
export const SHOW_EXTEND_OUTLINE = 'java.action.showExtendedOutline';
368+
364369
}
365370

366371
/**
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { DocumentSymbolParams, LanguageClient, TextDocumentIdentifier } from "vscode-languageclient/node";
2+
import { getActiveLanguageClient } from "../extension";
3+
import { ExtendedDocumentSymbolRequest } from "./protocol";
4+
import { Location, Position, QuickPick, QuickPickItem, Uri, window, workspace } from "vscode";
5+
import { getLThemeIcon } from "../themeUtils";
6+
7+
export class ExtendedOutlineQuickPick {
8+
private api: QuickPick<QuickPickItem>;
9+
private client: LanguageClient;
10+
public initialized: boolean;
11+
12+
constructor() {
13+
this.initialized = false;
14+
}
15+
16+
async initialize() {
17+
this.api = window.createQuickPick();
18+
this.api.ignoreFocusOut = true;
19+
this.api.onDidChangeActive((items: QuickPickItem[]) => {
20+
if (items.length > 0) {
21+
const active: QuickPickItem = items[0];
22+
const uri = active["uri"];
23+
const range = active["range"];
24+
if (uri !== undefined) {
25+
workspace.openTextDocument(Uri.parse(uri)).then(doc => {
26+
window.showTextDocument(doc, {preserveFocus: true, selection: range});
27+
});
28+
} else {
29+
window.showTextDocument(window.activeTextEditor.document, {preserveFocus: true, selection: range});
30+
}
31+
}
32+
});
33+
this.api.onDidAccept(() => {
34+
this.api.hide();
35+
});
36+
this.client = await getActiveLanguageClient();
37+
this.initialized = true;
38+
}
39+
40+
async open(uri: Uri) {
41+
if (!this.initialized) {
42+
await this.initialize();
43+
}
44+
45+
if (!this.api) {
46+
return;
47+
}
48+
49+
const location = new Location(uri, new Position(0, 0));
50+
const params: DocumentSymbolParams = {
51+
textDocument: TextDocumentIdentifier.create(location.uri.toString())
52+
};
53+
const symbols = await this.client.sendRequest(ExtendedDocumentSymbolRequest.type, params);
54+
let quickPickItems: QuickPickItem[] = [];
55+
for (const s of symbols) {
56+
const icon = getLThemeIcon(s.kind).id;
57+
const item = {
58+
label: `$(${icon}) ${s.name}`,
59+
description: s.detail.trim(),
60+
uri: s.uri,
61+
range: s.range
62+
};
63+
quickPickItems.push(item);
64+
if (icon === 'symbol-class') {
65+
const items: QuickPickItem[] = s.children.map(s => ({
66+
label: `$(${getLThemeIcon(s.kind).id}) ${s.name}`,
67+
// custom quick pick has automatic space between label & description
68+
description: s.detail.trim(),
69+
uri: s.uri,
70+
range: s.range
71+
}));
72+
quickPickItems = quickPickItems.concat(items);
73+
}
74+
}
75+
this.api.items = quickPickItems;
76+
this.api.activeItems = [];
77+
this.api.show();
78+
}
79+
}
80+
81+
export const extendedOutlineQuickPick: ExtendedOutlineQuickPick = new ExtendedOutlineQuickPick();

src/outline/protocol.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { DocumentSymbol, DocumentSymbolParams, RequestType } from "vscode-languageclient";
2+
3+
export namespace ExtendedDocumentSymbolRequest {
4+
export const type = new RequestType<DocumentSymbolParams, ExtendedDocumentSymbol[], void>('java/extendedDocumentSymbol');
5+
}
6+
7+
export interface ExtendedDocumentSymbol extends DocumentSymbol {
8+
uri: string;
9+
children?: ExtendedDocumentSymbol[];
10+
}

src/standardLanguageClient.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { registerDocumentValidationListener } from './diagnostic';
4141
import { listJdks, sortJdksBySource, sortJdksByVersion } from './jdkUtils';
4242
import { ClientCodeActionProvider } from './clientCodeActionProvider';
4343
import { BuildFileSelector } from './buildFilesSelector';
44+
import { extendedOutlineQuickPick } from "./outline/extendedOutlineQuickPick";
4445

4546
const extensionName = 'Language Support for Java';
4647
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
@@ -593,6 +594,17 @@ export class StandardLanguageClient {
593594
}
594595
}));
595596

597+
context.subscriptions.push(commands.registerCommand(Commands.SHOW_EXTEND_OUTLINE, (location: any) => {
598+
if (location instanceof Uri) {
599+
extendedOutlineQuickPick.open(location);
600+
} else {
601+
if (window.activeTextEditor?.document?.languageId !== "java") {
602+
return;
603+
}
604+
extendedOutlineQuickPick.open(window.activeTextEditor.document.uri);
605+
}
606+
}));
607+
596608
buildPath.registerCommands(context);
597609
sourceAction.registerCommands(this.languageClient, context);
598610
refactorAction.registerCommands(this.languageClient, context);
@@ -897,4 +909,4 @@ export class DisableWillRenameFeature implements StaticFeature {
897909
fillInitializeParams?: () => void;
898910
preInitialize?: () => void;
899911
initialize(): void {}
900-
}
912+
}

src/themeUtils.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { SymbolKind as VSymbolKind, ThemeIcon } from "vscode";
2+
import { SymbolKind as LSymbolKind} from "vscode-languageclient";
3+
4+
const themeIconIds = [
5+
'symbol-file', 'symbol-module', 'symbol-namespace', 'symbol-package', 'symbol-class', 'symbol-method',
6+
'symbol-property', 'symbol-field', 'symbol-constructor', 'symbol-enum', 'symbol-interface',
7+
'symbol-function', 'symbol-variable', 'symbol-constant', 'symbol-string', 'symbol-number', 'symbol-boolean',
8+
'symbol-array', 'symbol-object', 'symbol-key', 'symbol-null', 'symbol-enum-member', 'symbol-struct',
9+
'symbol-event', 'symbol-operator', 'symbol-type-parameter'
10+
];
11+
12+
export function getLThemeIcon(kind: LSymbolKind): ThemeIcon | undefined {
13+
const id = themeIconIds[kind - 1];
14+
return id ? new ThemeIcon(id) : undefined;
15+
}
16+
17+
export function getThemeIcon(kind: VSymbolKind): ThemeIcon | undefined {
18+
const id = themeIconIds[kind];
19+
return id ? new ThemeIcon(id) : undefined;
20+
}

src/typeHierarchy/model.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getActiveLanguageClient } from "../extension";
55
import { LanguageClient } from "vscode-languageclient/node";
66
import { getRootItem, resolveTypeHierarchy, typeHierarchyDirectionToContextString } from "./util";
77
import { CancellationToken, commands, workspace } from "vscode";
8+
import { getThemeIcon } from "../themeUtils";
89

910
export class TypeHierarchyTreeInput implements SymbolTreeInput<TypeHierarchyItem> {
1011
readonly contextValue: string = "javaTypeHierarchy";
@@ -124,7 +125,7 @@ class TypeHierarchyTreeDataProvider implements vscode.TreeDataProvider<TypeHiera
124125
const treeItem: vscode.TreeItem = (element === this.model.getBaseItem()) ? new vscode.TreeItem({ label: element.name, highlights: [[0, element.name.length]] }) : new vscode.TreeItem(element.name);
125126
treeItem.contextValue = (element === this.model.getBaseItem() || !element.uri) ? "false" : "true";
126127
treeItem.description = element.detail;
127-
treeItem.iconPath = TypeHierarchyTreeDataProvider.getThemeIcon(element.kind);
128+
treeItem.iconPath = getThemeIcon(element.kind);
128129
treeItem.command = (element.uri) ? {
129130
command: 'vscode.open',
130131
title: 'Open Type Definition Location',
@@ -248,17 +249,4 @@ class TypeHierarchyTreeDataProvider implements vscode.TreeDataProvider<TypeHiera
248249
expand: false,
249250
};
250251
}
251-
252-
private static themeIconIds = [
253-
'symbol-file', 'symbol-module', 'symbol-namespace', 'symbol-package', 'symbol-class', 'symbol-method',
254-
'symbol-property', 'symbol-field', 'symbol-constructor', 'symbol-enum', 'symbol-interface',
255-
'symbol-function', 'symbol-variable', 'symbol-constant', 'symbol-string', 'symbol-number', 'symbol-boolean',
256-
'symbol-array', 'symbol-object', 'symbol-key', 'symbol-null', 'symbol-enum-member', 'symbol-struct',
257-
'symbol-event', 'symbol-operator', 'symbol-type-parameter'
258-
];
259-
260-
private static getThemeIcon(kind: vscode.SymbolKind): vscode.ThemeIcon | undefined {
261-
const id = TypeHierarchyTreeDataProvider.themeIconIds[kind];
262-
return id ? new vscode.ThemeIcon(id) : undefined;
263-
}
264252
}

0 commit comments

Comments
 (0)