@@ -277,8 +277,8 @@ function! s:newlsp() abort
277
277
if l: level < l: diag .severity
278
278
continue
279
279
endif
280
- let [l: error , l: matchpos ] = s: errorFromDiagnostic (l: diag , l: bufname , l: fname )
281
- let l: diagnostics = add (l: diagnostics , l: error )
280
+ let [l: diagnostic , l: matchpos ] = s: processDiagnostic (l: diag , l: bufname , l: fname )
281
+ let l: diagnostics = add (l: diagnostics , l: diagnostic )
282
282
283
283
if empty (l: matchpos )
284
284
continue
@@ -973,35 +973,68 @@ function! go#lsp#Hover(fname, line, col, handler) abort
973
973
let l: lsp = s: lspfactory .get ()
974
974
let l: msg = go#lsp#message#Hover (a: fname , a: line , a: col )
975
975
let l: state = s: newHandlerState (' ' )
976
- let l: state .handleResult = funcref (' s:hoverHandler' , [function (a: handler , [], l: state )], l: state )
977
- let l: state .error = funcref (' s:noop' )
976
+ let l: diagnosticMsg = ' '
977
+
978
+ if has_key (l: lsp .diagnostics, a: fname )
979
+ for l: diagnostic in l: lsp .diagnostics[a: fname ]
980
+ if ! s: within (l: diagnostic .range , a: line , a: col )
981
+ continue
982
+ endif
983
+
984
+ let l: diagnosticMsg = l: diagnostic .message
985
+ break
986
+ endfor
987
+ endif
988
+ let l: state .handleResult = funcref (' s:hoverHandler' , [function (a: handler , [], l: state ), l: diagnosticMsg ], l: state )
989
+ let l: state .error = funcref (' s:hoverError' , [function (a: handler , [], l: state ), l: diagnosticMsg ], l: state )
978
990
return l: lsp .sendMessage (l: msg , l: state )
979
991
endfunction
980
992
981
- function ! s: hoverHandler (next , msg) abort dict
993
+ function ! s: hoverHandler (next , diagnostic, msg) abort dict
982
994
if a: msg is v: null || ! has_key (a: msg , ' contents' )
995
+ if len (a: diagnostic ) > 0
996
+ call call (a: next , [a: diagnostic ])
997
+ endif
983
998
return
984
999
endif
985
1000
986
1001
try
987
1002
let l: value = json_decode (a: msg .contents.value)
988
1003
1004
+ let l: msg = []
1005
+ if len (a: diagnostic ) > 0
1006
+ let l: msg = split (a: diagnostic , " \n " )
1007
+ let l: msg = add (l: msg , ' ' )
1008
+ endif
989
1009
let l: signature = split (l: value .signature, " \n " )
990
- let l: msg = l: signature
1010
+ let l: msg = extend ( l: msg , l: signature)
991
1011
if go#config#DocBalloon ()
992
1012
" use synopsis instead of fullDocumentation to keep the hover window
993
1013
" small.
994
1014
let l: doc = l: value .synopsis
995
1015
if len (l: doc ) isnot 0
996
- let l: msg = l: signature + [' ' , l: doc ]
1016
+ let l: msg = extend ( l: msg , [' ' , l: doc ])
997
1017
endif
998
1018
endif
1019
+
999
1020
call call (a: next , [l: msg ])
1000
1021
catch
1001
1022
" TODO(bc): log the message and/or show an error message.
1002
1023
endtry
1003
1024
endfunction
1004
1025
1026
+ function ! s: hoverError (next , diagnostic, msg) abort dict
1027
+ try
1028
+ if len (a: diagnostic ) > 0
1029
+ let l: msg = split (a: diagnostic , " \n " )
1030
+ call call (a: next , [l: msg ])
1031
+ endif
1032
+ catch
1033
+ endtry
1034
+
1035
+ return
1036
+ endfunction
1037
+
1005
1038
function ! go#lsp#Doc () abort
1006
1039
let l: fname = expand (' %:p' )
1007
1040
let [l: line , l: col ] = go#lsp#lsp#Position ()
@@ -1379,7 +1412,7 @@ function! go#lsp#Diagnostics(...) abort
1379
1412
1380
1413
for l: arg in a: 000
1381
1414
if l: arg == l: pkg || l: arg == ' all'
1382
- let l: diagnostics = extend (l: diagnostics , l: val )
1415
+ let l: diagnostics = extend (l: diagnostics , map ( l: val, ' v:val["error"] ' ) )
1383
1416
endif
1384
1417
endfor
1385
1418
endfor
@@ -1399,7 +1432,7 @@ function! go#lsp#AnalyzeFile(fname) abort
1399
1432
1400
1433
let l: version = get (l: lsp .fileVersions, a: fname , 0 )
1401
1434
if l: version == getbufvar (a: fname , ' changedtick' )
1402
- return l: lastdiagnostics
1435
+ return map ( l: lastdiagnostics, ' v:val["error"] ' )
1403
1436
endif
1404
1437
1405
1438
call go#lsp#DidChange (a: fname )
@@ -1410,47 +1443,75 @@ function! go#lsp#AnalyzeFile(fname) abort
1410
1443
endfunction
1411
1444
1412
1445
function ! s: setDiagnostics (... ) abort
1413
- return a: 000
1446
+ return map ( a: 000, ' v:val["error"] ' )
1414
1447
endfunction
1415
1448
1416
- " s:processDiagnostic converts a diagnostic into an error string. It returns
1417
- " the errors string and the match position described in the diagnostic. The
1418
- " match position will be an empty list when bufname is not a valid name for
1419
- " the current buffer.
1420
- function ! s: errorFromDiagnostic (diagnostic, bufname , fname) abort
1449
+ " s:processDiagnostic converts a diagnostic from LSP into useful values for
1450
+ " Vim. It returns the a value with the original message, the diagnostic range
1451
+ " as expressed by LSP, an error string, and the Vim match position described
1452
+ " in the diagnostic. The match position will be an empty list when bufname is
1453
+ " not a valid name for the current buffer.
1454
+ function ! s: processDiagnostic (diagnostic, bufname , fname) abort
1421
1455
let l: range = a: diagnostic .range
1422
1456
1457
+ let l: diagnostic = {
1458
+ \ " message" : a: diagnostic .message,
1459
+ \ " range" : {
1460
+ \ " start" : {
1461
+ \ " line" : l: range .start .line ,
1462
+ \ " character" : l: range .start .character ,
1463
+ \ },
1464
+ \ " end" : {
1465
+ \ " line" : l: range .end .line ,
1466
+ \ " character" : l: range .end .character ,
1467
+ \ },
1468
+ \ },
1469
+ \ }
1470
+
1423
1471
let l: line = l: range .start .line + 1
1472
+ let l: endline = l: range .end .line + 1
1473
+
1424
1474
let l: buflines = getbufline (a: bufname , l: line )
1425
1475
let l: col = ' '
1426
1476
if len (l: buflines ) > 0
1427
1477
let l: col = go#lsp#lsp#PositionOf (l: buflines [0 ], l: range .start .character )
1428
1478
endif
1429
- let l: error = printf (' %s:%s:%s:%s: %s' , a: fname , l: line , l: col , go#lsp#lsp#SeverityToErrorType (a: diagnostic .severity), a: diagnostic .message)
1479
+
1480
+ let l: severity = go#lsp#lsp#SeverityToErrorType (a: diagnostic .severity)
1481
+ let l: diagnostic .error = printf (' %s:%s:%s:%s: %s' , a: fname , l: line , l: col , l: severity , l: diagnostic .message)
1430
1482
1431
1483
if ! (a: diagnostic .severity == 1 || a: diagnostic .severity == 2 )
1432
- return [l: error , []]
1484
+ return [l: diagnostic , []]
1433
1485
endif
1434
1486
1435
1487
" return when the diagnostic is not for the current buffer.
1436
1488
if bufnr (a: bufname ) != bufnr (' ' )
1437
- return [l: error , []]
1489
+ return [l: diagnostic , []]
1438
1490
end
1439
1491
1440
- let l: endline = l: range .end .line + 1
1441
1492
" don't bother trying to highlight errors or warnings that span
1442
1493
" the whole file (e.g when there's missing package documentation).
1443
1494
if l: line == 1 && (l: endline ) == line (' $' )
1444
- return [l: error , []]
1495
+ return [l: diagnostic , []]
1496
+ endif
1497
+
1498
+ if len (l: buflines ) == 0
1499
+ return [l: diagnostic , []]
1500
+ endif
1501
+
1502
+ let l: buflines = getbufline (a: bufname , l: endline )
1503
+ if len (l: buflines ) > 0
1504
+ let l: endcol = go#lsp#lsp#PositionOf (l: buflines [0 ], l: range .end .character )
1505
+ else
1506
+ return [l: diagnostic , []]
1445
1507
endif
1446
- let l: endcol = go#lsp#lsp#PositionOf (getline (l: endline ), l: range .end .character )
1447
1508
1448
1509
" the length of the match is the number of bytes between the start of
1449
1510
" the match and the end of the match.
1450
1511
let l: matchLength = line2byte (l: endline ) + l: endcol - (line2byte (l: line ) + l: col )
1451
1512
let l: pos = [l: line , l: col , l: matchLength ]
1452
1513
1453
- return [l: error , l: pos ]
1514
+ return [l: diagnostic , l: pos ]
1454
1515
endfunction
1455
1516
1456
1517
function ! s: highlightMatches (errorMatches, warningMatches) abort
@@ -1947,6 +2008,26 @@ function! s:lineinfile(fname, line) abort
1947
2008
endtry
1948
2009
endfunction
1949
2010
2011
+ function ! s: within (range , line , character ) abort
2012
+ if a: line < a: range .start .line
2013
+ return 0
2014
+ endif
2015
+
2016
+ if a: line > a: range .end .line
2017
+ return 0
2018
+ endif
2019
+
2020
+ if a: line == a: range .start .line && a: character < a: range .start .character
2021
+ return 0
2022
+ endif
2023
+
2024
+ if a: line == a: range .end .line && a: character > a: range .end .character
2025
+ return 0
2026
+ endif
2027
+
2028
+ return 1
2029
+ endfunction
2030
+
1950
2031
" restore Vi compatibility settings
1951
2032
let &cpo = s: cpo_save
1952
2033
unlet s: cpo_save
0 commit comments