Skip to content

Commit

Permalink
improve hierarchy
Browse files Browse the repository at this point in the history
add commands:
1. reopen hierarchy window.
2. Add a caller to current node manually.
3. PageUp and PageDown.
4. Close callers.
5. Remove callers.
  • Loading branch information
wenbodong2015 committed Jul 6, 2024
1 parent b5fe27b commit 601026e
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 21 deletions.
4 changes: 4 additions & 0 deletions autoload/youcompleteme.vim
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,10 @@ silent! nnoremap <silent> <plug>(YCMTypeHierarchy)
\ <cmd>call youcompleteme#hierarchy#StartRequest( 'type' )<cr>
silent! nnoremap <silent> <plug>(YCMCallHierarchy)
\ <cmd>call youcompleteme#hierarchy#StartRequest( 'call' )<cr>
silent! nnoremap <silent> <plug>(YCMResumeHierarchy)
\ <cmd>call youcompleteme#hierarchy#StartRequest( 'resume' )<cr>
silent! nnoremap <silent> <plug>(YCMAddCallHierarchy)
\ <cmd>call youcompleteme#hierarchy#StartRequest( 'addcall' )<cr>
" This is basic vim plugin boilerplate
let &cpo = s:save_cpo
Expand Down
85 changes: 72 additions & 13 deletions autoload/youcompleteme/hierarchy.vim
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,33 @@ function! youcompleteme#hierarchy#StartRequest( kind )
endif

call youcompleteme#symbol#InitSymbolProperties()
py3 ycm_state.ResetCurrentHierarchy()
py3 from ycm.client.command_request import GetRawCommandResponse

if a:kind == 'resume'
call s:SetUpMenu()
return
endif

if a:kind == 'addcall'
let handle = s:lines_and_handles[ s:select - 1 ][ 1 ]
let lines_and_handles = py3eval(
\ 'ycm_state.AddCurrentHierarchy( ' .
\ 'vimsupport.GetIntValue( "handle" ), ' .
\ 'GetRawCommandResponse( ' .
\ '[ "CallHierarchy" ], False ))' )
let s:lines_and_handles = lines_and_handles
call s:SetUpMenu()
return
endif

py3 ycm_state.ResetCurrentHierarchy()
if a:kind == 'call'
let lines_and_handles = py3eval(
\ 'ycm_state.InitializeCurrentHierarchy( GetRawCommandResponse( ' .
\ '[ "CallHierarchy" ], False ), ' .
\ 'vim.eval( "a:kind" ) )' )
else
let lines_and_handles = py3eval(
let lines_and_handles = py3eval(
\ 'ycm_state.InitializeCurrentHierarchy( GetRawCommandResponse( ' .
\ '[ "TypeHierarchy" ], False ), ' .
\ 'vim.eval( "a:kind" ) )' )
Expand All @@ -62,7 +80,22 @@ function! youcompleteme#hierarchy#StartRequest( kind )
endif
endfunction

function! s:RedrawMenu()
let pos = popup_getpos( s:popup_id )
call win_execute( s:popup_id,
\ 'call cursor( [' . string( s:select ) . ', 1 ] )' )
call win_execute( s:popup_id,
\ 'set cursorline cursorlineopt&' )
if s:select < pos.firstline
call win_execute( s:popup_id, "normal z\<CR>" )
endif
if s:select >= (pos.firstline + pos.core_height )
call win_execute( s:popup_id, ':normal z-' )
endif
endfunction

function! s:MenuFilter( winid, key )
let pos = popup_getpos( s:popup_id )
if a:key == "\<S-Tab>"
" Root changes if we're showing super-tree of a sub-tree of the root
" (indicated by the handle being positive)
Expand All @@ -81,6 +114,20 @@ function! s:MenuFilter( winid, key )
\ [ s:select - 1, 'resolve_down', will_change_root ] )
return 1
endif
if a:key == "c"
let will_change_root = 0
call popup_close(
\ s:popup_id,
\ [ s:select - 1, 'resolve_close', will_change_root ] )
return 1
endif
if a:key == "d"
let will_change_root = 0
call popup_close(
\ s:popup_id,
\ [ s:select - 1, 'resolve_remove', will_change_root ] )
return 1
endif
if a:key == "\<CR>"
call popup_close( s:popup_id, [ s:select - 1, 'jump', v:none ] )
return 1
Expand All @@ -90,21 +137,31 @@ function! s:MenuFilter( winid, key )
if s:select < 1
let s:select = 1
endif
call win_execute( s:popup_id,
\ 'call cursor( [' . string( s:select ) . ', 1 ] )' )
call win_execute( s:popup_id,
\ 'set cursorline cursorlineopt&' )
call s:RedrawMenu()
return 1
endif
if a:key == "\<PageUp>" || a:key == "\<kPageUp>"
let s:select -= pos.core_height
if s:select < 1
let s:select = 1
endif
call s:RedrawMenu()
return 1
endif
if a:key == "\<Down>" || a:key == "\<C-n>" || a:key == "\<C-j>" || a:key == "j"
let s:select += 1
if s:select > len( s:lines_and_handles )
let s:select = len( s:lines_and_handles )
endif
call win_execute( s:popup_id,
\ 'call cursor( [' . string( s:select ) . ', 1 ] )' )
call win_execute( s:popup_id,
\ 'set cursorline cursorlineopt&' )
call s:RedrawMenu()
return 1
endif
if a:key == "\<PageDown>" || a:key == "\<kPageDown>"
let s:select += pos.core_height
if s:select > len( s:lines_and_handles )
let s:select = len( s:lines_and_handles )
endif
call s:RedrawMenu()
return 1
endif
if index( s:ingored_keys, a:key ) >= 0
Expand All @@ -125,14 +182,15 @@ function! s:MenuCallback( winid, result )
call s:ResolveItem( selection, 'down', a:result[ 2 ] )
elseif operation == 'resolve_up'
call s:ResolveItem( selection, 'up', a:result[ 2 ] )
elseif operation == 'resolve_close'
call s:ResolveItem( selection, 'close', a:result[ 2 ] )
elseif operation == 'resolve_remove'
call s:ResolveItem( selection, 'remove', a:result[ 2 ] )
else
if operation == 'jump'
let handle = s:lines_and_handles[ selection ][ 1 ]
py3 ycm_state.JumpToHierarchyItem( vimsupport.GetIntValue( "handle" ) )
endif
py3 ycm_state.ResetCurrentHierarchy()
let s:kind = ''
let s:select = 1
endif
endfunction

