Skip to content

Commit a4cae4a

Browse files
authored
Merge pull request #326 from maralla/call-hierarchy
Support call hierarchy
2 parents 214853d + 1fff83e commit a4cae4a

5 files changed

Lines changed: 140 additions & 3 deletions

File tree

autoload/completor/action.vim

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,13 @@ function! completor#action#trigger(items)
324324
let items = a:items
325325
let action = s:action
326326
let ft = 'markdown'
327+
let do_method = ''
327328

328329
if type(a:items) == v:t_dict
329330
let items = a:items.data
330331
let action = get(a:items, 'action', action)
331332
let ft = get(a:items, 'ft', ft)
333+
let do_method = get(a:items, 'method', '')
332334
endif
333335

334336
if action ==# 'complete'
@@ -361,6 +363,15 @@ function! completor#action#trigger(items)
361363
echo "popup window not supported"
362364
endif
363365
endif
366+
elseif action ==# 'do'
367+
if empty(do_method)
368+
return
369+
endif
370+
let arg = ''
371+
if !empty(items)
372+
let arg = items[0]
373+
endif
374+
call completor#do(do_method, arg)
364375
elseif action ==# 'hover'
365376
if !empty(items)
366377
if completor#support_popup()

autoload/completor/popup.vim

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,19 @@ func s:select_filter(id, key)
461461
endfunc
462462

463463

464+
func s:select_preview_filter(id, key)
465+
if a:key == "j"
466+
call win_execute(a:id, "normal! \<C-d>")
467+
return 1
468+
elseif a:key == "k"
469+
call win_execute(a:id, "normal! \<C-u>")
470+
return 1
471+
endif
472+
473+
return 0
474+
endfunc
475+
476+
464477
let s:is_selector_content_shown = v:false
465478
let s:selector_content = -1
466479
func s:select_preview(id, type, item)
@@ -473,6 +486,7 @@ func s:select_preview(id, type, item)
473486
\ mapping: 0,
474487
\ scrollbar: 0,
475488
\ line: 1,
489+
\ filter: function('s:select_preview_filter'),
476490
\ maxheight: height,
477491
\ minheight: height,
478492
\ minwidth: &columns - 10,

pythonx/completers/lsp/__init__.py

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@
66
import os
77
import json
88
import io
9-
from completor import Completor, vim, get
9+
from completor import Completor, vim
1010
from completor.compat import to_unicode
1111

1212
from . import ext
1313
from .models import Initialize, DidOpen, Completion, DidChange, DidSave, \
1414
Definition, Format, Rename, Hover, Initialized, Implementation, \
1515
References, DidChangeConfiguration, Symbol, Signature, DocumentSymbol, \
16-
CodeAction, CodeResolve
16+
CodeAction, CodeResolve, PrepareCallHierarchy, IncomingCalls, \
17+
OutgoingCalls
1718
from .action import gen_jump_list, get_completion_word, gen_hover_doc, \
1819
filter_items, parse_symbols, rename
19-
from .utils import gen_uri
20+
from .utils import gen_uri, to_filename
2021

2122
logger = logging.getLogger('completor')
2223

@@ -30,6 +31,7 @@ def __init__(self, *args, **kwargs):
3031
self.server_cmd = None
3132
self.initialized = False
3233
self.current_id = None
34+
self.current_request_args = None
3335
self.current_options = None
3436
self.is_ext = False
3537
self.open_file_map = {}
@@ -134,6 +136,25 @@ def code_action(self, action):
134136
self.current_id = req_id
135137
return req
136138

139+
def prepare_call_hierarchy(self, args):
140+
if not args:
141+
return ''
142+
req = self.position_request(PrepareCallHierarchy)
143+
self.current_request_args = args
144+
return req
145+
146+
def call_hierarchy(self, data, call):
147+
try:
148+
item = json.loads(data)
149+
except Exception as e:
150+
logger.exception(e)
151+
return ''
152+
153+
c = call(item)
154+
req_id, req = c.to_request()
155+
self.current_id = req_id
156+
return req
157+
137158
def code_action_callback(self, data):
138159
if not data:
139160
return ''
@@ -220,6 +241,19 @@ def _gen_action_args(self, action, args):
220241
if action == b'hover':
221242
return self.position_request(Hover)
222243

