Add support for range diagnostics under cursor (#1586)

This commit is contained in:
Satoru Kitaguchi
2025-11-16 17:17:24 +09:00
committed by GitHub
parent c0de72708a
commit cb3406a591
3 changed files with 112 additions and 4 deletions

View File

@@ -29,20 +29,29 @@ function! lsp#internal#diagnostics#under_cursor#get_diagnostic(...) abort
let l:line = line('.') let l:line = line('.')
let l:col = col('.') let l:col = col('.')
return lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, l:line, l:col)
endfunction
" Returns a diagnostic object, or empty dictionary if no diagnostics are
" available.
function! lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(diagnostics, line, col) abort
let l:closest_diagnostic = {} let l:closest_diagnostic = {}
let l:closest_distance = -1 let l:closest_distance = -1
let l:closest_end_col = -1
for l:diagnostic in l:diagnostics for l:diagnostic in a:diagnostics
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim('%', l:diagnostic['range']['start']) let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim('%', l:diagnostic['range']['start'])
let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim('%', l:diagnostic['range']['end'])
if l:line == l:start_line if (a:line > l:start_line || (a:line == l:start_line && a:col >= l:start_col)) &&
let l:distance = abs(l:start_col - l:col) \ (a:line < l:end_line || (a:line == l:end_line && a:col < l:end_col))
let l:distance = abs(l:start_col - a:col)
if l:closest_distance < 0 || l:distance < l:closest_distance if l:closest_distance < 0 || l:distance < l:closest_distance
let l:closest_end_col = l:end_col
let l:closest_diagnostic = l:diagnostic let l:closest_diagnostic = l:diagnostic
let l:closest_distance = l:distance let l:closest_distance = l:distance
endif endif
endif endif
endfor endfor
return l:closest_diagnostic return l:closest_diagnostic
endfunction endfunction

View File

@@ -0,0 +1,88 @@
Describe lsp#internal#diagnostics#under_cursor
" refer to lsp#test#projectdir('go') . '/documentdiagnostics.go'
It should not trigger diagnostics when cursor is outside diagnostic range
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 1, 1), {})
End
It should trigger diagnostic when cursor is exactly at start position
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
let l:expected = { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 7, 13), l:expected)
End
It should not trigger diagnostic when cursor is at line before start position
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 6, 13), {})
End
It should not trigger diagnostic when cursor is one character before start position
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 7, 12), {})
End
It should trigger diagnostic when cursor is at start column on an intermediate line within range
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
let l:expected = { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 8, 1), l:expected)
End
It should trigger diagnostic when cursor is at end column on an intermediate line within range
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
let l:expected = { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 8, 15), l:expected)
End
It should trigger diagnostic when cursor is exactly at end position
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
let l:expected = { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 9, 5), l:expected)
End
It should not trigger diagnostic when cursor is at line after end position
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 10, 5), {})
End
It should not return diagnostic when cursor is one character after end position
let l:diagnostics = [
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 9, 6), {})
End
It should return the closest diagnostic when multiple diagnostics exist across different ranges
let l:diagnostics = [
\ { 'range': {'start': {'character': 10, 'line': 4}, 'end': {'character': 7, 'line': 10}} },
\ { 'range': {'start': {'character': 12, 'line': 6}, 'end': {'character': 5, 'line': 8}} }
\ ]
let l:expected = { 'range': {'start': {'character': 10, 'line': 4}, 'end': {'character': 7, 'line': 10}} }
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 7, 3), l:expected)
End
It should return the most specific diagnostic when multiple diagnostics overlap at cursor position
let l:diagnostics = [
\ { 'range': {'start': {'character': 10, 'line': 4}, 'end': {'character': 15, 'line': 4}} },
\ { 'range': {'start': {'character': 12, 'line': 4}, 'end': {'character': 14, 'line': 4}} }
\ ]
let l:expected = { 'range': {'start': {'character': 12, 'line': 4}, 'end': {'character': 14, 'line': 4}} }
Assert Equals(lsp#internal#diagnostics#under_cursor#_get_closest_diagnostic(l:diagnostics, 5, 13), l:expected)
End
End

View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func documentdiagnostics() {
msg := "msg"
fmt.Printf(msg +
msg +
msg,
)
}