Skip to content

Commit

Permalink
fix(diagnostic): avoid change range of diagnostics
Browse files Browse the repository at this point in the history
Change range could cause server not find the diagnostic with
codeAction, improve position check instead.
  • Loading branch information
chemzqm committed Jun 21, 2021
1 parent cad8c6b commit 91c1114
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 56 deletions.
2 changes: 1 addition & 1 deletion doc/coc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ normal mode, `v_` works for visual mode.

<Plug>(coc-fix-current) *n_coc-fix-current*

Try first quickfix action for diagnostics on the current line.
Try first quickfix action for diagnostics of current line.

<Plug>(coc-float-hide) *n_coc-float-hide*

Expand Down
1 change: 0 additions & 1 deletion src/__tests__/modules/diagnosticBuffer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ describe('diagnostic buffer', () => {

it('should add deprecated highlight', async () => {
let diagnostic = createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Information, [DiagnosticTag.Deprecated])
console.log(diagnostic)
let buf = await createDiagnosticBuffer()
await nvim.setLine('foo')
nvim.pauseNotification()
Expand Down
50 changes: 30 additions & 20 deletions src/__tests__/modules/diagnosticManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,6 @@ describe('diagnostic manager', () => {
expect(info).toBeDefined()
})

it('should adjust diagnostic range after document', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, 'foo'])
let collection = manager.create('test')
collection.set(doc.uri, [createDiagnostic('foo', Range.create(1, 0, 1, 1))])
let diagnostics = manager.getDiagnostics(doc.uri)
expect(diagnostics.length).toBe(1)
let o = diagnostics[0]
expect(o.range).toEqual({
start: {
line: 0,
character: 2
},
end: {
line: 0,
character: 3
}
})
})

it('should get sorted ranges of document', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['a', 'b', 'c']])
Expand Down Expand Up @@ -304,6 +284,36 @@ describe('diagnostic manager', () => {
collection.dispose()
})

it('should get diagnostic with empty range at end of line', async () => {
let doc = await helper.createDocument()
await nvim.setLine('foo')
doc.forceSync()
await nvim.command('normal! $')
let diagnostic = Diagnostic.create(Range.create(0, 3, 1, 0), 'error', DiagnosticSeverity.Error)
let collection = manager.create('empty')
collection.set(doc.uri, [diagnostic])
manager.refreshBuffer(doc.bufnr, true)
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBeGreaterThanOrEqual(1)
expect(diagnostics[0].message).toBe('error')
collection.dispose()
})

it('should get diagnostic pass end of the buffer lines', async () => {
let doc = await helper.createDocument()
await nvim.setLine('foo')
doc.forceSync()
await nvim.command('normal! ^')
let diagnostic = Diagnostic.create(Range.create(1, 0, 1, 0), 'error', DiagnosticSeverity.Error)
let collection = manager.create('empty')
collection.set(doc.uri, [diagnostic])
manager.refreshBuffer(doc.bufnr, true)
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBeGreaterThanOrEqual(1)
expect(diagnostics[0].message).toBe('error')
collection.dispose()
})

