-
-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support hierarchical document symbols #316
base: master
Are you sure you want to change the base?
Changes from 4 commits
1613b8a
c10565d
c2145fc
5015f92
d4ddb30
3667942
bd0fe70
a127221
4b291e0
d4a6ba9
6067050
7ac9505
15fe18d
af2ed02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,8 @@ let s:symbol_kind = { | |
\ '26': 'TypeParameter', | ||
\ } | ||
|
||
" The kind field in the result is a number instead of a readable text, we | ||
" should transform the number to the symbol text first. | ||
function! s:Kind2Symbol(kind) abort | ||
return has_key(s:symbol_kind, a:kind) ? s:symbol_kind[a:kind] : 'Unknown kind '.a:kind | ||
endfunction | ||
|
@@ -41,80 +43,103 @@ function! s:IsFileUri(uri) abort | |
return stridx(a:uri, 'file:///') == 0 | ||
endfunction | ||
|
||
" The kind field in the result is a number instead of a readable text, we | ||
" should transform the number to the symbol text first. | ||
function! vista#parser#lsp#KindToSymbol(line, container) abort | ||
let line = a:line | ||
" SymbolInformation interface | ||
if has_key(line, 'location') | ||
let location = line.location | ||
if s:IsFileUri(location.uri) | ||
let lnum = location.range.start.line + 1 | ||
let col = location.range.start.character + 1 | ||
call add(a:container, { | ||
\ 'lnum': lnum, | ||
\ 'col': col, | ||
\ 'kind': s:Kind2Symbol(line.kind), | ||
\ 'text': line.name, | ||
\ }) | ||
endif | ||
" DocumentSymbol class | ||
elseif has_key(line, 'range') | ||
let range = line.range | ||
let lnum = range.start.line + 1 | ||
let col = range.start.character + 1 | ||
call add(a:container, { | ||
\ 'lnum': lnum, | ||
\ 'col': col, | ||
\ 'kind': s:Kind2Symbol(line.kind), | ||
\ 'text': line.name, | ||
\ }) | ||
if has_key(line, 'children') | ||
for child in line.children | ||
call vista#parser#lsp#KindToSymbol(child, a:container) | ||
endfor | ||
function! s:LspToLocalSymbol(sym, range) | ||
return { | ||
\ 'lnum': a:range.start.line + 1, | ||
\ 'col': a:range.start.character + 1, | ||
\ 'kind': s:Kind2Symbol(a:sym.kind), | ||
\ 'text': a:sym.name, | ||
\ } | ||
endfunction | ||
|
||
function! s:LocalToRawSymbol(sym) | ||
return { | ||
\ 'line': a:sym.lnum, | ||
\ 'kind': a:sym.kind, | ||
\ 'name': a:sym.text, | ||
\ } | ||
endfunction | ||
|
||
function! s:IsDocumentSymbol(sym) | ||
return has_key(a:sym, 'selectionRange') | ||
endfunction | ||
|
||
function! s:ParseSymbolInfoList(outlist, symbols) abort | ||
liuchengxu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for lspsym in a:symbols | ||
let l:loc = lspsym.location | ||
if s:IsFileUri(l:loc.uri) | ||
call add(a:outlist, s:LspToLocalSymbol(lspsym, l:loc.range)) | ||
endif | ||
endif | ||
endfor | ||
endfunction | ||
|
||
function! vista#parser#lsp#CocSymbols(symbol, container) abort | ||
if vista#ShouldIgnore(a:symbol.kind) | ||
return | ||
endif | ||
function! s:ParseDocumentSymbolsRec(outlist, symbols, level) abort | ||
for lspsym in a:symbols | ||
greye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let l:sym = s:LspToLocalSymbol(lspsym, lspsym.selectionRange) | ||
let l:sym.level = a:level | ||
call add(a:outlist, l:sym) | ||
if has_key(lspsym, 'children') | ||
call s:ParseDocumentSymbolsRec(a:outlist, lspsym.children, a:level + 1) | ||
endif | ||
endfor | ||
endfunction | ||
|
||
let raw = { 'line': a:symbol.lnum, 'kind': a:symbol.kind, 'name': a:symbol.text } | ||
call add(g:vista.raw, raw) | ||
function! s:GroupSymbolsByKind(symbols) abort | ||
let l:groups = {} | ||
for l:sym in a:symbols | ||
let l:list = get(l:groups, l:sym.kind) | ||
if !has_key(l:groups, l:sym.kind) | ||
let l:list = [] | ||
let l:groups[l:sym.kind] = l:list | ||
endif | ||
call add(l:list, l:sym) | ||
greye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
endfor | ||
return l:groups | ||
endfunction | ||
|
||
if a:symbol.kind ==? 'Method' || a:symbol.kind ==? 'Function' | ||
call add(g:vista.functions, a:symbol) | ||
function! vista#parser#lsp#ParseDocumentSymbolPayload(resp) abort | ||
let l:symbols = [] | ||
if s:IsDocumentSymbol(a:resp[0]) | ||
call s:ParseDocumentSymbolsRec(l:symbols, a:resp, 0) | ||
liuchengxu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
call vista#parser#lsp#FilterDocumentSymbols(l:symbols) | ||
call vista#parser#lsp#DispatchDocumentSymbols(l:symbols) | ||
return l:symbols | ||
else | ||
call s:ParseSymbolInfoList(l:symbols, a:resp) | ||
call vista#parser#lsp#FilterDocumentSymbols(l:symbols) | ||
return s:GroupSymbolsByKind(l:symbols) | ||
endif | ||
endfunction | ||
|
||
call add(a:container, { | ||
\ 'lnum': a:symbol.lnum, | ||
\ 'col': a:symbol.col, | ||
\ 'text': a:symbol.text, | ||
\ 'kind': a:symbol.kind, | ||
\ 'level': a:symbol.level | ||
\ }) | ||
function! vista#parser#lsp#FilterDocumentSymbols(symbols) abort | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function don't have to be public. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DispatchDocumentSymbols and FilterDocumentSymbols were made public to allow to reuse them in actual CoC handler: the latter contains this exact code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, where is the actual coc handler? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, not really: |
||
let l:symlist = a:symbols | ||
if exists('g:vista_ignore_kinds') | ||
call filter(l:symlist, 'index(g:vista_ignore_kinds, v:val) < 0') | ||
endif | ||
let g:vista.functions = [] | ||
for l:sym in l:symlist | ||
if l:sym.kind ==? 'Method' || l:sym.kind ==? 'Function' | ||
call add(g:vista.functions, l:sym) | ||
endif | ||
endfor | ||
greye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return l:symlist | ||
endfunction | ||
|
||
" https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol | ||
function! vista#parser#lsp#ExtractSymbol(symbol, container) abort | ||
let symbol = a:symbol | ||
function! vista#parser#lsp#DispatchDocumentSymbols(symbols) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be used only once, therefore it's not worthy to define another function. |
||
let g:vista.raw = map(copy(a:symbols), { _, sym -> s:LocalToRawSymbol(sym) }) | ||
return g:vista.raw | ||
endfunction | ||
|
||
if vista#ShouldIgnore(symbol.kind) | ||
function! vista#parser#lsp#CocSymbols(symbol, container) abort | ||
if vista#ShouldIgnore(a:symbol.kind) | ||
return | ||
endif | ||
|
||
if symbol.kind ==? 'Method' || symbol.kind ==? 'Function' | ||
call add(g:vista.functions, symbol) | ||
endif | ||
|
||
let picked = {'lnum': symbol.lnum, 'col': symbol.col, 'text': symbol.text} | ||
call add(g:vista.raw, s:LocalToRawSymbol(a:symbol)) | ||
|
||
if has_key(a:container, symbol.kind) | ||
call add(a:container[symbol.kind], picked) | ||
else | ||
let a:container[symbol.kind] = [picked] | ||
if a:symbol.kind ==? 'Method' || a:symbol.kind ==? 'Function' | ||
call add(g:vista.functions, a:symbol) | ||
endif | ||
|
||
call add(a:container, copy(a:symbol)) | ||
greye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
endfunction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change? The author of previous patch about this part uses the
range
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both
range
andselectionRange
are mandatory in documentSymbol response, the latter is used for consistency with CoC behavior.