From f945db3aba0adad07c47dfd34a1841960a250744 Mon Sep 17 00:00:00 2001 From: maralla Date: Wed, 14 Sep 2016 13:48:13 +0800 Subject: [PATCH] init --- .gitignore | 2 + LICENSE | 21 +++++++++ autoload/completor.vim | 80 ++++++++++++++++++++++++++++++++++ autoload/completor/utils.vim | 5 +++ plugin/completor.vim | 43 ++++++++++++++++++ pythonx/completers/__init__.py | 0 pythonx/completers/rust.py | 39 +++++++++++++++++ pythonx/completor/__init__.py | 52 ++++++++++++++++++++++ 8 files changed, 242 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 autoload/completor.vim create mode 100644 autoload/completor/utils.vim create mode 100644 plugin/completor.vim create mode 100644 pythonx/completers/__init__.py create mode 100644 pythonx/completers/rust.py create mode 100644 pythonx/completor/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9a3498 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +.cache diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..628ded6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/autoload/completor.vim b/autoload/completor.vim new file mode 100644 index 0000000..5a4c52b --- /dev/null +++ b/autoload/completor.vim @@ -0,0 +1,80 @@ +" vim: et ts=2 sts=2 sw=2 + +let s:save_cpo = &cpo +set cpo&vim + +let s:completions = [] + + +function! completor#omnifunc(findstart, base) + if a:findstart + let word = matchstr(getline('.'), '\w*\%'.col('.').'c') + return col('.') - 1 - len(word) + endif + return s:completions +endfunction + + +function! s:handle(ch) + let msg = [] + while ch_status(a:ch) == 'buffered' + call add(msg, ch_read(a:ch)) + endwhile + +Py << EOF +import completor, vim +completer = completor.load_completer(vim.current.buffer.options['ft']) +result = completer.parse(vim.eval('msg')) if completer else [] +EOF + + let s:completions = Pyeval('result') + setlocal omnifunc=completor#omnifunc + if !empty(s:completions) + setlocal completeopt-=longest + setlocal completeopt+=menuone + setlocal completeopt-=menu + if &completeopt !~# 'noinsert\|noselect' + setlocal completeopt+=noselect + endif + call feedkeys("\\", 'n') + endif +endfunction + + +function! s:execute(cmd) + let job = job_start(a:cmd, {"close_cb": {c->s:handle(c)}, "in_io": 'null', "err_io": 'out'}) +endfunction + + +function! s:complete() +Py << EOF +import completor, vim +completer = completor.load_completer(vim.current.buffer.options['ft']) +cmd = completer.format_cmd() if completer else '' +EOF + + let cmd = Pyeval('cmd') + if !empty(cmd) + call s:execute(cmd) + endif +endfunction + + +function! s:set_events() + augroup completor + autocmd! + autocmd TextChangedI * call s:complete() + augroup END +endfunction + + +function! completor#enable() + if &diff + return + endif + + call s:set_events() +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/autoload/completor/utils.vim b/autoload/completor/utils.vim new file mode 100644 index 0000000..bf6ca81 --- /dev/null +++ b/autoload/completor/utils.vim @@ -0,0 +1,5 @@ +function! completor#utils#tempname() + let tmp = escape(tempname(), ' ') + call writefile(getline(1, '$'), tmp) + return tmp +endfunction diff --git a/plugin/completor.vim b/plugin/completor.vim new file mode 100644 index 0000000..e839467 --- /dev/null +++ b/plugin/completor.vim @@ -0,0 +1,43 @@ +" vim: et ts=2 sts=2 sw=2 + +let s:save_cpo = &cpo +set cpo&vim + +function! s:restore_cpo() + let &cpo = s:save_cpo + unlet s:save_cpo +endfunction + +if exists("g:loaded_completor_plugin") + call s:restore_cpo() + finish +elseif !(has('python') || has('python3')) || !(has('job') && has('timers') && has('lambda')) + echohl WarningMsg | + \ echomsg "Completor requires vim compiled with python or python3 and has features `job`, `timers` and `lambda`" | + \ echohl None + call s:restore_cpo() + finish +endif + + +let g:loaded_completor_plugin = 1 + +if has("python3") + command! -nargs=1 Py py3 + function! Pyeval(arg) + return py3eval(a:arg) + endfunction +else + command! -nargs=1 Py py + function! Pyeval(arg) + return pyeval(a:arg) + endfunction +endif + +augroup completor + autocmd! + autocmd VimEnter * call completor#enable() +augroup END + + +call s:restore_cpo() diff --git a/pythonx/completers/__init__.py b/pythonx/completers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pythonx/completers/rust.py b/pythonx/completers/rust.py new file mode 100644 index 0000000..03cd253 --- /dev/null +++ b/pythonx/completers/rust.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +from completor import Completor + +type_map = { + 'Struct' : 's', 'Module' : 'M', 'Function' : 'f', + 'Crate' : 'C', 'Let' : 'v', 'StructField' : 'm', + 'Impl' : 'i', 'Enum' : 'e', 'EnumVariant' : 'E', + 'Type' : 't', 'FnArg' : 'v', 'Trait' : 'T' +} + +class Racer(Completor): + __filetype__ = 'rust' + + name = 'racer' + + def format_cmd(self): + line, col = self.cursor + return "{} complete {} {} {} {}".format(self.name, line, col, + self.filename, self.tempname) + + def parse(self, items): + completions = [] + for item in items: + if not item.startswith('MATCH'): + continue + + parts = item.split(',') + name = parts[0][6:] + kind = type_map.get(parts[4], '') + spec = ', '.join(parts[5:]) + + completions.append({ + 'kind': kind, + 'word': name, + 'menu': spec, + 'dup': 1 + }) + return completions diff --git a/pythonx/completor/__init__.py b/pythonx/completor/__init__.py new file mode 100644 index 0000000..60b7dd5 --- /dev/null +++ b/pythonx/completor/__init__.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +import importlib +import vim + + +class Meta(type): + def __init__(cls, name, bases, attrs): + if name not in ('Completor', 'Base'): + Completor._registry[cls.__filetype__] = cls() + + return super(Meta, cls).__init__(name, bases, attrs) + +Base = Meta('Base', (object,), {}) + + +class Unusable(object): + def __get__(self, inst, owner): + raise RuntimeError('unusable') + + +class Completor(Base): + _registry = {} + + __filetype__ = Unusable() + name = Unusable() + + @property + def tempname(self): + return vim.eval('completor#utils#tempname()') + + @property + def filename(self): + return vim.current.buffer.name + + @property + def cursor(self): + return vim.current.window.cursor + +_completor = Completor() + + +def load_completer(ft): + if not ft: + return None + + if ft not in _completor._registry: + try: + importlib.import_module("completers.{}".format(ft)) + except ImportError: + return None + return _completor._registry[ft]