summaryrefslogtreecommitdiff
path: root/vim/pack/downloads/opt/lsp/autoload/lsp/callhierarchy.vim
blob: aca6a55310a8bcf5e9e0b739233cf2488c8027bb (plain)
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