1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
vim9script
# Functions for dealing with call hierarchy (incoming/outgoing calls)
import './util.vim'
import './buffer.vim' as buf
# Jump to the location of the symbol under the cursor in the call hierarchy
# tree window.
def CallHierarchyItemJump()
var item: dict<any> = w:LspCallHierItemMap[line('.')].item
util.JumpToLspLocation(item, '')
enddef
# Refresh the call hierarchy tree for the symbol at index "idx".
def CallHierarchyTreeItemRefresh(idx: number)
var treeItem: dict<any> = w:LspCallHierItemMap[idx]
if treeItem.open
# Already retrieved the children for this item
return
endif
if !treeItem->has_key('children')
# First time retrieving the children for the item at index "idx"
var lspserver = buf.BufLspServerGet(w:LspBufnr, 'callHierarchy')
if lspserver->empty() || !lspserver.running
return
endif
var reply: any
if w:LspCallHierIncoming
reply = lspserver.getIncomingCalls(treeItem.item)
else
reply = lspserver.getOutgoingCalls(treeItem.item)
endif
treeItem.children = []
if !reply->empty()
for item in reply
treeItem.children->add({item: w:LspCallHierIncoming ? item.from :
item.to, open: false})
endfor
endif
endif
# Clear and redisplay the tree in the window
treeItem.open = true
var save_cursor = getcurpos()
CallHierarchyTreeRefresh()
setpos('.', save_cursor)
enddef
# Open the call hierarchy tree item under the cursor
def CallHierarchyTreeItemOpen()
CallHierarchyTreeItemRefresh(line('.'))
enddef
# Refresh the entire call hierarchy tree
def CallHierarchyTreeRefreshCmd()
w:LspCallHierItemMap[2].open = false
w:LspCallHierItemMap[2]->remove('children')
CallHierarchyTreeItemRefresh(2)
enddef
# Display the incoming call hierarchy tree
def CallHierarchyTreeIncomingCmd()
w:LspCallHierItemMap[2].open = false
w:LspCallHierItemMap[2]->remove('children')
w:LspCallHierIncoming = true
CallHierarchyTreeItemRefresh(2)
enddef
# Display the outgoing call hierarchy tree
def CallHierarchyTreeOutgoingCmd()
w:LspCallHierItemMap[2].open = false
w:LspCallHierItemMap[2]->remove('children')
w:LspCallHierIncoming = false
CallHierarchyTreeItemRefresh(2)
enddef
# Close the call hierarchy tree item under the cursor
def CallHierarchyTreeItemClose()
var treeItem: dict<any> = w:LspCallHierItemMap[line('.')]
treeItem.open = false
var save_cursor = getcurpos()
CallHierarchyTreeRefresh()
setpos('.', save_cursor)
enddef
# Recursively add the call hierarchy items to w:LspCallHierItemMap
def CallHierarchyTreeItemShow(incoming: bool, treeItem: dict<any>, pfx: string)
var item = treeItem.item
var treePfx: string
if treeItem.open && treeItem->has_key('children')
treePfx = has('gui_running') ? '▼' : '-'
else
treePfx = has('gui_running') ? '▶' : '+'
endif
var fname = util.LspUriToFile(item.uri)
var s = $'{pfx}{treePfx} {item.name} ({fname->fnamemodify(":t")} [{fname->fnamemodify(":h")}])'
append('$', s)
w:LspCallHierItemMap->add(treeItem)
if treeItem.open && treeItem->has_key('children')
for child in treeItem.children
CallHierarchyTreeItemShow(incoming, child, $'{pfx} ')
endfor
endif
enddef
def CallHierarchyTreeRefresh()
:setlocal modifiable
:silent! :%d _
setline(1, $'# {w:LspCallHierIncoming ? "Incoming calls to" : "Outgoing calls from"} "{w:LspCallHierarchyTree.item.name}"')
w:LspCallHierItemMap = [{}, {}]
CallHierarchyTreeItemShow(w:LspCallHierIncoming, w:LspCallHierarchyTree, '')
:setlocal nomodifiable
enddef
def CallHierarchyTreeShow(incoming: bool, prepareItem: dict<any>,
items: list<dict<any>>)
var save_bufnr = bufnr()
var wid = bufwinid('LSP-CallHierarchy')
if wid != -1
wid->win_gotoid()
else
:new LSP-CallHierarchy
:setlocal buftype=nofile
:setlocal bufhidden=wipe
:setlocal noswapfile
:setlocal nonumber nornu
:setlocal fdc=0 signcolumn=no
:nnoremap <buffer> <CR> <ScriptCmd>CallHierarchyItemJump()<CR>
:nnoremap <buffer> - <ScriptCmd>CallHierarchyTreeItemOpen()<CR>
:nnoremap <buffer> + <ScriptCmd>CallHierarchyTreeItemClose()<CR>
:command -buffer LspCallHierarchyRefresh CallHierarchyTreeRefreshCmd()
:command -buffer LspCallHierarchyIncoming CallHierarchyTreeIncomingCmd()
:command -buffer LspCallHierarchyOutgoing CallHierarchyTreeOutgoingCmd()
:syntax match Comment '^#.*$'
:syntax match Directory '(.*)$'
endif
w:LspBufnr = save_bufnr
w:LspCallHierIncoming = incoming
w:LspCallHierarchyTree = {}
w:LspCallHierarchyTree.item = prepareItem
w:LspCallHierarchyTree.open = true
w:LspCallHierarchyTree.children = []
for item in items
w:LspCallHierarchyTree.children->add({item: incoming ? item.from : item.to, open: false})
endfor
CallHierarchyTreeRefresh()
:setlocal nomodified
:setlocal nomodifiable
enddef
export def IncomingCalls(lspserver: dict<any>)
var prepareReply = lspserver.prepareCallHierarchy()
if prepareReply->empty()
util.WarnMsg('No incoming calls')
return
endif
var reply = lspserver.getIncomingCalls(prepareReply)
if reply->empty()
util.WarnMsg('No incoming calls')
return
endif
CallHierarchyTreeShow(true, prepareReply, reply)
enddef
export def OutgoingCalls(lspserver: dict<any>)
var prepareReply = lspserver.prepareCallHierarchy()
if prepareReply->empty()
util.WarnMsg('No outgoing calls')
return
endif
var reply = lspserver.getOutgoingCalls(prepareReply)
if reply->empty()
util.WarnMsg('No outgoing calls')
return
endif
CallHierarchyTreeShow(false, prepareReply, reply)
enddef
# vim: tabstop=8 shiftwidth=2 softtabstop=2
|