1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 07:00:04 +08:00

pref(bundle): update bundle deoplete

This commit is contained in:
wsdjeg 2022-04-23 12:09:55 +08:00
parent 023c48c740
commit b730079c88
50 changed files with 928 additions and 574 deletions

View File

@ -22,3 +22,4 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
- [deoplete-lsp](https://github.com/deoplete-plugins/deoplete-lsp/tree/6299a22bedfb4f814d95cb0010291501472f8fd0)
- [nvim-cmp](https://github.com/hrsh7th/nvim-cmp/tree/3192a0c57837c1ec5bf298e4f3ec984c7d2d60c0)
- [coc-neosnippet](https://github.com/notomo/cmp-neosnippet/tree/2d14526af3f02dcea738b4cea520e6ce55c09979)
- [deoplete](https://github.com/Shougo/deoplete.nvim/tree/1c40f648d2b00e70beb4c473b7c0e32b633bd9ae)

View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: Shougo # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -0,0 +1,64 @@
name: Lint, Test & Coverage
on: [push, pull_request]
jobs:
test:
name: Python ${{ matrix.python-version }} - Neovim (${{ matrix.build }})
runs-on: ubuntu-latest
strategy:
matrix:
python-version:
- 3.7
- 3.8
- 3.9
build:
- nightly
- stable
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f test/requirements.txt ]; then pip install -r test/requirements.txt; fi
- name: Initialize Neovim
uses: rhysd/action-setup-vim@v1
id: vim
with:
neovim: true
version: ${{ matrix.build }}
- name: Clone vim-themis
uses: actions/checkout@v2
with:
repository: thinca/vim-themis
path: vim-themis
- name: Run Lint & Test
run: make --keep-going THEMIS_VIM=${{ steps.vim.outputs.executable }} test lint
coverage:
name: Generate Codecav Report
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f test/requirements.txt ]; then pip install -r test/requirements.txt; fi
- name: Generate Report
run: pytest --cov=./rplugin/python3/deoplete --cov=./test --cov-report=xml
- uses: codecov/codecov-action@v1
with:
files: ./coverage.xml
functionalities: coveragepy, fix, gcov, search, xcode

View File

@ -1,22 +0,0 @@
dist: xenial
language: python
python:
- 3.6
- 3.7
install:
- eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64"
- make install
env:
global:
- PATH=$HOME/neovim/bin:$PATH
- PYTEST_ADDOPTS=--cov rplugin/python3/deoplete
script:
- make --keep-going test lint
- coverage report -m --skip-covered
- coverage xml
- bash <(curl -s https://codecov.io/bash) -X gcov -X coveragepy -X fix -X search -X xcode -f coverage.xml

View File

@ -2,10 +2,19 @@
> Dark powered asynchronous completion framework for neovim/Vim8
[![Build Status](https://travis-ci.org/Shougo/deoplete.nvim.svg?branch=master)](https://travis-ci.org/Shougo/deoplete.nvim)
**Note**: The development of this plugin is finished. Accepts minor patches and
issues but no new features.
[ddc.vim](https://github.com/Shougo/ddc.vim) is the next generation auto
completion plugin. Consider migrating to it.
[![Join the chat at https://gitter.im/Shougo/deoplete.nvim](https://badges.gitter.im/Shougo/deoplete.nvim.svg)](https://gitter.im/Shougo/deoplete.nvim?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Doc](https://img.shields.io/badge/doc-%3Ah%20deoplete-orange.svg)](doc/deoplete.txt)
Please read [help](doc/deoplete.txt) for details.
Note: If you need to understand what's different between deoplete and other
similar plugins, please read "deoplete-faq" section in the documentation.
Deoplete is the abbreviation of "dark powered neo-completion". It
provides an extensible and asynchronous completion framework for
neovim/Vim8.
@ -26,7 +35,7 @@ Here are some [completion sources](https://github.com/Shougo/deoplete.nvim/wiki/
## Install
**Note:** deoplete requires Neovim (0.3.0+ and of course, **latest** is
recommended) or Vim8 with Python 3.6.1+ and timers enabled. See
recommended) or Vim8.1 with Python 3.6.1+ and timers enabled. See
[requirements](#requirements) if you aren't sure whether you have this.
Note: deoplete requires msgpack package 1.0.0+.
@ -75,7 +84,8 @@ For manual installation(not recommended)
deoplete requires Neovim or Vim8 with `if_python3`.
If `:echo has("python3")` returns `1`, then you have python 3 support; otherwise, see below.
If `:echo has("python3")` returns `1`, then you have python 3 support;
otherwise, see below.
You can enable Python3 interface with pip:
@ -157,3 +167,5 @@ Deoplete for JavaScript
![Rust using rls](https://user-images.githubusercontent.com/1750795/38780764-8524b0b8-40a9-11e8-91bc-6e4148c398a3.png)
![Ruby dictionary completion](https://user-images.githubusercontent.com/1314340/44786516-5bb57a00-abcf-11e8-8687-492fa5f9f905.gif)
![LanguageClient-neovim integration](https://user-images.githubusercontent.com/4245199/87716288-efd25f80-c7ae-11ea-8080-334d155b3155.png)

View File

@ -72,7 +72,6 @@ function! deoplete#close_popup() abort
return pumvisible() ? "\<C-y>" : ''
endfunction
function! deoplete#smart_close_popup() abort
call deoplete#handler#_skip_next_completion()
return pumvisible() ? "\<C-e>" : ''
endfunction
function! deoplete#cancel_popup() abort
@ -88,3 +87,7 @@ endfunction
function! deoplete#complete_common_string() abort
return deoplete#mapping#_complete_common_string()
endfunction
function! deoplete#can_complete() abort
return !empty(get(get(g:, 'deoplete#_context', {}), 'candidates', []))
\ && deoplete#mapping#_can_complete()
endfunction

View File

@ -18,10 +18,10 @@ function! deoplete#custom#_init() abort
let s:cached.source_vars = {}
endfunction
function! deoplete#custom#_init_buffer() abort
let b:custom = {}
let b:custom.option = {}
let b:custom.source_vars = {}
let b:custom.filter = {}
let b:deoplete_custom = {}
let b:deoplete_custom.option = {}
let b:deoplete_custom.source_vars = {}
let b:deoplete_custom.filter = {}
endfunction
function! deoplete#custom#_update_cache() abort
@ -65,11 +65,11 @@ function! deoplete#custom#_get() abort
return s:custom
endfunction
function! deoplete#custom#_get_buffer() abort
if !exists('b:custom')
if !exists('b:deoplete_custom')
call deoplete#custom#_init_buffer()
endif
return b:custom
return b:deoplete_custom
endfunction
function! deoplete#custom#_get_source(source_name) abort
@ -92,8 +92,14 @@ function! deoplete#custom#_get_filetype_option(name, filetype, default) abort
endif
let option = s:cached.option[a:name]
let filetype = has_key(option, a:filetype) ? a:filetype : '_'
return get(option, filetype, a:default)
" Check filetype -> a.b filetype -> '_'
for filetype in [a:filetype] + split(a:filetype, '\.') + ['_']
if has_key(option, filetype)
return option[filetype]
endif
endfor
return a:default
endfunction
function! deoplete#custom#_get_source_vars(name) abort
return get(s:cached.source_vars, a:name, {})

View File

@ -14,7 +14,7 @@ function! deoplete#handler#_init() abort
for event in [
\ 'InsertEnter', 'InsertLeave',
\ 'BufReadPost', 'BufWritePost',
\ 'VimLeavePre',
\ 'VimLeavePre', 'FileType',
\ ]
call s:define_on_event(event)
endfor
@ -26,11 +26,7 @@ function! deoplete#handler#_init() abort
call s:define_completion_via_timer('InsertEnter')
endif
if deoplete#custom#_get_option('refresh_always')
if exists('##TextChangedP')
call s:define_completion_via_timer('TextChangedP')
else
call s:define_completion_via_timer('InsertCharPre')
endif
call s:define_completion_via_timer('TextChangedP')
endif
" Note: Vim 8 GUI(MacVim and Win32) is broken
@ -51,11 +47,7 @@ function! deoplete#handler#_do_complete() abort
let context = g:deoplete#_context
let event = get(context, 'event', '')
if s:is_exiting() || v:insertmode !=# 'i' || s:check_input_method()
return
endif
if !has_key(context, 'candidates')
\ || deoplete#util#get_input(context.event) !=# context.input
\ || !has_key(context, 'candidates')
return
endif
@ -65,6 +57,11 @@ function! deoplete#handler#_do_complete() abort
let prev.candidates = context.candidates
let prev.complete_position = context.complete_position
let prev.linenr = line('.')
let prev.time = context.time
if context.event ==# 'Manual'
let context.event = ''
endif
let auto_popup = deoplete#custom#_get_option(
\ 'auto_complete_popup') !=# 'manual'
@ -74,13 +71,10 @@ function! deoplete#handler#_do_complete() abort
let auto_popup = v:true
endif
if context.event ==# 'Manual'
let context.event = ''
elseif !exists('g:deoplete#_saved_completeopt') && auto_popup
call deoplete#mapping#_set_completeopt()
endif
if auto_popup
" Note: completeopt must be changed before complete() and feedkeys()
call deoplete#mapping#_set_completeopt(g:deoplete#_context.is_async)
call feedkeys("\<Plug>_", 'i')
endif
endfunction
@ -108,16 +102,8 @@ function! deoplete#handler#_check_omnifunc(context) abort
let prev.input = a:context.input
let prev.candidates = []
if &completeopt =~# 'noselect'
call deoplete#mapping#_set_completeopt()
call feedkeys("\<C-x>\<C-o>", 'in')
else
call deoplete#util#print_error(
\ 'omni_patterns feature is disabled.')
call deoplete#util#print_error(
\ 'You need to set "noselect" in completeopt option.')
endif
return 1
call deoplete#mapping#_set_completeopt(v:true)
call feedkeys("\<C-x>\<C-o>", 'in')
endif
endfor
endfor
@ -145,7 +131,7 @@ function! s:completion_timer_stop() abort
unlet s:completion_timer
endfunction
function! s:check_prev_completion(event) abort
function! deoplete#handler#_check_prev_completion(event) abort
let prev = g:deoplete#_prev_completion
if a:event ==# 'Async' || a:event ==# 'Update' || mode() !=# 'i'
\ || empty(get(prev, 'candidates', []))
@ -160,8 +146,6 @@ function! s:check_prev_completion(event) abort
return
endif
call deoplete#mapping#_set_completeopt()
let mode = deoplete#custom#_get_option('prev_completion_mode')
let candidates = copy(prev.candidates)
@ -169,9 +153,9 @@ function! s:check_prev_completion(event) abort
let input = input[prev.complete_position :]
let escaped_input = escape(input, '~\.^$[]*')
let pattern = substitute(escaped_input, '\w', '\\w*\0', 'g')
call filter(candidates, 'v:val.word =~? pattern')
call filter(candidates, { _, val -> val.word =~? pattern })
if mode ==# 'length'
call filter(candidates, 'len(v:val.word) > len(input)')
call filter(candidates, { _, val -> len(val.word) > len(input) })
endif
elseif mode ==# 'mirror'
" pass
@ -183,7 +167,7 @@ function! s:check_prev_completion(event) abort
\ 'complete_position': prev.complete_position,
\ 'candidates': candidates,
\ }
call feedkeys("\<Plug>+", 'i')
return 1
endfunction
function! deoplete#handler#_async_timer_start() abort
@ -198,12 +182,26 @@ endfunction
function! deoplete#handler#_completion_begin(event) abort
call deoplete#custom#_update_cache()
if s:is_skip(a:event)
let auto_popup = deoplete#custom#_get_option(
\ 'auto_complete_popup') !=# 'manual'
let prev_input = get(g:deoplete#_context, 'input', '')
let cur_input = deoplete#util#get_input(a:event)
let check_back_space = auto_popup
\ && cur_input !=# prev_input
\ && len(cur_input) + 1 ==# len(prev_input)
\ && stridx(prev_input, cur_input) == 0
let refresh_backspace = deoplete#custom#_get_option('refresh_backspace')
if s:is_skip(a:event) || (check_back_space && !refresh_backspace)
let g:deoplete#_context.candidates = []
let g:deoplete#_context.input = cur_input
return
endif
call s:check_prev_completion(a:event)
if auto_popup && deoplete#handler#_check_prev_completion(a:event)
call feedkeys("\<Plug>+", 'i')
endif
if a:event !=# 'Update' && a:event !=# 'Async'
call deoplete#init#_prev_completion()
@ -211,6 +209,11 @@ function! deoplete#handler#_completion_begin(event) abort
call deoplete#util#rpcnotify(
\ 'deoplete_auto_completion_begin', {'event': a:event})
" For <BS> popup flicker
if check_back_space && empty(v:completed_item)
call feedkeys("\<Plug>_", 'i')
endif
endfunction
function! s:is_skip(event) abort
if a:event ==# 'TextChangedP' && !empty(v:completed_item)
@ -231,11 +234,19 @@ function! s:is_skip(event) abort
return 1
endif
" Check nofile buffers
if &l:buftype =~# 'nofile' && bufname('%') !=# '[Command Line]'
let nofile_complete_filetypes = deoplete#custom#_get_option(
\ 'nofile_complete_filetypes')
if index(nofile_complete_filetypes, &l:filetype) < 0
return 1
endif
endif
let auto_complete = deoplete#custom#_get_option('auto_complete')
if &paste
\ || (a:event !=# 'Manual' && a:event !=# 'Update' && !auto_complete)
\ || (&l:completefunc !=# '' && &l:buftype =~# 'nofile')
\ || v:insertmode !=# 'i'
return 1
endif
@ -266,6 +277,11 @@ function! s:is_skip_prev_text(event) abort
endfunction
function! s:is_skip_text(event) abort
let input = deoplete#util#get_input(a:event)
if !has('nvim') && iconv(iconv(input, 'utf-8', 'utf-16'),
\ 'utf-16', 'utf-8') !=# input
" In Vim8, invalid bytes brokes nvim-yarp.
return 1
endif
let lastchar = matchstr(input, '.$')
let skip_multibyte = deoplete#custom#_get_option('skip_multibyte')
@ -280,12 +296,17 @@ function! s:is_skip_text(event) abort
\ && displaywidth >= &l:textwidth
if &l:formatoptions =~# '[ta]'
\ || !empty(filter(deoplete#util#get_syn_names(),
\ "v:val ==# 'Comment'"))
\ { _, val -> val ==# 'Comment' }))
\ || is_virtual
return 1
endif
endif
if a:event =~# '^TextChanged' && s:matched_indentkeys(input) !=# ''
call deoplete#util#indent_current_line()
return 1
endif
let skip_chars = deoplete#custom#_get_option('skip_chars')
return (a:event !=# 'Manual' && input !=# ''
@ -294,6 +315,32 @@ endfunction
function! s:check_input_method() abort
return exists('*getimstatus') && getimstatus()
endfunction
function! s:matched_indentkeys(input) abort
if &l:indentexpr ==# ''
" Disable auto indent
return ''
endif
" Note: check the last word
let checkstr = matchstr(a:input, '\w\+$')
for word in filter(map(split(&l:indentkeys, ','),
\ { _, val -> matchstr(val, 'e\|=\zs.*') }),
\ { _, val -> val !=# '' && val =~# '\h\w*' })
if word ==# 'e'
let word = 'else'
endif
let lastpos = len(a:input) - len(word)
if checkstr ==# word || (word =~# '^\W\+$' &&
\ lastpos >= 0 && strridx(a:input, word) == lastpos)
return word
endif
endfor
return ''
endfunction
function! s:define_on_event(event) abort
if !exists('##' . a:event)
@ -325,11 +372,27 @@ endfunction
function! s:on_complete_done() abort
if get(v:completed_item, 'word', '') ==# ''
\ || !has_key(g:deoplete#_context, 'complete_str')
return
endif
call deoplete#handler#_skip_next_completion()
let max_used = 100
let g:deoplete#_recently_used = insert(
\ g:deoplete#_recently_used,
\ tolower(v:completed_item.word),
\ )
let min_pattern_length = deoplete#custom#_get_option('min_pattern_length')
if len(g:deoplete#_context['complete_str']) > min_pattern_length
let g:deoplete#_recently_used = insert(
\ g:deoplete#_recently_used,
\ tolower(g:deoplete#_context['complete_str']),
\ )
endif
let g:deoplete#_recently_used = deoplete#util#uniq(
\ g:deoplete#_recently_used)[: max_used]
let user_data = get(v:completed_item, 'user_data', '')
if type(user_data) !=# v:t_string || user_data ==# ''
return

View File

@ -38,7 +38,7 @@ function! deoplete#init#_channel() abort
return 1
endif
let python3 = get(g:, 'python3_host_prog', 'python3')
let python3 = expand(get(g:, 'python3_host_prog', 'python3'), 1)
if !executable(python3)
call deoplete#util#print_error(
\ string(python3) . ' is not executable.')
@ -49,8 +49,8 @@ function! deoplete#init#_channel() abort
call deoplete#util#print_error('deoplete requires nvim 0.3.0+.')
return 1
endif
if !has('nvim') && v:version < 800
call deoplete#util#print_error('deoplete requires Vim 8.0+.')
if !has('nvim') && v:version < 801
call deoplete#util#print_error('deoplete requires Vim 8.1+.')
return 1
endif
@ -112,6 +112,7 @@ function! s:init_internal_variables() abort
call deoplete#init#_prev_completion()
let g:deoplete#_context = {}
let g:deoplete#_recently_used = []
if !exists('g:deoplete#_logging')
let g:deoplete#_logging = {}
@ -136,7 +137,7 @@ function! s:init_internal_variables() abort
if deoplete#util#has_yarp()
" Dummy call is needed to check exists()
call neovim_rpc#serveraddr()
silent! call neovim_rpc#serveraddr()
if !exists('*neovim_rpc#serveraddr')
call deoplete#util#print_error(
\ 'deoplete requires vim-hug-neovim-rpc plugin in Vim.')
@ -220,7 +221,8 @@ function! s:check_custom_var(source_name, old_var, new_var) abort
call deoplete#util#print_error(
\ printf('%s is deprecated variable. '.
\ 'Please use deoplete#custom#var() instead.', a:old_var))
\ 'Please use deoplete#custom#var("%s", "%s", {value}) instead.',
\ a:old_var, a:source_name, a:new_var))
call deoplete#custom#var(a:source_name, a:new_var, eval(a:old_var))
endfunction
function! s:check_custom_option(old_var, new_var) abort
@ -230,36 +232,36 @@ function! s:check_custom_option(old_var, new_var) abort
call deoplete#util#print_error(
\ printf('%s is deprecated variable. '.
\ 'Please use deoplete#custom#option() instead.', a:old_var))
\ 'Please use deoplete#custom#option("%s", {value}) instead.',
\ a:old_var, a:new_var))
call deoplete#custom#option(a:new_var, eval(a:old_var))
endfunction
function! deoplete#init#_option() abort
" Note: HTML omni func use search().
return {
\ 'auto_complete': v:true,
\ 'auto_complete_delay': 0,
\ 'auto_complete_popup': 'auto',
\ 'auto_refresh_delay': 100,
\ 'camel_case': v:false,
\ 'auto_refresh_delay': 20,
\ 'candidate_marks': [],
\ 'overwrite_completeopt': v:true,
\ 'check_stderr': v:true,
\ 'complete_suffix': v:true,
\ 'ignore_case': &ignorecase,
\ 'ignore_sources': {},
\ 'keyword_patterns': {'_': '[a-zA-Z_]\k*'},
\ 'max_list': 500,
\ 'min_pattern_length': 2,
\ 'num_processes': 4,
\ 'num_processes': 1,
\ 'nofile_complete_filetypes': ['denite-filter'],
\ 'omni_patterns': {},
\ 'on_insert_enter': v:true,
\ 'on_text_changed_i': v:true,
\ 'prev_completion_mode': '',
\ 'prev_completion_mode': 'filter',
\ 'profile': v:false,
\ 'refresh_always': v:true,
\ 'refresh_backspace': v:true,
\ 'skip_chars': ['(', ')'],
\ 'skip_multibyte': v:false,
\ 'smart_case': &smartcase,
\ 'sources': {},
\ 'trigger_key': v:char,
\ 'yarp': v:false,
@ -272,6 +274,7 @@ function! deoplete#init#_prev_completion() abort
\ 'linenr': -1,
\ 'candidates': [],
\ 'complete_position': -1,
\ 'time': reltime(),
\ }
endfunction

View File

@ -10,6 +10,12 @@ function! deoplete#mapping#_init() abort
\ deoplete#mapping#_dummy('deoplete#mapping#_complete')
inoremap <expr><silent> <Plug>+
\ deoplete#mapping#_dummy('deoplete#mapping#_prev_complete')
" Note: The dummy mappings may be inserted on other modes.
cnoremap <silent> <Plug>_ <Nop>
cnoremap <silent> <Plug>+ <Nop>
noremap <silent> <Plug>_ <Nop>
noremap <silent> <Plug>+ <Nop>
endfunction
function! deoplete#mapping#_dummy(func) abort
return "\<C-r>=".a:func."()\<CR>"
@ -35,16 +41,41 @@ function! s:check_completion_info(candidates) abort
endif
return 0
let old_candidates = sort(map(copy(info.items), 'v:val.word'))
return sort(map(copy(a:candidates), 'v:val.word')) ==# old_candidates
let old_candidates = sort(map(copy(info.items), { _, val -> val.word }))
return sort(map(copy(a:candidates),
\ { _, val -> val.word })) ==# old_candidates
endfunction
function! deoplete#mapping#_can_complete() abort
let context = get(g:, 'deoplete#_context', {})
return has_key(context, 'candidates') && has_key(context, 'event')
\ && has_key(context, 'input')
\ && !s:check_completion_info(context.candidates)
\ && &modifiable
endfunction
function! deoplete#mapping#_complete() abort
if !has_key(g:deoplete#_context, 'candidates')
\ || s:check_completion_info(g:deoplete#_context.candidates)
\ || !&modifiable
if !deoplete#mapping#_can_complete()
let g:deoplete#_context.candidates = []
return ''
endif
if deoplete#util#get_input(g:deoplete#_context.event)
\ !=# g:deoplete#_context.input
" Use prev completion instead
if deoplete#handler#_check_prev_completion(g:deoplete#_context.event)
call feedkeys("\<Plug>+", 'i')
endif
return ''
endif
let auto_popup = deoplete#custom#_get_option(
\ 'auto_complete_popup') !=# 'manual'
if auto_popup
" Note: completeopt must be changed before complete()
call deoplete#mapping#_set_completeopt(g:deoplete#_context.is_async)
endif
" echomsg string(g:deoplete#_context)
if empty(g:deoplete#_context.candidates) && deoplete#util#check_popup()
" Note: call complete() to close the popup
@ -62,20 +93,34 @@ function! deoplete#mapping#_prev_complete() abort
return ''
endif
let auto_popup = deoplete#custom#_get_option(
\ 'auto_complete_popup') !=# 'manual'
if auto_popup
" Note: completeopt must be changed before complete()
call deoplete#mapping#_set_completeopt(v:false)
endif
call complete(g:deoplete#_filtered_prev.complete_position + 1,
\ g:deoplete#_filtered_prev.candidates)
return ''
endfunction
function! deoplete#mapping#_set_completeopt() abort
if exists('g:deoplete#_saved_completeopt')
function! deoplete#mapping#_set_completeopt(is_async) abort
if !deoplete#custom#_get_option('overwrite_completeopt')
return
endif
let g:deoplete#_saved_completeopt = &completeopt
if !exists('g:deoplete#_saved_completeopt')
let g:deoplete#_saved_completeopt = &completeopt
endif
set completeopt-=longest
set completeopt+=menuone
set completeopt-=menu
if &completeopt !~# 'noinsert\|noselect'
if &completeopt !~# 'noinsert\|noselect' || a:is_async
" Note: If is_async, noselect is needed to prevent without confirmation
" problem
set completeopt-=noinsert
set completeopt+=noselect
endif
endfunction
@ -117,16 +162,9 @@ function! deoplete#mapping#_complete_common_string() abort
return ''
endif
let complete_str = prev.input[prev.complete_position :]
let candidates = filter(copy(prev.candidates),
\ 'stridx(tolower(v:val.word), tolower(complete_str)) == 0')
if empty(candidates) || complete_str ==# ''
return ''
endif
let common_str = candidates[0].word
for candidate in candidates[1:]
let complete_str = deoplete#util#get_input('')[prev.complete_position :]
let common_str = prev.candidates[0].word
for candidate in prev.candidates[1:]
while stridx(tolower(candidate.word), tolower(common_str)) != 0
let common_str = common_str[: -2]
endwhile

View File

@ -35,10 +35,6 @@ function! deoplete#util#get_input(event) abort
\ '^.*\%' . (mode ==# 'i' ? col('.') : col('.') - 1)
\ . 'c' . (mode ==# 'i' ? '' : '.'))
if a:event ==# 'InsertCharPre'
let input .= v:char
endif
return input
endfunction
function! deoplete#util#get_next_input(event) abort
@ -88,7 +84,7 @@ function! s:vimoption2python(option) abort
endfunction
function! deoplete#util#uniq(list) abort
let list = map(copy(a:list), '[v:val, v:val]')
let list = map(copy(a:list), { _, val -> [val, val] })
let i = 0
let seen = {}
while i < len(list)
@ -100,7 +96,7 @@ function! deoplete#util#uniq(list) abort
let i += 1
endif
endwhile
return map(list, 'v:val[0]')
return map(list, { _, val -> val[0] })
endfunction
function! deoplete#util#get_syn_names() abort
@ -183,8 +179,8 @@ endfunction
" >0 if a > b
" 0 if versions are equal.
function! deoplete#util#versioncmp(a, b) abort
let a = map(split(a:a, '\.'), 'str2nr(v:val)')
let b = map(split(a:b, '\.'), 'str2nr(v:val)')
let a = map(split(a:a, '\.'), { _, val -> str2nr(val) })
let b = map(split(a:b, '\.'), { _, val -> str2nr(val) })
let l = min([len(a), len(b)])
let d = 0
@ -213,3 +209,17 @@ endfunction
function! deoplete#util#check_popup() abort
return exists('*complete_info') && complete_info().mode ==# 'eval'
endfunction
function! deoplete#util#indent_current_line() abort
let pos = getpos('.')
let len = len(getline('.'))
let equalprg = &l:equalprg
try
setlocal equalprg=
silent normal! ==
finally
let &l:equalprg = equalprg
let pos[2] += len(getline('.')) - len
call setpos('.', pos)
endtry
endfunction

View File

@ -59,11 +59,11 @@ function! s:still_have_issues() abort
let indentation = ' '
call health#report_info("If you're still having problems, " .
\ "try the following commands:\n" .
\ indentation . "$ export NVIM_PYTHON_LOG_FILE=/tmp/log\n" .
\ indentation . "$ export NVIM_PYTHON_LOG_LEVEL=DEBUG\n" .
\ indentation . "$ nvim\n" .
\ indentation . "$ cat /tmp/log_{PID}\n" .
\ indentation . ' and then create an issue on github'
\ indentation . "- $ export NVIM_PYTHON_LOG_FILE=/tmp/log\n" .
\ indentation . "- $ export NVIM_PYTHON_LOG_LEVEL=DEBUG\n" .
\ indentation . "- $ nvim\n" .
\ indentation . "- $ cat /tmp/log_{PID}\n" .
\ indentation . '- and then create an issue on github'
\ )
endfunction

View File

@ -1,8 +0,0 @@
coverage:
status:
project: false
patch: true
changes: true
comment:
layout: "diff"

View File

@ -1,6 +1,6 @@
*deoplete.txt* Dark powered asynchronous completion framework for Neovim/Vim8
Version: 6.0
Version: 6.2
Author: Shougo <Shougo.Matsu at gmail.com>
License: MIT license
@ -30,14 +30,14 @@ Compatibility |deoplete-compatibility|
INTRODUCTION *deoplete-introduction*
*deoplete* is the abbreviation of "dark powered neo-completion". It
provides asynchronous keyword completion system in the
provides an asynchronous keyword completion system in the
current buffer.
Note: deoplete may consume more memory than other plugins do.
Improvements in deoplete in comparison to |neocomplete|:
Improvements in deoplete in comparison to neocomplete:
1. Real asynchronous completion behavior like |YouCompleteMe| by default.
1. Real asynchronous completion behavior like YouCompleteMe by default.
2. Uses Python3 to implement sources.
3. Removes legacy interface.
4. Requires |+python3|.
@ -45,8 +45,8 @@ Improvements in deoplete in comparison to |neocomplete|:
==============================================================================
INSTALL *deoplete-install*
Note: deoplete requires Neovim (0.3.0+) or Vim8 (latest is recommended) with
Python 3.6.1+ and |+timers| enabled.
Note: deoplete requires Neovim (0.3.0+) or Vim8.1+ (latest is recommended)
with Python 3.6.1+ and |+timers| enabled.
Please install/upgrade msgpack package (1.0.0+).
https://github.com/msgpack/msgpack-python
@ -113,7 +113,7 @@ auto_complete
auto_complete_delay
Delay the completion after input in milliseconds.
Default value: 0 (milliseconds)
Default value: 20 (milliseconds)
*deoplete-options-auto_complete_popup*
auto_complete_popup
@ -131,21 +131,19 @@ auto_refresh_delay
Default value: 100 (milliseconds)
*deoplete-options-camel_case*
camel_case
If it is True, lowercase letters are also matched with the
corresponding uppercase ones.
Ex: "foB" is matched with "FooBar" but not with "foobar".
Note: This feature is only available in
|deoplete-filter-matcher_fuzzy| or
|deoplete-filter-matcher_full_fuzzy|.
Default value: v:false
*deoplete-options-candidate_marks*
candidate_marks
The candidate additional marks.
If set, this will be used to display an additional mark next
to the the first {N} candidates. The first mark is used for
the top ranked candidate, the second for the second candidate
and so forth.
In the example below, the first 5 candidates are marked A..G,
which serve as mnemonics for commands to insert that
candidate.
Default value: []
>
call deoplete#custom#option('candidate_marks',
@ -174,16 +172,11 @@ complete_suffix
Default value: v:true
*deoplete-options-ignore_case*
ignore_case
If it is True, deoplete ignores case.
Default value: same with your 'ignorecase' value
*deoplete-options-ignore_sources*
ignore_sources
It is a dictionary to decide ignore source names.
The key is filetype and the value is source names list.
Note: It is disabled in |deoplete#manual_complete()|.
Default value: {}
@ -209,15 +202,25 @@ max_list
Default value: 500
*deoplete-options-nofile_complete_filetypes*
nofile_complete_filetypes
If 'buftype' is "nofile", deoplete completion is disabled
automatically except the filetype list.
Default value: ["denite-filter"]
*deoplete-options-num_processes*
num_processes
The number of processes used for the deoplete parallel
feature.
completion feature.
The parallel completion increases the completion speed, but it
increases the screen flicker.
If it is 1, this feature is disabled.
If it is less than or equal to 0, the number of processes is
equal to that of sources.
Default value: 4
Default value: 1
*deoplete-options-omni_patterns*
omni_patterns
@ -260,6 +263,14 @@ on_text_changed_i
Deoplete enables the auto completion on |TextChangedI| autocmd
if this value is True.
Default value: v:true
*deoplete-options-overwrite_completeopt*
overwrite_completeopt
Deoplete overwrites 'completeopt' option.
You can disable the feature but if you change it, deoplete may
not work.
Default value: v:true
*deoplete-options-profile*
@ -289,13 +300,22 @@ prev_completion_mode
refresh_always
Deoplete refreshes the candidates automatically if this value
is True.
Note: It increases the screen flicker.
Note: It increases the screen flicker when
|deoplete-options-num_processes| != 0.
Default value: v:true
*deoplete-options-refresh_backspace*
refresh_backspace
Deoplete refreshes the candidates automatically when you
press <BS> or <C-h> key.
Default value: v:true
*deoplete-options-skip_multibyte*
skip_multibyte
Deoplete skip multibyte text completion automatically if this
Deoplete skips multibyte text completion automatically if this
value is True.
Default value: v:false
@ -306,20 +326,13 @@ skip_chars
Default value: ['(', ')']
*deoplete-options-smart_case*
smart_case
When a capital letter is included in input, deoplete does
not ignore the upper- and lowercase.
Default value: same with your 'smartcase' value
*deoplete-options-sources*
sources
It is a dictionary to specify source names. The key is
filetype and the value is source names list. If the key is
"_", the value will be used for default filetypes. For
example, you can load some sources in C++ filetype.
If the value is [], it will load all sources.
filetype and the value is a list of source names. If the key
is "_", the value will be used for default filetypes. For
example, you can load some sources in C++ filetype. If the
value is [], it will load all sources.
Default value: {}
>
@ -339,7 +352,7 @@ min_pattern_length
Default: 2
*deoplete-options-yarp*
*deoplete-options-yarp*
yarp
Use nvim-yarp library instead of neovim remote plugin feature.
Note: nvim-yarp plugin is needed.
@ -470,7 +483,7 @@ deoplete#custom#source({source-name}, {dict})
" Disable the candidates in Comment/String syntaxes.
call deoplete#custom#source('_',
\ 'disabled_syntaxes', ['Comment', 'String'])
\ 'disabled_syntaxes', ['Comment', 'String', 'Constant'])
" Change the truncate width.
call deoplete#custom#source('javacomplete2',
@ -492,7 +505,8 @@ deoplete#custom#source({source-name}, {dict})
" Enable jedi source debug messages
" call deoplete#custom#option('profile', v:true)
" call deoplete#enable_logging('DEBUG', 'deoplete.log')
" call deoplete#custom#source('jedi', 'is_debug_enabled', 1)
" call deoplete#custom#source('jedi',
\ 'is_debug_enabled', v:true)
<
*deoplete#custom#var()*
deoplete#custom#var({source-name}, {var-name}, {value})
@ -510,9 +524,14 @@ KEY MAPPINGS *deoplete-key-mappings*
deoplete#auto_complete([{event}])
It calls the auto completion of deoplete. You can use it to
call auto completion again.
{event} is autocmd event name. If it is omit, "Async" is
{event} is autocmd event name. If it is omitted, "Async" is
used.
*deoplete#can_complete()*
deoplete#can_complete()
Return v:true if current word completion is available.
Note: |deoplete-options-auto_complete_popup| must be "manual".
*deoplete#close_popup()*
deoplete#close_popup()
Insert candidate and close popup menu for deoplete.
@ -525,18 +544,18 @@ deoplete#complete()
*deoplete#complete_common_string()*
deoplete#complete_common_string()
complete common string in candidates. It will be convenient
when candidates have long common string.
complete common string in candidates.
This can be useful when candidates have a long common prefix.
Note: It must be in |:map-<expr>|.
*deoplete#insert_candidate()*
deoplete#insert_candidate({number})
Insert {number}th candidate.
deoplete#insert_candidate({index})
Insert the candidate at index {index}. Indices start at 0.
Note: It must be in |:map-<expr>|.
*deoplete#manual_complete()*
deoplete#manual_complete([{sources}])
It calls the completion of deoplete. You can use it with
Trigger deoplete completion. You can use it with
custom completion setups.
You can provide a list of {sources}: It can be the name of a
source or a list of sources name.
@ -544,16 +563,16 @@ deoplete#manual_complete([{sources}])
Note: It must be in |:map-<expr>|.
If you want to trigger deoplete manually, see also
|deoplete-options-auto_complete|, which should be 1 then
typically.
|deoplete-options-auto_complete|, which should typically then
be 1.
>
inoremap <silent><expr> <TAB>
\ pumvisible() ? "\<C-n>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ deoplete#manual_complete()
function! s:check_back_space() abort "{{{
let col = col('.') - 1
return !col || getline('.')[col - 1] =~ '\s'
let col = col('.') - 1
return !col || getline('.')[col - 1] =~ '\s'
endfunction"}}}
<
*deoplete#smart_close_popup()*
@ -566,13 +585,12 @@ deoplete#smart_close_popup()
inoremap <expr><BS>
\ deoplete#smart_close_popup()."\<C-h>"
<
Note: This mapping conflicts with |SuperTab| or |endwise|
plugins.
Note: This mapping conflicts with SuperTab or endwise plugins.
Note: This key mapping is for <C-h> or <BS> keymappings.
*deoplete#undo_completion()*
deoplete#undo_completion()
Undo inputted candidate.
Undo inserted candidate.
Note: It must be in |:map-<expr>|.
>
inoremap <expr><C-g> deoplete#undo_completion()
@ -583,7 +601,7 @@ EXAMPLES *deoplete-examples*
" Use deoplete.
let g:deoplete#enable_at_startup = 1
" Use smartcase.
call deoplete#custom#option('smart_case', v:true)
call deoplete#custom#source('_', 'smart_case', v:true)
" <CR>: close popup and save indent.
inoremap <silent> <CR> <C-r>=<SID>my_cr_function()<CR>
@ -656,15 +674,21 @@ file *deoplete-source-file*
Source custom variables:
enable_buffer_path
If it is True, file source completes the files
from the buffer path instead of the current
directory.
from the buffer directory instead of the
current directory.
(default: v:true)
enable_slash_completion
If it is True, file source completes the files
when user input "/".
(default: v:false)
force_completion_length
The completion length if the input does not
contain "/".
If it is less than 0, it is disabled.
(default: -1)
member *deoplete-source-member*
This source collects members from current buffer.
@ -706,7 +730,7 @@ omni *deoplete-source-omni*
setting.
(default: {})
>
call deoplete#custom#source('omni', 'functions', {
call deoplete#custom#var('omni', 'functions', {
\ 'javascript': ['tern#Complete', 'jspc#omni']
\})
<
@ -730,6 +754,10 @@ omni *deoplete-source-omni*
==============================================================================
FILTERS *deoplete-filters*
Once candidates have been supplied by one or more sources, they are passed
through the filters, which are matchers, converters or sorters. Sources can
have specific filters.
*deoplete-filter-matcher_default*
Default matchers: ['matcher_fuzzy']
@ -778,9 +806,13 @@ matcher_length
Length matching matcher.
It removes candidates shorter than or equal to the user input.
*deoplete-filter-matcher_matchfuzzy*
matcher_matchfuzzy
|matchfuzzy()| matcher.
*deoplete-filter-sorter_rank*
sorter_rank Matched rank order sorter. The higher the head matched word
or already typed word.
or already typed or inserted word.
The locality bonus feature is implemented like VSCode.
*deoplete-filter-sorter_word*
@ -889,8 +921,7 @@ converter_reorder_attr
*deoplete-filter-converter_auto_paren*
converter_auto_paren
It adds parentheses character in a candidate's word.
It is useful if you use |neopairs| or |neosnippet|
plugins.
It is useful if you use neopairs or neosnippet plugins.
*deoplete-filter-converter_case*
converter_case
@ -920,7 +951,10 @@ converter_truncate_info
converter_truncate_menu
It truncates a candidate's menu by the current window width.
==============================================================================
*deoplete-filter-converter_word_abbr*
converter_word_abbr
Convert candidate word to abbr.
CREATE SOURCE *deoplete-create-source*
To create source, you should read default sources implementation in
@ -928,7 +962,7 @@ rplugin/python3/deoplete/source/*.py.
The files are automatically loaded and deoplete creates new Source class
object.
Source class must extend Base class in ".base".
Source class must extend the Base class in ".base".
Note: The sources must be written in Python3 language.
@ -946,9 +980,20 @@ __init__ (Function)
*deoplete-source-attribute-__*
__{name} (Unspecified) (Optional)
Additional source information.
Note: Recommend sources save variables instead of
Note: Sources should save variables instead of
global variables.
*deoplete-source-attribute-camel_case*
camel_case
If it is True, lowercase letters are also matched with the
corresponding uppercase ones.
Ex: "foB" is matched with "FooBar" but not with "foobar".
Note: This feature is only available in
|deoplete-filter-matcher_fuzzy| or
|deoplete-filter-matcher_full_fuzzy|.
Default value: v:false
*deoplete-source-attribute-converters*
converters (List[str]) (Optional)
Source default converters list.
@ -989,40 +1034,58 @@ filetypes (List[str]) (Optional)
Available filetype list.
Default: []
Note: It means this source available in all filetypes.
Note: It means this source is available for all filetypes.
*deoplete-source-attribute-gather_candidates*
gather_candidates
(Function) (Required)
It is called to gather candidates.
It takes {self} and {context} as its parameter and returns a
It takes {self} and {context} as parameters and returns a
list of {candidate}.
If the error is occurred, it must return None.
If an error occurrs, it must return None.
{candidate} must be String or Dictionary contains
|deoplete-candidate-attributes|.
Here, {context} is the context information when the source is
called (|deoplete-notation-{context}|).
Note: The source must not filter the candidates by user input.
It is |deoplete-filters| work. If the source filter the
candidates, user cannot filter the candidates by fuzzy match.
Instead, let the |deoplete-filters| match and sort the
results. If the source filters the candidates, the user
cannot then filter the candidates by fuzzy match.
Instead, let the |deoplete-filters| match and sort the
results. If the source filters the candidates, the user
cannot then filter the candidates by fuzzy match.
candidates, the user cannot then filter the candidates by
fuzzy match.
*deoplete-source-attribute-get_complete_position*
get_complete_position
(Function) (Optional)
It is called to get complete position.
It is called to get the position of the current completion.
It takes {self} and {context} as its parameter and returns
complete position in current line.
Here, {context} is the context information when the source is
a number representing the starting position of the completion
in the current line.
Here, {context} is the context information from when the
source is called (|deoplete-notation-{context}|).
called (|deoplete-notation-{context}|).
Default: position using |deoplete-options-keyword_patterns|.
Note: If |deoplete-source-attribute-is_bytepos| is True, it
must return byte position.
This is useful if you want to complete terms that are more.
*deoplete-source-attribute-ignore_case*
ignore_case
If it is True, deoplete ignores case.
Default value: v:false
*deoplete-source-attribute-input_pattern*
input_pattern
(String) (Optional)
If it is matched with input, deoplete ignores
If it matches the input, deoplete ignores
|deoplete-source-attribute-min_pattern_length|.
It is useful for omni function sources.
Note: It is Python3 regexp.
@ -1036,7 +1099,7 @@ input_patterns
The dictionary version of
|deoplete-source-attribute-input_pattern|.
A key is filetype and a value is input pattern.
Note: It is Python3 regexp.
Note: Values are Python3 regexps.
*deoplete-source-attribute-is_bytepos*
is_bytepos
@ -1045,7 +1108,7 @@ is_bytepos
|deoplete-source-attribute-get_complete_position|
returns byteposition instead of character position.
It is useful for Vim script to create sources because Vim
script string uses byte position. Python string uses
script string uses byte position. Python strings use
character position.
Default: False
@ -1067,7 +1130,7 @@ is_silent
*deoplete-source-attribute-is_skip_langmap*
is_skip_langmap
(Bool) (Optional)
If it is True, the source skips the |langmap| completion.
If it is True, the source skips the 'langmap' completion.
Default: True
@ -1087,6 +1150,11 @@ is_volatile
*deoplete-source-attribute-mark*
mark (String) (Optional)
The mark of a source.
Note: If the source set candidate menu, the source must set
it. If the attribute is empty string, the candidate menu will
be disabled.
Default: ''
*deoplete-source-attribute-matchers*
matchers (List[str]) (Optional)
@ -1104,44 +1172,43 @@ matcher_key (String) (Optional)
*deoplete-source-attribute-max_abbr_width*
max_abbr_width
(Integer) (Optional)
If the candidate abbr length exceeds the length it will be cut
If the candidate abbr length exceeds this value, it will be
cut down.
down.
If it is less than or equal to 0, it will be disabled.
Default: 80
*deoplete-source-attribute-max_candidates*
max_candidates
(Integer) (Optional)
If the candidates are more than it, deoplete will ignore the
filtering.
If there are more candidates than this value, deoplete will
ignore the filtering.
Default: 500
*deoplete-source-attribute-max_kind_width*
max_kind_width
(Integer) (Optional)
If the candidate kind length exceeds the length it will be cut
down.
If it is less than or equal to 0, it will be disabled.
If the candidate kind length exceeds this value it will be
trimmed. If this value is less than or equal to 0, it will be
disabled.
Default: 40
*deoplete-source-attribute-max_info_width*
max_info_width
(Integer) (Optional)
If the candidate info length exceeds the length it will be cut
down.
If it is less than or equal to 0, it will be disabled.
If the candidate info length exceeds this value it is trimmed.
If this value is less than or equal to 0, it will be disabled.
Default: 200
*deoplete-source-attribute-max_menu_width*
max_menu_width
(Integer) (Optional)
If the candidate menu length exceeds the length it will be cut
If the candidate menu length exceeds this value it is trimmed.
down.
If it is less than or equal to 0, it will be disabled.
If this value is less than or equal to 0, it will be disabled.
Default: 40
@ -1199,6 +1266,13 @@ rank (Integer) (Optional)
Default: 100
*deoplete-source-attribute-smart_case*
smart_case
When a capital letter is included in input, deoplete does
not ignore the upper- and lowercase.
Default value: v:false
*deoplete-source-attribute-sorters*
sorters (List[str]) (Optional)
Source default sorters list.
@ -1249,6 +1323,9 @@ vars (Dictionary) (Optional)
The input string of the current line, namely the part
before the cursor.
is_refresh (Bool)
If the input is changed, it will be "True".
is_async (Bool)
If the gather is asynchronous, the source must set
it to "True". A typical strategy for an asynchronous
@ -1287,10 +1364,6 @@ vars (Dictionary) (Optional)
context['is_async'] = self._count < 10
return [context['input'].split()[-1] + str(self._count)]
<
is_refresh (Bool)
If the input is changed, it will be "True".
------------------------------------------------------------------------------
CANDIDATE ATTRIBUTES *deoplete-candidate-attributes*
@ -1333,6 +1406,9 @@ The files are automatically loaded and deoplete creates new Filter class
object.
Filter class must extend Base class in ".base".
Matchers, sorters and converters are all kinds of filters, and should all
be placed in the same filter directory.
Note: The filters must be written in Python3 language.
------------------------------------------------------------------------------
@ -1362,6 +1438,8 @@ filter
==============================================================================
EXTERNAL SOURCES *deoplete-external-sources*
Please see https://github.com/Shougo/deoplete.nvim/wiki/Completion-Sources
neco-vim: "vim" source for Vim script
https://github.com/Shougo/neco-vim
@ -1374,124 +1452,11 @@ https://github.com/Shougo/neoinclude.vim
neco-syntax: "syntax" source
https://github.com/Shougo/neco-syntax
vimshell: "vimshell" source for vimshell
https://github.com/Shougo/vimshell.vim
neco-ghc: "ghc" source for Haskell
https://github.com/eagletmt/neco-ghc
neco-look: "look" source to suggest words from sorted dictionary
https://github.com/ujihisa/neco-look
vim-racer: "racer" source for Rust
https://github.com/racer-rust/vim-racer
UltiSnips source: "ultisnips" source for UltiSnips
https://github.com/SirVer/ultisnips
clang-complete: "clang_complete" source for C/C++/Objective-C
https://github.com/Rip-Rip/clang_complete
deoplete-go: "go" source for Go
https://github.com/deoplete-plugins/deoplete-go
elixir.nvim: "elixir" source for Elixir
https://github.com/awetzel/elixir.nvim
deoplete-jedi: "jedi" source for Python
https://github.com/deoplete-plugins/deoplete-jedi
perlomni.vim: "PerlOmni" source for Perl
https://github.com/c9s/perlomni.vim
nvim-typescript: "typescript" source for typescript
https://github.com/mhartington/nvim-typescript
async-clj-omni: "async_clj" source for Clojure
https://github.com/SevereOverfl0w/async-clj-omni
deoplete-ternjs: "ternjs" source for JavaScript
https://github.com/carlitux/deoplete-ternjs
deoplete-swift: "swift" source for Swift
https://github.com/landaire/deoplete-swift
neovim-intellij-complete-deoplete: "intellij" source for Intellij IDE
https://github.com/vhakulinen/neovim-intellij-complete-deoplete
tmux-complete: "tmuxcomplete" source for tmux panes
https://github.com/wellle/tmux-complete.vim
deoplete-github: "github" source for "gitcommit" filetype
https://github.com/SevereOverfl0w/deoplete-github
deoplete-flow: "flow" source for JavaScript
https://github.com/steelsojka/deoplete-flow
deoplete-d: "d" source for D language
https://github.com/landaire/deoplete-d
deoplete-rtags: "rtags" source for "c", "cpp", "objc" and "objcpp" filetypes
https://github.com/LuXuryPro/deoplete-rtags
deoplete-solargraph "solargraph" source for Ruby language
https://github.com/uplus/deoplete-solargraph
deoplete-padawan: "padawan" source for padawan.php
https://github.com/pbogut/deoplete-padawan
webcomplete.vim: "webcomplete" source for browser opened pages
https://github.com/thalesmello/webcomplete.vim
deoplete-julia: "julia" source for Julia
https://github.com/JuliaEditorSupport/deoplete-julia
acid.nvim: "acid" source for Clojure
https://github.com/hkupty/acid.nvim
deoplete-omnisharp: "cs" source for C#
https://github.com/Robzz/deoplete-omnisharp/
deoplete-omnisharp: Improved version of deoplete-omnisharp
https://github.com/dimixar/deoplete-omnisharp/
deoplete-omnisharp: Embedded omnisharp server version of deoplete-omnisharp
https://github.com/cyansprite/deoplete-omnisharp
deoplete-hack: "hack" source for Hack and PHP
https://github.com/zefei/deoplete-hack
deoplete-laravel-plugin: "laravel-plugin" source for "php" and "blade"
filetypes
https://github.com/rafaelndev/deoplete-laravel-plugin
deoplete-zsh: "zsh" source for Zsh
https://github.com/deoplete-plugins/deoplete-zsh
deoplete-fish: "fish" source for fish shell
https://github.com/ponko2/deoplete-fish
deoplete-fsharp: "fsharp" source for F#
https://github.com/callmekohei/deoplete-fsharp
autocomplete-flow: "flow" source for JavaScript
https://github.com/wokalski/autocomplete-flow
deoplete-asm: "asm" source for Assembly Language
https://github.com/deoplete-plugins/deoplete-asm
deoplete-abook: "abook" source for abook contacts
https://github.com/fszymanski/deoplete-abook
deoplete-emoji: "emoji" source for emoji codes
https://github.com/fszymanski/deoplete-emoji
LanguageClient-neovim: "LanguageClient" source for Language Server
Protocol(LSP)
https://github.com/autozimu/LanguageClient-neovim
deoplete-vim-lsp: "lsp" source for vim-lsp
https://github.com/lighttiger2505/deoplete-vim-lsp
deoplete-lsp source for neovim builtin LSP features
https://github.com/deoplete-plugins/deoplete-lsp
deoplete-tags: "tag" source for tag files
https://github.com/deoplete-plugins/deoplete-tag
@ -1617,7 +1582,7 @@ A: Please enable logging feature like this. >
call deoplete#custom#option('profile', v:true)
call deoplete#enable_logging('DEBUG', 'deoplete.log')
call deoplete#custom#source('jedi', 'is_debug_enabled', 1)
call deoplete#custom#source('jedi', 'is_debug_enabled', v:true)
Q: "Channel id must be a positive integer" error.
https://github.com/Shougo/deoplete.nvim/issues/406
@ -1666,6 +1631,13 @@ Q: deoplete conflicts with lexima.vim
A: >
https://github.com/cohama/lexima.vim/issues/65#issuecomment-339338677
Q: Vim's build-in completion behavior(|i_CTRL-P| etc) is changed after
deoplete is enabled. The first entry is not inserted.
A: It is the feature of deoplete. The default insertion is disabled to enable
completion asynchronously. If you don't like the behavior, you should use
other auto completion plugin.
*deoplete-faq-config*
2. Configuration~
@ -1675,11 +1647,9 @@ Q: I want to silence the |ins-completion-menu| messages in the command line
A: You can disable the messages through the 'shortmess' option. >
if has("patch-7.4.314")
set shortmess+=c
endif
set shortmess+=c
Q: I want to use the auto select feature like |neocomplete|.
Q: I want to use the auto select feature like neocomplete.
A: You can use it by the 'completeopt' option. >
@ -1747,6 +1717,11 @@ Q: How can I sort all entries alphabetically?
A: >
call deoplete#custom#source('_', 'sorters', ['sorter_word'])
Q: I want to disable all sources marks.
A: >
call deoplete#custom#source('_', 'mark', '')
Q: I want to use head matcher instead of fuzzy matcher.
A: You can achieve this by following >
@ -1848,10 +1823,10 @@ A: >
inoremap <silent><expr> <TAB>
\ pumvisible() ? "\<C-n>" :
\ <SID>check_back_space() ? "\<Tab>" :
\ deoplete#complete()
\ deoplete#can_complete() ? deoplete#complete() : ''
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
Q: Why I have to trigger |deoplete#complete()| at least twice for the popup to
@ -1876,6 +1851,15 @@ If you really need the feature, it works for me. >
inoremap <expr> <C-h> pumvisible() ?
\ "\<C-h>" . deoplete#complete() : "\<C-h>"
<
Q: deoplete has the flicker issue when parallel completion feature is enabled.
A: I recommend for you to disable |deoplete-options-refresh_always|option when
you enable deoplete parallel completion. >
call deoplete#custom#option('num_processes', 4)
call deoplete#custom#option('refresh_always', v:false)
*deoplete-faq-ft-specific*
3. Filetype Specific Questions~
@ -1888,7 +1872,7 @@ A: Please use |deoplete-options-auto_complete|. >
Q: I want to use C/C++ omni completion with deoplete.
A: You should use |deoplete-clangx|.
A: You should use deoplete-clangx.
https://github.com/Shougo/deoplete-clangx
@ -1963,10 +1947,10 @@ A: >
Q: How to donate money to you?
A: I don't get the donation, but if you want to donate, please support neovim
project. My plugins depends on neovim development.
A: I have started github sponsorship to spend more time for Vim/neovim
plugins. You can donate money to help me!
https://salt.bountysource.com/teams/neovim
https://github.com/sponsors/Shougo
Q: What means "dark powered"?
@ -2005,6 +1989,11 @@ A: deoplete is:
If you don't like node.js based plugin or huge plugin base system, you
should not choose coc.nvim.
completion-nvim is Lua based plugin for neovim.
You cannot use it in Vim8.
If you like Lua, you don't use Vim8, and you don't like external
dependency, it is a better choice.
And the important view is the author.
If you like the author or the author created plugins, you should choose the
auto completion plugin.
@ -2021,9 +2010,26 @@ A: deoplete is:
I don't think deoplete is the best for everyone. Please choose auto
completion plugin.
Q: deoplete with coc.nvim does not work.
https://github.com/Shougo/deoplete.nvim/issues/1192
A: Unfortunately, both deoplete and coc.nvim provide auto completion feature.
So deoplete conflicts with coc.nvim.
You cannot use both. You need to choose coc.nvim or deoplete.
Note: But to change |deoplete-options-overwrite_completeopt| may work for
you.
==============================================================================
COMPATIBILITY *deoplete-compatibility*
2021.05.30
* "smart_case" and "ignore_case" and "camel_case" are source specific options
instead.
2020.11.07
* Disable nofile buffers completion except
deoplete-options-nofile_complete_filetypes.
2020.04.26
* Add deprecated variables warnings.

View File

@ -4,19 +4,19 @@
# License: MIT license
# ============================================================================
from importlib.util import find_spec
from pynvim import Nvim
import typing
from importlib.util import find_spec
from deoplete.deoplete import Deoplete
from deoplete.util import Nvim
if find_spec('yarp'):
try:
# For Vim8
import vim
elif find_spec('pynvim'):
except ModuleNotFoundError:
# For neovim
# Note: neovim cannot import vim module
import pynvim as vim
else:
import neovim as vim
Context = typing.Dict[str, typing.Any]
@ -26,8 +26,8 @@ if hasattr(vim, 'plugin'):
@vim.plugin
class DeopleteHandlers(object):
def __init__(self, vim: Nvim):
self._vim = vim
def __init__(self, _vim: Nvim):
self._vim = _vim
@vim.function('_deoplete_init', sync=False) # type: ignore
def init_channel(self,

View File

@ -4,11 +4,12 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import typing
from abc import abstractmethod
from deoplete.logger import LoggingMixin
from deoplete.util import error_vim, Nvim, UserContext, Candidates
from deoplete.util import error_vim, UserContext, Candidates
class Base(LoggingMixin):
@ -22,14 +23,14 @@ class Base(LoggingMixin):
def on_event(self, context: UserContext) -> None:
pass
def get_var(self, var_name: str) -> typing.Optional[typing.Any]:
def get_var(self, var_name: str) -> typing.Any:
custom_vars = self.vim.call(
'deoplete#custom#_get_filter', self.name)
if var_name in custom_vars:
return custom_vars[var_name]
if var_name in self.vars:
return self.vars[var_name]
return None
return ''
@abstractmethod
def filter(self, context: UserContext) -> Candidates:

View File

@ -4,12 +4,13 @@
# License: MIT license
# ============================================================================
from abc import abstractmethod
from pynvim import Nvim
import re
import typing
from abc import abstractmethod
from deoplete.logger import LoggingMixin
from deoplete.util import debug, error_vim, Nvim, UserContext, Candidates
from deoplete.util import debug, error_vim, UserContext, Candidates
class Base(LoggingMixin):
@ -51,6 +52,9 @@ class Base(LoggingMixin):
self.max_candidates = 500
self.matcher_key = ''
self.dup = False
self.ignore_case = False
self.smart_case = False
self.camel_case = False
def get_complete_position(self, context: UserContext) -> int:
m = re.search('(?:' + context['keyword_pattern'] + ')$|$',
@ -72,14 +76,14 @@ class Base(LoggingMixin):
def on_event(self, context: UserContext) -> None:
pass
def get_var(self, var_name: str) -> typing.Optional[typing.Any]:
def get_var(self, var_name: str) -> typing.Any:
custom_vars = self.vim.call(
'deoplete#custom#_get_source_vars', self.name)
if var_name in custom_vars:
return custom_vars[var_name]
if var_name in self.vars:
return self.vars[var_name]
return None
return ''
def get_filetype_var(self, filetype: str,
var_name: str) -> typing.Optional[typing.Any]:

View File

@ -4,24 +4,24 @@
# License: MIT license
# ============================================================================
from collections import defaultdict
from pathlib import Path
from pynvim import Nvim
import copy
import os.path
import msgpack
import re
import sys
import time
import msgpack
import typing
from collections import defaultdict
from deoplete import logger
from deoplete.exceptions import SourceInitError
from deoplete.util import (bytepos2charpos, charpos2bytepos, error, error_tb,
import_plugin, get_custom, get_syn_names,
convert2candidates, uniq_list_dict, Nvim)
convert2candidates, uniq_list_dict)
UserContext = typing.Dict[str, typing.Any]
Candidates = typing.Dict[str, typing.Any]
Candidates = typing.List[typing.Dict[str, typing.Any]]
Result = typing.Dict[str, typing.Any]
@ -75,7 +75,8 @@ class Child(logger.LoggingMixin):
self._vim.call('deoplete#auto_complete', 'Update')
def main(self, name: str, args: typing.List[typing.Any],
queue_id: typing.Optional[int]) -> typing.Optional[Candidates]:
queue_id: typing.Optional[int]) -> typing.Optional[
typing.Dict[str, typing.Any]]:
ret = None
if name == 'enable_logging':
self._enable_logging()
@ -103,6 +104,9 @@ class Child(logger.LoggingMixin):
self.is_debug_enabled = True
def _add_source(self, path: str) -> None:
# Resolve symbolic link
path = str(Path(path).resolve())
source = None
try:
Source = import_plugin(path, 'source', 'Source')
@ -110,14 +114,15 @@ class Child(logger.LoggingMixin):
return
source = Source(self._vim)
name = os.path.splitext(os.path.basename(path))[0]
name = Path(path).stem
source.name = getattr(source, 'name', name)
source.path = path
if source.name in self._loaded_sources:
loaded_path = self._loaded_sources.get(source.name, '')
if source.name in self._loaded_sources and path != loaded_path:
# Duplicated name
error_tb(self._vim, 'Duplicated source: %s' % source.name)
error_tb(self._vim, 'path: "%s" "%s"' %
(path, self._loaded_sources[source.name]))
(path, loaded_path))
source = None
except Exception:
error_tb(self._vim, 'Could not load source: %s' % path)
@ -129,6 +134,9 @@ class Child(logger.LoggingMixin):
f'Loaded Source: {source.name} ({path})')
def _add_filter(self, path: str) -> None:
# Resolve symbolic link
path = str(Path(path).resolve())
f = None
try:
Filter = import_plugin(path, 'filter', 'Filter')
@ -136,14 +144,15 @@ class Child(logger.LoggingMixin):
return
f = Filter(self._vim)
name = os.path.splitext(os.path.basename(path))[0]
name = Path(path).stem
f.name = getattr(f, 'name', name)
f.path = path
if f.name in self._loaded_filters:
loaded_path = self._loaded_filters.get(f.name, '')
if f.name in self._loaded_filters and path != loaded_path:
# Duplicated name
error_tb(self._vim, 'Duplicated filter: %s' % f.name)
error_tb(self._vim, 'path: "%s" "%s"' %
(path, self._loaded_filters[f.name]))
(path, loaded_path))
f = None
except Exception:
# Exception occurred when loading a filter. Log stack trace.
@ -230,6 +239,8 @@ class Child(logger.LoggingMixin):
source.is_volatile, source.is_async)):
return self._prev_results[source.name]
ctx['bufpath'] = context['bufpath']
ctx['cwd'] = context['cwd']
ctx['is_async'] = False
ctx['is_refresh'] = True
ctx['max_abbr_width'] = min(source.max_abbr_width,
@ -248,6 +259,8 @@ class Child(logger.LoggingMixin):
if ctx['max_menu_width'] > 0:
ctx['max_menu_width'] = max(10, ctx['max_menu_width'])
self._set_context_case(source, ctx)
# Gathering
self._profile_start(ctx, source.name)
ctx['vars'] = self._vim.vars
@ -289,6 +302,19 @@ class Child(logger.LoggingMixin):
except Exception as exc:
self._handle_source_exception(source, exc)
def _set_context_case(self, source: typing.Any,
context: UserContext) -> None:
case = source.smart_case or source.camel_case
ignorecase = source.ignore_case
if case:
if re.search(r'[A-Z]', context['complete_str']):
ignorecase = False
else:
ignorecase = True
context['camelcase'] = source.camel_case
context['ignorecase'] = ignorecase
context['smartcase'] = source.smart_case
def _handle_source_exception(self,
source: typing.Any, exc: Exception) -> None:
if isinstance(exc, SourceInitError):
@ -330,8 +356,7 @@ class Child(logger.LoggingMixin):
error_tb(self._vim, 'Errors from: %s' % f)
def _get_candidates(self, result: Result,
context_input: str, next_input: str
) -> typing.Optional[Candidates]:
context_input: str, next_input: str) -> Candidates:
source = result['source']
# Gather async results
@ -339,7 +364,7 @@ class Child(logger.LoggingMixin):
self._gather_async_results(result, source)
if not result['candidates']:
return None
return []
# Source context
ctx = copy.copy(result['context'])
@ -349,14 +374,7 @@ class Child(logger.LoggingMixin):
ctx['complete_str'] = context_input[ctx['char_position']:]
ctx['is_sorted'] = False
# Set ignorecase
case = ctx['smartcase'] or ctx['camelcase']
if case:
if re.search(r'[A-Z]', ctx['complete_str']):
ctx['ignorecase'] = False
else:
ctx['ignorecase'] = True
ignorecase = ctx['ignorecase']
self._set_context_case(source, ctx)
# Match
matchers = [self._filters[x] for x
@ -397,14 +415,19 @@ class Child(logger.LoggingMixin):
for candidates in sorted_candidates:
ctx['candidates'] += candidates
ctx['ignorecase'] = ignorecase
# On post filter
if hasattr(source, 'on_post_filter'):
ctx['candidates'] = source.on_post_filter(ctx)
mark = source.mark + ' '
# Check user mark set
user_mark = self._vim.call(
'deoplete#custom#_get_source', source.name).get('mark', '')
if user_mark == '':
user_mark = self._vim.call(
'deoplete#custom#_get_source', '_').get('mark', mark)
refresh = False
refresh_always = self._vim.call(
'deoplete#custom#_get_option', 'refresh_always')
@ -418,10 +441,13 @@ class Child(logger.LoggingMixin):
for candidate in ctx['candidates']:
candidate['icase'] = 1
candidate['equal'] = refresh
candidate['source'] = source.name
# Set default menu
if (mark != ' ' and
candidate.get('menu', '').find(mark) != 0):
if user_mark == '':
# Disable menu
candidate['menu'] = ''
elif mark != ' ' and candidate.get('menu', '').find(mark) != 0:
candidate['menu'] = mark + candidate.get('menu', '')
if source.dup:
@ -431,7 +457,7 @@ class Child(logger.LoggingMixin):
# Remove duplicates
ctx['candidates'] = uniq_list_dict(ctx['candidates'])
return ctx['candidates'] # type: ignore
return list(ctx['candidates'])
def _itersource(self, context: UserContext
) -> typing.Generator[typing.Any, None, None]:
@ -443,7 +469,9 @@ class Child(logger.LoggingMixin):
'ignore_sources', ft, []))
for source_name, source in self._get_sources().items():
if source.filetypes is None or source_name in ignore_sources:
if source.filetypes is None or (
source_name in ignore_sources and
context['event'] != 'Manual'):
continue
if context['sources'] and source_name not in context['sources']:
continue
@ -509,10 +537,10 @@ class Child(logger.LoggingMixin):
context['input'].find(result['prev_input']) == 0)
def _is_skip(self, context: UserContext, source: typing.Any) -> bool:
if 'syntax_names' in context and source.disabled_syntaxes:
p = re.compile('(' + '|'.join(source.disabled_syntaxes) + ')$')
if next(filter(p.search, context['syntax_names']), None):
return True
if (context.get('syntax_names', []) and source.disabled_syntaxes
and len(set(context['syntax_names']) &
set(source.disabled_syntaxes)) > 0):
return True
iminsert = self._vim.call('getbufvar', '%', '&iminsert')
if iminsert == 1 and source.is_skip_langmap:
@ -536,11 +564,14 @@ class Child(logger.LoggingMixin):
Each item in `attrs` is the attribute name.
"""
attrs = (
'camel_case',
'converters',
'disabled_syntaxes',
'dup',
'filetypes',
'ignore_case',
'input_pattern',
'input_patterns',
'is_debug_enabled',
'is_silent',
'is_volatile',
@ -553,6 +584,7 @@ class Child(logger.LoggingMixin):
'max_menu_width',
'max_pattern_length',
'min_pattern_length',
'smart_case',
'sorters',
)

View File

@ -4,11 +4,12 @@
# License: MIT license
# ============================================================================
import os
from pathlib import Path
from pynvim import Nvim
import re
import typing
from deoplete.util import Nvim
from deoplete.util import exists_path
UserContext = typing.Dict[str, typing.Any]
@ -48,6 +49,7 @@ class Context(object):
'deoplete#util#get_next_input', event),
'position': self._vim.call('getpos', '.'),
'same_filetypes': same_filetypes,
'time': self._vim.call('reltime'),
}
context.update(self._cached) # type: ignore
@ -79,26 +81,20 @@ class Context(object):
bufname = self._vim.call('bufname', bufnr)
cwd = self._vim.call('getcwd')
buftype = self._vim.call('getbufvar', '%', '&buftype')
bufpath = (bufname if os.path.isabs(bufname)
else os.path.join(cwd, bufname))
if not os.path.exists(bufpath) or 'nofile' in buftype:
bufpath = (bufname if Path(bufname).is_absolute()
else str(Path(cwd).joinpath(bufname)))
if not exists_path(bufpath) or 'nofile' in buftype:
bufpath = ''
self._cached = {
'bufnr': bufnr,
'bufname': bufname,
'bufpath': bufpath,
'camelcase': self._vim.call(
'deoplete#custom#_get_option', 'camel_case'),
'complete_str': '',
'custom': self._vim.call('deoplete#custom#_get'),
'cwd': cwd,
'encoding': self._vim.options['encoding'],
'ignorecase': self._vim.call(
'deoplete#custom#_get_option', 'ignore_case'),
'is_windows': self._vim.call('has', 'win32'),
'smartcase': self._vim.call(
'deoplete#custom#_get_option', 'smart_case'),
}
def _get_context_filetype(self,

View File

@ -4,15 +4,15 @@
# License: MIT license
# ============================================================================
from pathlib import Path
from pynvim import Nvim
import copy
import glob
import os
import typing
import deoplete.parent
from deoplete import logger
from deoplete.context import Context
from deoplete.util import error, error_tb, Nvim
from deoplete.util import error, error_tb
UserContext = typing.Dict[str, typing.Any]
Candidates = typing.Dict[str, typing.Any]
@ -26,7 +26,6 @@ class Deoplete(logger.LoggingMixin):
self._vim = vim
self._runtimepath = ''
self._runtimepath_list: typing.List[str] = []
self._custom: typing.Dict[str, typing.Dict[str, typing.Any]] = {}
self._loaded_paths: typing.Set[str] = set()
self._prev_results: typing.Dict[int, Candidates] = {}
@ -70,6 +69,8 @@ class Deoplete(logger.LoggingMixin):
def completion_begin(self, user_context: UserContext) -> None:
if not self._context:
self.init_context()
else:
self._context._init_cached()
context = self._context.get(user_context['event']) # type: ignore
context.update(user_context)
@ -96,24 +97,30 @@ class Deoplete(logger.LoggingMixin):
if needs_poll:
self._vim.call('deoplete#handler#_async_timer_start')
if not candidates:
self._vim.call('deoplete#mapping#_restore_completeopt')
# Async update is skipped if same.
prev_completion = self._vim.vars['deoplete#_prev_completion']
# Skip if async update is same.
# Note: If needs_poll, it cannot be skipped.
prev_candidates = prev_completion['candidates']
event = context['event']
if (event == 'Async' or event == 'Update' and
prev_candidates and candidates == prev_candidates):
same_candidates = prev_candidates and candidates == prev_candidates
if not needs_poll and same_candidates and (
event == 'Async' or event == 'Update'):
return
# Skip if old completion.
if context['time'] < prev_completion['time']:
return
# error(self._vim, candidates)
self._vim.vars['deoplete#_context'] = {
'complete_position': position,
'complete_str': context['input'][position:],
'candidates': candidates,
'event': context['event'],
'input': context['input'],
'is_async': is_async,
'time': context['time'],
'is_async': needs_poll,
}
if candidates or self._vim.call('deoplete#util#check_popup'):
@ -165,9 +172,15 @@ class Deoplete(logger.LoggingMixin):
def _merge_results(self, context: UserContext) -> typing.Tuple[
bool, bool, int, typing.List[typing.Any]]:
# If parallel feature is enabled, it is updated frequently.
# But if it is single process, it cannot be updated.
# So it must be updated.
async_check = len(self._parents) > 1 or (
context['event'] != 'Async' and context['event'] != 'Update')
use_prev = (context['input'] == self._prev_input
and context['next_input'] == self._prev_next_input
and context['event'] != 'Manual')
and context['event'] != 'Manual'
and async_check)
if not use_prev:
self._prev_results = {}
@ -182,7 +195,8 @@ class Deoplete(logger.LoggingMixin):
complete_position = min(x['complete_position'] for x in results)
all_candidates: typing.List[Candidates] = []
for result in sorted(results, key=lambda x: x['rank'], reverse=True):
for result in sorted(results,
key=lambda x: int(x['rank']), reverse=True):
candidates = result['candidates']
prefix = context['input'][
complete_position:result['complete_position']]
@ -218,43 +232,38 @@ class Deoplete(logger.LoggingMixin):
parent.enable_logging()
self._parents.append(parent)
def _find_rplugins(self,
source: str) -> typing.Generator[str, None, None]:
def _find_rplugins(self, source: str) -> typing.List[Path]:
"""Search for base.py or *.py
Searches $VIMRUNTIME/*/rplugin/python3/deoplete/$source[s]/
"""
if not self._runtimepath_list:
return
sources = (
os.path.join('rplugin', 'python3', 'deoplete',
source, '*.py'),
os.path.join('rplugin', 'python3', 'deoplete',
source + 's', '*.py'),
os.path.join('rplugin', 'python3', 'deoplete',
source, '*', '*.py'),
)
for src in sources:
for path in self._runtimepath_list:
yield from glob.iglob(os.path.join(path, src))
result = []
result += self._vim.call(
'globpath', self._vim.options['runtimepath'],
f'rplugin/python3/deoplete/{source}/*.py', 1, 1)
result += self._vim.call(
'globpath', self._vim.options['runtimepath'],
f'rplugin/python3/deoplete/{source}s/*.py', 1, 1)
result += self._vim.call(
'globpath', self._vim.options['runtimepath'],
f'rplugin/python3/deoplete/{source}/*/*.py', 1, 1)
return [Path(x) for x in result]
def _load_sources(self, context: UserContext) -> None:
if not self._parents and self._max_parents == 1:
self._add_parent(deoplete.parent.SyncParent)
for path in self._find_rplugins('source'):
if (path in self._loaded_paths
or os.path.basename(path) == 'base.py'):
if str(path) in self._loaded_paths or path.name == 'base.py':
continue
self._loaded_paths.add(path)
self._loaded_paths.add(str(path))
if len(self._parents) <= self._parent_count:
# Add parent automatically
self._add_parent(deoplete.parent.AsyncParent)
self._parents[self._parent_count].add_source(path)
self._parents[self._parent_count].add_source(str(path))
self.debug( # type: ignore
f'Process {self._parent_count}: {path}')
@ -267,7 +276,7 @@ class Deoplete(logger.LoggingMixin):
def _load_filters(self, context: UserContext) -> None:
for path in self._find_rplugins('filter'):
for parent in self._parents:
parent.add_filter(path)
parent.add_filter(str(path))
def _set_source_attributes(self, context: UserContext) -> None:
for parent in self._parents:
@ -277,7 +286,6 @@ class Deoplete(logger.LoggingMixin):
runtimepath = self._vim.options['runtimepath']
if runtimepath != self._runtimepath:
self._runtimepath = runtimepath
self._runtimepath_list = runtimepath.split(',')
self._load_sources(context)
self._load_filters(context)

View File

@ -4,9 +4,9 @@
# License: MIT license
# ============================================================================
# For backward compatibility
from pynvim import Nvim
from deoplete.base.filter import Base as _Base
from deoplete.util import Nvim
class Base(_Base):

View File

@ -4,10 +4,11 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import typing
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -21,8 +22,7 @@ class Filter(Base):
}
def filter(self, context: UserContext) -> Candidates:
delimiters: typing.List[str] = self.get_var( # type: ignore
'delimiters')
delimiters: typing.List[str] = self.get_var('delimiters')
for candidate, delimiter in [
[x, last_find(x['abbr'], delimiters)]
for x in context['candidates']
@ -30,7 +30,7 @@ class Filter(Base):
not last_find(x['word'], delimiters) and
last_find(x['abbr'], delimiters)]:
candidate['word'] += delimiter
return context['candidates'] # type: ignore
return list(context['candidates'])
def last_find(s: str, needles: typing.List[str]) -> typing.Optional[str]:

View File

@ -4,10 +4,11 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -26,4 +27,4 @@ class Filter(Base):
(('abbr' in x and p2.search(x['abbr'])) or
('info' in x and p2.search(x['info'])))]:
candidate['word'] += '('
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -4,10 +4,11 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -20,7 +21,7 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
complete_str = context['complete_str']
if not re.search(r'[A-Z]', complete_str):
return context['candidates'] # type: ignore
return list(context['candidates'])
complete_lower = complete_str.lower()
complete_len = len(complete_str)
@ -29,4 +30,4 @@ class Filter(Base):
if x['word'].lower().startswith(complete_lower)]:
candidate['word'] = complete_str + candidate[
'word'][complete_len:]
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -4,11 +4,12 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
import typing
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -20,26 +21,36 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
if not context['next_input']:
return context['candidates'] # type: ignore
return list(context['candidates'])
next_input_words = [x for x in re.split(
r'([a-zA-Z_]+|\W)', context['next_input']) if x]
# Skip parentheses if close parentheses is found after cursor
cur_pos = self.vim.call('getcurpos')[1:3]
check_pairs = []
if self.vim.call('searchpair', '(', '', ')', 'bnw'):
check_pairs.append(['(', ')'])
if self.vim.call('searchpair', '[', '', ']', 'bnw'):
check_pairs.append(['[', ']'])
pair_pos = self.vim.call('searchpairpos', '(', '', ')', 'nW')
if ('(' in context['input'] and cur_pos < pair_pos and
cur_pos[0] == pair_pos[0]):
check_pairs.append(['(', ')', pair_pos])
pair_pos = self.vim.call('searchpairpos', '[', '', ']', 'nW')
if ('[' in context['input'] and cur_pos < pair_pos and
cur_pos[0] == pair_pos[0]):
check_pairs.append(['[', ']', pair_pos])
for [overlap, candidate, word] in [
[x, y, y['word']] for x, y
in [[overlap_length(x['word'], next_input_words), x]
for x in context['candidates']] if x > 0]:
if [x for x in check_pairs if x[0] in word and x[1] in word]:
word_end_pos = (context['complete_position'] +
self.vim.call('len', word))
if [x for x in check_pairs
if x[0] in word and x[1] in word[-overlap:] and
word_end_pos >= x[2][1]]:
continue
if 'abbr' not in candidate:
candidate['abbr'] = word
candidate['word'] = word[: -overlap]
return context['candidates'] # type: ignore
return list(context['candidates'])
def overlap_length(left: str, next_input_words: typing.List[str]) -> int:

View File

@ -4,10 +4,11 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -22,4 +23,4 @@ class Filter(Base):
if '(' in x['word']]:
candidate['word'] = re.sub(r'\(.*\)(\$\d+)?', '',
candidate['word'])
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -4,11 +4,12 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
import typing
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -63,10 +64,10 @@ class Filter(Base):
return new_candidates
def filter(self, context: UserContext) -> Candidates:
preferred_order_attrs = self.get_var( # type: ignore
preferred_order_attrs = self.get_var(
'attrs_order').get(context['filetype'], [])
if not context['candidates'] or not preferred_order_attrs:
return context['candidates'] # type: ignore
return list(context['candidates'])
max_list_size = self.vim.call(
'deoplete#custom#_get_option', 'max_list'

View File

@ -4,8 +4,10 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import truncate_skipping, Nvim, UserContext, Candidates
from deoplete.util import truncate_skipping, UserContext, Candidates
class Filter(Base):
@ -18,11 +20,11 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
max_width = context['max_abbr_width']
if max_width <= 0:
return context['candidates'] # type: ignore
return list(context['candidates'])
footer_width = max_width / 3
for candidate in context['candidates']:
candidate['abbr'] = truncate_skipping(
candidate.get('abbr', candidate['word']),
max_width, '..', footer_width)
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -4,8 +4,10 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import truncate_skipping, Nvim, UserContext, Candidates
from deoplete.util import truncate_skipping, UserContext, Candidates
class Filter(Base):
@ -18,11 +20,11 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
max_width = context['max_info_width']
if not context['candidates'] or max_width <= 0:
return context['candidates'] # type: ignore
return list(context['candidates'])
footer_width = 1
for candidate in context['candidates']:
candidate['info'] = truncate_skipping(
candidate.get('info', ''),
max_width, '..', footer_width)
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -4,8 +4,10 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import truncate_skipping, Nvim, UserContext, Candidates
from deoplete.util import truncate_skipping, UserContext, Candidates
class Filter(Base):
@ -19,11 +21,11 @@ class Filter(Base):
max_width = context['max_kind_width']
if not context['candidates'] or 'kind' not in context[
'candidates'][0] or max_width <= 0:
return context['candidates'] # type: ignore
return list(context['candidates'])
footer_width = max_width / 3
for candidate in context['candidates']:
candidate['kind'] = truncate_skipping(
candidate.get('kind', ''),
max_width, '..', footer_width)
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -4,8 +4,10 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import truncate_skipping, Nvim, UserContext, Candidates
from deoplete.util import truncate_skipping, UserContext, Candidates
class Filter(Base):
@ -19,11 +21,11 @@ class Filter(Base):
max_width = context['max_menu_width']
if not context['candidates'] or 'menu' not in context[
'candidates'][0] or max_width <= 0:
return context['candidates'] # type: ignore
return list(context['candidates'])
footer_width = max_width / 3
for candidate in context['candidates']:
candidate['menu'] = truncate_skipping(
candidate.get('menu', ''),
max_width, '..', footer_width)
return context['candidates'] # type: ignore
return list(context['candidates'])

View File

@ -0,0 +1,23 @@
# ============================================================================
# FILE: converter_word_abbr.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import UserContext, Candidates
class Filter(Base):
def __init__(self, vim: Nvim) -> None:
super().__init__(vim)
self.name = 'converter_word_abbr'
self.description = 'word abbr converter'
def filter(self, context: UserContext) -> Candidates:
for candidate in context['candidates']:
candidate['abbr'] = candidate['word']
return list(context['candidates'])

View File

@ -4,13 +4,14 @@
# License: MIT license
# ============================================================================
import os
from pathlib import Path
from pynvim import Nvim
import sys
import typing
from deoplete.base.filter import Base
from deoplete.util import error, globruntime
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -26,7 +27,7 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
if (not context['candidates'] or not context['input']
or self._cpsm is False):
return context['candidates'] # type: ignore
return list(context['candidates'])
if self._cpsm is None:
errmsg = self._init_cpsm(context)
@ -49,7 +50,7 @@ class Filter(Base):
found = globruntime(self.vim.options['runtimepath'], fname)
errmsg = ''
if found:
sys.path.insert(0, os.path.dirname(found[0]))
sys.path.insert(0, str(Path(found[0]).parent))
try:
import cpsm_py
except ImportError as exc:

View File

@ -4,9 +4,11 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
from deoplete.base.filter import Base
from deoplete.util import fuzzy_escape, Nvim, UserContext, Candidates
from deoplete.util import fuzzy_escape, UserContext, Candidates
class Filter(Base):

View File

@ -4,12 +4,12 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
from deoplete.base.filter import Base
from deoplete.util import (
fuzzy_escape, binary_search_begin, binary_search_end)
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import binary_search_begin, binary_search_end
from deoplete.util import fuzzy_escape, UserContext, Candidates
class Filter(Base):
@ -25,7 +25,7 @@ class Filter(Base):
if context['ignorecase']:
complete_str = complete_str.lower()
if not complete_str:
return context['candidates'] # type: ignore
return list(context['candidates'])
if context['is_sorted']:
begin = binary_search_begin(

View File

@ -4,9 +4,11 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import binary_search_begin, binary_search_end
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -32,7 +34,7 @@ class Filter(Base):
candidates = context['candidates'][begin:end+1]
if context['ignorecase']:
return candidates # type: ignore
return list(candidates)
else:
candidates = context['candidates']

View File

@ -4,8 +4,10 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):

View File

@ -0,0 +1,28 @@
# ============================================================================
# FILE: matcher_matchfuzzy.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import UserContext, Candidates
class Filter(Base):
def __init__(self, vim: Nvim) -> None:
super().__init__(vim)
self.name = 'matcher_matchfuzzy'
self.description = 'matchfuzzy() matcher'
def filter(self, context: UserContext) -> Candidates:
if not self.vim.call('exists', '*matchfuzzy'):
return []
return list(self.vim.call(
'matchfuzzy', context['candidates'],
context['complete_str'], {'key': 'word'}
))

View File

@ -4,12 +4,13 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
import typing
from deoplete.base.filter import Base
from deoplete.util import getlines
from deoplete.util import Nvim, UserContext, Candidates, Candidate
from deoplete.util import UserContext, Candidates, Candidate
LINES_MAX = 150
@ -39,11 +40,15 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
complete_str = context['complete_str'].lower()
linenr = context['position'][1]
recently_used = self.vim.vars['deoplete#_recently_used']
def compare(x: Candidate) -> int:
word = x['word']
matched = int(complete_str in word.lower())
lower = x['word'].lower()
matched = int(complete_str in lower)
score = -matched * 40
if [x for x in recently_used if lower.startswith(x)]:
score -= 1000
if word in self._cache:
mru = min([abs(x - linenr) for x in self._cache[word]])
mru -= LINES_MAX

View File

@ -4,8 +4,10 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
from deoplete.base.filter import Base
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Filter(Base):
@ -18,4 +20,4 @@ class Filter(Base):
def filter(self, context: UserContext) -> Candidates:
return sorted(context['candidates'],
key=lambda x: x['word'].swapcase())
key=lambda x: str(x['word'].swapcase()))

View File

@ -8,10 +8,9 @@ import time
import logging
import typing
from deoplete.util import Nvim
from functools import wraps
from collections import defaultdict
from functools import wraps
from pynvim import Nvim
log_format = '%(asctime)s %(levelname)-8s [%(process)d] (%(name)s) %(message)s'
log_message_cooldown = 0.5
@ -50,19 +49,11 @@ def setup(vim: Nvim, level: str, output_file: str = '') -> None:
level = 'DEBUG'
root.setLevel(getattr(logging, level))
try:
import pkg_resources
pynvim_version = pkg_resources.get_distribution('pynvim').version
except Exception:
pynvim_version = 'unknown'
log = getLogger('logging')
log.info('--- Deoplete Log Start ---')
log.info('%s, Python %s, pynvim %s',
log.info('%s, Python %s',
vim.call('deoplete#util#neovim_version'),
'.'.join(map(str, sys.version_info[:3])),
pynvim_version)
'.'.join(map(str, sys.version_info[:3])))
if 'deoplete#_logging_notified' not in vim.vars:
vim.vars['deoplete#_logging_notified'] = 1

View File

@ -4,20 +4,20 @@
# License: MIT license
# ============================================================================
import time
import os
import msgpack
import subprocess
import sys
import typing
from abc import abstractmethod
from functools import partial
from pathlib import Path
from pynvim import Nvim
from queue import Queue
import msgpack
import subprocess
import sys
import time
import typing
from deoplete import logger
from deoplete.process import Process
from deoplete.util import error_tb, error, Nvim
from deoplete.util import error_tb, error
UserContext = typing.Dict[str, typing.Any]
@ -91,7 +91,7 @@ class AsyncParent(_Parent):
Taken from jedi.api.environment._try_get_same_env.
"""
exe = sys.executable
if not os.path.basename(exe).lower().startswith('python'):
if not Path(exe).name.lower().startswith('python'):
checks: typing.Tuple[typing.Any, ...]
if sys.platform == 'win32':
checks = (r'Scripts\python.exe', 'python.exe')
@ -103,8 +103,8 @@ class AsyncParent(_Parent):
'bin/python',
)
for check in checks:
guess = os.path.join(sys.exec_prefix, check)
if os.path.isfile(str(guess)):
guess = Path(sys.exec_prefix).joinpath(check)
if guess.is_file():
return str(guess)
if 'python3_host_prog' not in self._vim.vars:
return 'python3'

View File

@ -4,11 +4,12 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
from deoplete.base.source import Base
from deoplete.util import parse_buffer_pattern, getlines
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Source(Base):

View File

@ -4,9 +4,9 @@
# License: MIT license
# ============================================================================
# For backward compatibility
from pynvim import Nvim
from deoplete.base.source import Base as _Base
from deoplete.util import Nvim
class Base(_Base):

View File

@ -4,11 +4,12 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import typing
from deoplete.base.source import Base
from deoplete.util import parse_buffer_pattern, getlines
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Source(Base):

View File

@ -5,13 +5,13 @@
# License: MIT license
# ============================================================================
import os
from pathlib import Path
from pynvim import Nvim
import re
import typing
from os.path import exists, dirname
from deoplete.base.source import Base
from deoplete.util import expand, Nvim, UserContext, Candidates
from deoplete.util import expand, exists_path, UserContext, Candidates
class Source(Base):
@ -26,6 +26,7 @@ class Source(Base):
self.events: typing.List[str] = ['InsertEnter']
self.vars = {
'enable_buffer_path': True,
'enable_slash_completion': False,
'force_completion_length': -1,
}
@ -39,7 +40,7 @@ class Source(Base):
def get_complete_position(self, context: UserContext) -> int:
pos = int(context['input'].rfind('/'))
force_completion_length = int(
self.get_var('force_completion_length')) # type: ignore
self.get_var('force_completion_length'))
if pos < 0 and force_completion_length >= 0:
fmt = '[a-zA-Z0-9.-]{{{}}}$'.format(force_completion_length)
m = re.search(fmt, context['input'])
@ -55,20 +56,38 @@ class Source(Base):
if context['input'].rfind('/') >= 0
else './')
p = self._longest_path_that_exists(context, input_str)
if not p or p == '/' or re.search('//+$', p):
# Note: context['bufpath'] will be empty if not exists file
bufname = context['bufname']
bufpath = (bufname if Path(bufname).is_absolute()
else str(Path(context['cwd']).joinpath(bufname)))
buftype = self.vim.call('getbufvar', '%', '&buftype')
if not bufname or 'nofile' in buftype or not self.get_var(
'enable_buffer_path'):
bufpath = ''
p = self._longest_path_that_exists(context, input_str, bufpath)
slash_completion = bool(self.get_var('enable_slash_completion'))
if not p or re.search('//+$', p) or (
p == '/' and not slash_completion):
return []
complete_str = self._substitute_path(context, dirname(p) + '/')
if not os.path.isdir(complete_str):
p = expand(p)
if p[-1] != '/':
p += '/'
complete_str = self._substitute_path(context, p, bufpath)
if not Path(complete_str).is_dir():
return []
hidden = context['complete_str'].find('.') == 0
contents: typing.List[typing.Any] = [[], []]
try:
for item in sorted(os.listdir(complete_str), key=str.lower):
for item in sorted([str(x.name) for x
in Path(complete_str).iterdir()],
key=str.lower):
if not hidden and item[0] == '.':
continue
contents[not os.path.isdir(complete_str + item)].append(item)
except PermissionError:
is_dir = not Path(complete_str + '/' + item).is_dir()
contents[is_dir].append(item)
except (PermissionError, FileNotFoundError):
pass
dirs, files = contents
@ -76,25 +95,32 @@ class Source(Base):
] + [{'word': x} for x in files]
def _longest_path_that_exists(self, context: UserContext,
input_str: str) -> str:
input_str: str, bufpath: str) -> str:
input_str = re.sub(r'[^/]*$', '', input_str)
data = re.split(r'((?:%s+|(?:(?<![\w\s/\.])(?:~|\.{1,2})?/)+))' %
self._isfname, input_str)
data = [x for x in 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))
existing_paths = sorted(filter(
lambda x: exists_path(self._substitute_path(
context, x, bufpath)), data))
return existing_paths[-1] if existing_paths else ''
def _substitute_path(self, context: UserContext, path: str) -> str:
def _substitute_path(self, context: UserContext,
path: str, bufpath: str) -> str:
m = re.match(r'(\.{1,2})/+', path)
if m:
if self.get_var('enable_buffer_path') and context['bufpath']:
base = context['bufpath']
else:
base = os.path.join(context['cwd'], 'x')
if not m:
return expand(path)
for _ in m.group(1):
base = dirname(base)
return os.path.abspath(os.path.join(
base, path[len(m.group(0)):])) + '/'
return expand(path)
if bufpath:
base = str(Path(bufpath).parent)
else:
base = context['cwd']
if m.group(1) == '..':
base = str(Path(base).parent)
rest = path[len(m.group(0)):]
if rest:
return str(Path(base).joinpath(rest)) + '/'
else:
return base

