From d159ea189ba3368d8114969a9e2dd7921188daef Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 22 Nov 2021 14:54:45 +0100 Subject: [PATCH] improve json language indicator --- .../client/src/languageStatus.ts | 80 ++++++++++++++++--- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/extensions/json-language-features/client/src/languageStatus.ts b/extensions/json-language-features/client/src/languageStatus.ts index c3366399b13..63541be773d 100644 --- a/extensions/json-language-features/client/src/languageStatus.ts +++ b/extensions/json-language-features/client/src/languageStatus.ts @@ -3,28 +3,85 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, languages, Uri, LanguageStatusSeverity, Disposable, commands, QuickPickItem } from 'vscode'; +import { window, languages, Uri, LanguageStatusSeverity, Disposable, commands, QuickPickItem, extensions, workspace } from 'vscode'; import { JSONLanguageStatus } from './jsonClient'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); +type ShowSchemasInput = { + schemas: string[]; + uri: string; +}; + +interface ShowSchemasItem extends QuickPickItem { + uri: Uri; +} + +function equalsIgnoreCase(a: string, b: string): boolean { + return a.length === b.length && a.toLowerCase().localeCompare(b.toLowerCase()) === 0; +} + +function isEqualAuthority(a1: string | undefined, a2: string | undefined) { + return a1 === a2 || (a1 !== undefined && a2 !== undefined && equalsIgnoreCase(a1, a2)); +} + +function findExtension(uri: Uri) { + for (const ext of extensions.all) { + const parent = ext.extensionUri; + if (uri.scheme === parent.scheme && isEqualAuthority(uri.authority, parent.authority) && uri.path.startsWith(parent.path + '/')) { + return ext; + } + } + return undefined; +} + +function findWorkspaceFolder(uri: Uri) { + if (workspace.workspaceFolders) { + for (const wf of workspace.workspaceFolders) { + const parent = wf.uri; + if (uri.scheme === parent.scheme && isEqualAuthority(uri.authority, parent.authority) && uri.path.startsWith(parent.path + '/')) { + return wf; + } + } + } + return undefined; +} + +function renderShowSchemasItem(schema: string): ShowSchemasItem { + const uri = Uri.parse(schema); + const extension = findExtension(uri); + if (extension) { + return { label: extension.id, description: uri.path.substring(extension.extensionUri.path.length + 1), uri }; + } + const wf = findWorkspaceFolder(uri); + if (wf) { + return { label: uri.path.substring(wf.uri.path.length + 1), description: 'Workspace', uri }; + } + if (uri.scheme === 'file') { + return { label: uri.fsPath, uri }; + } else if (uri.scheme === 'vscode') { + return { label: schema, description: 'internally generated', uri }; + } + return { label: schema, uri }; +} + + export function createLanguageStatusItem(documentSelector: string[], statusRequest: (uri: string) => Promise): Disposable { const statusItem = languages.createLanguageStatusItem('json.projectStatus', documentSelector); statusItem.name = localize('statusItem.name', "JSON Validation Status"); statusItem.severity = LanguageStatusSeverity.Information; - const showSchemasCommand = commands.registerCommand('_json.showAssociatedSchemaList', arg => { - const items = arg.schemas.sort().map((a: string) => ({ label: a })); - const quickPick = window.createQuickPick(); - quickPick.title = localize('schemaPicker.title', 'Associated JSON Schemas'); + const showSchemasCommand = commands.registerCommand('_json.showAssociatedSchemaList', (arg: ShowSchemasInput) => { + const items: ShowSchemasItem[] = arg.schemas.sort().map(renderShowSchemasItem); + const quickPick = window.createQuickPick(); + quickPick.title = localize('schemaPicker.title', 'JSON Schemas used for {0}', arg.uri.toString()); quickPick.placeholder = localize('schemaPicker.placeholder', 'Select the schema to open'); quickPick.items = items; quickPick.show(); quickPick.onDidAccept(() => { - const selectedSchema = quickPick.selectedItems[0].label; - commands.executeCommand('vscode.open', Uri.parse(selectedSchema)); + commands.executeCommand('vscode.open', quickPick.selectedItems[0].uri); quickPick.dispose(); }); }); @@ -46,19 +103,20 @@ export function createLanguageStatusItem(documentSelector: string[], statusReque if (schemas.length === 0) { statusItem.text = localize('status.noSchema', 'Validated without JSON schema'); } else if (schemas.length === 1) { + const item = renderShowSchemasItem(schemas[0]); statusItem.text = localize('status.singleSchema', 'Validated with JSON schema'); statusItem.command = { command: 'vscode.open', title: localize('status.openSchemaLink', 'Open Schema'), - tooltip: schemas[0], - arguments: [Uri.parse(schemas[0])] + tooltip: item.description ? `${item.label} - ${item.description}` : item.label, + arguments: [item.uri] }; } else { statusItem.text = localize('status.multipleSchema', 'Validated with multiple JSON schemas'); statusItem.command = { command: '_json.showAssociatedSchemaList', title: localize('status.openSchemasLink', 'Show Schemas'), - arguments: [{ schemas }] + arguments: [{ schemas, uri: document.uri.toString() } as ShowSchemasInput] }; } } catch (e) { @@ -79,5 +137,3 @@ export function createLanguageStatusItem(documentSelector: string[], statusReque return Disposable.from(statusItem, activeEditorListener, showSchemasCommand); } - -