vim: open fold with remote-silent - vim

I have this function to do inverse searches (from the pdf to Vim) when working with LaTeX documents in MS Windows:
function! ViewTex()
if has('win32') || has('win64')
let execstr = 'silent! !start SumatraPDF -reuse-instance '.
\ '-inverse-search "gvim --remote-silent +\%l \%f"'.
\ '%:p:r.pdf'
endif
exec execstr
endfunction
This works fine except that it will not open closed folds. So my question is: how to pass normal zv command to --remote-silent? I tried (without success) the following:
"gvim --remote-silent +\%l|normal\ zv \%f"

Back to your first attempt, in most situations the Windows cmd.exe shell doesn't use '\' to escape anything. So I think you need to surround your init commands in quotes instead of backslash-escaping the spaces. Also, according to :help --remote, the commands in the init must be able to have a following '|' to separate them, meaning normal will not work unless surrounded with an execute command. So in your case something like this will eventually need to execute in the shell:
gvim --remote-silent +"%l|exe 'normal! zv'" %f (with the quotes included)
But I'm not sure whether this allows expansion as desired of %1 and %f.
Edit:
Or, use foldopen! instead of exe 'normal! zv' to avoid the need for spaces or exe at all. But, note this actually opens more folds than just zv; maybe that's OK for you.
From your comments, it looks like whatever platform you're using requires backslash-escaping any '%' characters, so:
gvim --remote-silent +\%l|foldopen! \%f

Edit: The explanation below is slightly wrong but the method is sound. I missed that the --remote family takes an optional "init" command argument; it's part of the --remote-silent command not a new argument to gvim. The explanation below fits for if it was a new argument to gvim.
The problem is that the Vim which runs to send the remote file will also run the +... command, rather than the Vim which actually edits the file. Try using --remote-send or --remote-expr after the --remote-silent, to send the commands you need to run after loading the file.
I.e. something like:
gvim --remote-silent myfile
gvim --remote-send zv
etc.

Related

Run command from vim without leaving the vim window

I'd like to run a command from vim editor as follows.
:!mplayer %.mp3
The mp3 file contains spoken word related to the opened file.
When I run the command, it will close the vim window.
I'd like the vim window stay open and hear the mp3 file.
When you don't need to read the output of the external command, better use system() over :!, like this:
:call system('mplayer ' . expand('%') . '.mp3 &')
% won't be automatically expanded here, but that's no problem. The & is needed to avoid blocking Vim during playback. The call returns the output of mplayer, but you're apparently only interested in hearing the sound.
The following should do the trick:
:execute 'silent !mplayer %.mp3 &' | redraw!
Source
Maybe you want to run the command on the background? Then add &:
:!mplayer %.mp3&

vim: map command with confirmation to key