Expand Down Expand Up @@ -208,6 +266,7 @@ function! s:SetUpMenu()
\ . "\t"
\ .. trunc_desc
call add( menu_lines, { 'text': line, 'props': props } )

endfor
call win_execute( s:popup_id,
\ 'setlocal tabstop=' . tabstop )
Expand Down
22 changes: 22 additions & 0 deletions doc/youcompleteme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2162,13 +2162,20 @@ are supported:
- Call hierarchy '<Plug>(YCMCallHierarchy)': Display callees and callers of
the symbol under cursor. Expand down to callers and up to callees.

- Resume hierarchy '<Plug>(YCMResumeHierarchy)': Reopen the Hierarchy window.

- Add hierarchy '<Plug>(YCMAddCallHierarchy)': Add a caller to current node
manually.

Take a look at this Image: asciicast [85] for brief demo.

Hierarchy UI can be initiated by mapping something to the indicated plug
mappings, for example:
>
nmap <leader>yth <Plug>(YCMTypeHierarchy)
nmap <leader>ych <Plug>(YCMCallHierarchy)
nmap <leader>ycr <Plug>(YCMResumeHierarchy)
nmap <leader>yca <Plug>(YCMAddCallHierarchy)
<
This opens a "modal" popup showing the current element in the hierarchy tree.
The current tree root is aligned to the left and child and parent nodes are
Expand All @@ -2181,6 +2188,16 @@ inheritance where a "child" of the current root may actually have other,
invisible, parent links. '<S-Tab>' on that row will show these by setting the
display root to the selected item.

When YCMCallHierarchy cannot find the actual caller, '<Plug>(YCMAddCallHierarchy)'
will be very useful. For example, when tracking the caller of callback functions
in C language, YCMCallHierarchy may not be able to find the true caller; instead,
it may trace related registration functions or initialization functions. The
relevant code passes the callback function to a function pointer, resulting in
a call stack that may not be what you are looking for. In this case, you can
manually find the function that calls the function pointer, which is the true
caller, and use '<Plug>(YCMAddCallHierarchy)' to manually add the true caller
to the call stack, thus extending the call stack.

When the hierarchy is displayed, the following keys are intercepted:

- '<Tab>': Drill into the hierarchy at the selected item: expand and show
Expand All @@ -2191,6 +2208,11 @@ When the hierarchy is displayed, the following keys are intercepted:
- '<CR>': Jump to the symbol currently selected.
- '<Down>', '<C-n>', '<C-j>', 'j': Select the next item
- '<Up>', '<C-p>', '<C-k>', 'k'; Select the previous item
- '<PageUp>': Select the item on the previous page.
- '<PageDown>': Select the item on the next page.
- '<c>': Close the current item, in other words, remove the caller of the
item under the cursorline.
- '<d>': Remove the current item.
- Any other key: closes the popup without jumping to any location

