This plugin will provide different async communication implementations
Switch branches/tags
Nothing to show
Pull request Compare This branch is 73 commits behind MarcWeber:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
C
autoload
plugin
.gitignore
README

README

list of plugins using vim-addon-async:
===============================================================================
- ensime (Scala server providing fast type checking and completion)
- vim-addon-xdebug (xdebug implementation for Vim)

two REPL (read print eval loop) implementations are available for
  - Scala
  - Ruby
providing completion on objects etc.

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#Start(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.

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': '^>>> $'})
  then type:
    oprint "abc"<space><cr>
  (everything started by "> " will be treated as text to be sent to python when
  <space><cr> is typed in insert mode
  Alternatively you can visually select lines and press <cr> in visual mode to
  send the text to the buffer as is (thus no leading > will be removed)

  See commentary of the LogToBuffer function has more sophisticated examples.

  Sample python session:

  pid: 24067
  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.
  > print "hello world"
  hello world
  > num1 = 40 #1
  > num2 = 42 #2
  > for i in range(num1, num2):
  >    print i
  > 
  ... ... 40
  41
  > 

  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


(the ... sent by the interpreter still has to be removed ! TODO)


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 mode (Vim should not disturb you when typing)
- you're in command line or command win buffer (q:)
  Reason: You can't switch buffers or tabs when its open.

installation & implementation details:
===============================================================================

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)

      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)


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.


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.

  vimproc plugin
  http://github.com/Shougo/vimproc/tree/master/doc/

  Conque Shell plugin:
  http://code.google.com/p/conque

IMHO their only issue is that they block Vim if have long running tasks.

  Screen (vim + gnu screen/tmux) : Simulate a split shell, using gnu screen or tmux:
  http://www.vim.org/scripts/script.php?script_id=2711

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)

TIPS:
==============================================================================
this debugging worked best for me:
call append('$', string)

TROUBLE?
==============================================================================
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()

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.


TODO:
===============================================================================
* c_executable implementation: pass huge chunks of data using a files.
  Having many calls is too slow!

* find a way to send interrupt signals (ctrl-c) ?

* LogToBuffer could be made even smarter: make it skip repeating lines. Make it

* 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