]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Display child symbols in the outline window
authorYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 4 Jan 2021 03:58:17 +0000 (19:58 -0800)
committerYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 4 Jan 2021 03:58:17 +0000 (19:58 -0800)
autoload/handlers.vim
autoload/lsp.vim

index 5bc7f803f975494ec0bf3229c33a68392eee72ee..4c589fca2ff0bf22c98b9df8cb1ba014fcd329ea 100644 (file)
@@ -289,6 +289,68 @@ def LspSymbolKindToName(symkind: number): string
   return symbolMap[symkind]
 enddef
 
+# process SymbolInformation[]
+def s:processSymbolInfoTable(symbolInfoTable: list<dict<any>>,
+                               symbolTypeTable: dict<list<dict<any>>>,
+                               symbolLineTable: list<dict<any>>)
+  var fname: string
+  var symbolType: string
+  var name: string
+  var r: dict<dict<number>>
+  var symInfo: dict<any>
+
+  for symbol in symbolInfoTable
+    fname = LspUriToFile(symbol.location.uri)
+    symbolType = LspSymbolKindToName(symbol.kind)
+    name = symbol.name
+    if symbol->has_key('containerName')
+      if symbol.containerName != ''
+       name ..= ' [' .. symbol.containerName .. ']'
+      endif
+    endif
+    r = symbol.location.range
+
+    if !symbolTypeTable->has_key(symbolType)
+      symbolTypeTable[symbolType] = []
+    endif
+    symInfo = {name: name, range: r}
+    symbolTypeTable[symbolType]->add(symInfo)
+    symbolLineTable->add(symInfo)
+  endfor
+enddef
+
+# process DocumentSymbol[]
+def s:processDocSymbolTable(docSymbolTable: list<dict<any>>,
+                               symbolTypeTable: dict<list<dict<any>>>,
+                               symbolLineTable: list<dict<any>>)
+  var symbolType: string
+  var name: string
+  var r: dict<dict<number>>
+  var symInfo: dict<any>
+  var symbolDetail: string
+  var childSymbols: dict<list<dict<any>>>
+
+  for symbol in docSymbolTable
+    name = symbol.name
+    symbolType = LspSymbolKindToName(symbol.kind)
+    r = symbol.range
+    if symbol->has_key('detail')
+      symbolDetail = symbol.detail
+    endif
+    if !symbolTypeTable->has_key(symbolType)
+      symbolTypeTable[symbolType] = []
+    endif
+    childSymbols = {}
+    if symbol->has_key('children')
+      s:processDocSymbolTable(symbol.children, childSymbols, symbolLineTable)
+    endif
+    symInfo = {name: name, range: r, detail: symbolDetail,
+                                               children: childSymbols}
+    symbolTypeTable[symbolType]->add(symInfo)
+    symbolLineTable->add(symInfo)
+  endfor
+enddef
+
 # process the 'textDocument/documentSymbol' reply from the LSP server
 # Open a symbols window and display the symbols as a tree
 def s:processDocSymbolReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
