Fixed vim and zsh
This commit is contained in:
5
vim/plugins/nvim-yarp/.gitignore
vendored
Normal file
5
vim/plugins/nvim-yarp/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
__pycache__
|
||||
|
||||
# demo
|
||||
/plugin/hello.vim
|
||||
/pythonx/hello.py
|
115
vim/plugins/nvim-yarp/README.md
Normal file
115
vim/plugins/nvim-yarp/README.md
Normal file
@ -0,0 +1,115 @@
|
||||
|
||||
# Yet Another Remote Plugin Framework for Neovim
|
||||
|
||||
This is my attempt on writing a remote plugin framework without
|
||||
`:UpdateRemotePlugins`.
|
||||
|
||||
## Requirements
|
||||
|
||||
- `has('python3')`
|
||||
- For Vim 8:
|
||||
- [roxma/vim-hug-neovim-rpc](https://github.com/roxma/vim-hug-neovim-rpc)
|
||||
- `g:python3_host_prog` pointed to your python3 executable, or `echo
|
||||
exepath('python3')` is not empty.
|
||||
- [neovim python client](https://github.com/neovim/python-client) (`pip3
|
||||
install neovim`)
|
||||
|
||||
## Usage
|
||||
|
||||
pythonx/hello.py
|
||||
|
||||
```python
|
||||
import vim, time
|
||||
def greet():
|
||||
time.sleep(3)
|
||||
vim.command('echo "Hello world"')
|
||||
```
|
||||
|
||||
plugin/hello.vim
|
||||
|
||||
```vim
|
||||
" Create a python3 process running the hello module. The process is lazy load.
|
||||
let s:hello = yarp#py3('hello')
|
||||
|
||||
com HelloSync call s:hello.request('greet')
|
||||
com HelloAsync call s:hello.notify('greet')
|
||||
|
||||
" You could type :Hello greet
|
||||
com -nargs=1 Hello call s:hello.request(<f-args>)
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
Add logging settigns to your vimrc. Log files will be generated with prefix
|
||||
`/tmp/nvim_log`. An alternative is to export environment variables before
|
||||
starting vim/nvim.
|
||||
|
||||
```vim
|
||||
let $NVIM_PYTHON_LOG_FILE="/tmp/nvim_log"
|
||||
let $NVIM_PYTHON_LOG_LEVEL="DEBUG"
|
||||
```
|
||||
|
||||
## Example for existing neovim rplugin porting to Vim 8
|
||||
|
||||
More realistic examples could be found at
|
||||
[nvim-typescript#84](https://github.com/mhartington/nvim-typescript/pull/84),
|
||||
[deoplete#553](https://github.com/Shougo/deoplete.nvim/pull/553),
|
||||
[callmekohei/quickdebug](https://github.com/callmekohei/quickdebug).
|
||||
|
||||
Now let's consider the following simple rplugin.
|
||||
|
||||
After `UpdateRemotePlugins` and restarting neovim, you get `foobar` by `:echo
|
||||
Bar()`.
|
||||
|
||||
```python
|
||||
# rplugin/python3/foo.py
|
||||
import neovim
|
||||
|
||||
@neovim.plugin
|
||||
class Foo(object):
|
||||
|
||||
def __init__(self, vim):
|
||||
self._vim = vim
|
||||
|
||||
@neovim.function("Bar", sync=True)
|
||||
def bar(self, args):
|
||||
return 'hello' + str(args)
|
||||
```
|
||||
|
||||
For working on Vim 8, you need to add these two files:
|
||||
|
||||
|
||||
```vim
|
||||
" plugin/foo.vim
|
||||
if has('nvim')
|
||||
finish
|
||||
endif
|
||||
|
||||
let s:foo = yarp#py3('foo_wrap')
|
||||
|
||||
func! Bar(v)
|
||||
return s:foo.call('bar',a:v)
|
||||
endfunc
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# pythonx/foo_wrap.py
|
||||
from foo import Foo as _Foo
|
||||
import vim
|
||||
|
||||
_obj = _Foo(vim)
|
||||
|
||||
|
||||
def bar(*args):
|
||||
return _obj.bar(args)
|
||||
```
|
||||
|
||||
How to use
|
||||
```
|
||||
$ vim
|
||||
|
||||
: echo bar('world')
|
||||
|
||||
hello('world',)
|
||||
```
|
17
vim/plugins/nvim-yarp/autoload/yarp.vim
Normal file
17
vim/plugins/nvim-yarp/autoload/yarp.vim
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
func! yarp#py3(module)
|
||||
let rp = yarp#core#new()
|
||||
let rp.type = 'py3'
|
||||
let rp.module = a:module
|
||||
let rp.init = function('yarp#pyx#init')
|
||||
return rp
|
||||
endfunc
|
||||
|
||||
func! yarp#py(module)
|
||||
let rp = yarp#core#new()
|
||||
let rp.type = 'py'
|
||||
let rp.module = a:module
|
||||
let rp.init = function('yarp#pyx#init')
|
||||
return rp
|
||||
endfunc
|
||||
|
149
vim/plugins/nvim-yarp/autoload/yarp/core.vim
Normal file
149
vim/plugins/nvim-yarp/autoload/yarp/core.vim
Normal file
@ -0,0 +1,149 @@
|
||||
if get(s:, 'loaded', 0)
|
||||
finish
|
||||
endif
|
||||
let s:loaded = 1
|
||||
|
||||
let s:id = 1
|
||||
let s:reg = {}
|
||||
let s:leaving = 0
|
||||
|
||||
augroup yarp
|
||||
autocmd!
|
||||
" this one is which you're most likely to use?
|
||||
autocmd VimLeavePre * let s:leaving = 1
|
||||
augroup end
|
||||
|
||||
if has('nvim')
|
||||
let s:rpcrequest = 'rpcrequest'
|
||||
let s:rpcnotify = 'rpcnotify'
|
||||
let s:jobstart = 'jobstart'
|
||||
fun! s:_serveraddr()
|
||||
return v:servername
|
||||
endfunc
|
||||
let s:serveraddr = function('s:_serveraddr')
|
||||
else
|
||||
let s:rpcrequest = get(g:, 'yarp_rpcrequest', 'neovim_rpc#rpcrequest')
|
||||
let s:rpcnotify = get(g:, 'yarp_rpcnotify', 'neovim_rpc#rpcnotify')
|
||||
let s:jobstart = get(g:, 'yarp_jobstart', 'neovim_rpc#jobstart')
|
||||
let s:serveraddr = get(g:, 'yarp_serveraddr', 'neovim_rpc#serveraddr')
|
||||
endif
|
||||
|
||||
func! yarp#core#new()
|
||||
let s:id = s:id + 1
|
||||
|
||||
let rp = {}
|
||||
|
||||
let rp.jobstart = function('yarp#core#jobstart')
|
||||
func rp.error(msg) dict
|
||||
call yarp#core#error(self.module, a:msg)
|
||||
endfunc
|
||||
let rp.call = function('yarp#core#request')
|
||||
let rp.request = function('yarp#core#request')
|
||||
let rp.notify = function('yarp#core#notify')
|
||||
let rp.wait_channel = function('yarp#core#wait_channel')
|
||||
let rp.id = s:id
|
||||
let rp.job_is_dead = 0
|
||||
let s:reg[rp.id] = rp
|
||||
|
||||
" reserved for user
|
||||
let rp.extra = {}
|
||||
return rp
|
||||
endfunc
|
||||
|
||||
func! yarp#core#on_stderr(chan_id, data, event) dict
|
||||
let mod = self.self
|
||||
call mod.error(filter(a:data, 'len(v:val)'))
|
||||
endfunc
|
||||
|
||||
func! yarp#core#on_exit(chan_id, data, event) dict
|
||||
let mod = self.self
|
||||
let mod.job_is_dead = 1
|
||||
if v:dying == 0 && s:leaving == 0
|
||||
call mod.error("Job is dead. cmd=" . string(mod.cmd))
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func! yarp#core#channel_started(id, channel)
|
||||
let s:reg[a:id].channel = a:channel
|
||||
endfunc
|
||||
|
||||
func! yarp#core#request(method, ...) dict
|
||||
call self.wait_channel()
|
||||
return call(s:rpcrequest, [self.channel, a:method] + a:000)
|
||||
endfunc
|
||||
|
||||
func! yarp#core#notify(method, ...) dict
|
||||
call self.wait_channel()
|
||||
call call(s:rpcnotify, [self.channel, a:method] + a:000)
|
||||
endfunc
|
||||
|
||||
func! yarp#core#wait_channel() dict
|
||||
if has_key(self, 'channel')
|
||||
return
|
||||
endif
|
||||
if ! has_key(self, 'job')
|
||||
call self.jobstart()
|
||||
endif
|
||||
if get(self, 'job', -1) == -1
|
||||
throw '[yarp] [' . self.module . '] job is not running'
|
||||
endif
|
||||
let cnt = 5000 / 20
|
||||
while ! has_key(self, 'channel')
|
||||
if self.job_is_dead
|
||||
throw '[yarp] [' . self.module .
|
||||
\ '] job is dead. failed establishing channel for ' .
|
||||
\ string(self.cmd)
|
||||
endif
|
||||
if cnt <= 0
|
||||
throw '[yarp] [' . self.module . '] timeout establishing channel for ' . string(self.cmd)
|
||||
endif
|
||||
let cnt = cnt - 1
|
||||
silent sleep 20m
|
||||
endwhile
|
||||
endfunc
|
||||
|
||||
func! yarp#core#jobstart() dict
|
||||
if ! has_key(self, 'cmd')
|
||||
call self.init()
|
||||
if ! has_key(self, 'cmd')
|
||||
call self.error("cmd of the job is not set")
|
||||
return
|
||||
endif
|
||||
endif
|
||||
if has_key(self, 'job')
|
||||
return
|
||||
endif
|
||||
let opts = {'on_stderr': function('yarp#core#on_stderr'),
|
||||
\ 'on_exit': function('yarp#core#on_exit'),
|
||||
\ 'self': self}
|
||||
try
|
||||
let self.job = call(s:jobstart, [self.cmd, opts])
|
||||
if self.job == -1
|
||||
call self.error('Failed starting job: ' . string(self.cmd))
|
||||
endif
|
||||
catch
|
||||
let self.job = -1
|
||||
call self.error(['Failed starting job: ' . string(self.cmd), v:exception])
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func! yarp#core#serveraddr()
|
||||
return call (s:serveraddr, [])
|
||||
endfunc
|
||||
|
||||
func! yarp#core#error(mod, msg)
|
||||
if mode() == 'i'
|
||||
" NOTE: side effect, sorry, but this is necessary
|
||||
set nosmd
|
||||
endif
|
||||
if type(a:msg) == type("")
|
||||
let lines = split(a:msg, "\n", 1)
|
||||
else
|
||||
let lines = a:msg
|
||||
endif
|
||||
echoh ErrorMsg
|
||||
for line in lines
|
||||
echom '[' . a:mod . '@yarp] ' . line
|
||||
endfor
|
||||
echoh None
|
||||
endfunc
|
70
vim/plugins/nvim-yarp/autoload/yarp/pyx.vim
Normal file
70
vim/plugins/nvim-yarp/autoload/yarp/pyx.vim
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
func! yarp#pyx#init() dict
|
||||
if self.type == 'py'
|
||||
let l:Detect = function('s:pyexe')
|
||||
else
|
||||
let l:Detect = function('s:py3exe')
|
||||
endif
|
||||
|
||||
let exe = call(l:Detect, [], self)
|
||||
|
||||
if get(s:, 'script', '') == ''
|
||||
let s:script = globpath(&rtp,'pythonx/yarp.py',1)
|
||||
endif
|
||||
|
||||
let self.cmd = [exe,
|
||||
\ '-u',
|
||||
\ s:script,
|
||||
\ yarp#core#serveraddr(),
|
||||
\ self.id,
|
||||
\ self.module]
|
||||
call self.jobstart()
|
||||
endfunc
|
||||
|
||||
func! s:pyexe() dict
|
||||
if get(g:, '_yarp_py', '')
|
||||
return g:_yarp_py
|
||||
endif
|
||||
let g:_yarp_py = get(g:, 'python_host_prog', '')
|
||||
if g:_yarp_py == '' && has('nvim') && has('python')
|
||||
" heavy weight
|
||||
" but better support for python detection
|
||||
python import sys
|
||||
let g:_yarp_py = pyeval('sys.executable')
|
||||
endif
|
||||
if g:_yarp_py == ''
|
||||
let g:_yarp_py = 'python2'
|
||||
endif
|
||||
return g:_yarp_py
|
||||
endfunc
|
||||
|
||||
func! s:py3exe() dict
|
||||
if get(g:, '_yarp_py3', '')
|
||||
return g:_yarp_py3
|
||||
endif
|
||||
let g:_yarp_py3 = get(g:, 'python3_host_prog', '')
|
||||
if g:_yarp_py3 == '' && has('nvim') && has('python3')
|
||||
" heavy weight
|
||||
" but better support for python detection
|
||||
python3 import sys
|
||||
let g:_yarp_py3 = py3eval('sys.executable')
|
||||
endif
|
||||
if g:_yarp_py3 == ''
|
||||
let g:_yarp_py3 = 'python3'
|
||||
endif
|
||||
if exepath(g:_yarp_py3) == ''
|
||||
call self.error(
|
||||
\ "Python3 executable [" .
|
||||
\ g:_yarp_py3 .
|
||||
\ "] not found.")
|
||||
if has('vim_starting')
|
||||
call self.error("")
|
||||
endif
|
||||
call self.error("###### Please configure g:python3_host_prog properly ######")
|
||||
if has('vim_starting')
|
||||
call self.error("")
|
||||
endif
|
||||
endif
|
||||
return g:_yarp_py3
|
||||
endfunc
|
||||
|
55
vim/plugins/nvim-yarp/pythonx/yarp.py
Normal file
55
vim/plugins/nvim-yarp/pythonx/yarp.py
Normal file
@ -0,0 +1,55 @@
|
||||
from neovim import attach, setup_logging
|
||||
import sys
|
||||
import importlib
|
||||
|
||||
serveraddr = sys.argv[1]
|
||||
yarpid = int(sys.argv[2])
|
||||
module = sys.argv[3]
|
||||
module_obj = None
|
||||
|
||||
setup_logging(module)
|
||||
|
||||
# create another connection to avoid synchronization issue?
|
||||
if len(serveraddr.split(':')) == 2:
|
||||
serveraddr, port = serveraddr.split(':')
|
||||
port = int(port)
|
||||
nvim = attach('tcp', address=serveraddr, port=port)
|
||||
else:
|
||||
nvim = attach('socket', path=serveraddr)
|
||||
|
||||
sys.modules['vim'] = nvim
|
||||
sys.modules['nvim'] = nvim
|
||||
|
||||
paths = nvim.eval(r'globpath(&rtp,"pythonx",1) . "\n" .'
|
||||
r' globpath(&rtp,"rplugin/python3",1)')
|
||||
for path in paths.split("\n"):
|
||||
if not path:
|
||||
continue
|
||||
if path not in sys.path:
|
||||
sys.path.append(path)
|
||||
|
||||
nvim.call('yarp#core#channel_started', yarpid, nvim.channel_id)
|
||||
|
||||
module_obj = importlib.import_module(module)
|
||||
|
||||
|
||||
def on_request(method, args):
|
||||
if hasattr(module_obj, method):
|
||||
return getattr(module_obj, method)(*args)
|
||||
else:
|
||||
raise Exception('method %s not found' % method)
|
||||
|
||||
|
||||
def on_notification(method, args):
|
||||
if hasattr(module_obj, method):
|
||||
getattr(module_obj, method)(*args)
|
||||
else:
|
||||
raise Exception('method %s not found' % method)
|
||||
pass
|
||||
|
||||
|
||||
def on_setup():
|
||||
pass
|
||||
|
||||
|
||||
nvim.run_loop(on_request, on_notification, on_setup)
|
Reference in New Issue
Block a user