mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 06:40:05 +08:00
185 lines
5.4 KiB
Python
185 lines
5.4 KiB
Python
# =============================================================================
|
||
# FILE: lsp.py
|
||
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||
# =============================================================================
|
||
|
||
import json
|
||
import re
|
||
|
||
from deoplete.source.base import Base
|
||
|
||
|
||
LSP_KINDS = [
|
||
'Text',
|
||
'Method',
|
||
'Function',
|
||
'Constructor',
|
||
'Field',
|
||
'Variable',
|
||
'Class',
|
||
'Interface',
|
||
'Module',
|
||
'Property',
|
||
'Unit',
|
||
'Value',
|
||
'Enum',
|
||
'Keyword',
|
||
'Snippet',
|
||
'Color',
|
||
'File',
|
||
'Reference',
|
||
'Folder',
|
||
'EnumMember',
|
||
'Constant',
|
||
'Struct',
|
||
'Event',
|
||
'Operator',
|
||
'TypeParameter',
|
||
]
|
||
|
||
LSP_KINDS_WITH_ICONS = [
|
||
' [text] ',
|
||
' [method] ',
|
||
' [function] ',
|
||
' [constructor]',
|
||
'ﰠ [field] ',
|
||
'𝒙 [variable] ',
|
||
' [class] ',
|
||
' [interface]',
|
||
' [module] ',
|
||
' [property] ',
|
||
' [unit] ',
|
||
' [value] ',
|
||
' [enum] ',
|
||
' [key] ',
|
||
' [snippet] ',
|
||
' [color] ',
|
||
' [file] ',
|
||
' [refrence] ',
|
||
' [folder] ',
|
||
' [enumMember]',
|
||
' [constant] ',
|
||
' [struct] ',
|
||
' [event] ',
|
||
' [operator] ',
|
||
' [typeParameter]',
|
||
]
|
||
|
||
|
||
class Source(Base):
|
||
def __init__(self, vim):
|
||
Base.__init__(self, vim)
|
||
|
||
self.name = 'lsp'
|
||
self.mark = '[lsp]'
|
||
self.rank = 500
|
||
self.input_pattern = r'(\.|:|->)$'
|
||
self.is_volatile = True
|
||
self.vars = {}
|
||
self.vim.vars['deoplete#source#lsp#_results'] = []
|
||
self.vim.vars['deoplete#source#lsp#_success'] = False
|
||
self.vim.vars['deoplete#source#lsp#_requested'] = False
|
||
self.vim.vars['deoplete#source#lsp#_prev_input'] = ''
|
||
if 'deoplete#lsp#use_icons_for_candidates' not in self.vim.vars:
|
||
self.vim.vars['deoplete#lsp#use_icons_for_candidates'] = False
|
||
|
||
self.lsp_kinds = LSP_KINDS
|
||
|
||
def gather_candidates(self, context):
|
||
if not self.vim.call('has', 'nvim-0.5.0'):
|
||
return []
|
||
|
||
prev_input = self.vim.vars['deoplete#source#lsp#_prev_input']
|
||
if context['input'] == prev_input and self.vim.vars[
|
||
'deoplete#source#lsp#_requested']:
|
||
return self.process_candidates()
|
||
|
||
vars = self.vim.vars
|
||
vars['deoplete#source#lsp#_requested'] = False
|
||
vars['deoplete#source#lsp#_prev_input'] = context['input']
|
||
vars['deoplete#source#lsp#_complete_position'] = context[
|
||
'complete_position']
|
||
|
||
params = self.vim.call(
|
||
'luaeval',
|
||
'vim.lsp.util.make_position_params()')
|
||
|
||
self.vim.call(
|
||
'luaeval', 'require("candidates").request_candidates('
|
||
'_A.arguments)',
|
||
{'arguments': params})
|
||
|
||
return []
|
||
|
||
def process_candidates(self):
|
||
candidates = []
|
||
vars = self.vim.vars
|
||
results = vars['deoplete#source#lsp#_results']
|
||
|
||
if not results:
|
||
return
|
||
elif isinstance(results, dict):
|
||
if 'items' not in results:
|
||
self.print_error(
|
||
'LSP results does not have "items" key:{}'.format(
|
||
str(results)))
|
||
return
|
||
items = results['items']
|
||
else:
|
||
items = results
|
||
|
||
use_icons = vars['deoplete#lsp#use_icons_for_candidates']
|
||
if use_icons:
|
||
self.lsp_kinds = LSP_KINDS_WITH_ICONS
|
||
|
||
for rec in items:
|
||
if 'textEdit' in rec and rec['textEdit'] is not None:
|
||
textEdit = rec['textEdit']
|
||
if ('range' in textEdit and textEdit['range']['start'] ==
|
||
textEdit['range']['end']):
|
||
previous_input = vars['deoplete#source#lsp#_prev_input']
|
||
complete_position = vars[
|
||
'deoplete#source#lsp#_complete_position']
|
||
new_text = textEdit['newText']
|
||
word = f'{previous_input[complete_position:]}{new_text}'
|
||
else:
|
||
word = textEdit['newText']
|
||
elif rec.get('insertText', ''):
|
||
if rec.get('insertTextFormat', 1) != 1:
|
||
word = rec.get('entryName', rec.get('label'))
|
||
else:
|
||
word = rec['insertText']
|
||
else:
|
||
word = rec.get('entryName', rec.get('label'))
|
||
|
||
# Remove parentheses from word.
|
||
# Note: some LSP includes snippet parentheses in word(newText)
|
||
word = re.sub(r'[\(|<].*[\)|>](\$\d+)?', '', word)
|
||
|
||
item = {
|
||
'word': word,
|
||
'abbr': rec['label'],
|
||
'dup': 0,
|
||
'user_data': json.dumps({
|
||
'lspitem': rec
|
||
})
|
||
}
|
||
|
||
if isinstance(rec.get('kind'), int):
|
||
item['kind'] = self.lsp_kinds[rec['kind'] - 1]
|
||
elif rec.get('insertTextFormat') == 2:
|
||
item['kind'] = 'Snippet'
|
||
|
||
if rec.get('detail'):
|
||
item['menu'] = rec['detail']
|
||
|
||
if isinstance(rec.get('documentation'), str):
|
||
item['info'] = rec['documentation']
|
||
elif (isinstance(rec.get('documentation'), dict) and
|
||
'value' in rec['documentation']):
|
||
item['info'] = rec['documentation']['value']
|
||
|
||
candidates.append(item)
|
||
|
||
return candidates
|