Fixed vim and zsh
This commit is contained in:
@ -0,0 +1,52 @@
|
||||
# ============================================================================
|
||||
# FILE: around.py
|
||||
# AUTHOR: Khalidov Oleg <brooth at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
import re
|
||||
|
||||
from .base import Base
|
||||
from deoplete.util import parse_buffer_pattern, getlines
|
||||
|
||||
LINES_ABOVE = 20
|
||||
LINES_BELOW = 20
|
||||
|
||||
|
||||
class Source(Base):
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
self.name = 'around'
|
||||
self.mark = '[~]'
|
||||
self.rank = 300
|
||||
|
||||
def gather_candidates(self, context):
|
||||
line = context['position'][1]
|
||||
candidates = []
|
||||
|
||||
# lines above
|
||||
words = parse_buffer_pattern(
|
||||
reversed(getlines(self.vim, max([1, line - LINES_ABOVE]), line)),
|
||||
context['keyword_patterns'])
|
||||
candidates += [{'word': x, 'menu': 'A'} for x in words]
|
||||
|
||||
# grab ':changes' command output
|
||||
p = re.compile(r'[\s\d]+')
|
||||
lines = set()
|
||||
for change_line in [x[p.search(x).span()[1]:] for x
|
||||
in self.vim.call(
|
||||
'execute', 'changes').split('\n')
|
||||
if p.search(x)]:
|
||||
if change_line and change_line != '-invalid-':
|
||||
lines.add(change_line)
|
||||
|
||||
words = parse_buffer_pattern(lines, context['keyword_patterns'])
|
||||
candidates += [{'word': x, 'menu': 'C'} for x in words]
|
||||
|
||||
# lines below
|
||||
words = parse_buffer_pattern(
|
||||
getlines(self.vim, line, line + LINES_BELOW),
|
||||
context['keyword_patterns'])
|
||||
candidates += [{'word': x, 'menu': 'B'} for x in words]
|
||||
|
||||
return candidates
|
@ -0,0 +1,56 @@
|
||||
# ============================================================================
|
||||
# FILE: base.py
|
||||
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
import re
|
||||
from abc import abstractmethod
|
||||
from deoplete.logger import LoggingMixin
|
||||
from deoplete.util import debug, error_vim
|
||||
|
||||
|
||||
class Base(LoggingMixin):
|
||||
|
||||
def __init__(self, vim):
|
||||
self.vim = vim
|
||||
self.description = ''
|
||||
self.mark = ''
|
||||
self.max_pattern_length = 80
|
||||
self.input_pattern = ''
|
||||
self.matchers = ['matcher_fuzzy']
|
||||
self.sorters = ['sorter_rank']
|
||||
self.converters = [
|
||||
'converter_remove_overlap',
|
||||
'converter_truncate_abbr',
|
||||
'converter_truncate_kind',
|
||||
'converter_truncate_menu']
|
||||
self.filetypes = []
|
||||
self.debug_enabled = False
|
||||
self.is_bytepos = False
|
||||
self.is_initialized = False
|
||||
self.is_volatile = False
|
||||
self.is_silent = False
|
||||
self.rank = 100
|
||||
self.disabled_syntaxes = []
|
||||
self.events = None
|
||||
|
||||
def get_complete_position(self, context):
|
||||
m = re.search('(?:' + context['keyword_patterns'] + ')$',
|
||||
context['input'])
|
||||
return m.start() if m else -1
|
||||
|
||||
def print(self, expr):
|
||||
if not self.is_silent:
|
||||
debug(self.vim, expr)
|
||||
|
||||
def print_error(self, expr):
|
||||
if not self.is_silent:
|
||||
error_vim(self.vim, expr)
|
||||
|
||||
@abstractmethod
|
||||
def gather_candidates(self, context):
|
||||
pass
|
||||
|
||||
def on_event(self, context):
|
||||
pass
|
@ -0,0 +1,63 @@
|
||||
# ============================================================================
|
||||
# FILE: buffer.py
|
||||
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
from .base import Base
|
||||
|
||||
from deoplete.util import parse_buffer_pattern, getlines
|
||||
|
||||
|
||||
class Source(Base):
|
||||
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
|
||||
self.name = 'buffer'
|
||||
self.mark = '[B]'
|
||||
self.events = ['Init', 'InsertEnter', 'BufWritePost']
|
||||
|
||||
self._limit = 1000000
|
||||
self._buffers = {}
|
||||
self._max_lines = 5000
|
||||
|
||||
def on_event(self, context):
|
||||
if (context['bufnr'] not in self._buffers
|
||||
or context['event'] == 'BufWritePost'):
|
||||
self._make_cache(context)
|
||||
|
||||
def gather_candidates(self, context):
|
||||
self.on_event(context)
|
||||
|
||||
tab_bufnrs = self.vim.call('tabpagebuflist')
|
||||
same_filetype = context['vars'].get(
|
||||
'deoplete#buffer#require_same_filetype', True)
|
||||
return {'sorted_candidates': [
|
||||
x['candidates'] for x in self._buffers.values()
|
||||
if not same_filetype or
|
||||
x['filetype'] in context['filetypes'] or
|
||||
x['filetype'] in context['same_filetypes'] or
|
||||
x['bufnr'] in tab_bufnrs
|
||||
]}
|
||||
|
||||
def _make_cache(self, context):
|
||||
# Bufsize check
|
||||
size = self.vim.call('line2byte',
|
||||
self.vim.call('line', '$') + 1) - 1
|
||||
if size > self._limit:
|
||||
return
|
||||
|
||||
try:
|
||||
self._buffers[context['bufnr']] = {
|
||||
'bufnr': context['bufnr'],
|
||||
'filetype': self.vim.eval('&l:filetype'),
|
||||
'candidates': [
|
||||
{'word': x} for x in
|
||||
sorted(parse_buffer_pattern(getlines(self.vim),
|
||||
context['keyword_patterns']),
|
||||
key=str.lower)
|
||||
]
|
||||
}
|
||||
except UnicodeDecodeError:
|
||||
return []
|
@ -0,0 +1,51 @@
|
||||
# ============================================================================
|
||||
# FILE: dictionary.py
|
||||
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
from os.path import getmtime, exists
|
||||
from collections import namedtuple
|
||||
from .base import Base
|
||||
|
||||
DictCacheItem = namedtuple('DictCacheItem', 'mtime candidates')
|
||||
|
||||
|
||||
class Source(Base):
|
||||
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
|
||||
self.name = 'dictionary'
|
||||
self.mark = '[D]'
|
||||
self.events = ['Init', 'InsertEnter']
|
||||
|
||||
self._cache = {}
|
||||
|
||||
def on_event(self, context):
|
||||
self._make_cache(context)
|
||||
|
||||
def gather_candidates(self, context):
|
||||
self._make_cache(context)
|
||||
|
||||
candidates = []
|
||||
for filename in [x for x in self._get_dictionaries(context)
|
||||
if x in self._cache]:
|
||||
candidates.append(self._cache[filename].candidates)
|
||||
return {'sorted_candidates': candidates}
|
||||
|
||||
def _make_cache(self, context):
|
||||
for filename in self._get_dictionaries(context):
|
||||
mtime = getmtime(filename)
|
||||
if filename in self._cache and self._cache[
|
||||
filename].mtime == mtime:
|
||||
continue
|
||||
with open(filename, 'r', errors='replace') as f:
|
||||
self._cache[filename] = DictCacheItem(
|
||||
mtime, [{'word': x} for x in sorted(
|
||||
[x.strip() for x in f], key=str.lower)]
|
||||
)
|
||||
|
||||
def _get_dictionaries(self, context):
|
||||
return [x for x in context['dict__dictionary'].split(',')
|
||||
if exists(x)]
|
@ -0,0 +1,86 @@
|
||||
# ============================================================================
|
||||
# FILE: file.py
|
||||
# AUTHOR: Felipe Morales <hel.sheep at gmail.com>
|
||||
# Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
import os
|
||||
import re
|
||||
from os.path import exists, dirname
|
||||
from .base import Base
|
||||
from deoplete.util import expand
|
||||
|
||||
|
||||
class Source(Base):
|
||||
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
|
||||
self.name = 'file'
|
||||
self.mark = '[F]'
|
||||
self.min_pattern_length = 0
|
||||
self.rank = 150
|
||||
self.events = ['Init', 'InsertEnter']
|
||||
|
||||
self._isfname = ''
|
||||
|
||||
def on_init(self, context):
|
||||
self._buffer_path = context['vars'].get(
|
||||
'deoplete#file#enable_buffer_path', 0)
|
||||
|
||||
def on_event(self, context):
|
||||
self._isfname = self.vim.call(
|
||||
'deoplete#util#vimoption2python_not',
|
||||
self.vim.options['isfname'])
|
||||
|
||||
def get_complete_position(self, context):
|
||||
pos = context['input'].rfind('/')
|
||||
return pos if pos < 0 else pos + 1
|
||||
|
||||
def gather_candidates(self, context):
|
||||
if not self._isfname:
|
||||
self.on_event(context)
|
||||
|
||||
p = self._longest_path_that_exists(context, context['input'])
|
||||
if p in (None, []) or p == '/' or re.search('//+$', p):
|
||||
return []
|
||||
complete_str = self._substitute_path(context, dirname(p) + '/')
|
||||
if not os.path.isdir(complete_str):
|
||||
return []
|
||||
hidden = context['complete_str'].find('.') == 0
|
||||
contents = [[], []]
|
||||
try:
|
||||
for item in sorted(os.listdir(complete_str), key=str.lower):
|
||||
if not hidden and item[0] == '.':
|
||||
continue
|
||||
contents[not os.path.isdir(complete_str + item)].append(item)
|
||||
except PermissionError:
|
||||
pass
|
||||
|
||||
dirs, files = contents
|
||||
return [{'word': x, 'abbr': x + '/'} for x in dirs
|
||||
] + [{'word': x} for x in files]
|
||||
|
||||
def _longest_path_that_exists(self, context, input_str):
|
||||
input_str = re.sub(r'[^/]*$', '', input_str)
|
||||
data = re.split(r'((?:%s+|(?:(?<![\w\s/\.])(?:~|\.{1,2})?/)+))' %
|
||||
self._isfname, input_str)
|
||||
data = [''.join(data[i:]) for i in range(len(data))]
|
||||
existing_paths = sorted(filter(lambda x: exists(
|
||||
dirname(self._substitute_path(context, x))), data))
|
||||
return existing_paths[-1] if existing_paths else None
|
||||
|
||||
def _substitute_path(self, context, path):
|
||||
m = re.match(r'(\.{1,2})/+', path)
|
||||
if m:
|
||||
if self._buffer_path and context['bufpath']:
|
||||
base = context['bufpath']
|
||||
else:
|
||||
base = os.path.join(context['cwd'], 'x')
|
||||
|
||||
for _ in m.group(1):
|
||||
base = dirname(base)
|
||||
return os.path.abspath(os.path.join(
|
||||
base, path[len(m.group(0)):])) + '/'
|
||||
return expand(path)
|
@ -0,0 +1,62 @@
|
||||
# ============================================================================
|
||||
# FILE: member.py
|
||||
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
from .base import Base
|
||||
|
||||
import re
|
||||
from deoplete.util import (
|
||||
get_buffer_config, convert2list,
|
||||
parse_buffer_pattern, set_pattern, getlines)
|
||||
|
||||
|
||||
class Source(Base):
|
||||
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
|
||||
self.name = 'member'
|
||||
self.mark = '[M]'
|
||||
self.min_pattern_length = 0
|
||||
|
||||
self._object_pattern = r'[a-zA-Z_]\w*(?:\(\)?)?'
|
||||
self._prefix = ''
|
||||
|
||||
self._prefix_patterns = {}
|
||||
set_pattern(self._prefix_patterns,
|
||||
'_', '\.')
|
||||
set_pattern(self._prefix_patterns,
|
||||
'c,objc', ['\.', '->'])
|
||||
set_pattern(self._prefix_patterns,
|
||||
'cpp,objcpp', ['\.', '->', '::'])
|
||||
set_pattern(self._prefix_patterns,
|
||||
'perl,php', ['->'])
|
||||
set_pattern(self._prefix_patterns,
|
||||
'ruby', ['\.', '::'])
|
||||
set_pattern(self._prefix_patterns,
|
||||
'lua', ['\.', ':'])
|
||||
|
||||
def get_complete_position(self, context):
|
||||
# Check member prefix pattern.
|
||||
for prefix_pattern in convert2list(
|
||||
get_buffer_config(context, context['filetype'],
|
||||
'deoplete_member_prefix_patterns',
|
||||
'deoplete#member#prefix_patterns',
|
||||
self._prefix_patterns)):
|
||||
m = re.search(self._object_pattern + prefix_pattern + r'\w*$',
|
||||
context['input'])
|
||||
if m is None or prefix_pattern == '':
|
||||
continue
|
||||
self._prefix = re.sub(r'\w*$', '', m.group(0))
|
||||
return re.search(r'\w*$', context['input']).start()
|
||||
return -1
|
||||
|
||||
def gather_candidates(self, context):
|
||||
return [{'word': x} for x in
|
||||
parse_buffer_pattern(
|
||||
getlines(self.vim),
|
||||
r'(?<=' + re.escape(self._prefix) + r')\w+'
|
||||
)
|
||||
if x != context['complete_str']]
|
@ -0,0 +1,98 @@
|
||||
# ============================================================================
|
||||
# FILE: omni.py
|
||||
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
import re
|
||||
from .base import Base
|
||||
from deoplete.util import (
|
||||
get_buffer_config, convert2list, set_pattern, convert2candidates)
|
||||
|
||||
|
||||
class Source(Base):
|
||||
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
|
||||
self.name = 'omni'
|
||||
self.mark = '[O]'
|
||||
self.rank = 500
|
||||
self.is_bytepos = True
|
||||
self.min_pattern_length = 0
|
||||
|
||||
self._input_patterns = {}
|
||||
set_pattern(self._input_patterns, 'css,less,scss,sass',
|
||||
[r'\w{2}', r'\w+[):;]?\s*\w*', r'[@!]'])
|
||||
set_pattern(self._input_patterns, 'lua',
|
||||
[r'\w+[.:]\w*', r'require\s*\(?["'']\w*'])
|
||||
|
||||
def get_complete_position(self, context):
|
||||
current_ft = self.vim.eval('&filetype')
|
||||
|
||||
for filetype in list(set([context['filetype']] +
|
||||
context['filetype'].split('.'))):
|
||||
pos = self._get_complete_position(context, current_ft, filetype)
|
||||
if pos >= 0:
|
||||
return pos
|
||||
return -1
|
||||
|
||||
def _get_complete_position(self, context, current_ft, filetype):
|
||||
for omnifunc in convert2list(
|
||||
get_buffer_config(context, filetype,
|
||||
'deoplete_omni_functions',
|
||||
'deoplete#omni#functions',
|
||||
{'_': ''})):
|
||||
if omnifunc == '' and (filetype == current_ft or
|
||||
filetype in ['css', 'javascript']):
|
||||
omnifunc = context['omni__omnifunc']
|
||||
if omnifunc == '':
|
||||
continue
|
||||
self._omnifunc = omnifunc
|
||||
for input_pattern in convert2list(
|
||||
get_buffer_config(context, filetype,
|
||||
'deoplete_omni_input_patterns',
|
||||
'deoplete#omni#input_patterns',
|
||||
self._input_patterns)):
|
||||
|
||||
m = re.search('(' + input_pattern + ')$', context['input'])
|
||||
# self.debug(filetype)
|
||||
# self.debug(input_pattern)
|
||||
if input_pattern == '' or (context['event'] !=
|
||||
'Manual' and m is None):
|
||||
continue
|
||||
|
||||
if filetype == current_ft and self._omnifunc in [
|
||||
'ccomplete#Complete',
|
||||
'htmlcomplete#CompleteTags',
|
||||
'LanguageClient#complete',
|
||||
'phpcomplete#CompletePHP']:
|
||||
# In the blacklist
|
||||
return -1
|
||||
try:
|
||||
complete_pos = self.vim.call(self._omnifunc, 1, '')
|
||||
except Exception as e:
|
||||
self.print_error('Error occurred calling omnifunction: ' +
|
||||
self._omnifunc)
|
||||
return -1
|
||||
return complete_pos
|
||||
return -1
|
||||
|
||||
def gather_candidates(self, context):
|
||||
try:
|
||||
candidates = self.vim.call(self._omnifunc, 0, '')
|
||||
if isinstance(candidates, dict):
|
||||
candidates = candidates['words']
|
||||
elif isinstance(candidates, int):
|
||||
candidates = []
|
||||
except Exception as e:
|
||||
self.print_error('Error occurred calling omnifunction: ' +
|
||||
self._omnifunc)
|
||||
candidates = []
|
||||
|
||||
candidates = convert2candidates(candidates)
|
||||
|
||||
for candidate in candidates:
|
||||
candidate['dup'] = 1
|
||||
|
||||
return candidates
|
156
vim/plugins/deoplete.nvim/rplugin/python3/deoplete/source/tag.py
Normal file
156
vim/plugins/deoplete.nvim/rplugin/python3/deoplete/source/tag.py
Normal file
@ -0,0 +1,156 @@
|
||||
# ============================================================================
|
||||
# FILE: tag.py
|
||||
# AUTHOR: Felipe Morales <hel.sheep at gmail.com>
|
||||
# Shougo Matsushita <Shougo.Matsu at gmail.com>
|
||||
# Roxma <roxma at qq.com>
|
||||
# License: MIT license
|
||||
# ============================================================================
|
||||
|
||||
from .base import Base
|
||||
|
||||
import re
|
||||
import os
|
||||
from os.path import exists, getsize
|
||||
|
||||
|
||||
class Source(Base):
|
||||
|
||||
def __init__(self, vim):
|
||||
super().__init__(vim)
|
||||
|
||||
self.name = 'tag'
|
||||
self.mark = '[T]'
|
||||
|
||||
def on_init(self, context):
|
||||
self._limit = context['vars'].get(
|
||||
'deoplete#tag#cache_limit_size', 500000)
|
||||
|
||||
def gather_candidates(self, context):
|
||||
candidates = []
|
||||
for filename in self._get_tagfiles(context):
|
||||
for line in binary_search_lines_by_prefix(
|
||||
context['complete_str'], filename):
|
||||
candidate = self._make_candidate(line)
|
||||
if candidate:
|
||||
candidates.append(candidate)
|
||||
return candidates
|
||||
|
||||
def _make_candidate(self, line):
|
||||
cols = line.strip().split('\t', 2)
|
||||
if not cols or cols[0].startswith('!_'):
|
||||
return {}
|
||||
|
||||
tagfield = {}
|
||||
if ';"' in cols[-1]:
|
||||
cols[-1], fields = cols[-1].split(';"', 1)
|
||||
for pair in fields.split('\t'):
|
||||
if ':' not in pair:
|
||||
tagfield['kind'] = pair
|
||||
else:
|
||||
k, v = pair.split(':', 1)
|
||||
tagfield[k] = v
|
||||
|
||||
kind = tagfield.get('kind', '')
|
||||
if kind == 'f':
|
||||
i = cols[2].find('(')
|
||||
if i != -1 and cols[2].find(')', i+1) != -1:
|
||||
m = re.search(r'(\w+\(.*\))', cols[2])
|
||||
if m:
|
||||
return {'word': cols[0], 'abbr': m.group(1), 'kind': kind}
|
||||
return {'word': cols[0], 'kind': kind}
|
||||
|
||||
def _get_tagfiles(self, context):
|
||||
include_files = self.vim.call(
|
||||
'neoinclude#include#get_tag_files') if self.vim.call(
|
||||
'exists', '*neoinclude#include#get_tag_files') else []
|
||||
return [x for x in self.vim.call(
|
||||
'map', self.vim.call('tagfiles') + include_files,
|
||||
'fnamemodify(v:val, ":p")')
|
||||
if exists(x) and getsize(x) < self._limit]
|
||||
|
||||
|
||||
def binary_search_lines_by_prefix(prefix, filename):
|
||||
|
||||
with open(filename, 'r', errors='ignore') as f:
|
||||
# to properly keep bounds of this loop it's important to understand
|
||||
# *exactly* what our variables mean.
|
||||
#
|
||||
# to make sure we process only full lines, we are going to always seek
|
||||
# to file position (x - 1), then skip partial or full line found there.
|
||||
# except for position 0 which we know belongs to full 1st line.
|
||||
|
||||
# each line (except 1st one) will have multiple corresponding seeking
|
||||
# positions.
|
||||
#
|
||||
# we are interested in finding such a seeking position for the first
|
||||
# line in the file that matches our prefix. (let's call it target)
|
||||
|
||||
# begin - guaranteed not to exceed our target position
|
||||
# e.g. (begin <= target) at any time.
|
||||
begin = 0
|
||||
|
||||
# end - guaranteed to be higher then at least one seeking position for
|
||||
# the target. e.g. (target < end) at any time.
|
||||
# Note that this means it can be below the actual target line
|
||||
f.seek(0, os.SEEK_END)
|
||||
end = f.tell()
|
||||
|
||||
while end > begin + 1:
|
||||
|
||||
# pos - current seeking position
|
||||
pos = int((begin + end) / 2) - 1
|
||||
|
||||
if pos == 0:
|
||||
f.seek(0, os.SEEK_SET)
|
||||
else:
|
||||
f.seek(pos - 1, os.SEEK_SET)
|
||||
f.readline() # skip partial line
|
||||
|
||||
line = f.readline()
|
||||
|
||||
l2 = f.tell() # start of next line (or end of file)
|
||||
|
||||
if l2 == 1:
|
||||
# this is a corner case of a single empty first line.
|
||||
# we mast advance here or we'll have an endless loop
|
||||
begin = 1
|
||||
next
|
||||
|
||||
if line:
|
||||
key = line[:len(prefix)]
|
||||
|
||||
if key < prefix:
|
||||
# we are strictly before the target line.
|
||||
# so it starts at least from l2
|
||||
begin = max(begin, l2)
|
||||
|
||||
elif key > prefix:
|
||||
# we are strictly past the target line.
|
||||
# our target seeking position is less than current pos
|
||||
end = pos
|
||||
else:
|
||||
# current line is a possible target. it's reachable from
|
||||
# current 'pos', so `target pos is <= current pos`, or
|
||||
# `target post < current post + 1`
|
||||
end = min(end, pos + 1)
|
||||
|
||||
else:
|
||||
# we reached end of file. our current seeking position doesn't
|
||||
# correspond to any line
|
||||
end = min(end, pos)
|
||||
|
||||
# now we are at a *seeking position* for the target line. need to skip
|
||||
# to the actual line
|
||||
if begin == 0:
|
||||
f.seek(0, os.SEEK_SET)
|
||||
else:
|
||||
f.seek(begin - 1, os.SEEK_SET)
|
||||
f.readline()
|
||||
|
||||
while True:
|
||||
line = f.readline()
|
||||
if line.startswith(prefix):
|
||||
yield line
|
||||
else:
|
||||
break
|
||||
return
|
Reference in New Issue
Block a user