-
Notifications
You must be signed in to change notification settings - Fork 6
/
README
389 lines (269 loc) · 13.5 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
TABLE OF CONTENTS:
====================
!! TODO: implement nvims job_control.txt
1) list of plugins using vim-addon-async (SCREENSHOTS!)
2) GOAL (provide API for Vim users)
3) porcelain LogToBuffer running interactive interpreter shells within Vim buffers
4) installation & implementation details
4b) customization
5) usage tips
6) credits
7) related work
8) yet another example
8) tips
10) TROUBLE?
11) testing new implementations
12) TODO
1) list of plugins using vim-addon-async:
===============================================================================
- ensime (Scala server providing fast type checking and completion)
- vim-addon-xdebug (xdebug implementation for Vim)
- vim-addon-rdebug (simple ruby debugging using require "debug")
REPL (read print eval loop) implementations are available for
- Scala http://mawercer.de/~marc/vim-addon-async-scala-repl.jpg
- Ruby [1] http://mawercer.de/~marc/vim-addon-async-irb-repl.jpg
- Python [1] http://mawercer.de/~marc/vim-addon-async-python-repl.jpg
works: dict[" : list keys
obj. : list dir() output
(nothing) : list globals
could be done:
- PHP - There is lot's of introspection eg see http://docstore.mik.ua/orelly/webprog/php/ch06_05.htm, php -a runs the interpreter
works: $arr_var : list keys, [ is prefixed
obj : list methods,properties -> is prefixed
providing completion on objects etc.
[1]: the interpreter is used. eg dir(obj) for python and .methods for Ruby.
This means you have to take care that you don't cause side effects when
invoking the completion!
Example showing how to run a background process in the async buffer while
continuing typing in another buffer:
http://mawercer.de/~marc/vim-addon-async-sh-example.jpg
2) GOAL (provide API for Vim users)
==============================================================================
provide an async communication interface for VimL which can be implemented in different ways.
It looks like this:
let ctx = { 'cmd' : '/bin/sh' }
fun ctx.receive(data, ...)
" ... will contain the file descriptor number or such in the future
echo "got data: ".a:data
" now that we have the date the process is no longer needed:
self.kill()
endf
call async#Exec(ctx)
call ctx.write("date") " run date
What's nice about this design? You can add your own state to the context easily.
Eg the LogToBuffer keeps state in a "pending" key which makes the code aware about
whether the last block of bytes contained a "\n" character at the end or not.
For debugger implementations etc this means you can keep lists of breakpoints
etc easily.
Different implementations will be provided. See below.
3) porcelain LogToBuffer running interactive interpreter shells within Vim buffers:
==============================================================================
How powerful this simple interface is is illustrated by
LogToBuffer which is porcelain on top of the API:
call async_porcelaine#LogToBuffer({'cmd':'python -i', 'move_last':1, 'prompt': '^>>> $'})
should yield:
pid: 27475, bufnr: 4
> Python 2.6.5 (r265:79063, May 9 2010, 14:26:02)
> [GCC 4.4.3] on linux2
_ > Type "help", "copyright", "credits" or "license" for more information.
Note the "_" Everything below that will be sent to the interpreter's stdin when pressing <space><cr>
You can also visually select arbitrary text and press <cr> to send those lines instead.
Eg try this:
# this comment starts at "no" indentation. keep the empty line for python interpreter!
def foo(text):
print text
foo("hello world")
Pay attention: the async#GetLines script will sent #1 and #2 when
pressing <space><cr> in the num2 line. I recommend using <c-u><cr>
in order to enter a blank line if you want to prevent this
and you should get the reply:
> >>> ... ... ... >>> hello world
the >>> ... .... ... >>> could be filtered by the "prompt" setting.
Note: because adding lines to background buffers are be annoying actions can be
delayed. In the LogToBuffer updates are delayed when
- you're in insert / visual mode (Vim should not disturb you when typing, selecting)
- you're in command line or command win buffer (q:)
Reason: You can't switch buffers or tabs when its open.
4) installation & implementation details:
===============================================================================
This plugin depends on vim-addon-signs. Thus I recommend using
vim-addon-manager for installing this addon.
For now I recommend using impl 2) (gvim) or impl 1) (non gui version of Vim)
impl 1 native):
================
(out of order because API changed - current upstream of this patch is here
http://github.com/bartman/vim )
compile my async version of Vim (github.com/MarcWeber/vim branch "work").
(-) doesn't work in gui very well yet. That's why its not used in that case
(-) patch as to be tested with valgrind and tidied up
impl 2 c_executable):
================
compile C/vim-addon-async-helper.c:
cd C; gcc -o vim-addon-async-helper vim-addon-async-helper.c
(-) requires client server (X connection or the like
(-) 20ms delay (vim -> app)
tested on linux and OSX. It should be easy to find a way to make the helper
app run on Windows as well.. Any volunteers ?
impl 3 possible others):
================
- mzscheme (racket)
implementation using threads. That would be the only solution working
everywhere.
(+) portable)
(-) not implemented yet
(_) very view users have mzscheme support
- python (also calling back into Vim cause its not threadsafe, but passing
data to Python could be done easily)
(ZyX says threads may not work on arm, but processes might)
4b) customization
===============================================================================
you can change / remove the default prefix which is added to lines output by
processes when using LogToBuffer:
~/.vimrc:
let g:async = {'line_prefix' = "other : " }
The line_prefix was chosen so that its easier to distinguish "input" from
"output".
The stdin input has no prefix so that editing behaves the way you know.
5) usage tips:
==============================================================================
create your own custom commands like this
" AsyncSh only works in gvim. if you use vim it magically suspends? Probably
" some signals taking a wrong path (?)
command! AsyncSh call async_porcelaine#LogToBuffer({'cmd':'/bin/sh -i', 'move_last':1, 'prompt': '^.*\$[$] '})
command! AsyncCoq call async_porcelaine#LogToBuffer({'cmd':'coqtop', 'move_last':1, 'prompt': '^Coq < '})
command! AsyncRubyIrb call repl_ruby#RubyBuffer({'cmd':'irb','move_last' : 1})
command! AsyncPHP call repl_php#PHPBuffer({'cmd':'php -a','move_last' : 1})
command! AsyncSML call repl_ruby#RubyBuffer({'cmd':'sml','move_last' : 1, 'prompt': '^- '})
command! AsyncPython call repl_python#PythonBuffer({'cmd':'python -i','move_last' : 1, 'prompt': '^>>> '})
command! AsyncScala call async_porcelaine#ScalaBuffer({'cmd':'scala','move_last' : 1, 'prompt': '^scala> '})
command! AsyncLogicblox call repl_logicblox#LogicbloxBuffer({'move_last' : 1})
A history has been implemented. Press <c-h> to use select a line you've used
previously. Or press ```<c-x><c-h>``` to get completion in buffer.
See plugin/vim-addon-async.vim for file location and max lines
6) Credits:
===============================================================================
Thanks to:
* Bart Trojanowski who provided the initial C implementation of the Vim patch
(Thus he did most of the work)
* Sergey Khorev who provided the initial racket (scheme implementation) code
Someone (me?) still has to make it complete.
7) related work:
==============================================================================
Nico Raffo told me that he's been working on a idle timer like event for Vim.
This would be another perfect match to provide a different implementation.
http://www.vim.org/scripts/script.php?script_id=4336
vimproc plugin
http://github.com/Shougo/vimproc/tree/master/doc/
- TODO: put more details here
Conque Shell plugin:
http://code.google.com/p/conque
- looks like being a complete terminal emulator trying to map terminal
commands to Vim buffer?
Thus Conque can do much more than vim-addon-async. It can even run vim
inside gvim!
- must be in insert mode to receive screen updates
- probably more cross platform
- probably causing less crashes
- TODO: put more details here, read its documentation
- neovim
Screen (vim + gnu screen/tmux) : Simulate a split shell, using gnu screen or tmux:
http://www.vim.org/scripts/script.php?script_id=2711
This was announced on the mailinglist (client-server without X):
http://code.google.com/r/yukihironakadaira-vim-cmdsrv-nox/
clone then hg update -C cmdsrv-nox works perfectly without X!
vim remote library:
https://github.com/ynkdir/vim-remote
http://vim.wikia.com/wiki/Execute_external_programs_asynchronously_under_Windows
Implementation based on netbeans protocol:
https://github.com/jlc/vim-async-beans
(using python thread and CursorHold event):
https://github.com/troydm/shellasync.vim
[conque repl](http://www.vim.org/scripts/script.php?script_id=4222)
[vim-dispatch](https://github.com/tpope/vim-dispatch)
8) yet two another examples:
==============================================================================
VIML CODE EXAMPLE: >
fun! s:Add(s)
let l = [{'text': string(a:s)}]
call setqflist(l, 'a')
endf
" ctx 1
let ctx = { 'cmd' : 'nr=1; while read f; do nr=`expr $nr + 1`; sleep 1; echo $nr $f - pong; if [ $nr == 5 ]; then break; fi; done; exit 12' }
fun ctx.receive(data, ...)
call s:Add(string(a:text))
call async_write(self, "ping\n")
endf
fun ctx.started()
call s:Add("ctx1: process started. pid: ". self.pid)
endf
fun ctx.terminated()
call s:Add("ctx1: process died. status (should be 12): ". self.status)
endf
call async_exec(ctx)
call async_write(ctx, "ping\n")
" ctx2 2
let ctx2 = { 'cmd' : 'find / | while read f; do echo $f; sleep 1; done' }
fun ctx2.receive(type, text)
call s:Add('ctx22: '.string(a:text))
endf
fun ctx2.started()
call s:Add("ctx22: process started. pid: ". self.pid)
endf
fun ctx2.terminated()
call s:Add("ctx22: process died. status: ". self.status)
endf
call async_exec(ctx2)
9) TIPS:
==============================================================================
this debugging worked best for me:
call append('$', string)
10) TROUBLE?
==============================================================================
MAC/OSX/Linux/...:
If vim in PATH does not support client-server nothing will happen. You have to
tell VAM which path to pass to the externel helper by putting this into your .vimrc:
let g:async = {'vim' : 'path-to-vim-executable-supporting-client-server'}
On OSX it is likely to be macvim. You can achieve the same by symlinking
macvim or vimx or whatsoever to vim.
Currently only the 'impl 2' implementation is supported fully (see above). This means
1) :echo has('clienserver') must report 1
2) :echo v:clientserver must not be null ( pass vim --servername NAME )
3) You must have the c executable compiled (The plugin should try doing this for
you though). Search for gcc above to learn how to compile it manually
I recommend using a command like this for debugging:
call async_porcelaine#LogToBuffer({'cmd':'/bin/sh -i', 'debug_process' : 1 })
More notes:
Using the client-server I faced several issues:
- if there is a VimL error you don't see it (try using debug or run the code
manually within Vim)
- some commands seem to behave strange.
Eg in vim-addon-xdebug I had to switch off syntax else Vim crashes. Also
"normal jdd" seem to never return in one case
Summary: Everything seems to work fine if you're willing to spend some time on
finding workarounds on some commands. If you have issues contact me and I'll
try to help.
11) testing new implementations
===============================
try running this test which checks whether all characters (0 - 255) are quoted
correctly:
call vim_addon_async_tests#Binary()
call vim_addon_async_tests#Chunksize()
12) TODO:
===============================================================================
* find out about the prompt automatically by pressing enter multiple times.
(eg irb also prints the line number. So maybe it should not be skipped?)
* Would such a function make sense: ? Maybe even having a timeout?
async_read_until({ctx}, {string} -- read bytes from stdout until one of the
chars contained in string is found
-- this way you can read lines etc easily.
Don't know yet how useful it is. This way
you can implement "blocking" read features
if you have to.
Example use case would be completion.
Another way would be returning no
completions restarting completion task if
cursor didn't move and the completion
results are received by the specified
receive function
* some apps require a (pseudo) terminal, eg debugging ruby.
This is a workaround: socat EXEC:ruby\ app.rb,pty,stderr -