@@ -300,45 +362,19 @@ def s:processDocSymbolReply(lspserver: dict<any>, req: dict<any>, reply: dict<an
   var fname: string
   var symbolTypeTable: dict<list<dict<any>>>
   var symbolLineTable: list<dict<any>> = []
-  var name: string
-  var symbolType: string
-  var r: dict<dict<number>>
-  var symbolDetail: string
-  var symInfo: dict<any>
 
   if req.params.textDocument.uri != ''
     fname = LspUriToFile(req.params.textDocument.uri)
   endif
 
-  for symbol in reply.result
-    symbolDetail = ''
-    if symbol->has_key('location')
-      # interface SymbolInformation
-      fname = LspUriToFile(symbol.location.uri)
-      symbolType = LspSymbolKindToName(symbol.kind)
-      name = symbol.name
-      if symbol->has_key('containerName')
-       if symbol.containerName != ''
-         name ..= ' [' .. symbol.containerName .. ']'
-       endif
-      endif
-      r = symbol.location.range
-    else
-      # interface DocumentSymbol
-      name = symbol.name
-      symbolType = LspSymbolKindToName(symbol.kind)
-      r = symbol.range
-      if symbol->has_key('detail')
-       symbolDetail = symbol.detail
-      endif
-    endif
-    if !symbolTypeTable->has_key(symbolType)
-      symbolTypeTable[symbolType] = []
-    endif
-    symInfo = {name: name, range: r, detail: symbolDetail}
-    symbolTypeTable[symbolType]->add(symInfo)
-    symbolLineTable->add(symInfo)
-  endfor
+  if reply.result[0]->has_key('location')
+    # SymbolInformation[]
+    s:processSymbolInfoTable(reply.result, symbolTypeTable, symbolLineTable)
+  else
+    # DocumentSymbol[]
+    s:processDocSymbolTable(reply.result, symbolTypeTable, symbolLineTable)
+  endif
+
   # sort the symbols by line number
   symbolLineTable->sort({a, b -> a.range.start.line - b.range.start.line})
   lsp#updateOutlineWindow(fname, symbolTypeTable, symbolLineTable)
index 83d11726fdebf66ed93ec55955d737fbf9a94a92..2e799c8e3b356312a27a196e810219aa701d4f80 100644 (file)
@@ -521,7 +521,8 @@ def s:outlineJumpToSymbol()
 
   # Highlight the selected symbol
   prop_remove({type: 'LspOutlineHighlight'})
-  prop_add(line('.'), 3, {type: 'LspOutlineHighlight',
+  var col: number = match(getline('.'), '\S') + 1
+  prop_add(line('.'), col, {type: 'LspOutlineHighlight',
                        length: w:lspSymbols.lnumTable[lnum].name->len()})
 
   # disable the outline window refresh
@@ -556,6 +557,39 @@ enddef
 
 var skipOutlineRefresh: bool = false
 
+def s:addSymbolText(symbolTypeTable: dict<list<dict<any>>>,
+                               pfx: string,
+                               text: list<string>,
+                               lnumMap: list<dict<any>>,
+                               children: bool)
+  var prefix: string = pfx .. '  '
+  for [symType, symbols] in items(symbolTypeTable)
+    if !children
+      # Add an empty line for the top level symbol types. For types in the
+      # children symbols, don't add the empty line.
+      text->extend([''])
+      lnumMap->extend([{}])
+    endif
+    if children
+      text->extend([prefix .. symType])
+      prefix ..= '  '
+    else
+      text->extend([symType])
+    endif
+    lnumMap->extend([{}])
+    for s in symbols
+      text->add(prefix .. s.name)
+      # remember the line number for the symbol
+      lnumMap->add({name: s.name, lnum: s.range.start.line + 1,
+      col: s.range.start.character + 1})
+      s.outlineLine = lnumMap->len()
+      if !s.children->empty()
+       s:addSymbolText(s.children, prefix, text, lnumMap, true)
+      endif
+    endfor
+  endfor
+enddef
+
 # update the symbols displayed in the outline window
 def lsp#updateOutlineWindow(fname: string,
                                symbolTypeTable: dict<list<dict<any>>>,
@@ -586,17 +620,7 @@ def lsp#updateOutlineWindow(fname: string,
   # First two lines in the buffer display comment information
   var lnumMap: list<dict<any>> = [{}, {}]
   var text: list<string> = []
-  for [symType, syms] in items(symbolTypeTable)
-    text->extend(['', symType])
-    lnumMap->extend([{}, {}])
-    for s in syms
-      text->add('  ' .. s.name)
-      # remember the line number for the symbol
-      lnumMap->add({name: s.name, lnum: s.range.start.line + 1,
-                                       col: s.range.start.character + 1})
-      s.outlineLine = lnumMap->len()
-    endfor
-  endfor
+  s:addSymbolText(symbolTypeTable, '', text, lnumMap, false)
   append('$', text)
   w:lspSymbols = {filename: fname, lnumTable: lnumMap,
                                symbolsByLine: symbolLineTable}
@@ -605,6 +629,7 @@ def lsp#updateOutlineWindow(fname: string,
   if !saveCursor->empty()
     setpos('.', saveCursor)
   endif
+
   win_gotoid(prevWinID)
 
   # Highlight the current symbol
@@ -664,7 +689,9 @@ def s:outlineHighlightCurrentSymbol()
   endif
 
   # Highlight the selected symbol
-  prop_add(symbolTable[mid].outlineLine, 3,
+  var col: number =
+       match(getbufline(bnr, symbolTable[mid].outlineLine)[0], '\S') + 1
+  prop_add(symbolTable[mid].outlineLine, col,
                        {bufnr: bnr, type: 'LspOutlineHighlight',
                        length: symbolTable[mid].name->len()})
 
@@ -702,6 +729,11 @@ def s:openOutlineWindow()
   :setlocal bufhidden=delete
   :setlocal noswapfile nobuflisted
   :setlocal nonumber norelativenumber fdc=0 nowrap winfixheight winfixwidth
+  :setlocal shiftwidth=2
+  :setlocal foldenable
+  :setlocal foldcolumn=4
+  :setlocal foldlevel=4
+  :setlocal foldmethod=indent
   setline(1, ['# File Outline'])
   :nnoremap <silent> <buffer> q :quit<CR>
   :nnoremap <silent> <buffer> <CR> :call <SID>outlineJumpToSymbol()<CR>