From eee87af252ac49b2d11672b02ee3efd0541a0cc6 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 17 Feb 2023 19:49:05 +0100 Subject: [PATCH] Adding the server and client code to the JSON language features extensions to enable JSONC sorting in VS Code (#174352) * temporarily changing the funcion onFromat to be able to trigger the sorting on real examples * adding the DocumentSortingRequest * accesssing directly the text edits from the request * added code in order to provide the link between the json sorting capabiliites and vscode * adapting to the new api output of the sort function * instead of using await use then inside of the command that registers * textEditor replaces window.activeTextEditor * adding changes from review * update service * use SortOptions --------- Co-authored-by: Martin Aeschlimann --- .../client/src/jsonClient.ts | 50 ++++++++++++++++++- .../json-language-features/package.json | 5 ++ .../json-language-features/package.nls.json | 3 +- .../server/package.json | 2 +- .../server/src/jsonServer.ts | 29 +++++++++-- .../json-language-features/server/yarn.lock | 18 +++---- src/vscode-dts/vscode.d.ts | 21 ++++++++ 7 files changed, 113 insertions(+), 15 deletions(-) diff --git a/extensions/json-language-features/client/src/jsonClient.ts b/extensions/json-language-features/client/src/jsonClient.ts index 54a8ecc64ed..c0881c57112 100644 --- a/extensions/json-language-features/client/src/jsonClient.ts +++ b/extensions/json-language-features/client/src/jsonClient.ts @@ -11,7 +11,7 @@ import { ProviderResult, TextEdit, Range, Position, Disposable, CompletionItem, CompletionList, CompletionContext, Hover, MarkdownString, FoldingContext, DocumentSymbol, SymbolInformation, l10n } from 'vscode'; import { - LanguageClientOptions, RequestType, NotificationType, + LanguageClientOptions, RequestType, NotificationType, FormattingOptions as LSPFormattingOptions, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError, DocumentRangeFormattingParams, DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, ProvideHoverSignature, BaseLanguageClient, ProvideFoldingRangeSignature, ProvideDocumentSymbolsSignature, ProvideDocumentColorsSignature } from 'vscode-languageclient'; @@ -36,6 +36,23 @@ namespace LanguageStatusRequest { export const type: RequestType = new RequestType('json/languageStatus'); } +interface SortOptions extends LSPFormattingOptions { +} + +interface DocumentSortingParams { + /** + * The uri of the document to sort. + */ + readonly uri: string; + /** + * The format options + */ + readonly options: SortOptions; +} + +namespace DocumentSortingRequest { + export const type: RequestType = new RequestType('json/sort'); +} export interface ISchemaAssociations { [pattern: string]: string[]; @@ -146,6 +163,37 @@ export async function startClient(context: ExtensionContext, newLanguageClient: window.showInformationMessage(l10n.t('JSON schema cache cleared.')); })); + toDispose.push(commands.registerCommand('json.sort', async () => { + + if (isClientReady) { + const textEditor = window.activeTextEditor; + if (textEditor) { + const document = textEditor.document; + const filesConfig = workspace.getConfiguration('files', document); + const options: SortOptions = { + tabSize: textEditor.options.tabSize ? Number(textEditor.options.tabSize) : 4, + insertSpaces: textEditor.options.insertSpaces ? Boolean(textEditor.options.insertSpaces) : true, + trimTrailingWhitespace: filesConfig.get('trimTrailingWhitespace'), + trimFinalNewlines: filesConfig.get('trimFinalNewlines'), + insertFinalNewline: filesConfig.get('insertFinalNewline'), + }; + const params: DocumentSortingParams = { + uri: document.uri.toString(), + options + }; + const textEdits = await client.sendRequest(DocumentSortingRequest.type, params); + const success = await textEditor.edit(mutator => { + for (const edit of textEdits) { + mutator.replace(client.protocol2CodeConverter.asRange(edit.range), edit.newText); + } + }); + if (!success) { + window.showErrorMessage(l10n.t('Failed to sort the JSONC document, please consider opening an issue.')); + } + } + } + })); + // Options to control the language client const clientOptions: LanguageClientOptions = { // Register the server for json documents diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 1c5c88794b4..198b3919657 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -149,6 +149,11 @@ "command": "json.clearCache", "title": "%json.command.clearCache%", "category": "JSON" + }, + { + "command": "json.sort", + "title": "%json.command.sort%", + "category": "JSON" } ] }, diff --git a/extensions/json-language-features/package.nls.json b/extensions/json-language-features/package.nls.json index a0d0a84b32c..db0c326510d 100644 --- a/extensions/json-language-features/package.nls.json +++ b/extensions/json-language-features/package.nls.json @@ -17,5 +17,6 @@ "json.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons).", "json.maxItemsExceededInformation.desc": "Show notification when exceeding the maximum number of outline symbols and folding regions.", "json.enableSchemaDownload.desc": "When enabled, JSON schemas can be fetched from http and https locations.", - "json.command.clearCache": "Clear schema cache" + "json.command.clearCache": "Clear schema cache", + "json.command.sort": "Sort document" } diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 5abe1a2d35c..d9b2a01af7a 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -15,7 +15,7 @@ "@vscode/l10n": "^0.0.11", "jsonc-parser": "^3.2.0", "request-light": "^0.7.0", - "vscode-json-languageservice": "^5.2.0", + "vscode-json-languageservice": "^5.3.0", "vscode-languageserver": "^8.1.0-next.6", "vscode-uri": "^3.0.7" }, diff --git a/extensions/json-language-features/server/src/jsonServer.ts b/extensions/json-language-features/server/src/jsonServer.ts index 6a40666d18d..27b5b8cbeae 100644 --- a/extensions/json-language-features/server/src/jsonServer.ts +++ b/extensions/json-language-features/server/src/jsonServer.ts @@ -11,7 +11,7 @@ import { import { runSafe, runSafeAsync } from './utils/runner'; import { DiagnosticsSupport, registerDiagnosticsPullSupport, registerDiagnosticsPushSupport } from './utils/validation'; -import { TextDocument, JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities, Range, Position } from 'vscode-json-languageservice'; +import { TextDocument, JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities, Range, Position, SortOptions } from 'vscode-json-languageservice'; import { getLanguageModelCache } from './languageModelCache'; import { Utils, URI } from 'vscode-uri'; @@ -39,6 +39,20 @@ namespace LanguageStatusRequest { export const type: RequestType = new RequestType('json/languageStatus'); } +export interface DocumentSortingParams { + /** + * The uri of the document to sort. + */ + uri: string; + /** + * The format options + */ + options: SortOptions; +} + +namespace DocumentSortingRequest { + export const type: RequestType = new RequestType('json/sort'); +} const workspaceContext = { resolveRelativePath: (relativePath: string, resource: string) => { @@ -112,9 +126,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) let jsonColorDecoratorLimit = Number.MAX_VALUE; let jsoncColorDecoratorLimit = Number.MAX_VALUE; - let formatterMaxNumberOfEdits = Number.MAX_VALUE; - let diagnosticsSupport: DiagnosticsSupport | undefined; @@ -295,6 +307,16 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) } }); + connection.onRequest(DocumentSortingRequest.type, async params => { + const uri = params.uri; + const options = params.options; + const document = documents.get(uri); + if (document) { + return languageService.sort(document, options); + } + return []; + }); + function updateConfiguration() { const languageSettings = { validate: validateEnabled, @@ -403,6 +425,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) }); function onFormat(textDocument: TextDocumentIdentifier, range: Range | undefined, options: FormattingOptions): TextEdit[] { + options.keepLines = keepLinesEnabled; const document = documents.get(textDocument.uri); if (document) { diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 5649955bbd4..db8d2feb850 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -27,15 +27,15 @@ request-light@^0.7.0: resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.7.0.tgz#885628bb2f8040c26401ebf258ec51c4ae98ac2a" integrity sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q== -vscode-json-languageservice@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.2.0.tgz#884b7f108be4310e3332167c3ea60ab17f03418c" - integrity sha512-q8Rdhu2HEddRxvlhVqwh0cWmKK+OtyMB2xRhtqXEQ7cjb0iZ14madb90iJe9fCHPjoj9CGBrq6QzuOp8OE6XWg== +vscode-json-languageservice@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.3.0.tgz#b8e8f220f4030af33144182029ac13090d3ceb96" + integrity sha512-yVC2WpAaF1swkUBA7EqG3hmSORxI6EpTBGdGgo5DIfJpG5hrk8PzPODAhQd0gVFtTF5j4yFxFD6V1x2XBqagcg== dependencies: "@vscode/l10n" "^0.0.11" jsonc-parser "^3.2.0" vscode-languageserver-textdocument "^1.0.8" - vscode-languageserver-types "^3.17.2" + vscode-languageserver-types "^3.17.3" vscode-uri "^3.0.7" vscode-jsonrpc@8.1.0-next.7: @@ -61,10 +61,10 @@ vscode-languageserver-types@3.17.3-next.3: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3-next.3.tgz#fc909d37d4200126d74583f2114e53ace27a3e04" integrity sha512-R36Wi5sHoVc/PsAva0QGoEgw+LRCXPDKcdjFfgoVwrRdrFOdYUkvp5G4NvrPUsVT2f2qS/bSs6QiRxyjNkcR9A== -vscode-languageserver-types@^3.17.2: - version "3.17.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" - integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== +vscode-languageserver-types@^3.17.3: + version "3.17.3" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz#72d05e47b73be93acb84d6e311b5786390f13f64" + integrity sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA== vscode-languageserver@^8.1.0-next.6: version "8.1.0-next.6" diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 7bdd9fefda4..8a1e826817f 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -4074,6 +4074,27 @@ declare module 'vscode' { provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): ProviderResult; } + /** + * Value-object describing what options formatting should use. + */ + export interface SortingOptions { + + /** + * Size of a tab in spaces. + */ + tabSize: number; + + /** + * Prefer spaces over tabs. + */ + insertSpaces: boolean; + + /** + * Signature for further properties. + */ + [key: string]: boolean | number | string; + } + /** * Value-object describing what options formatting should use. */