From 6651f8ab436fa7e2061f59e53ff45411bb6b3101 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 18 Nov 2021 14:46:54 +0100 Subject: [PATCH] [json] Adapt language status indicator. Fixes #137288 --- .../client/src/jsonClient.ts | 10 +++ .../client/src/languageStatus.ts | 83 +++++++++++++++++++ .../client/tsconfig.json | 3 +- .../json-language-features/package.json | 6 +- .../server/package.json | 2 +- .../server/src/jsonServer.ts | 16 ++++ .../json-language-features/server/yarn.lock | 8 +- 7 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 extensions/json-language-features/client/src/languageStatus.ts diff --git a/extensions/json-language-features/client/src/jsonClient.ts b/extensions/json-language-features/client/src/jsonClient.ts index 8fb6dda91e18d..eeae0d3f03aa9 100644 --- a/extensions/json-language-features/client/src/jsonClient.ts +++ b/extensions/json-language-features/client/src/jsonClient.ts @@ -6,6 +6,8 @@ import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); +export type JSONLanguageStatus = { schemas: string[] }; + import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, Diagnostic, StatusBarAlignment, TextEditor, TextDocument, FormattingOptions, CancellationToken, @@ -19,6 +21,7 @@ import { import { hash } from './utils/hash'; import { RequestService, joinPath } from './requests'; +import { createLanguageStatusItem } from './languageStatus'; namespace VSCodeContentRequest { export const type: RequestType = new RequestType('vscode/content'); @@ -32,6 +35,11 @@ namespace ForceValidateRequest { export const type: RequestType = new RequestType('json/validate'); } +namespace LanguageStatusRequest { + export const type: RequestType = new RequestType('json/languageStatus'); +} + + export interface ISchemaAssociations { [pattern: string]: string[]; } @@ -314,6 +322,8 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua } }); + toDispose.push(createLanguageStatusItem(documentSelector, (uri: string) => client.sendRequest(LanguageStatusRequest.type, uri))); + function updateFormatterRegistration() { const formatEnabled = workspace.getConfiguration().get(SettingIds.enableFormatter); if (!formatEnabled && rangeFormatting) { diff --git a/extensions/json-language-features/client/src/languageStatus.ts b/extensions/json-language-features/client/src/languageStatus.ts new file mode 100644 index 0000000000000..f06a750424b4a --- /dev/null +++ b/extensions/json-language-features/client/src/languageStatus.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * 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 { JSONLanguageStatus } from './jsonClient'; + +import * as nls from 'vscode-nls'; + +const localize = nls.loadMessageBundle(); + +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.showSchemasCommand', arg => { + const items = arg.schemas.sort().map((a: string) => ({ label: a })); + const quickPick = window.createQuickPick(); + quickPick.title = localize('schemaPicker.title', 'Associated JSON Schemas'); + 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)); + quickPick.dispose(); + }); + }); + + const activeEditorListener = window.onDidChangeActiveTextEditor(() => { + updateLanguageStatus(); + }); + + async function updateLanguageStatus() { + const document = window.activeTextEditor?.document; + if (document && documentSelector.indexOf(document.languageId) !== -1) { + try { + statusItem.text = '$(loading~spin)'; + statusItem.detail = localize('pending.detail', 'Loading JSON info'); + statusItem.command = undefined; + + const schemas = (await statusRequest(document.uri.toString())).schemas; + statusItem.detail = undefined; + if (schemas.length === 0) { + statusItem.text = localize('status.noSchema', 'Validated without JSON schema'); + } else if (schemas.length === 1) { + 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])] + }; + } else { + statusItem.text = localize('status.multipleSchema', 'Validated with multiple JSON schemas'); + statusItem.command = { + command: 'json.showSchemasCommand', + title: localize('status.openSchemasLink', 'Show Schemas'), + arguments: [{ schemas }] + }; + } + } catch (e) { + statusItem.text = localize('status.error', 'Unable to compute used schemas'); + statusItem.detail = undefined; + statusItem.command = undefined; + console.log(e); + } + } else { + statusItem.text = localize('status.notJSON', 'Not a JSON editor'); + statusItem.detail = undefined; + statusItem.command = undefined; + } + } + + updateLanguageStatus(); + + return Disposable.from(statusItem, activeEditorListener, showSchemasCommand); +} + + + diff --git a/extensions/json-language-features/client/tsconfig.json b/extensions/json-language-features/client/tsconfig.json index 573b24b4aa636..4254a37490ea7 100644 --- a/extensions/json-language-features/client/tsconfig.json +++ b/extensions/json-language-features/client/tsconfig.json @@ -5,6 +5,7 @@ }, "include": [ "src/**/*", - "../../../src/vscode-dts/vscode.d.ts" + "../../../src/vscode-dts/vscode.d.ts", + "../../../src/vscode-dts/vscode.proposed.languageStatus.d.ts", ] } diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 6a6fb61c9a660..6c5a15102cd14 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -12,7 +12,8 @@ "icon": "icons/json.png", "activationEvents": [ "onLanguage:json", - "onLanguage:jsonc" + "onLanguage:jsonc", + "onCommand:json.showSchemas" ], "main": "./client/out/node/jsonClientMain", "browser": "./client/dist/browser/jsonClientMain", @@ -22,6 +23,9 @@ "supported": true } }, + "enabledApiProposals": [ + "languageStatus" + ], "scripts": { "compile": "npx gulp compile-extension:json-language-features-client compile-extension:json-language-features-server", "watch": "npx gulp watch-extension:json-language-features-client watch-extension:json-language-features-server", diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 5c8bb31f68bd4..90ec7eb10d330 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,7 +14,7 @@ "dependencies": { "jsonc-parser": "^3.0.0", "request-light": "^0.5.4", - "vscode-json-languageservice": "^4.1.10", + "vscode-json-languageservice": "^4.2.0-next.1", "vscode-languageserver": "^7.0.0", "vscode-uri": "^3.0.2" }, diff --git a/extensions/json-language-features/server/src/jsonServer.ts b/extensions/json-language-features/server/src/jsonServer.ts index ffca9f401533c..eb970784d9bb9 100644 --- a/extensions/json-language-features/server/src/jsonServer.ts +++ b/extensions/json-language-features/server/src/jsonServer.ts @@ -16,6 +16,8 @@ import { RequestService, basename, resolvePath } from './requests'; type ISchemaAssociations = Record; +type JSONLanguageStatus = { schemas: string[] }; + namespace SchemaAssociationNotification { export const type: NotificationType = new NotificationType('json/schemaAssociations'); } @@ -36,6 +38,10 @@ namespace ForceValidateRequest { export const type: RequestType = new RequestType('json/validate'); } +namespace LanguageStatusRequest { + export const type: RequestType = new RequestType('json/languageStatus'); +} + const workspaceContext = { resolveRelativePath: (relativePath: string, resource: string) => { @@ -277,6 +283,16 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) }); }); + connection.onRequest(LanguageStatusRequest.type, async uri => { + const document = documents.get(uri); + if (document) { + const jsonDocument = getJSONDocument(document); + return languageService.getLanguageStatus(document, jsonDocument); + } else { + return { schemas: [] }; + } + }); + function updateConfiguration() { const languageSettings = { validate: true, diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 25e3ca5584529..9b542a82f9c5e 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -22,10 +22,10 @@ request-light@^0.5.4: resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.5.4.tgz#497a98c6d8ae49536417a5e2d7f383b934f3e38c" integrity sha512-t3566CMweOFlUk7Y1DJMu5OrtpoZEb6aSTsLQVT3wtrIEJ5NhcY9G/Oqxvjllzl4a15zXfFlcr9q40LbLVQJqw== -vscode-json-languageservice@^4.1.10: - version "4.1.10" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.1.10.tgz#5d5729fc4f3e02f41599e0104523a1877c25f0fb" - integrity sha512-IHliMEEYSY0tJjJt0ECb8ESx/nRXpoy9kN42WVQXgaqGyizFAf3jibSiezDQTrrY7f3kywXggCU+kkJEM+OLZQ== +vscode-json-languageservice@^4.2.0-next.1: + version "4.2.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.2.0-next.1.tgz#31a8c3be04c87d5aa593c11b98d84258b173a22f" + integrity sha512-aQvkkuZpeSPv86QLzyMdKTCgvXR+qSO39nSgj/XGaOcuHmTt7vMZB7ymYGGkQ4cAaQdHs/2G6a479LQybIGSbg== dependencies: jsonc-parser "^3.0.0" vscode-languageserver-textdocument "^1.0.1"