I've written a few macros in my .vimrc for the version control system I'm using (Perforce) (please don't suggest the perforce plugin for vim, I tried it and I don't like it). They all work fine except the revert macro, which breaks due to a confirmation prompt (which I need so I don't accidentally fat-finger my changes away). It currently looks like this:
map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif
This causes bash to complain when vim tries to load the file:
bin/bash: -c: line 0: syntax error near unexpected token `('
Looking at the buffer bash sees, it looks like the error is that vim sends it everything after the first pipe, not just the part meant for bash. I tried a few alternatives but I can't seem to make it work. I've got it to show confirm dialog correctly when I removed the pipes and endif (using shorthand if), but then vim complains after the user gives a response.
I think you want something along these lines:
:map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 <Bar> exe "!p4 revert" . expand("%:p") <Bar> edit <Bar> endif<CR><CR>
Remember that :map is a dumb sequence of keystrokes: what you're mapping F8 to has to be a sequence of keystrokes that would work if typed. A <CR> in the middle of the :if statement doesn't mean ‘and press Enter when executing the command at this point if the condition is true’; it means ‘press Enter here when in the middle of typing in the :if command’, which obviously isn't what you want.
Building it up a piece at time, from the inside out:
There's a shell command you sometimes want to run.
That shell command needs to be inside an :if to do the ‘sometimes’ bit, and so have an :endif following it.
After a literal ! everything following is passed to the shell, including | characters which normally signify the start of another Vim command. That's reasonable, because | is a perfectly good character to use in shell commands. So we need some way of containing the shell command. :exe can do this; it executes the supplied string as a command — and its argument, being a string, has a defined end. So the general form is :if condition | exe "!shell command" | endif.
Your shell command has an expression in it. Using :exe makes this easy, since you can simply concatenate the string constant parts of the command with the result of the expression. So the command becomes :exe "!p4 revert" . expand("%:p") — try that out on its own on a file, and check it does what you want before going any further.
Putting that inside the condition gives you :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — again try that out before defining the mapping.
Once you have that working, define the mapping. A literal | does end a mapping and signify the start of the next Vim command. In your original the mapping definition only went to the end of the condition (check it with :map <F8> after loading a file) and the !p4 part was being run immediately, on the Vim file that defines the mapping! You need to change each | in your command into <Bar>, similarly to how each press of Enter in your command needs writing as <CR>. That gives you the mapping above. Try it by typing it at the command line first, then do :map <F8> again to check it's what you think it is. And only then try pressing F8.
If that works, put the mapping in your .vimrc.
Use of the pipe to string multiple vim commands together is not particularly well-defined, and there are numerous eccentricities. Critically, (see :help :bar) it can't be used after a command like the shell command :! which sees a | character as its argument.
You might find it easier to use the system() function.
E.G.
:echo system("p4 revert " . shellescape(expand("%:p")))
The shellescape() wrapper is useful in case you have characters like spaces or quotes in the filename (or have cleverly named it ; rm -rf ~ (Don't try this at home!)).
In the interest of creating more readable/maintainable code, you may want to move your code into a function:
function Revert()
if confirm('Revert to original?', "&Yes\n&No", 1)==1
return system("p4 revert " . shellescape(expand("%:p")))
endif
endfunction
which you would access by using the :call or :echo command in your macro.

Vim --remote-expr example

Since my google-fu is failing me, can anyone give me a simple example on how to use --remote-expr or any other command line trick to insert text to current buffer, or to set a cfile. (Any : -command would be good.)
All I manage to get with --remote-expr is E449: Invalid expression received for anything.
:help E449 leads you to a basic example. Unfortunately it is a bit too basic:
remote_expr({server}, {string} [, {idvar}])
Examples:
:echo remote_expr("gvim", "2+2")
:echo remote_expr("gvim1", "b:current_syntax")
In command line, that turns into
$ vim --servername "gvim" --remote-expr "2+2"
4
To get an idea what you can do with expressions, see :help expr.
Ordering Vim to insert text from Command line
You are better off with --remote-send that sends key sequences in similar manner as you'd do with maps or abbrs:
$ vim --servername Foo --remote-send "GoHello world! <ESC>"
will append a new line at the end of the active window's buffer.
If you want to execute a command, let's say :ls, to get a list of buffers, you can do
vim --servername GVIM --remote-expr "execute(\"ls\")"
This will print the list of all buffers in GVIM server. Note the escaped quotes.

How to show the output from the last shell command run in vim? (e.g., :!echo foo)

When I run a shell command it asks to type ENTER at the end and once you do the output is hidden. Is there a way to see it again w/o running the command again?
Also some internal commands like make also run external commands, and those do not even stop for ENTER so if I have an error in my 'compiler' settings the command flashes on the screen too fast to see it. How do I see the command and its output? (quickfix is empty)
UPDATE
The output is DEFINITELY still there. at least on the terminal vim. if I type
:!cat
the output of the previous command is still there. the problem is a) it seems too much like a hack, I'm looking for a proper vim way b) it doesn't work in gui vim
just type :!
or you could try SingleCompile
Putting vim into the background normally works for me (hit Ctrl+Z).
This will show you the shell you started vim from and in my case I can see the output of all the commands that I ran in vim via ":!somecommand".
This is assuming that you ran vim from a shell, not the gui one (gvim).
Before executing a command, you can redirect output to a file, register, selection, clipboard or variable. For me, redirecting to a register is the most practical solution.
To start redirecting to register a, use
:redir #a
Then you run your commands, say
:!ls -l
And end redirecting with
:redir END
That's all, register a now contains the output from the redirected commands. You can view it with :reg a or put into a buffer with "ap, as you would do normally with a register.
Read the help for :redir to know more about the various ways of redirecting.
After months, I found a help file that you may be interested in taking a look: messages.txt.
Though incomplete, it helps a lot. There is a command (new to me) called g< that displays the last message given, but apparently only the Vim messages, like [No write since last change].
First, I suggest you to take a look in your settings for 'shm', and try to make your commands output more persistent (the "Hit ENTER" appearing more often). Then, check if this help file helps :-) I couldn't make it work 100%, but was a great advance.
Why I do not use :! anymore, and what is the alternative
I learn the :! from the currently chosen answer (and I upvoted it). It works, in a sense that it does show the previous screen.
However, the other day I learn another tip of using :!! to re-run the last command (which, by the way, is very useful when you are in a edit-test-edit-test-... cycle). And then I realize that, using :! somehow has a side effect of forgetting the last command, so that future :!! won't work. That is not cool.
I don't understand this, until I take a deep dive into vim's documentation.
:!{cmd} Execute {cmd} with the shell.
Any '!' in {cmd} is replaced with the previous
external command
Suddenly, everything starts to make sense. Let's examine it in this sequence:
Assuming you first run :!make foo bar baz tons of parameters and see its output, later come back to vim.
Now you can run :!!, the second ! will be replaced with the previous external command, so you will run make foo bar baz tons of parameters one more time.
Now if you run :!, vim will still treat it as "start a (new) external command", it is just that the command turns out to be EMPTY. So this is equivalent to you type an empty command (i.e. hitting ENTER once inside a normal shell). By switching the screen into shell, you happen to get a chance to see the previous screen output. That's it.
Now if you run :!!, vim will repeat the previous command, but this time, the previous command is an empty command. That's why your vim loses the memory for make foo bar baz tons of parameters so that next time you wanna make, you will have to type them again.
So, the next question will be, is there any other "pure vim command" to only show the previous shell output without messing up the last command memory? I don't know. But now I settle for using CTRL+Z to bring vim to background, therefore shows the shell console with the previous command output, and then I type fg and ENTER to switch back to vim. FWIW, the CTRL+Z solution actually needs one less key stroke than the :! solution (which requires shift+; shift+1 ENTER to show command screen, and a ENTER to come back).
I usually exit to the shell using :sh and that will show you the output from all commands that has been executed and did not have it's output redirected.
Simply close the shell and you will be back inside of vim.
Found this script -- which will open up a new tab
function! s:ExecuteInShell(command)
let command = join(map(split(a:command), 'expand(v:val)'))
let winnr = bufwinnr('^' . command . '$')
silent! execute winnr < 0 ? 'botright new ' . fnameescape(command) : winnr . 'wincmd w'
setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap number
echo 'Execute ' . command . '...'
silent! execute 'silent %!'. command
silent! execute 'resize ' . line('$')
silent! redraw
silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>'
echo 'Shell command ' . command . ' executed.'
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
Paste it in your .vimrc
It works on gui vim too..
Example Usage -- :Shell make
Scroll up (tested on iTerm 2). Note: this might not work depending on your vim configuration..
Example: I'm about to run !rspec --color % from my vim.
The buffer is filled with the output.
Now, after hitting ENTER, you can scroll up to see the previous output.
maybe the guys are forgetting about the :r
r !ls ~/
Put this where my cursor is:
bug_72440.html
bug_72440.vim
Desktop
dmtools
Docear
docear.sh
Documents
Downloads
examples.desktop
index.html
linux_home
Music
Pictures
Public
Templates
A simple u could get rid of the new text after I yank it or whatever;
Commands like make save their output to /tmp/vsoMething. The errorfile setting seems to be set to the file backing the quickfix/location list. If you want the output to be somewhere specific, see makeef. You can open the current errorfile like this:
:edit <C-r>=&errorfile<CR>
(Unfortunately, this doesn't seem to work for :grep.)
redir doesn't have to be tedious. See this plugin for simplifying it. (I have ftdetect and ftplugin scripts to make the output buffer not backed by a file.)
You see the output on the terminal when you type :!cat because of your terminal, not vim. You'd see the same thing if you used Ctrl-z which suspends vim so vim isn't actively doing anything.

Format code with VIM using external commands

I know that using VIM I can format C++ code just using
gg=G
Now I have to format 30 files, so doing it by hand becomes tedious. I had a look how to do it passing external commands to VIM, so I tried
vim -c gg=G -c wq file.cpp
but it does not work.
Can you give me a hint?
Thanks
Why not load all the files up in buffers and use bufdo to execute the command on all of them at one time?
:bufdo "execute normal gg=G"
Change -c gg=G to -c 'normal! gg=G'. -c switch accepts only ex mode commands, gg=G are two normal mode commands.
I prefer a slight change on the :bufdo answer. I prefer the arg list instead of the buffer list, so I don't need to worry about closing current buffers or opening up new vim session. For example:
:args ~/src/myproject/**/*.cpp | argdo execute "normal gg=G" | update
args sets the arglist, using wildcards (** will match the current directory as well as subdirectories)
| lets us run multiple commands on one line
argdo runs the following commands on each arg (it will swallow up the second |)
execute prevents normal from swallowing up the next pipe.
normal runs the following normal mode commands (what you were working with in the first place)
update is like :w, but only saves when the buffer is modified.
This :args ... | argdo ... | update pattern is very useful for any sort of project wide file manipulation (e.g. search and replace via '%s/foo/bar/ge' or setting uniform fileformat or fileencoding).

Resources