Skip to content

Commit

Permalink
Add support for range diagnostics under cursor
Browse files Browse the repository at this point in the history
  • Loading branch information
satorunooshie committed Nov 27, 2024
1 parent 04428c9 commit cfb2e19
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 4 deletions.
17 changes: 13 additions & 4 deletions autoload/lsp/internal/diagnostics/under_cursor.vim
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,29 @@ function! lsp#internal#diagnostics#under_cursor#get_diagnostic(...) abort
let l:line = line('.')
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_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:end_line, l:end_col] = lsp#utils#position#lsp_to_vim('%', l:diagnostic['range']['end'])

if l:line == l:start_line
let l:distance = abs(l:start_col - l:col)
if (a:line > l:start_line || (a:line == l:start_line && a:col >= l:start_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
let l:closest_end_col = l:end_col
let l:closest_diagnostic = l:diagnostic
let l:closest_distance = l:distance
endif
endif
endfor

return l:closest_diagnostic
endfunction
88 changes: 88 additions & 0 deletions test/lsp/internal/diagnostics/under_cursor.vimspec
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions test/testproject-go/documentdiagnositcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func documentdiagnostics() {
msg := "msg"
fmt.Printf(msg +
msg +
msg,
)
}

0 comments on commit cfb2e19

Please sign in to comment.