]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Use a popup window instead of the preview window to display the symbol references
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 20 Nov 2022 21:36:53 +0000 (13:36 -0800)
committerYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 20 Nov 2022 21:36:53 +0000 (13:36 -0800)
autoload/lsp/lspserver.vim
autoload/lsp/symbol.vim
autoload/lsp/typehierarchy.vim
doc/lsp.txt
test/unit_tests.vim

index 67ceb599eb9ee2160b66534899cbc0da7d40e206..1319a9555b3c66027c12cfdcc38289434871bd23 100644 (file)
@@ -1543,6 +1543,7 @@ export def NewLspServer(path: string, args: list<string>, isSync: bool, initiali
     workspaceSymbolPopup: -1,
     workspaceSymbolQuery: '',
     peekSymbolPopup: -1,
+    peekSymbolFilePopup: -1,
     callHierarchyType: '',
     selection: {}
   }
index 41d0b4dc0136ab9bd7f613fbcb5d064b8ff08cc7..5562d8a518e309c2c70de54244260049ed749f54 100644 (file)
@@ -128,7 +128,7 @@ def ShowSymbolMenu(lspserver: dict<any>, query: string)
   var lnum = &lines - &cmdheight - 2 - 10
   var popupAttr = {
       title: 'Workspace Symbol Search',
-      wrap: 0,
+      wrap: false,
       pos: 'topleft',
       line: lnum,
       col: 2,
@@ -227,8 +227,132 @@ export def SymbolKindToName(symkind: number): string
   return symbolMap[symkind]
 enddef
 
+def UpdatePeekFilePopup(lspserver: dict<any>, refs: list<dict<any>>)
+  if lspserver.peekSymbolPopup->winbufnr() == -1
+    return
+  endif
+
+  lspserver.peekSymbolFilePopup->popup_close()
+
+  var n = line('.', lspserver.peekSymbolPopup) - 1
+  var fname: string = util.LspUriToFile(refs[n].uri)
+
+  var bnr: number = fname->bufnr()
+  if bnr == -1
+    bnr = fname->bufadd()
+  endif
+
+  var popupAttrs = {
+    title: $"{fname->fnamemodify(':t')} ({fname->fnamemodify(':h')})",
+    wrap: false,
+    fixed: true,
+    minheight: 10,
+    maxheight: 10,
+    minwidth: winwidth(0) - 38,
+    maxwidth: winwidth(0) - 38,
+    cursorline: true,
+    border: [],
+    line: 'cursor+1',
+    col: 1
+  }
+
+  lspserver.peekSymbolFilePopup = popup_create(bnr, popupAttrs)
+  var cmds =<< trim eval END
+    [{refs[n].range.start.line + 1}, 1]->cursor()
+    normal! z.
+  END
+  win_execute(lspserver.peekSymbolFilePopup, cmds)
+
+  lspserver.peekSymbolFilePopup->clearmatches()
+  var start_col = util.GetLineByteFromPos(bnr,
+                                       refs[n].range.start) + 1
+  var end_col = util.GetLineByteFromPos(bnr, refs[n].range.end)
+  var pos = [[refs[n].range.start.line + 1,
+            start_col, end_col - start_col + 1]]
+  matchaddpos('Search', pos, 10, -1, {window: lspserver.peekSymbolFilePopup})
+enddef
+
+def RefPopupFilter(lspserver: dict<any>, refs: list<dict<any>>,
+                       popup_id: number, key: string): bool
+  popup_filter_menu(popup_id, key)
+  if lspserver.peekSymbolPopup->winbufnr() == -1
+    if lspserver.peekSymbolFilePopup->winbufnr() != -1
+      lspserver.peekSymbolFilePopup->popup_close()
+    endif
+    lspserver.peekSymbolPopup = -1
+    lspserver.peekSymbolFilePopup = -1
+  else
+    UpdatePeekFilePopup(lspserver, refs)
+  endif
+  return true
+enddef
+
+def RefPopupCallback(lspserver: dict<any>, refs: list<dict<any>>,
+                    popup_id: number, selIdx: number)
+  if lspserver.peekSymbolFilePopup->winbufnr() != -1
+    lspserver.peekSymbolFilePopup->popup_close()
+  endif
+  lspserver.peekSymbolPopup = -1
+  if selIdx != -1
+    var fname: string = util.LspUriToFile(refs[selIdx - 1].uri)
+    util.PushCursorToTagStack()
+    util.JumpToLspLocation(refs[selIdx - 1], '')
+  endif
+enddef
+
+# Display the references in a popup menu.  Display the corresponding file in
+# an another popup window.
+def PeekReferences(lspserver: dict<any>, refs: list<dict<any>>)
+  if lspserver.peekSymbolPopup->winbufnr() != -1
+    # If the symbol popup window is already present, close it.
+    lspserver.peekSymbolPopup->popup_close()
+  endif
+
+  var w: number = &columns
+  var fnamelen = float2nr(w * 0.4)
+
+  var menuItems: list<string> = []
+  for loc in refs
+    var fname: string = util.LspUriToFile(loc.uri)
+    var bnr: number = fname->bufnr()
+    if bnr == -1
+      bnr = fname->bufadd()
+    endif
+    if !bnr->bufloaded()
+      bnr->bufload()
+    endif
+
+    var text: string = bnr->getbufline(loc.range.start.line + 1)[0]
+    var lnum = loc.range.start.line + 1
+    menuItems->add($'{lnum}: {text}')
+  endfor
+
+  var popupAttrs = {
+    title: 'References',
+    wrap: false,
+    pos: 'topleft',
+    line: 'cursor+1',
+    col: winwidth(0) - 34,
+    minheight: 10,
+    maxheight: 10,
+    minwidth: 30,
+    maxwidth: 30,
+    mapping: false,
+    fixed: true,
+    filter: function(RefPopupFilter, [lspserver, refs]),
+    callback: function(RefPopupCallback, [lspserver, refs])
+  }
+  lspserver.peekSymbolPopup = popup_menu(menuItems, popupAttrs)
+  UpdatePeekFilePopup(lspserver, refs)
+enddef
+
 # Display or peek symbol references in a location list
 export def ShowReferences(lspserver: dict<any>, refs: list<dict<any>>, peekSymbol: bool)
+  if peekSymbol
+    PeekReferences(lspserver, refs)
+    return
+  endif
+
   # create a location list with the location of the references
   var qflist: list<dict<any>> = []
   for loc in refs
@@ -249,24 +373,26 @@ export def ShowReferences(lspserver: dict<any>, refs: list<dict<any>>, peekSymbo
   endfor
 
   var save_winid = win_getid()
-  if peekSymbol
-    silent! pedit
-    wincmd P
-  endif
   setloclist(0, [], ' ', {title: 'Symbol Reference', items: qflist})
   var mods: string = ''
-  if peekSymbol
-    # When peeking the references, open the location list in a vertically
-    # split window to the right and make the location list window 30% of the
-    # source window width
-    mods = $'belowright vert :{(winwidth(0) * 30) / 100}'
-  endif
   exe $'{mods} lopen'
   if !opt.lspOptions.keepFocusInReferences
     save_winid->win_gotoid()
   endif
 enddef
 
+# Key filter callback function used for the symbol popup window.
+# Vim doesn't close the popup window when the escape key is pressed.
+# This is function supports that.
+def SymbolFilterCB(lspserver: dict<any>, id: number, key: string): bool
+  if key == "\<Esc>"
+    lspserver.peekSymbolPopup->popup_close()
+    return true
+  endif
+
+  return false
+enddef
+
 # Display the file specified by LSP 'location' in a popup window and highlight
 # the range in 'location'.
 def PeekSymbolLocation(lspserver: dict<any>, location: dict<any>)
@@ -283,14 +409,17 @@ def PeekSymbolLocation(lspserver: dict<any>, location: dict<any>)
     lspserver.peekSymbolPopup->popup_close()
   endif
   var ptitle = $"{fnamemodify(fname, ':t')} ({fnamemodify(fname, ':h')})"
-  lspserver.peekSymbolPopup = popup_atcursor(bnum, {moved: 'any',
+  var CbFunc = function(SymbolFilterCB, [lspserver])
+  lspserver.peekSymbolPopup = popup_atcursor(bnum, {
+                                       moved: 'any',
                                        title: ptitle,
                                        minwidth: 10,
                                        maxwidth: 60,
                                        minheight: 10,
                                        maxheight: 10,
                                        mapping: false,
-                                       wrap: false})
+                                       wrap: false,
+                                       filter: CbFunc})
 
   # Highlight the symbol name and center the line in the popup
   var pwid = lspserver.peekSymbolPopup
index faedaae5832f32e97482d0864cb2851daa60e688..510a4463cf984b46a1ecd3dc1fbd19c04b208bfd 100644 (file)
@@ -71,7 +71,7 @@ def UpdateTypeHierFileInPopup(lspserver: dict<any>, typeUriMap: list<dict<any>>)
     return
   endif
 
-  var popupAttr = {
+  var popupAttrs = {
     title: $"{fname->fnamemodify(':t')} ({fname->fnamemodify(':h')})",
     wrap: false,
     fixed: true,
@@ -84,12 +84,13 @@ def UpdateTypeHierFileInPopup(lspserver: dict<any>, typeUriMap: list<dict<any>>)
     line: 'cursor+1',
     col: 1
   }
-  lspserver.typeHierFilePopup = popup_create(bnr, popupAttr)
+  lspserver.typeHierFilePopup = popup_create(bnr, popupAttrs)
   var cmds =<< trim eval END
     [{typeUriMap[n].range.start.line + 1}, 1]->cursor()
     normal! z.
   END
   win_execute(lspserver.typeHierFilePopup, cmds)
+
   lspserver.typeHierFilePopup->clearmatches()
   var start_col = util.GetLineByteFromPos(bnr,
                                        typeUriMap[n].selectionRange.start) + 1
@@ -150,7 +151,7 @@ export def ShowTypeHierarchy(lspserver: dict<any>, super: bool, types: dict<any>
 
   # Display a popup window with the type hierarchy tree and a popup window for
   # the file.
-  var popupAttr = {
+  var popupAttrs = {
       title: $'{super ? "Super" : "Sub"}Type Hierarchy',
       wrap: 0,
       pos: 'topleft',
@@ -161,11 +162,11 @@ export def ShowTypeHierarchy(lspserver: dict<any>, super: bool, types: dict<any>
       minwidth: 30,
       maxwidth: 30,
       mapping: false,
-      fixed: 1,
+      fixed: true,
       filter: function(TypeHierPopupFilter, [lspserver, typeUriMap]),
       callback: function(TypeHierPopupCallback, [lspserver, typeUriMap])
     }
-  lspserver.typeHierPopup = popup_menu(typeTree, popupAttr)
+  lspserver.typeHierPopup = popup_menu(typeTree, popupAttrs)
   UpdateTypeHierFileInPopup(lspserver, typeUriMap)
 enddef
 
index 635f485ad56f0665604d69e3076b3db49d062d04..36abd1ef06f2ff09949fb3d7418e6993e1bf08e6 100644 (file)
@@ -105,9 +105,8 @@ The following commands are provided:
                        popup window.
 :LspPeekImpl           Open the implementation of the symbol under cursor in
                        a popup window.
-:LspPeekReferences     Display the list of references to the keyword under
-                       cursor in a location list associated with the preview
-                       window.
+:LspPeekReferences     Display the list of references to the symbol under
+                       cursor in a popup window.
 :LspPeekTypeDef                Open the type definition of the symbol under cursor in
                        a popup window.
 :LspRename             Rename the current symbol
@@ -446,9 +445,11 @@ To get a particular option value you can use the following: >
                        opens the location window.
 
                                                *:LspPeekReferences*
-:LspPeekReferences     Opens the preview window and creates a new location
-                       list with the list of locations where the symbol under
-                       the cursor is referenced and opens the location window.
+:LspPeekReferences     Displays the list of references to the symbol under
+                       cursor in a popup menu.  The corresponding file for
+                       the reference is displayed in another popup window.
+                       As the selection in the reference popup menu changes,
+                       the file in the popup is updated.
 
                                                *:LspHighlight*
 :LspHighlight          Highlights all the matches for the symbol under
index 069f6d04ef1d92455df98cca5d8816252cc99660..9903b17a79112a662bc0e27266dd315b1c6be21a 100644 (file)
@@ -229,9 +229,14 @@ def Test_LspShowReferences()
   setlocal nomodified
   cursor(1, 5)
   :LspPeekReferences
-  assert_equal([3, 3], [winnr('$'), winnr()])
-  assert_equal('preview', win_gettype(1))
-  assert_equal('loclist', win_gettype(2))
+  var ids = popup_list()
+  assert_equal(2, ids->len())
+  var filePopupAttrs = ids[0]->popup_getoptions()
+  var refPopupAttrs = ids[1]->popup_getoptions()
+  assert_match('Xtest', filePopupAttrs.title)
+  assert_equal('References', refPopupAttrs.title)
+  assert_equal(1, line('.', ids[0]))
+  popup_clear()
 
   bw!