**Note:** you might think the call hierarchy tree is inverted, but we think
Expand Down
57 changes: 50 additions & 7 deletions python/ycm/hierarchy_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@


class HierarchyNode:
def __init__( self, data, distance : int ):
def __init__( self, data, distance : int, parent ):
self._references : Optional[ List[ int ] ] = None
self._data = data
self._distance_from_root = distance

self._parent = parent

def ToRootLocation( self, subindex : int ):
if location := self._data.get( 'root_location' ):
Expand Down Expand Up @@ -70,8 +70,8 @@ def SetRootNode( self, items, kind : str ):
if items:
assert len( items ) == 1
self._root_node_indices = [ 0 ]
self._down_nodes.append( HierarchyNode( items[ 0 ], 0 ) )
self._up_nodes.append( HierarchyNode( items[ 0 ], 0 ) )
self._down_nodes.append( HierarchyNode( items[ 0 ], 0, None ) )
self._up_nodes.append( HierarchyNode( items[ 0 ], 0, None ) )
self._kind = kind
return self.HierarchyToLines()
return []
Expand All @@ -80,15 +80,58 @@ def SetRootNode( self, items, kind : str ):
def UpdateHierarchy( self, handle : int, items, direction : str ):
current_index = handle_to_index( handle )
nodes = self._down_nodes if direction == 'down' else self._up_nodes
node = nodes[ current_index ]
if items:
nodes.extend( [
HierarchyNode( item,
nodes[ current_index ]._distance_from_root + 1 )
node._distance_from_root + 1, node )
for item in items ] )
nodes[ current_index ]._references = list(
node._references = list(
range( len( nodes ) - len( items ), len( nodes ) ) )
else:
nodes[ current_index ]._references = []
node._references = []


def AddNodes( self, handle : int, items ):
if not items:
return
current_index = handle_to_index( handle )
nodes = self._down_nodes
node = nodes[ current_index ]
nodes.extend( [
HierarchyNode( item, node._distance_from_root + 1, node )
for item in items ] )
new_refs = list( range( len( nodes ) - len( items ), len( nodes ) ) )
if node._references:
node._references.extend( new_refs)
else:
node._references = new_refs


def RemoveNode( self, handle : int ):
current_index = handle_to_index( handle )
nodes = self._down_nodes
node = nodes[ current_index ]
self._CloseNode( node )
if node._parent:
idx = node._parent._references.remove( current_index )
nodes[ current_index ] = None

def _CloseNode( self, node: HierarchyNode ):
nodes = self._down_nodes
if node._references:
for subindex in node._references:
if nodes[ subindex ]:
self._CloseNode( nodes[ subindex ])
nodes[ subindex ] = None
node._references = None


def CloseNode( self, handle : int):
current_index = handle_to_index( handle )
nodes = self._down_nodes
node = nodes[ current_index ]
self._CloseNode( node )


def Reset( self ):
Expand Down
18 changes: 17 additions & 1 deletion python/ycm/youcompleteme.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,13 @@ def InitializeCurrentHierarchy( self, items, kind ):


def UpdateCurrentHierarchy( self, handle : int, direction : str ):
if not self._current_hierarchy.UpdateChangesRoot( handle, direction ):
if direction == 'close':
self._current_hierarchy.CloseNode( handle )
return self._current_hierarchy.HierarchyToLines(), 0
elif direction == 'remove':
self._current_hierarchy.RemoveNode( handle )
return self._current_hierarchy.HierarchyToLines(), 0
elif not self._current_hierarchy.UpdateChangesRoot( handle, direction ):
items = self._ResolveHierarchyItem( handle, direction )
self._current_hierarchy.UpdateHierarchy( handle, items, direction )

Expand All @@ -143,6 +149,16 @@ def UpdateCurrentHierarchy( self, handle : int, direction : str ):
return self.UpdateCurrentHierarchy( handle, direction )


def AddCurrentHierarchy( self, handle : int, items ):
self._current_hierarchy.AddNodes( handle, items )
return self._current_hierarchy.HierarchyToLines()


def RemoveCurrentHierarchy( self, handle : int ):
self._current_hierarchy.RemoveNode( handle )
return self._current_hierarchy.HierarchyToLines()


def _ResolveHierarchyItem( self, handle : int, direction : str ):
return GetRawCommandResponse(
self._current_hierarchy.ResolveArguments( handle, direction ),
Expand Down

0 comments on commit 601026e

Please sign in to comment.