Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to emulate Matlab’s Run command (F5) from within Vim?

I’m using Linux and gVim/Vim as an external editor for Matlab.

In Matlab editor you can run a file by pressing F5. I’m trying to reproduce this in Vim (installed from the gvim-gtk Debian package).

I know it is possible to send the name or the current file or the selected text to Matlab in “shell mode” like so:

execute '!echo "' ."run(\'".expand("%:p")."\')" . '"| matlab -nojvm' 
execute '!matlab -nodisplay < '.expand("%:p") 
noremap <C-CR> :?%%?;/%%/w !matlab -nojvm

But I want to use the Matlab GUI (which in my case is already opened).

Here is the solution I thought could work out for me:

  1. Use a key mapping in vim that would:

    • (a) Put in the clipboard something like: run('path-to-file') or cd('folder');run('filename').
    • (b) Call a shell command that gives the focus to the Matlab GUI
  2. At this point, I should be in Matlab command window, so I just press Ctrl-V, and the content of the clipboard should be pasted. (Even though I’m on Linux, I use Matlab with Windows keybindings.)

Step 1(a): The following will put the run('filename') command to the clipboard, and Matlab will paste it when Ctrl-V is pressed:

let @+="run(\'".expand("%:p")."')" 

The following two commands would work with the Linux middle button pasting, but that is not what I want, as I want to avoid the mouse in this step:

let @*="run(\'".expand("%:p")."')" 

execute '!echo "' . "run(\'".expand("%:p")."\')" . '"| xclip'  

Step 1(b): To give the focus to the Matlab window, I use the following command:

wmctrl -a MATLAB &

This works well, but it might also raise a browser window, if it happens to have a page open with the word Matlab in its title (like the one you are reading at the moment).

See also a more complex solution: Is there a linux command to determine the window IDs associated with a given process ID?.

My (now old) option, but Ctrl-V does not work! Only mouse pasting does:

function! MatRun()
    let @+="run(\'".expand("%:p")."')" 
    let @*="run(\'".expand("%:p")."\')" 
    :call system('xclip', @+)
    !wmctrl -a MAT
endfunction

map <F5> :call MatRun() <cr><cr>

Somehow, Ctrl-V does not work in this case when combined with wmctrl (see the edit below). The whole point for me is to avoid using the mouse for this operation.

Thank you for your help.

Update: a working option

My bad, I was using xclip where I should have used xclip -selection c. See my reply below.

I’d be glad if somebody find a better solution, for instance: pasting directly in Matlab command windows, making sure you are in the command windows (Ctrl-0), or avoiding catching browser windows with wmctrl.

like image 956
e-malito Avatar asked Apr 20 '12 16:04

e-malito


2 Answers

EDIT: See plugin made from it: https://github.com/elmanuelito/vim-matlab-behave

Sorry for replying to my own question. It's my bad, I was using xclip where I should have used xclip -selection c . I put below the different codes that work out for me: it reproduces the F5 and the evaluate cell behavior but you have to press Ctrl-V or use the mouse to paste in Matlab Command Window. If you are not on the command window, use matlab shortcut Ctrl-0 to jump to it. The script automatically goes from vim to matlab(unless you have another window with the name "matlab" in it). I added marks to go back to the former cursor position afterwards.

To run the whole script matlab: This is the "Run/F5" behavior (goes to the right directory and execute the whole script):

function! MatRun()
   normal mm " mark current cursor in mark m"
   let @+="cd('".expand("%:p:h")."\'); run('./".expand("%:f"). "')"
   call system('xclip -selection c ', @+)
   call system('xclip ', @+)
   normal `m "go back to cursor location"
   !wmctrl -a MATLAB 
endfunction
map ,m :call MatRun() <cr><cr>

To run, evaluate the cell only : This is the Ctrl+Enter behavior. In the same line than above: (edit: I now extended it so that it will work from the first upward %% OR the start of the file (\%^) till the first downward %% OR the end of the file (\^$) end edit)

function! MatRunCell()
    normal mm "remember cursor"
    :?%%\|\%^?;/%%\|\%$/w !xclip -selection c  "pipe the cell to xclip"
    normal `m "go back to cursor location"
    !wmctrl -a MATLAB  "go to matlab window"
endfunction
map ,k :call MatRunCell()  <cr><cr>

But I like better the following one, though more complicated (and could certainly be made vim-only). The following, ensures you are in the right directory to run the cell, and also goes back to Vim after evaluating the cell (if you have correctly configured the external editor in matlab. I use:gvim --servername MAT --remote-tab-silent).

 function! MatRunCellAdvanced()
     execute "!echo \"cd(\'".expand("%:p:h")."\')\">/tmp/buff"  
     normal mm
     :?%%\|\%^?;/%%\|\%$/w>> /tmp/buff
     execute "!echo \"edit ".expand("%:f")."\">>/tmp/buff"
     !cat /tmp/buff|xclip -selection c
     !cat /tmp/buff|xclip
     normal `m
     !wmctrl -a MATLAB 
 endfunction
map ,n :call MatRunCellAdvanced()  <cr><cr>

Run current line : Copy current line to clipboard and go to matlab window. (once again Control+V to paste it in matlab, if it's the short-cut you use in matlab)

 function! MatRunLine()
     " write current line and pipe to xclip "
     :.w !xclip -selection c
     !wmctrl -a MATLAB 
 endfunction
 map ,l :call MatRunLine()  <cr><cr>

Run selection : Emulates F9 behavior.

  function! MatRunSelect()
     normal mm
     !rm -f /tmp/buff
     :redir > /tmp/buff
     :echo @*
     :redir END
     execute "!echo \" \">>/tmp/buff"
     execute "!echo \"edit ".expand("%:p")."\">>/tmp/buff"
     !cat /tmp/buff|xclip -selection c
      normal `m
     !wmctrl -a MATLAB 
  endfunction

Bold Cell title Bold font in the cell title

 highlight MATCELL cterm=bold term=bold gui=bold
 match MATCELL /%%.*$/

Where to put those commands All of these commands in .vim/after/ftplugin/matlab.vim

edit Instead of using:

 run('./".expand("%:f")."')"

I now use

run('".expand("%:p")."')"

To deal with the case where vim 'pwd' is different from the script directory. I didn't find a way to extract just the script name, so I use the full path. Somebody can probably find a nicer solution for that.

like image 183
e-malito Avatar answered Nov 16 '22 15:11

e-malito


For those of you who just want to be able to run matlab scripts from vim and do not need the other fancy GUI stuff you could try using matlab's command line shell.

:! matlab -nosplash -nodesktop -r %:r will start a new matlab shell and run the current file as script (or function with no parameters) similar to what F5 in the matlab GUI does. You will need to type 'exit' to get out of the matlab shell and back to vim afterwards. And of course this works only if the file you want to run is in the matlab path or the terminal's working directory.

This may be a bit inconvenient and since a new matlab instance is started all the time, running the script may take a while. You could try using -nojvm to avoid the overhead caused by java but the best solution in my opinion is keeping the matlab shell open.

You can do this with a Vim Plugin called Conque-Shell.
Once installed you can start the matlab shell with :ConqueTerm matlab -nodesktop and you will get a buffer that you can use like the matlab console. Executing code parts will work just fine with yank and paste. Or you could create vim functions that do this for you. Since I'm not very good at this I can only provide this ugly mapping here:

:nmap <f5> :let @"=expand('%:r')<cr>:buffer matlab\ -nodesktop<tab><cr>""p<cr>

like image 40
swenzel Avatar answered Nov 16 '22 15:11

swenzel