244+
if action == b'prepare_call_hierarchy':
245+
return self.prepare_call_hierarchy(args)
246+
247+
if action == b'incoming_calls':
248+
if not args:
249+
return ''
250+
return self.call_hierarchy(args[0], IncomingCalls)
251+
252+
if action == b'outgoing_calls':
253+
if not args:
254+
return ''
255+
return self.call_hierarchy(args[0], OutgoingCalls)
256+
223257
handler = ext.get_action_handler(action, self.ft_orig)
224258
if handler:
225259
self.is_ext = True
@@ -229,6 +263,7 @@ def _gen_action_args(self, action, args):
229263
return ''
230264

231265
def gen_request(self, action, args):
266+
self.current_request_args = None
232267
self.current_options = {}
233268
if args:
234269
last = args[-1]
@@ -453,6 +488,54 @@ def on_hover(self, data):
453488

454489
return [gen_hover_doc(self.ft_orig, '\n\n'.join(values))]
455490

491+
def on_prepare_call_hierarchy(self, data):
492+
logger.info("prepare_call_hierarchy -> %r", data)
493+
if not data:
494+
return []
495+
496+
if not self.current_request_args:
497+
return []
498+
499+
method = self.current_request_args[0]
500+
501+
items = data[0]
502+
if not items:
503+
return []
504+
505+
item = items[0]
506+
507+
try:
508+
data = json.dumps(item)
509+
except Exception as e:
510+
logger.exception(e)
511+
return []
512+
513+
return vim.Dictionary(data=[data], action='do', method=method)
514+
515+
def on_incoming_calls(self, data, direction='from'):
516+
logger.info("incoming_calls -> %r", data)
517+
if not data:
518+
return []
519+
520+
res = []
521+
for item in data[0]:
522+
data = item[direction]
523+
if direction == 'from':
524+
start = item['fromRanges'][0]['start']
525+
else:
526+
start = data['selectionRange']['start']
527+
res.append({
528+
'filename': to_filename(data['uri']),
529+
'lnum': start['line'] + 1,
530+
'col': start['character'] + 1,
531+
'name': data['name'],
532+
})
533+
534+
return vim.Dictionary(data=res, action='references')
535+
536+
def on_outgoing_calls(self, data):
537+
return self.on_incoming_calls(data, direction='to')
538+
456539
def on_lsp_ext(self, data):
457540
if not data or len(data) < 3:
458541
return []

pythonx/completers/lsp/models.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,23 @@ def to_dict(self):
314314
return {
315315
"query": self.query,
316316
}
317+
318+
319+
class PrepareCallHierarchy(Completion):
320+
method = "textDocument/prepareCallHierarchy"
321+
322+
323+
class IncomingCalls(Base):
324+
method = "callHierarchy/incomingCalls"
325+
326+
def __init__(self, item):
327+
self.item = item
328+
329+
def to_dict(self):
330+
return {
331+
"item": self.item
332+
}
333+
334+
335+
class OutgoingCalls(IncomingCalls):
336+
method = "callHierarchy/outgoingCalls"

pythonx/completers/lsp/utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# -*- coding: utf-8 -*-
22

3+
try:
4+
from urlparse import unquote
5+
except ImportError:
6+
from urllib.parse import unquote
7+
38

49
def gen_uri(path):
510
return 'file://' + path
@@ -9,3 +14,7 @@ def parse_uri(uri):
914
if uri.startswith('file://'):
1015
return uri[7:]
1116
return uri
17+
18+
19+
def to_filename(uri):
20+
return unquote(parse_uri(uri))

0 commit comments

Comments
 (0)