it('should send ale diagnostic items', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('displayByAle', true)
Expand Down
24 changes: 3 additions & 21 deletions src/diagnostic/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,35 +38,17 @@ export default class Collection implements DiagnosticCollection {
} else {
diagnostics = (diagnosticsPerFile.get(uri) || []).concat(diagnostics)
}

diagnosticsPerFile.set(uri, diagnostics)
}
}
for (let item of diagnosticsPerFile) {
let [uri, diagnostics] = item
let doc = workspace.getDocument(uri)
uri = URI.parse(uri).toString()
diagnostics.forEach(o => {
// should be message for the file, but we need range
o.range = o.range || Range.create(0, 0, 1, 0)
o.message = o.message || 'Undefined error message'
let { start, end } = o.range
if (doc) {
// fix empty diagnostic at the and of line
if (end.character == 0 && end.line - start.line == 1 && start.character > 0) {
// add last character when start character is end
let line = doc.getline(start.line)
if (start.character == line.length) {
o.range.start.character = start.character - 1
}
}
// fix diagnostic pass last line, since vim not showing last line like VSCode.
if (start.line != 0 && start.line >= doc.lineCount) {
let lastline = doc.getline(doc.lineCount - 1)
let endCharacter = lastline.length == 0 ? 1 : lastline.length
o.range = Range.create(doc.lineCount - 1, endCharacter - 1, doc.lineCount - 1, endCharacter)
}
}
o.range = o.range || Range.create(0, 0, 0, 0)
o.message = o.message || 'unknown error message'
// TODO make sure we check start position of next line when cursor at the end.
o.source = o.source || this.name
})
this.diagnosticsMap.set(uri, diagnostics)
Expand Down
33 changes: 20 additions & 13 deletions src/diagnostic/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,9 @@ export class DiagnosticManager implements Disposable {
* Show diagnostics under curosr in preview window
*/
public async preview(): Promise<void> {
let [bufnr, cursor, atEnd] = await this.nvim.eval(`[bufnr("%"),coc#util#cursor(),col('.')==col('$')-1]`) as [number, [number, number], number]
let { nvim } = this
let diagnostics = this.getDiagnosticsAt(bufnr, cursor, atEnd == 1)
let diagnostics = await this.getCurrentDiagnostics()
if (diagnostics.length == 0) {
nvim.command('pclose', true)
this.nvim.command('pclose', true)
window.showMessage(`Empty diagnostics`, 'warning')
return
}
Expand All @@ -261,7 +259,7 @@ export class DiagnosticManager implements Disposable {
lines.push(...message.split(/\r?\n/))
lines.push('')
}
nvim.call('coc#util#preview_info', [lines, 'txt'], true)
this.nvim.call('coc#util#preview_info', [lines, 'txt'], true)
}

/**
Expand Down Expand Up @@ -376,34 +374,43 @@ export class DiagnosticManager implements Disposable {
return res
}

private getDiagnosticsAt(bufnr: number, cursor: [number, number], atEnd = false): Diagnostic[] {
private getDiagnosticsAt(bufnr: number, cursor: [number, number], atEnd = false, lastline = false): Diagnostic[] {
let buffer = this.buffers.getItem(bufnr)
if (!buffer) return []
let pos = Position.create(cursor[0], cursor[1])
let res = buffer.getDiagnosticsAt(pos, this.config.checkCurrentLine)
if (!res.length && atEnd && !this.config.checkCurrentLine) {
return this.getDiagnosticsAt(bufnr, [cursor[0], cursor[1] + 1])
if (this.config.checkCurrentLine || res.length) return res
// check next character when cursor at end of line.
if (atEnd) {
pos = Position.create(cursor[0], cursor[1] + 1)
res = buffer.getDiagnosticsAt(pos, false)
if (res.length) return res
}
// check next line when cursor at the beginning of last line.
if (lastline && cursor[1] == 0) {
pos = Position.create(cursor[0] + 1, 0)
res = buffer.getDiagnosticsAt(pos, false)
}
return res
}

public async getCurrentDiagnostics(): Promise<Diagnostic[]> {
let [bufnr, cursor, atEnd] = await this.nvim.eval(`[bufnr("%"),coc#util#cursor(),col('.')==col('$')-1]`) as [number, [number, number], number]
return this.getDiagnosticsAt(bufnr, cursor, atEnd == 1)
let [bufnr, cursor, eol, lastline] = await this.nvim.eval(`[bufnr("%"),coc#util#cursor(),col('.')==col('$')-1,line('.')==line('$')]`) as [number, [number, number], number, number]
return this.getDiagnosticsAt(bufnr, cursor, eol == 1, lastline == 1)
}

/**
* Echo diagnostic message of currrent position
* Echo diagnostic message under cursor.
*/
public async echoMessage(truncate = false): Promise<void> {
const config = this.config
if (!this.enabled || config.displayByAle) return
if (this.timer) clearTimeout(this.timer)
let useFloat = config.messageTarget == 'float'
// echo
let [bufnr, cursor, filetype, mode, atEnd] = await this.nvim.eval(`[bufnr("%"),coc#util#cursor(),&filetype,mode(),col('.')==col('$')-1]`) as [number, [number, number], string, string, number]
let [filetype, mode] = await this.nvim.eval(`[&filetype,mode()]`) as [string, string]
if (mode != 'n') return
let diagnostics = this.getDiagnosticsAt(bufnr, cursor, atEnd == 1)
let diagnostics = await this.getCurrentDiagnostics()
if (diagnostics.length == 0) {
if (useFloat) {
this.floatFactory.close()
Expand Down

0 comments on commit 91c1114

Please sign in to comment.