Skip to content
This repository has been archived by the owner on Dec 20, 2021. It is now read-only.

Commit

Permalink
Improve buffer switching / add pause-continue messages
Browse files Browse the repository at this point in the history
* Buffer switching:

Vim, when receiving insert() messages from NetBeans is switching to the
buffer which has receiving such messages.
Such insert messages are used in order to help vim to communicate with the
outside world (as opposed to some developers who have a strong tendency
to avoid such communications - specially when involved in fascinating
projects - hum, I have been interrupted by myself again...), therefore,
it is strongly advised that vim stay in its current buffer and keep its
position.

In order to do so, 2 solutions:

- before each messages (may be optimizable), ask vim about the cursor
  position (thanks to NetBeans' getcursor), and then, right after
  sending the inserted text, send a setdot message with the previously
  received position.
  This solution, without the fact of its absolute inefficiency, works in
  most cases, except when vim does not know itself which buffer it is on,
  (which may happen in some cases), and reply -1 to the getCursor call.
  The direct effect is to show you the input buffer.

- another options, as newly implemented here, is simply to keep track
  about the current buffer and cursor position thanks to vim's events.
  Then, whenever receiving an insert message, simply swtich back to the
  previous buffer and cursor position.
  This works quite well!

* Pause / continue messages:

2 new messages have been added to the "kind of" protocol which support
communications between Vim and VimProcRunner.
(Sure, after reading the few lines which implement it, it _must_ be
redone, however, for now, it deserves to do its job.)

Anyway, these new messages enable vim to pause and/or continue messages
sending from VimProcRunner.

One of the side effect of this "buffer switching on insert", appears
whenever a popup menu, or so called omni-completion menu, is displayed:
it is making it disapear from the screen.

Pause/continue is quite a good solution for now to avoid this behavior.

After few days behind the screen, I am sorry to impose you my talkative mood.
  • Loading branch information
Jeanluc Chasseriau committed Apr 9, 2012
1 parent 5f35c94 commit c7cbb2a
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.swp
*.swo
*.pyc
80 changes: 59 additions & 21 deletions autoload/abeans.vim
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ let g:abeans['addon-dir'] = get(g:abeans, 'addon-dir', expand('<sfile>:h:h'))
let g:abeans['ctxs'] = get(g:abeans, 'ctxs', {})
let g:abeans['connected'] = get(g:abeans, 'connected', 0)

let g:abeans.currentBuffer = bufnr('%')
let g:abeans.currentPos = getpos('.')

python << endpython
import vim
import sys
Expand All @@ -38,6 +41,8 @@ VIM_BUFFER_IN_FILENAME = 'vim-async-beans.in'

EXEC_CMD = "##_EXEC_%d_[%s]_##"
KILL_CMD = "##_KILL_%d_##"
PAUSE_CMD = "##_PAUSE_##"
CONTINUE_CMD = "##_CONTINUE_##"

RE_STARTED = re.compile("^##_STARTED_(\d+)_##$")
RE_TERMINATED = re.compile("^##_TERMINATED_(\d+)_##$")
Expand Down Expand Up @@ -104,18 +109,11 @@ def parse(line):
# updateBuffer()
# update given buffer by executing given function
# take care of setting buffer options
# note: this reset the message
def updateBuffer(id, f):
preCmds = [
"buffer %d" % (id),
"setlocal modifiable",
]
postCmds = [
"setlocal nomodifiable",
"buffer %d" % (vim.current.buffer.number)
]
vim.command("\n".join(preCmds))
vim.command("call setbufvar(%d, '&modifiable', 1)" % (id))
f()
vim.command("\n".join(postCmds))
vim.command("call setbufvar(%d, '&modifiable', 0)" % (id))

@CatchAndLogException
def send(data):
Expand All @@ -133,20 +131,30 @@ def startExec(cmd):
@CatchAndLogException
def processInput():
global VIM_BUFFER_IN_ID

currentBuffer = vim.eval("g:abeans.currentBuffer")
ablog().debug("processInput: currentBuffer: %s", currentBuffer)

id = VIM_BUFFER_IN_ID - 1 # array index start at 0
lines = []
lines.extend(vim.buffers[id])

def clear():
for i in range(len(vim.buffers[id])):
del vim.buffers[id][i]
def clear(): vim.buffers[id][:] = None

updateBuffer(VIM_BUFFER_IN_ID, clear)

cmds = [
"buffer %s" % (currentBuffer),
"call setpos('.', g:abeans.currentPos)"
]
vim.command("\n".join(cmds))

# parse line after switching buffer
for line in lines:
ablog().debug("processInput: parsing: '%s'", line)
parse(line)


@CatchAndLogException
def findBuffers():
global _processInput, VIM_BUFFER_OUT_ID, VIM_BUFFER_IN_ID
Expand All @@ -161,20 +169,27 @@ def findBuffers():
setBufferOptions(VIM_BUFFER_OUT_ID)
setBufferOptions(VIM_BUFFER_IN_ID)

vim.command("buffer %s" % (vim.eval("bufnr('$')")))
currentBuffer = vim.eval("bufnr('$')")
cmds = [
"let g:abeans.currentBuffer = %s" % (currentBuffer),
"buffer %s" % (currentBuffer),
"redraw"
]
vim.command("\n".join(cmds))

_processInput = findBuffers

def setBufferOptions(id):
options = [
"buftype=nofile",
"bufhidden=hide",
"noswapfile",
"nobuflisted",
"nomodifiable"
('buftype', "'nofile'"),
('bufhidden', "'hide'"),
('swapfile', "0"),
('buflisted', "0"),
('modifiable', "0"),
('lazyredraw', "1")
]
vim.command("buffer %d" % (id))
vim.command("setlocal "+' '.join(options))
cmds = ["call setbufvar(%d, '&%s', %s)" % (id, opt, value) for opt, value in options]
vim.command("\n".join(cmds))
endpython

fun! abeans#start()
Expand Down Expand Up @@ -206,6 +221,10 @@ fun! abeans#exec(ctx)
call abeans#write(self, a:data)
endfun

fun! a:ctx.writeAndPause(data, after)
call abeans#writeAndPause(self, a:data, a:after)
endfun

python << endpython
global EXEC_CMD
cmd = vim.eval("a:ctx.cmd")
Expand All @@ -223,10 +242,29 @@ fun! abeans#write(ctx, data)
py send("##_DATA_%s_##%s" % (vim.eval("a:ctx.abeans_id"), vim.eval("a:data")))
endfun

fun! abeans#writeAndPause(ctx, data, after)
py send("##_DATA_%s_AND_PAUSE_AFTER_%s_##%s" % (vim.eval("a:ctx.abeans_id"), vim.eval("a:after"), vim.eval("a:data")))
endfun

fun! abeans#kill(ctx)
endfun

fun! abeans#processInput()
py _processInput()
endfun

fun! abeans#setCurrentBuffer(event)
let g:abeans.currentBuffer = bufnr('%')
let g:abeans.currentPos = getpos('.')
endfun

fun! abeans#pauseMessages()
py ablog().debug("abeans#pauseMessages: pausing")
py send(PAUSE_CMD)
endfun

fun! abeans#continueMessages()
py ablog().debug("abeans#continueMessages: continuing")
py send(CONTINUE_CMD)
endfun

13 changes: 13 additions & 0 deletions plugin/abeans.vim
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,18 @@ command! -nargs=0 AsyncBeans call abeans#start()

augroup ASYNCBEANS
au!

" setCurrentBuffer: keep tracking where we are
" DEBUG: pass event name for debugging only
" BufEnter is catched when entering into vim-async-beans.*
" If necessary, we should find a way to exclude those ones
autocmd BufNewFile * :call abeans#setCurrentBuffer("BufNewFile")
autocmd BufAdd * :call abeans#setCurrentBuffer("BufAdd")
autocmd BufCreate * :call abeans#setCurrentBuffer("BufCreate")
autocmd BufFilePost * :call abeans#setCurrentBuffer("BufFilePost")
autocmd BufNew * :call abeans#setCurrentBuffer("BufNew")
autocmd TabEnter * :call abeans#setCurrentBuffer("TabEnter")
autocmd CursorMoved,CursorMovedI * :call abeans#setCurrentBuffer("CursorMoved")

autocmd BufReadPost vim-async-beans.in :call abeans#processInput()
augroup end
93 changes: 82 additions & 11 deletions python/VimProcRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,19 @@ def __init__(self, main, vimSocket):

self.reProtoExecCmd = re.compile("^##_EXEC_(\d+)_\[(.*)\]_##$")
self.reProtoKillCmd = re.compile("^##_KILL_(\d+)_##$")
self.reProtoDataCmd = re.compile("^##_DATA_(\d+)_##(.*)$")
self.reProtoDataCmd = re.compile("^##_DATA_(\d+)_##(.*)$")
self.reProtoDataAndPauseCmd = re.compile("^##_DATA_(\d+)_AND_PAUSE_AFTER_(\d+)_##(.*)$")
self.reProtoPauseCmd = re.compile("^##_PAUSE_##$")
self.reProtoContinueCmd = re.compile("^##_CONTINUE_##$")
self.protoStarted = "##_STARTED_%d_##"
self.protoTerminated = "##_TERMINATED_%d_##"
self.protoData = "##_DATA_%d_##%s"

self.isPause = False
self.pausedMessages = []
self.pauseAfter = 0 # nb messages to count before pausing
self.pauseAfterProcId = 0 # id of the process to count message from

def hasInsert(self, bufId):
if not self.buffersInserts.has_key(bufId):
return False
Expand All @@ -206,6 +214,23 @@ def getLastInsert(self, bufId):
self.buffersInserts[bufId].reverse()
return insert

def pauseVimMessages(self, after=0, procId=0):
log.debug("ProcRunner.pauseVimMessages: pausing")
if after > 0:
self.pauseAfter = after
self.pauseAfterProcId = procId
else:
self.isPause = True

def continueVimMessages(self):
log.debug("ProcRunner.continueVimMessages: continuing")
self.isPause = False

for msg in self.pausedMessages:
self.sendToVim(msg)

self.pausedMessages = []

def setupInOutBuffers(self):
# note: when using create(), buffer ids are killed and reopened by vim
# weirdly, initial ids are still used by vim later on
Expand Down Expand Up @@ -309,10 +334,33 @@ def dataCmd(m):
self.writeRawToProc(id, data)
return True

def dataAndPauseCmd(m):
try:
id = int(m.group(1))
pauseAfter = int(m.group(2))
data = m.group(3)
except:
log.exception("ProcRunner.fromVim.dataCmd: exception")
return False

self.pauseVimMessages(after=pauseAfter, procId=id)

self.writeRawToProc(id, data)
return True

def pauseCmd(m):
self.pauseVimMessages(after=0)

def continueCmd(m):
self.continueVimMessages()

regexps = [
(self.reProtoExecCmd, execCmd),
(self.reProtoKillCmd, killCmd),
(self.reProtoDataCmd, dataCmd)
(self.reProtoDataCmd, dataCmd),
(self.reProtoDataAndPauseCmd, dataAndPauseCmd),
(self.reProtoPauseCmd, pauseCmd),
(self.reProtoContinueCmd, continueCmd)
]

for (r, cb) in regexps:
Expand All @@ -325,19 +373,42 @@ def dataCmd(m):

def fromProc(self, desc, data):
id = self.invProcesses[desc]

log.debug("ProcRunner.fromProc: %d : %s" % (id, data))
self.sendToVim(self.protoData % (id, data))

if self.pauseAfter > 0 and self.pauseAfterProcId == id:
self.pauseAfter -= 1
if self.pauseAfter == 0:
self.isPause = True

def sendToVim(self, data):
def cb(bufId, lnum, column, offset):
self.startAtomic()
self.insert(self.vimProxyInId, 99999, data.strip())
self.initDone(self.vimProxyInId)
if bufId >= 0:
self.setDot(bufId, offset)
self.endAtomic()

self.getCursor(cb)
if self.isPause:
self.pausedMessages.append(data)
return True

# NOTE:
# when vim receive insert() and initDone(), it set the buffer as visible,
# this is not what we want. In order to hide this behavior, either
# a) call getCursor() before and then setDot() which is not efficient and
# not always reliable, or
# b) autocmd vim's events to keep track of the current buffer and then set the buffer

# b)
self.startAtomic()
self.insert(self.vimProxyInId, 99999, data.strip())
self.initDone(self.vimProxyInId)
self.endAtomic()

# a)
#def cb(bufId, lnum, column, offset):
# self.startAtomic()
# self.insert(self.vimProxyInId, 99999, data.strip())
# self.initDone(self.vimProxyInId)
# if bufId >= 0:
# self.setDot(bufId, offset)
# self.endAtomic()
#self.getCursor(cb)

def send(self, data):
self.writeRawToVim(data)
Expand Down

0 comments on commit c7cbb2a

Please sign in to comment.