View File

@ -4,13 +4,14 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
import typing
from deoplete.base.source import Base
from deoplete.util import (
convert2list, parse_buffer_pattern, set_pattern, getlines)
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Source(Base):

View File

@ -4,13 +4,14 @@
# License: MIT license
# ============================================================================
from pynvim import Nvim
import re
import typing
from deoplete.base.source import Base
from deoplete.util import (
convert2list, set_pattern, convert2candidates)
from deoplete.util import Nvim, UserContext, Candidates
from deoplete.util import UserContext, Candidates
class Source(Base):
@ -44,6 +45,8 @@ class Source(Base):
def _get_complete_position(self, context: UserContext,
current_ft: str, filetype: str) -> int:
complete_pos = -1
for omnifunc in convert2list(
self.get_filetype_var(filetype, 'functions')):
if omnifunc == '' and (filetype == current_ft or
@ -69,15 +72,16 @@ class Source(Base):
'rubycomplete#Complete',
'phpcomplete#CompletePHP']:
# In the blacklist
return -1
continue
try:
complete_pos = int(self.vim.call(self._omnifunc, 1, ''))
except Exception:
self.print_error('Error occurred calling omnifunction: ' +
self._omnifunc)
return -1
return complete_pos
return -1
if complete_pos >= 0:
break
return complete_pos
def gather_candidates(self, context: UserContext) -> Candidates:
try:
@ -95,4 +99,4 @@ class Source(Base):
candidate['dup'] = 1
candidate['equal'] = 1
return candidates # type: ignore
return list(candidates)

