From 7f186da3cedff0e31f549e2843ae28956f1007ad Mon Sep 17 00:00:00 2001 From: hexh <250786313@qq.com> Date: Thu, 18 Jul 2024 09:39:24 +0800 Subject: [PATCH 1/4] feat(diagnostic): add `showRelatedInformation` --- data/schema.json | 6 ++++++ doc/coc-config.txt | 6 ++++++ src/diagnostic/buffer.ts | 27 ++++++++++++++++++++++++--- src/diagnostic/util.ts | 1 + src/language-client/client.ts | 6 ------ 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/data/schema.json b/data/schema.json index 87ab26f2f8a..89aa8fc3d5e 100644 --- a/data/schema.json +++ b/data/schema.json @@ -1139,6 +1139,12 @@ "description": "Text of warning sign", "default": "⚠" }, + "diagnostic.showRelatedInformation": { + "type": "boolean", + "default": true, + "scope": "language-overridable", + "description": "Show related information in diagnostics." + }, "dialog.confirmKey": { "type": "string", "default": "", diff --git a/doc/coc-config.txt b/doc/coc-config.txt index cd63fbc880a..c97f87edf49 100644 --- a/doc/coc-config.txt +++ b/doc/coc-config.txt @@ -371,6 +371,12 @@ Diagnostic~ Scope: `application`, default: `"⚠"` +"diagnostic.showRelatedInformation" *coc-config-diagnostic-showRelatedInformation* + + Show related information in diagnostics. + + Scope: `language-overridable`, default: `true` + ------------------------------------------------------------------------------ Dialog~ *coc-config-dialog* diff --git a/src/diagnostic/buffer.ts b/src/diagnostic/buffer.ts index 75ec04eaa83..cf4b32de0a0 100644 --- a/src/diagnostic/buffer.ts +++ b/src/diagnostic/buffer.ts @@ -1,6 +1,7 @@ 'use strict' import type { Buffer, Neovim, VirtualTextOption } from '@chemzqm/neovim' import { Diagnostic, DiagnosticSeverity, Position, TextEdit } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' import events from '../events' import { SyncItem } from '../model/bufferSync' import Document from '../model/document' @@ -10,6 +11,7 @@ import { isFalsyOrEmpty } from '../util/array' import { lineInRange, positionInRange } from '../util/position' import { Emitter, Event } from '../util/protocol' import window from '../window' +import { path } from '../util/node' import workspace from '../workspace' import { adjustDiagnostics, DiagnosticConfig, formatDiagnostic, getHighlightGroup, getLocationListItem, getNameFromSeverity, getSeverityType, LocationListItem, severityLevel, sortDiagnostics } from './util' import { stripAnsiColoring } from '../util/ansiparse' @@ -124,6 +126,7 @@ export class DiagnosticBuffer implements SyncItem { showUnused: config.get('showUnused', true), showDeprecated: config.get('showDeprecated', true), format: config.get('format', '[%source%code] [%severity] %message'), + showRelatedInformation: config.get('showRelatedInformation', true), } if (this._config.virtualText && !virtualTextSrcId) { void this.nvim.createNamespace('coc-diagnostic-virtualText').then(id => { @@ -352,9 +355,27 @@ export class DiagnosticBuffer implements SyncItem { } else { filetype = ft } - docs.push({ filetype, content: formatDiagnostic(config.format, diagnostic) }) - if (diagnostic.codeDescription?.href) { - docs.push({ filetype: 'txt', content: diagnostic.codeDescription.href }) + let msg = diagnostic.message + let links = diagnostic.codeDescription?.href ?? '' + if (config.showRelatedInformation && diagnostic.relatedInformation?.length) { + msg = `${diagnostic.message}\n\nRelated diagnostics:\n` + for (const info of diagnostic.relatedInformation) { + const fsPath = URI.parse(info.location.uri).fsPath + const basename = path.basename(fsPath) + const line = info.location.range.start.line + 1 + const column = info.location.range.start.character + 1 + msg = `${msg}\n * ${basename}#${line},${column}: ${info.message}` + links = `${links}\n${basename}#${line},${column}: ${fsPath}` + } + msg = msg + "\n\n" + links = links.trim() + } + docs.push({ filetype, content: formatDiagnostic(config.format, { + ...diagnostic, + message: msg + }) }) + if (links.length) { + docs.push({ filetype: 'txt', content: links }) } }) await floatFactory.show(docs, this.config.floatConfig) diff --git a/src/diagnostic/util.ts b/src/diagnostic/util.ts index 47b9e487805..1bf459c3362 100644 --- a/src/diagnostic/util.ts +++ b/src/diagnostic/util.ts @@ -61,6 +61,7 @@ export interface DiagnosticConfig { showDeprecated: boolean format: string floatConfig: FloatConfig + showRelatedInformation: boolean } export function formatDiagnostic(format: string, diagnostic: Diagnostic): string { diff --git a/src/language-client/client.ts b/src/language-client/client.ts index 1af5fee67af..ed19d9e8444 100644 --- a/src/language-client/client.ts +++ b/src/language-client/client.ts @@ -1582,17 +1582,11 @@ export abstract class BaseLanguageClient implements FeatureClient Date: Mon, 22 Jul 2024 10:24:03 +0800 Subject: [PATCH 2/4] feat(diagnostic): Remove `separateRelatedInformationAsDiagnostics` --- data/schema.json | 6 ---- doc/coc-config.txt | 6 ---- src/__tests__/client/integration.test.ts | 45 ------------------------ src/language-client/client.ts | 25 +------------ 4 files changed, 1 insertion(+), 81 deletions(-) diff --git a/data/schema.json b/data/schema.json index 89aa8fc3d5e..00f6b549f0a 100644 --- a/data/schema.json +++ b/data/schema.json @@ -1039,12 +1039,6 @@ "description": "Enable diagnostic refresh on insert mode, default false.", "default": false }, - "diagnostic.separateRelatedInformationAsDiagnostics": { - "type": "boolean", - "default": false, - "scope": "application", - "description": "Separate related information as diagnostics." - }, "diagnostic.showDeprecated": { "type": "boolean", "default": true, diff --git a/doc/coc-config.txt b/doc/coc-config.txt index c97f87edf49..4046928e5d5 100644 --- a/doc/coc-config.txt +++ b/doc/coc-config.txt @@ -272,12 +272,6 @@ Diagnostic~ Scope: `language-overridable`, default: `false` -"diagnostic.separateRelatedInformationAsDiagnostics" *coc-config-diagnostic-separateRelatedInformationAsDiagnostics* - - Separate related information as diagnostics. - - Scope: `application`, default: `false` - "diagnostic.showDeprecated" *coc-config-diagnostic-showDeprecated* Show diagnostics with deprecated tag. diff --git a/src/__tests__/client/integration.test.ts b/src/__tests__/client/integration.test.ts index 62a44e21a75..27210a51d7f 100644 --- a/src/__tests__/client/integration.test.ts +++ b/src/__tests__/client/integration.test.ts @@ -598,51 +598,6 @@ describe('Client integration', () => { expect(fn).toBeCalled() }) - it('should separate diagnostics', async () => { - async function startServer(disable?: boolean, handleDiagnostics?: (uri: string, diagnostics: Diagnostic[], next: HandleDiagnosticsSignature) => void): Promise { - let clientOptions: lsclient.LanguageClientOptions = { - disableDiagnostics: disable, - separateDiagnostics: true, - initializationOptions: {}, - middleware: { - handleDiagnostics - } - } - let serverModule = path.join(__dirname, './server/eventServer.js') - let serverOptions: lsclient.ServerOptions = { - module: serverModule, - transport: lsclient.TransportKind.stdio, - } - let client = new lsclient.LanguageClient('html', 'Test Language Server', serverOptions, clientOptions) - await client.start() - return client - } - let client = await startServer() - await client.sendNotification('diagnostics') - await helper.waitValue(() => { - let collection = client.diagnostics - let res = collection.get('lsptest:/2') - return res.length - }, 2) - await client.stop() - client = await startServer(true) - await client.sendNotification('diagnostics') - await helper.wait(50) - let collection = client.diagnostics - expect(collection).toBeUndefined() - await client.stop() - let called = false - client = await startServer(false, (uri, diagnostics, next) => { - called = true - next(uri, diagnostics) - }) - await client.sendNotification('diagnostics') - await helper.waitValue(() => { - return called - }, true) - await client.stop() - }) - it('should check version on apply workspaceEdit', async () => { let uri = URI.file(__filename) await workspace.loadFile(uri.toString()) diff --git a/src/language-client/client.ts b/src/language-client/client.ts index ed19d9e8444..436eb490417 100644 --- a/src/language-client/client.ts +++ b/src/language-client/client.ts @@ -174,7 +174,6 @@ export type LanguageClientOptions = { rootPatterns?: string[] requireRootPattern?: boolean documentSelector?: DocumentSelector - separateDiagnostics?: boolean disableMarkdown?: boolean disableWorkspaceFolders?: boolean disableDiagnostics?: boolean @@ -206,7 +205,6 @@ type ResolvedClientOptions = { disabledFeatures: string[] disableMarkdown: boolean disableDynamicRegister: boolean - separateDiagnostics: boolean rootPatterns?: string[] requireRootPattern?: boolean documentSelector: DocumentSelector @@ -382,15 +380,10 @@ export abstract class BaseLanguageClient implements FeatureClient 0) { - const entries: Map = new Map() - entries.set(uri, diagnostics) - for (const diagnostic of diagnostics) { - if (diagnostic.relatedInformation?.length) { - for (const info of diagnostic.relatedInformation) { - const diags: Diagnostic[] = entries.get(info.location.uri) || [] - diags.push(Diagnostic.create(info.location.range, info.message, DiagnosticSeverity.Hint, diagnostic.code, diagnostic.source)) - entries.set(info.location.uri, diags) - } - } - this._diagnostics.set(Array.from(entries)) - } - } else { - this._diagnostics.set(uri, diagnostics) - } + this._diagnostics.set(uri, diagnostics) } private handleApplyWorkspaceEdit(params: ApplyWorkspaceEditParams): Promise { From eaa43f04e8cabe1b829e68af3d460c2e942002dc Mon Sep 17 00:00:00 2001 From: hexh <250786313@qq.com> Date: Mon, 22 Jul 2024 10:52:25 +0800 Subject: [PATCH 3/4] feat(diagnostic): Not show full path of related info The full paths info make floating window less readable. --- data/schema.json | 2 +- doc/coc-config.txt | 2 +- src/diagnostic/buffer.ts | 10 ++++------ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/data/schema.json b/data/schema.json index 00f6b549f0a..3f1c7eebee7 100644 --- a/data/schema.json +++ b/data/schema.json @@ -1137,7 +1137,7 @@ "type": "boolean", "default": true, "scope": "language-overridable", - "description": "Show related information in diagnostics." + "description": "Display related information in the diagnostic floating window." }, "dialog.confirmKey": { "type": "string", diff --git a/doc/coc-config.txt b/doc/coc-config.txt index 4046928e5d5..0a8d2274ac3 100644 --- a/doc/coc-config.txt +++ b/doc/coc-config.txt @@ -367,7 +367,7 @@ Diagnostic~ "diagnostic.showRelatedInformation" *coc-config-diagnostic-showRelatedInformation* - Show related information in diagnostics. + Display related information in the diagnostic floating window. Scope: `language-overridable`, default: `true` diff --git a/src/diagnostic/buffer.ts b/src/diagnostic/buffer.ts index cf4b32de0a0..a883f3cfa8b 100644 --- a/src/diagnostic/buffer.ts +++ b/src/diagnostic/buffer.ts @@ -356,26 +356,24 @@ export class DiagnosticBuffer implements SyncItem { filetype = ft } let msg = diagnostic.message - let links = diagnostic.codeDescription?.href ?? '' + let link = diagnostic.codeDescription?.href ?? '' if (config.showRelatedInformation && diagnostic.relatedInformation?.length) { - msg = `${diagnostic.message}\n\nRelated diagnostics:\n` + msg = `${diagnostic.message}\n\nRelated information:\n` for (const info of diagnostic.relatedInformation) { const fsPath = URI.parse(info.location.uri).fsPath const basename = path.basename(fsPath) const line = info.location.range.start.line + 1 const column = info.location.range.start.character + 1 msg = `${msg}\n * ${basename}#${line},${column}: ${info.message}` - links = `${links}\n${basename}#${line},${column}: ${fsPath}` } msg = msg + "\n\n" - links = links.trim() } docs.push({ filetype, content: formatDiagnostic(config.format, { ...diagnostic, message: msg }) }) - if (links.length) { - docs.push({ filetype: 'txt', content: links }) + if (link) { + docs.push({ filetype: 'txt', content: link }) } }) await floatFactory.show(docs, this.config.floatConfig) From 51d54c17787468ec95438a12e18e12472ab696d6 Mon Sep 17 00:00:00 2001 From: hexh <250786313@qq.com> Date: Mon, 22 Jul 2024 11:44:14 +0800 Subject: [PATCH 4/4] feat(diagnostic): Add action `diagnosticRelatedInformation` --- src/diagnostic/manager.ts | 11 ++++++++--- src/language-client/client.ts | 1 - src/plugin.ts | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/diagnostic/manager.ts b/src/diagnostic/manager.ts index 2dc30e6a3e1..8d94b83ef5b 100644 --- a/src/diagnostic/manager.ts +++ b/src/diagnostic/manager.ts @@ -431,9 +431,7 @@ class DiagnosticManager implements Disposable { } public async jumpRelated(): Promise { - let diagnostics = await this.getCurrentDiagnostics() - let diagnostic = diagnostics.find(o => o.relatedInformation != null) - let locations = diagnostic ? diagnostic.relatedInformation.map(o => o.location) : [] + let locations = await this.relatedInformation() if (locations.length == 1) { await workspace.jumpTo(locations[0].uri, locations[0].range.start) } else if (locations.length > 1) { @@ -443,6 +441,13 @@ class DiagnosticManager implements Disposable { } } + public async relatedInformation(): Promise { + let diagnostics = await this.getCurrentDiagnostics() + let diagnostic = diagnostics.find(o => o.relatedInformation != null) + let locations = diagnostic ? diagnostic.relatedInformation.map(o => o.location) : [] + return locations + } + public reset(): void { clearTimeout(this.messageTimer) this.buffers.reset() diff --git a/src/language-client/client.ts b/src/language-client/client.ts index 436eb490417..7f4406be71b 100644 --- a/src/language-client/client.ts +++ b/src/language-client/client.ts @@ -1568,7 +1568,6 @@ export abstract class BaseLanguageClient implements FeatureClient diagnosticManager.jumpPrevious(severity)) this.addAction('diagnosticPreview', () => diagnosticManager.preview()) this.addAction('diagnosticList', () => diagnosticManager.getDiagnosticList()) + this.addAction('diagnosticRelatedInformation', () => diagnosticManager.relatedInformation()) this.addAction('findLocations', (id, method, params, openCommand) => this.handler.locations.findLocations(id, method, params, openCommand)) this.addAction('getTagList', () => this.handler.locations.getTagList()) this.addAction('definitions', () => this.handler.locations.definitions())