keflavich / macvim-skim

Interlink macvim & skim for an integrated LaTeX DE
16 stars 6 forks source link

Need to select correct window after selecting tab in mvim #6

Open CptStubing opened 11 years ago

CptStubing commented 11 years ago

I was working on my "SmartOpen" script, and thought of an issue that I came back to check on in your bash script...

# you find the correct instance of mvim if several are running, 
# and find one that contains a loaded buffer of the file you're 
# looking for ($foundfile)
mvim --servername $server --remote-expr "foreground()"
mvim --servername $server --remote-send ":exec \"tabnext $foundfile\" <CR>"
mvim --servername $server --remote-send ":$line <CR>"

OK, so you select the correct tab, then jump to the desired line. The problem is that tabs can have multiple split windows inside them, and this technique is just going to give focus to whichever window was last used on that tab by mvim when it switches to it with :tabnext.

To reproduce: 1) open the doc in Skim.app 2) open the source in mvim 3) in that same tab in mvim, create another window with :new whatever 4) make another tab in mvim (not necessary, but helps to demonstrate) 5) go back and invoke your bash script from within Skim.app (shift-command-click?)

This should switch to the correct tab, but not the correct window within that tab, and your --remote-send ":$line <CR>" will either jump to the line in the other window's buffer or its last line if $line exceeds its number of lines.

So, you could write another function and instead of making 3 calls to mvim from the shell, just make one call that executes the foreground, tabnext, SelectWindow of some sort, and then :$line. However, I was also thinking.. you probably need to break that loop after you succeed in finding an mvim server with your source file open. If you have multiple mvim servers (gui windows) running, you probably don't want this script playing a game of musical windows on your desktop. ;)

I wrote a vim function that has been working great the past few days of use, although I can't say it's 100% bulletproof. Instead of trying to find the right tab and window, it takes advantage of vim's behavior in the command :sbuffer:

:[N]sb[uffer] [N]                   *:sb* *:sbuffer*
    Split window and edit buffer [N] from the buffer list.  If [N]
    is not given, the current buffer is edited.  Respects the
    "useopen" setting of 'switchbuf' when splitting.  This will
    also edit a buffer that is not in the buffer list, without
    setting the 'buflisted' flag.

So, what I do is capture the user's current settings for &switchbuf, save them, set it to the necessary setting of let &switchbuf = "useopen,usetab", then check if the buffer's loaded somewhere and call exec "sbuffer" bufNo. Vim then switches to the correct tab & window automagically without me having to muck with searching through tabs and windows myself. Then I set the user's original settings back to &switchbuf. Anyway, I modified what I had for you:

function! MVS_Focus(filename, line)
  " See if the given filename is found to be loaded in any tab/window
  " if so, raise window, switch to file's tab, window, and jump line
  let oldSwitchBufOpt = &switchbuf
  let &switchbuf = "useopen,usetab"
  let bufNo = bufnr('\(^\|/\)' . a:filename . '$')
  if (!bufNo || !bufloaded(bufNo))
    return 0
  endif
  call foreground()
  exec "sbuffer" bufNo
  let &switchbuf = oldSwitchBufOpt " restore user's switchbuf option
  exe ":silent! :".a:line
  " see if you like this... could also pass a number of lines down to highlight
  exe ":normal V"
  call REcho(printf("Focused on %s line %d by macvim-skim.", fnamemodify(bufname("%"), ":f"), a:line))
  return 1
endfunction

" Redraw-echo (:he echo-redraw) -- more reliable echo!
function! REcho(msg)
  redraw | echo a:msg
endfunction

Now you can just make a single call to each mvim server...

for server in mvim --serverlist do if [[ $debug ]] ; then echo mvim --servername $server --remote-expr "MVS_Focus('$file', '$line')"; fi finished=mvim --servername $server --remote-expr "MVS_Focus('$file', '$line')" if [[ $finished > 0 ]] then echo Succeeded on servername: $server break fi done

CptStubing commented 11 years ago

Oh yeah, regarding the exe ":normal V"... I think visual mode isn't on if compatible is set and maybe under some other circumstances, but I was just throwing the idea out there for you along with sending an echo message.

keflavich commented 11 years ago

Just FYI - I worked on this a bit, then had to set the project aside. There's a branch (https://github.com/keflavich/macvim-skim/tree/smartbuffer) that tries to implement these changes.