View File

@ -4,22 +4,18 @@
# License: MIT license
# ============================================================================
import os
import re
import sys
from os.path import expandvars
from pathlib import Path
from pynvim import Nvim
from pynvim.api import Buffer
import glob
import importlib.util
import re
import sys
import traceback
import typing
import unicodedata
if importlib.util.find_spec('pynvim'):
from pynvim import Nvim
from pynvim.api import Buffer
else:
from neovim import Nvim
from neovim.api import Buffer
UserContext = typing.Dict[str, typing.Any]
Candidate = typing.Dict[str, typing.Any]
Candidates = typing.List[Candidate]
@ -61,17 +57,19 @@ def import_plugin(path: str, source: str,
If the class exists, add its directory to sys.path.
"""
name = os.path.splitext(os.path.basename(path))[0]
name = str(Path(path).name)[: -3]
module_name = 'deoplete.%s.%s' % (source, name)
spec = importlib.util.spec_from_file_location(module_name, path)
if not spec:
return None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # type: ignore
cls = getattr(module, classname, None)
if not cls:
return None
dirname = os.path.dirname(path)
dirname = str(Path(path).parent)
if dirname not in sys.path:
sys.path.insert(0, dirname)
return cls
@ -96,7 +94,7 @@ def error_tb(vim: Nvim, msg: str) -> None:
t, v, tb = sys.exc_info()
if t and v and tb:
lines += traceback.format_exc().splitlines()
lines += ['%s. Use :messages / see above for error details.' % msg]
lines += ['%s Use :messages / see above for error details.' % msg]
if hasattr(vim, 'err_write'):
vim.err_write('[deoplete] %s\n' % '\n'.join(lines))
else:
@ -141,8 +139,8 @@ def get_custom(custom: typing.Dict[str, typing.Any],
return default
def get_syn_names(vim: Nvim) -> str:
return str(vim.call('deoplete#util#get_syn_names'))
def get_syn_names(vim: Nvim) -> typing.List[str]:
return list(vim.call('deoplete#util#get_syn_names'))
def parse_file_pattern(f: typing.Iterable[str],
@ -169,8 +167,8 @@ def fuzzy_escape(string: str, camelcase: bool) -> str:
def load_external_module(base: str, module: str) -> None:
current = os.path.dirname(os.path.abspath(base))
module_dir = os.path.join(os.path.dirname(current), module)
current = Path(base).parent.resolve()
module_dir = str(current.parent.joinpath(module))
if module_dir not in sys.path:
sys.path.insert(0, module_dir)
@ -219,7 +217,20 @@ def charwidth(c: str) -> int:
def expand(path: str) -> str:
return os.path.expanduser(os.path.expandvars(path))
if path.startswith('~'):
try:
path = str(Path(path).expanduser())
except Exception:
pass
return expandvars(path)
def exists_path(path: str) -> bool:
try:
return Path(path).exists()
except Exception:
pass
return False
def getlines(vim: Nvim, start: int = 1,
@ -230,7 +241,9 @@ def getlines(vim: Nvim, start: int = 1,
lines: typing.List[str] = []
current = start
while current <= int(end):
lines += vim.call('getline', current, current + max_len)
# Skip very long lines
lines += [x for x in vim.call('getline', current, current + max_len)
if len(x) < 300]
current += max_len + 1
return lines

View File

@ -1,5 +1,5 @@
import os
from pathlib import Path
import sys
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(BASE_DIR, 'rplugin/python3'))
BASE_DIR = Path(__file__).parent.parent
sys.path.insert(0, str(Path(BASE_DIR).joinpath('rplugin/python3')))