Dock the results table in the bottom panel
createWebviewPanel only ever lives in the editor area, so the table could not be dragged next to Terminal / Problems. A WebviewView can, and it can also be dragged to either side bar. - Extract ResultsView: the table's html, messaging, row building and navigation, independent of what hosts the webview. ReferencePanel keeps hosting it in an editor group; ReferenceViewProvider hosts it in a contributed panel view container. Results that arrive before the docked view has been resolved are queued and applied on resolve. - coloredReferences.panelLocation selects the placement: bottom (default), beside, or below. "below" makes the editor row first so the table is wide and short, which suits the column layout better than a tall narrow group. - sourceColumn() now ignores editors with no view column, so opening a reference from the docked view lands in a real editor group. - toggleView and the refresh button work from either host. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,9 @@ source file*, so your theme's grammar colors every line for free. File headers s
|
||||
shown in the gutter.
|
||||
|
||||
**Panel view** shows the same results as a table with resizable, sortable columns — Code, File, Line, Project
|
||||
and Containing member — grouped by file, with a filter box.
|
||||
and Containing member — grouped by file, with a filter box. By default it docks in the **bottom panel**
|
||||
alongside Terminal and Problems, where a wide, short table reads best; you can drag it to either side bar,
|
||||
or set `coloredReferences.panelLocation` to put it in an editor group instead.
|
||||
|
||||
Works with any language server that implements references: DotRush, C# Dev Kit, OmniSharp, TypeScript, Rust, Go, ...
|
||||
|
||||
@@ -29,6 +31,9 @@ column edge to resize it; double-click the edge to reset it.
|
||||
## Settings
|
||||
|
||||
- `coloredReferences.view` — which view `Find All References (Colored)` opens: `document` (default) or `panel`
|
||||
- `coloredReferences.panelLocation` — where the panel opens: `bottom` (default, docked next to Terminal /
|
||||
Problems and draggable to a side bar), `beside` (editor group to the side), or `below` (editor group
|
||||
underneath, so the table is wide and short)
|
||||
- `coloredReferences.openBeside` — open results beside the current editor (default `true`)
|
||||
- `coloredReferences.showProject` — show the containing project in file headers (default `true`)
|
||||
- `coloredReferences.reuseTab` — reuse one results tab/panel instead of opening a new one per search (default `true`)
|
||||
|
||||
+39
-3
@@ -18,7 +18,9 @@
|
||||
"dotnet",
|
||||
"visual studio"
|
||||
],
|
||||
"activationEvents": [],
|
||||
"activationEvents": [
|
||||
"onView:coloredReferences.resultsView"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
@@ -75,7 +77,7 @@
|
||||
"command": "coloredReferences.toggleView",
|
||||
"key": "ctrl+alt+shift+f12",
|
||||
"mac": "cmd+alt+shift+f12",
|
||||
"when": "resourceScheme == colored-refs || activeWebviewPanelId == coloredReferences.results"
|
||||
"when": "resourceScheme == colored-refs || activeWebviewPanelId == coloredReferences.results || view == coloredReferences.resultsView"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
@@ -109,7 +111,7 @@
|
||||
},
|
||||
{
|
||||
"command": "coloredReferences.toggleView",
|
||||
"when": "resourceScheme == colored-refs || activeWebviewPanelId == coloredReferences.results"
|
||||
"when": "resourceScheme == colored-refs || activeWebviewPanelId == coloredReferences.results || view == coloredReferences.resultsView"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -143,8 +145,42 @@
|
||||
],
|
||||
"default": "document",
|
||||
"description": "Which view Find All References (Colored) opens."
|
||||
},
|
||||
"coloredReferences.panelLocation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"bottom",
|
||||
"beside",
|
||||
"below"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Dock the results table in the bottom panel, beside Terminal and Problems. Drag it to a side bar if you prefer.",
|
||||
"Open the results table in an editor group beside the current one.",
|
||||
"Open the results table in an editor group below the current one, so it is wide and short."
|
||||
],
|
||||
"default": "bottom",
|
||||
"description": "Where the results panel opens."
|
||||
}
|
||||
}
|
||||
},
|
||||
"viewsContainers": {
|
||||
"panel": [
|
||||
{
|
||||
"id": "coloredReferences",
|
||||
"title": "References",
|
||||
"icon": "media/references-dark.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"coloredReferences": [
|
||||
{
|
||||
"id": "coloredReferences.resultsView",
|
||||
"name": "References",
|
||||
"type": "webview",
|
||||
"contextualTitle": "References"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
+11
-8
@@ -1,6 +1,6 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { PanelManager, ReferencePanel } from './panel';
|
||||
import { PanelManager, Placement, ResultsView } from './panel';
|
||||
import {
|
||||
CODE_INDENT, Origin, ReferenceResults, RenderedDocument, ResultLine, SCHEME,
|
||||
findReferences, gather, invalidateSymbols, relativePath, renderDocument,
|
||||
@@ -199,21 +199,23 @@ async function showDocument(results: ReferenceResults, targetUri?: vscode.Uri):
|
||||
applyDecorations(editor);
|
||||
}
|
||||
|
||||
async function showPanel(results: ReferenceResults, target?: ReferencePanel): Promise<void> {
|
||||
async function showPanel(results: ReferenceResults, target?: ResultsView): Promise<void> {
|
||||
if (target) {
|
||||
await target.update(results);
|
||||
return;
|
||||
}
|
||||
const cfg = config();
|
||||
const column = cfg.get<boolean>('openBeside', true) ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active;
|
||||
await panels.show(results, cfg.get<boolean>('reuseTab', true), column);
|
||||
await panels.show(
|
||||
results,
|
||||
cfg.get<boolean>('reuseTab', true),
|
||||
cfg.get<Placement>('panelLocation', 'bottom'));
|
||||
}
|
||||
|
||||
interface SearchTarget {
|
||||
/** Refresh an existing results document in place. */
|
||||
uri?: vscode.Uri;
|
||||
/** Refresh an existing panel in place. */
|
||||
panel?: ReferencePanel;
|
||||
/** Refresh an existing results table in place. */
|
||||
panel?: ResultsView;
|
||||
/** Which view to open for a new search. */
|
||||
view?: View;
|
||||
}
|
||||
@@ -318,7 +320,7 @@ async function refreshCommand(): Promise<void> {
|
||||
await runSearch(origin, languageId, symbol, { uri: editor.document.uri });
|
||||
}
|
||||
|
||||
function refreshPanel(panel: ReferencePanel): void {
|
||||
function refreshPanel(panel: ResultsView): void {
|
||||
const origin = panel.origin;
|
||||
if (!origin) {
|
||||
return;
|
||||
@@ -336,7 +338,7 @@ async function toggleViewCommand(): Promise<void> {
|
||||
await showPanel(stored.results);
|
||||
return;
|
||||
}
|
||||
// Coming from a panel: the panel is the active tab, so there is no active editor.
|
||||
// Coming from the table: it holds the focus, so there is no active editor.
|
||||
const active = panels.active;
|
||||
if (active?.shown) {
|
||||
await showDocument(active.shown);
|
||||
@@ -374,6 +376,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
};
|
||||
|
||||
context.subscriptions.push(
|
||||
panels.register(),
|
||||
vscode.workspace.registerTextDocumentContentProvider(SCHEME, contentProvider),
|
||||
vscode.languages.registerDefinitionProvider({ scheme: SCHEME }, definitionProvider),
|
||||
vscode.languages.registerHoverProvider({ scheme: SCHEME }, hoverProvider),
|
||||
|
||||
+191
-65
@@ -4,6 +4,9 @@ import {
|
||||
ReferenceResults, containingMembers, displayLine, relativePath,
|
||||
} from './references';
|
||||
|
||||
/** Where the results table is shown. */
|
||||
export type Placement = 'bottom' | 'beside' | 'below';
|
||||
|
||||
/** One reference, as shown in a table row. */
|
||||
export interface PanelRow {
|
||||
id: number;
|
||||
@@ -74,52 +77,35 @@ function nonce(): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* A results panel: the same references as the virtual document, as a table with
|
||||
* resizable, sortable columns plus a containing-member column.
|
||||
* What `ResultsView` needs from whatever is hosting the webview — an editor-area
|
||||
* `WebviewPanel` or a `WebviewView` docked in the bottom panel / a side bar.
|
||||
*/
|
||||
export class ReferencePanel {
|
||||
static readonly viewType = 'coloredReferences.results';
|
||||
interface ViewHost {
|
||||
readonly webview: vscode.Webview;
|
||||
setTitle(title: string): void;
|
||||
/** The editor group the host occupies, or undefined when it is not in the editor grid. */
|
||||
readonly viewColumn: vscode.ViewColumn | undefined;
|
||||
}
|
||||
|
||||
private readonly panel: vscode.WebviewPanel;
|
||||
private readonly disposables: vscode.Disposable[] = [];
|
||||
/**
|
||||
* The results table: the same references as the virtual document, with resizable,
|
||||
* sortable columns plus a containing-member column. Host-agnostic.
|
||||
*/
|
||||
export class ResultsView {
|
||||
private locations = new Map<number, vscode.Location>();
|
||||
private results: ReferenceResults | undefined;
|
||||
/** Set once the webview has loaded and is listening for results. */
|
||||
private ready = false;
|
||||
private pending: unknown;
|
||||
private readonly listener: vscode.Disposable;
|
||||
|
||||
constructor(
|
||||
private readonly extensionUri: vscode.Uri,
|
||||
column: vscode.ViewColumn,
|
||||
private readonly onRefresh: (panel: ReferencePanel) => void,
|
||||
private readonly onDispose: (panel: ReferencePanel) => void,
|
||||
private readonly host: ViewHost,
|
||||
private readonly onRefresh: (view: ResultsView) => void,
|
||||
) {
|
||||
this.panel = vscode.window.createWebviewPanel(
|
||||
ReferencePanel.viewType,
|
||||
'References',
|
||||
{ viewColumn: column, preserveFocus: false },
|
||||
{
|
||||
enableScripts: true,
|
||||
// Ctrl+F focuses the panel's own filter box instead.
|
||||
enableFindWidget: false,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')],
|
||||
},
|
||||
);
|
||||
this.panel.iconPath = {
|
||||
light: vscode.Uri.joinPath(extensionUri, 'media', 'references-light.svg'),
|
||||
dark: vscode.Uri.joinPath(extensionUri, 'media', 'references-dark.svg'),
|
||||
};
|
||||
this.panel.webview.html = this.html();
|
||||
|
||||
this.disposables.push(
|
||||
this.panel.webview.onDidReceiveMessage(message => void this.receive(message)),
|
||||
this.panel.onDidDispose(() => this.dispose()),
|
||||
);
|
||||
}
|
||||
|
||||
get viewColumn(): vscode.ViewColumn | undefined {
|
||||
return this.panel.viewColumn;
|
||||
this.host.webview.html = this.html();
|
||||
this.listener = this.host.webview.onDidReceiveMessage(message => void this.receive(message));
|
||||
}
|
||||
|
||||
get origin(): ReferenceResults['origin'] | undefined {
|
||||
@@ -138,17 +124,9 @@ export class ReferencePanel {
|
||||
return this.results;
|
||||
}
|
||||
|
||||
get isActive(): boolean {
|
||||
return this.panel.active;
|
||||
}
|
||||
|
||||
reveal(): void {
|
||||
this.panel.reveal(this.panel.viewColumn, false);
|
||||
}
|
||||
|
||||
async update(results: ReferenceResults): Promise<void> {
|
||||
this.results = results;
|
||||
this.panel.title = `References to ${results.symbol}`;
|
||||
this.host.setTitle(`References to ${results.symbol}`);
|
||||
|
||||
const members = await containingMembers(results);
|
||||
const { rows, locations } = buildRows(results, members);
|
||||
@@ -165,7 +143,7 @@ export class ReferencePanel {
|
||||
|
||||
private post(message: unknown): void {
|
||||
if (this.ready) {
|
||||
void this.panel.webview.postMessage(message);
|
||||
void this.host.webview.postMessage(message);
|
||||
} else {
|
||||
// The webview asks for its results as soon as its script runs.
|
||||
this.pending = message;
|
||||
@@ -178,7 +156,7 @@ export class ReferencePanel {
|
||||
case 'ready':
|
||||
this.ready = true;
|
||||
if (this.pending) {
|
||||
void this.panel.webview.postMessage(this.pending);
|
||||
void this.host.webview.postMessage(this.pending);
|
||||
this.pending = undefined;
|
||||
}
|
||||
return;
|
||||
@@ -192,9 +170,10 @@ export class ReferencePanel {
|
||||
}
|
||||
}
|
||||
|
||||
/** The group a source file should open in: never the one holding this panel. */
|
||||
/** The group a source file should open in: never the one holding this view. */
|
||||
private sourceColumn(): vscode.ViewColumn {
|
||||
const editors = vscode.window.visibleTextEditors.filter(e => e.viewColumn !== this.panel.viewColumn);
|
||||
const editors = vscode.window.visibleTextEditors.filter(
|
||||
e => e.viewColumn !== undefined && e.viewColumn !== this.host.viewColumn);
|
||||
const origin = editors.find(e => e.document.uri.toString() === this.results?.origin.uri.toString());
|
||||
return origin?.viewColumn ?? editors[0]?.viewColumn ?? vscode.ViewColumn.Beside;
|
||||
}
|
||||
@@ -226,7 +205,7 @@ export class ReferencePanel {
|
||||
}
|
||||
|
||||
private html(): string {
|
||||
const webview = this.panel.webview;
|
||||
const webview = this.host.webview;
|
||||
const asset = (name: string) =>
|
||||
webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, 'media', name));
|
||||
const token = nonce();
|
||||
@@ -261,38 +240,181 @@ export class ReferencePanel {
|
||||
</html>`;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.listener.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function webviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions {
|
||||
return {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')],
|
||||
};
|
||||
}
|
||||
|
||||
/** The results table in an editor group. */
|
||||
export class ReferencePanel {
|
||||
static readonly viewType = 'coloredReferences.results';
|
||||
|
||||
private readonly panel: vscode.WebviewPanel;
|
||||
private readonly subscription: vscode.Disposable;
|
||||
readonly view: ResultsView;
|
||||
|
||||
constructor(
|
||||
extensionUri: vscode.Uri,
|
||||
column: vscode.ViewColumn,
|
||||
onRefresh: (view: ResultsView) => void,
|
||||
private readonly onDispose: (panel: ReferencePanel) => void,
|
||||
) {
|
||||
const panel = vscode.window.createWebviewPanel(
|
||||
ReferencePanel.viewType,
|
||||
'References',
|
||||
{ viewColumn: column, preserveFocus: false },
|
||||
{
|
||||
...webviewOptions(extensionUri),
|
||||
// Ctrl+F focuses the panel's own filter box instead.
|
||||
enableFindWidget: false,
|
||||
retainContextWhenHidden: true,
|
||||
},
|
||||
);
|
||||
panel.iconPath = {
|
||||
light: vscode.Uri.joinPath(extensionUri, 'media', 'references-light.svg'),
|
||||
dark: vscode.Uri.joinPath(extensionUri, 'media', 'references-dark.svg'),
|
||||
};
|
||||
this.panel = panel;
|
||||
|
||||
this.view = new ResultsView(extensionUri, {
|
||||
webview: panel.webview,
|
||||
setTitle: title => { panel.title = title; },
|
||||
// Read live: the user can drag the panel to another group.
|
||||
get viewColumn() { return panel.viewColumn; },
|
||||
}, onRefresh);
|
||||
|
||||
this.subscription = panel.onDidDispose(() => this.dispose());
|
||||
}
|
||||
|
||||
get isActive(): boolean {
|
||||
return this.panel.active;
|
||||
}
|
||||
|
||||
reveal(): void {
|
||||
this.panel.reveal(this.panel.viewColumn, false);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.onDispose(this);
|
||||
for (const disposable of this.disposables.splice(0)) {
|
||||
disposable.dispose();
|
||||
}
|
||||
this.subscription.dispose();
|
||||
this.view.dispose();
|
||||
this.panel.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/** Owns the open panels and decides whether a search reuses one. */
|
||||
export class PanelManager {
|
||||
private readonly panels: ReferencePanel[] = [];
|
||||
/** The results table docked in the bottom panel (draggable to a side bar). */
|
||||
export class ReferenceViewProvider implements vscode.WebviewViewProvider {
|
||||
static readonly viewId = 'coloredReferences.resultsView';
|
||||
|
||||
private view: ResultsView | undefined;
|
||||
private webviewView: vscode.WebviewView | undefined;
|
||||
/** Results that arrived before the view was resolved. */
|
||||
private queued: ReferenceResults | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly extensionUri: vscode.Uri,
|
||||
private readonly refresh: (panel: ReferencePanel) => void,
|
||||
private readonly onRefresh: (view: ResultsView) => void,
|
||||
) { }
|
||||
|
||||
/** The focused panel, falling back to the most recent one. */
|
||||
get active(): ReferencePanel | undefined {
|
||||
return this.panels.find(p => p.isActive) ?? this.panels[this.panels.length - 1];
|
||||
get current(): ResultsView | undefined {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
/** Shows `results`, reusing the most recent panel when `reuse` is set. */
|
||||
async show(results: ReferenceResults, reuse: boolean, column: vscode.ViewColumn): Promise<ReferencePanel> {
|
||||
const panel = (reuse ? this.panels[this.panels.length - 1] : undefined) ?? this.create(column);
|
||||
await panel.update(results);
|
||||
resolveWebviewView(webviewView: vscode.WebviewView): void {
|
||||
webviewView.webview.options = webviewOptions(this.extensionUri);
|
||||
this.webviewView = webviewView;
|
||||
this.view = new ResultsView(this.extensionUri, {
|
||||
webview: webviewView.webview,
|
||||
setTitle: title => { webviewView.title = title; },
|
||||
viewColumn: undefined,
|
||||
}, this.onRefresh);
|
||||
|
||||
webviewView.onDidDispose(() => {
|
||||
this.view?.dispose();
|
||||
this.view = undefined;
|
||||
this.webviewView = undefined;
|
||||
});
|
||||
|
||||
if (this.queued) {
|
||||
void this.view.update(this.queued);
|
||||
this.queued = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reveals the view, resolving it first if the panel has never been opened. */
|
||||
async show(results: ReferenceResults): Promise<ResultsView | undefined> {
|
||||
if (!this.view) {
|
||||
this.queued = results;
|
||||
// Focusing the view makes the workbench open the container and resolve it,
|
||||
// which then applies the queued results.
|
||||
await vscode.commands.executeCommand(`${ReferenceViewProvider.viewId}.focus`);
|
||||
return this.view;
|
||||
}
|
||||
await this.view.update(results);
|
||||
this.webviewView?.show(true);
|
||||
return this.view;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.view?.dispose();
|
||||
this.view = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/** Owns the open results views and decides whether a search reuses one. */
|
||||
export class PanelManager {
|
||||
private readonly panels: ReferencePanel[] = [];
|
||||
private readonly bottom: ReferenceViewProvider;
|
||||
/** The view the last search rendered into. */
|
||||
private lastShown: ResultsView | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly extensionUri: vscode.Uri,
|
||||
private readonly refresh: (view: ResultsView) => void,
|
||||
) {
|
||||
this.bottom = new ReferenceViewProvider(extensionUri, refresh);
|
||||
}
|
||||
|
||||
register(): vscode.Disposable {
|
||||
return vscode.window.registerWebviewViewProvider(
|
||||
ReferenceViewProvider.viewId, this.bottom,
|
||||
{ webviewOptions: { retainContextWhenHidden: true } });
|
||||
}
|
||||
|
||||
/** The focused results view, falling back to the one shown most recently. */
|
||||
get active(): ResultsView | undefined {
|
||||
const focused = this.panels.find(p => p.isActive);
|
||||
return focused?.view ?? this.lastShown ?? this.bottom.current;
|
||||
}
|
||||
|
||||
/** Shows `results` in `placement`, reusing an existing view when `reuse` is set. */
|
||||
async show(results: ReferenceResults, reuse: boolean, placement: Placement): Promise<void> {
|
||||
if (placement === 'bottom') {
|
||||
this.lastShown = await this.bottom.show(results) ?? this.lastShown;
|
||||
return;
|
||||
}
|
||||
|
||||
const existing = reuse ? this.panels[this.panels.length - 1] : undefined;
|
||||
const panel = existing ?? await this.create(placement);
|
||||
await panel.view.update(results);
|
||||
panel.reveal();
|
||||
return panel;
|
||||
this.lastShown = panel.view;
|
||||
}
|
||||
|
||||
private create(column: vscode.ViewColumn): ReferencePanel {
|
||||
private async create(placement: Placement): Promise<ReferencePanel> {
|
||||
if (placement === 'below') {
|
||||
// ViewColumn only addresses columns, so make the row first and open into it.
|
||||
await vscode.commands.executeCommand('workbench.action.newGroupBelow');
|
||||
}
|
||||
const column = placement === 'below' ? vscode.ViewColumn.Active : vscode.ViewColumn.Beside;
|
||||
|
||||
const panel = new ReferencePanel(
|
||||
this.extensionUri, column, this.refresh,
|
||||
closed => {
|
||||
@@ -300,6 +422,9 @@ export class PanelManager {
|
||||
if (index >= 0) {
|
||||
this.panels.splice(index, 1);
|
||||
}
|
||||
if (this.lastShown === closed.view) {
|
||||
this.lastShown = undefined;
|
||||
}
|
||||
});
|
||||
this.panels.push(panel);
|
||||
return panel;
|
||||
@@ -309,5 +434,6 @@ export class PanelManager {
|
||||
for (const panel of this.panels.splice(0)) {
|
||||
panel.dispose();
|
||||
}
|
||||
this.bottom.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,20 @@ async function search(relativeFile: string, declaration: string, symbol: string)
|
||||
return { results, position, uri };
|
||||
}
|
||||
|
||||
function coloredEditorTabs(): vscode.Tab[] {
|
||||
return vscode.window.tabGroups.all.flatMap(g => g.tabs).filter(tab => {
|
||||
const input = tab.input as { uri?: vscode.Uri } | undefined;
|
||||
return input?.uri?.scheme === 'colored-refs';
|
||||
});
|
||||
}
|
||||
|
||||
async function setPlacement(placement: string): Promise<void> {
|
||||
await vscode.workspace.getConfiguration('coloredReferences')
|
||||
.update('panelLocation', placement, vscode.ConfigurationTarget.Workspace);
|
||||
assert.strictEqual(
|
||||
vscode.workspace.getConfiguration('coloredReferences').get('panelLocation'), placement);
|
||||
}
|
||||
|
||||
suite('Results panel', () => {
|
||||
let results: ReferenceResults;
|
||||
|
||||
@@ -64,6 +78,8 @@ suite('Results panel', () => {
|
||||
const ext = vscode.extensions.getExtension('local.colored-references');
|
||||
assert.ok(ext);
|
||||
await ext.activate();
|
||||
// These tests cover the editor-area placement; the docked view has its own suite.
|
||||
await setPlacement('beside');
|
||||
results = (await search(TARGET_FILE, TARGET_DECL, TARGET_SYMBOL)).results;
|
||||
});
|
||||
|
||||
@@ -138,12 +154,57 @@ suite('Results panel', () => {
|
||||
await vscode.commands.executeCommand('coloredReferences.toggleView');
|
||||
await sleep(1500);
|
||||
|
||||
const editorTabs = vscode.window.tabGroups.all.flatMap(g => g.tabs).filter(tab => {
|
||||
const input = tab.input as { uri?: vscode.Uri } | undefined;
|
||||
return input?.uri?.scheme === 'colored-refs';
|
||||
});
|
||||
const editorTabs = coloredEditorTabs();
|
||||
assert.strictEqual(editorTabs.length, 1, 'expected the results to open in an editor tab');
|
||||
assert.ok(editorTabs[0].label.startsWith(`References to ${SECOND_SYMBOL}`),
|
||||
`unexpected tab label: ${editorTabs[0].label}`);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Results panel docked in the bottom panel', () => {
|
||||
suiteSetup(async () => {
|
||||
const ext = vscode.extensions.getExtension('local.colored-references');
|
||||
assert.ok(ext);
|
||||
await ext.activate();
|
||||
await setPlacement('bottom');
|
||||
|
||||
// Close the editor-area panels the previous suite left behind.
|
||||
for (const tab of panelTabs()) {
|
||||
await vscode.window.tabGroups.close(tab, true);
|
||||
}
|
||||
for (const tab of coloredEditorTabs()) {
|
||||
await vscode.window.tabGroups.close(tab, true);
|
||||
}
|
||||
await sleep(500);
|
||||
});
|
||||
|
||||
test('the docked view is contributed and focusable', async () => {
|
||||
const commands = await vscode.commands.getCommands(true);
|
||||
assert.ok(commands.includes(`${PANEL_VIEW_TYPE}View.focus`) ||
|
||||
commands.includes('coloredReferences.resultsView.focus'),
|
||||
'the webview view did not contribute a focus command');
|
||||
});
|
||||
|
||||
test('a search fills the docked view instead of opening an editor tab', async () => {
|
||||
await search(TARGET_FILE, TARGET_DECL, TARGET_SYMBOL);
|
||||
await vscode.commands.executeCommand('coloredReferences.findInPanel');
|
||||
await sleep(2000);
|
||||
|
||||
assert.strictEqual(panelTabs().length, 0,
|
||||
'panelLocation is "bottom" but a webview opened in the editor area');
|
||||
assert.strictEqual(coloredEditorTabs().length, 0,
|
||||
'no results document should have been opened');
|
||||
});
|
||||
|
||||
test('toggleView reaches the results held by the docked view', async () => {
|
||||
// Only possible if the docked view actually received the results.
|
||||
await vscode.commands.executeCommand('coloredReferences.toggleView');
|
||||
await sleep(1500);
|
||||
|
||||
const editorTabs = coloredEditorTabs();
|
||||
assert.strictEqual(editorTabs.length, 1,
|
||||
'toggleView could not find the results shown in the docked view');
|
||||
assert.ok(editorTabs[0].label.startsWith(`References to ${TARGET_SYMBOL}`),
|
||||
`unexpected tab label: ${editorTabs[0].label}`);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user