What options are set when exim commands are given through a heredoc? - vim

I have a bash script that runs (something like) the following command:
vim -E <<EOT
call Myfunc()
EOT
where Myfunc() is defined in my .vimrc. I've discovered that using the heredoc (but not simply calling it with -E and entering commands manually) causes vim to skip loading my .vimrc, consequently setting compatible mode (causing other problems down the road).
I can load my .vimrc manually if I have to, but I'm assuming I don't know a priori where it is, so I'd like to let vim do the work.
Does using the heredoc make vim set some other option (-u NORC, say), which I can just unset to get normal behaviour?
I'm in Vim 7.3, if it matters.

Giving arguments to vim through a heredoc is equivalent to taking input from stdin:
vim -E -
call Myfunc()
qa!
This starts vim in silent mode (see :help -s-ex) and only loads plugins specified by the -u argument. To load all plugins, write the ex command to a file and use that file for input:
cat <<EOT > input.vim
call Myfunc()
qa!
EOT
vim -E input.vim
(I added qa: to force vim to exit after running Myfunc().)

Related

Can't run a script with fzf from vim

I have a bash script that assembles some data, then pipes it through fzf for the user to choose, then manipulates the choice, then prints it to stdout.
This simulates the script:
#!/bin/sh
echo hello | fzf | sed 's/h/j/g'
This works great from the command line, but when running it from vim to include in the current buffer, the fzf TUI never displays, and I get ANSI escape sequences included in the result:
It doesn't matter how I run the command from vim. I've tried :read !{cmd}, :.!{cmd}, and even :let a=system('{cmd}').
For example, I would expect this to work:
:read !echo hello | fzf | sed 's/h/j/g'
fzf seems to be confusing stdout for a tty.
I know this isn't a limitation of vim, since if I substitute fzf for another interactive chooser with a tty, it works.
Is there an fzf or vim option to make this work?
Vim doesn't deal with interactive commands that easily. As you've seen, fzf outputs a lot of code to manipulate the display, and read is expecting a raw result.
You can do this with execute instead of using read directly.
Building off another answer ( Capture the output of an interactive script in vim ) but changing things up to work with fzf, I've modified #joshtch's solution to work with an arbitrary script, and checked that it works with fzf:
my-fzf-script.sh:
#!/bin/sh
ls | fzf
and the vim side of things:
function! <SID>InteractiveFZFCommand()
let tempfile=tempname()
execute '!./my-fzf-script.sh >' . shellescape(tempfile)
try
silent execute 'read' tempfile
finally
call delete(tempfile)
endtry
endfunction
command! -nargs=0 InteractiveFZFCommand call <SID>InteractiveFZFCommand()

Specify vim filetype on command line

I've been working with a lot of C++ files that have no extensions and it's too annoying to have to type :set ft=cpp every time I open them, so I'm mostly just working without syntax highlighting. Is there a way to tell vim the file type in the command line? Something like:
$ vim --ft=cpp file_name
You can use the -c option when launching vim to execute commands after the first file has been read.
For your situation, you can simply use the standard set filetype command -
vim -c 'set filetype=javascript'
You could also use --cmd to execute the command after the first file is loaded.
Lifted from the vim man pages:
-c {command}
{command} will be executed after the first file has been read. {command} is interpreted as an Ex command. If the {command} contains spaces it must be enclosed in double quotes (this depends on the shell that is used).
Example: Vim "+set si" main.c
Note: You can use up to 10 "+" or "-c" commands.
--cmd {command}
Like using "-c", but the command is executed just before processing any vimrc file. You can use up to 10 of these commands, independently from "-c" commands.

How to make Vim ignore file extensions when opening files through the command line/shell?

Consider the following directory tree:
root/include/file.hpp
root/source/file.cpp
root/images/file.png
The command line is inside the directory root.
In the vimrc file, there is set wildignore=*.png.
If you open Vim in the folder root and run :next */file.*, it opens only file.hpp and file.cpp.
However, if you launch Vim from command line with vim */file.*, it opens all three files.
So, when feeding it a filename, it first loads the files, then vimrc? Is there a way to ignore extensions when opening files with Vim through the command line? Or to make Vim load vimrc first?
In the first scenario, the glob expansion is done by Vim and thus obeys the rules in your vimrc.
In the second scenario, the glob expansion is done by your shell and there's no reason to expect it to obey the rules in your vimrc.
You can do something like $ vim -c "next */file.*", which essentially opens Vim without a filename and executes next */file.*.
Or you can exclude the pattern directly in your shell. Assuming you have extglob set, this can be done in bash with $ vim !(file.png).
When doing :next */file.* from within Vim, vim expands the wildcard and filters by wildignore. When doing vim */file.* from your shell, the shell expands the wildcard, and passes all three files to Vim.
Depending on your shell, this will probably work instead:
vim +"args */file.*"

Options for .vimrc from command-line arguments?

I have a custom .vimrc file which I use across many different machines.
Some machines are less powerful than others, and it would be nice to be able to load a "stripped-down" version of the .vimrc file. However, I'd like to maintain a single .vimrc to avoid fragmentation.
Ideally, I'd like to pass arguments to my .vimrc from the command line. If the "minimal" option is selected, the .vimrc would skip over loading the most resource-intensive plugins.
Does anyone know the best/cleanest way to do this?
Thanks!
Edit: The slower machine I'm talking about is a Raspberry Pi over SSH. Vim itself isn't slow, although I have several plugins including NERDTree and Syntastic that take lots of time to load on the Pi's limited CPU. By taking out most plugins for my "minimal" configuration, I cut down the loading time from 3.5 seconds to 0.5 seconds.
You can use the --cmd switch to execute a command before any VIMRC is loaded.
So on your less powerful machines you could alias vim to something like vim --cmd 'let weak=1' and then in your $VIMRC you can say:
if exists('weak')
echo "poor machine"
endif
take a look at source:
source /foo/bar/another_vimrc
Your 'heavy' vimrc can just source the basic vimrc and add what you want. This is also really handy for project/machine specific abbreviations, ctags, etc.
This will not keep a single vimrc file, but for the sake of others who have the same question (as stated at the top of the page):
$ vim -u ~/.vim-min.vim
Note that this will suppress loading both the system vimrc file (if any) and your personal vimrc file.
:help -u
:help startup
(See Step 3 of the second reference.)
From the excellent answers above, I got this working:
~/.vimrc :
if exists('FLAG') " 'FLAG' passed from ~/.bashrc 'vimm' alias
set textwidth=150 " (launches vim in expanded terminal window)
set lines=58
else
set textwidth=79
set lines=40
endif
~/.bashrc :
# Needed to combine following two lines for ~/.vimrc use:
# alias vimm='konsole --geometry 1900x1040+0+0 -e "bash -c \"vim\""; exit'
# vim --cmd 'let FLAG=1'
str="'let FLAG=1'"
alias vimm='konsole --geometry 1900x1040+0+0 -e "bash -c \"vim --cmd $str\""; exit'
Now, 'vim' (normal use) launches Vim in a normal-sized terminal, whereas 'vimm' launches Vim in a larger terminal (alternate settings).
'Konsole' is the terminal that I use in Arch Linux.

How to open another file in background Vim from Bash command-line?

I am transitioning from using Gvim to console Vim.
I open a file in Vim, and then suspend Vim, run a few commands on the command-line and then want to return to Vim.
Ctrl+Z (in normal mode) suspends Vim and drops back to the console
fg can be used to return focus to Vim
jobs lists background jobs and can be used to get the job number to
bring a given job to the foreground (e.g., fg %2 to bring job 2 to the
foreground).
However, when Vim is in the background and I issue vim file, the file opens in a new instance of Vim.
I'm used to using the --remote option with Gvim to open a file in an existing Gvim instance.
Question:
How can I open another file in a background Vim from the command-line?
Is this a reasonable workflow for moving between console and Vim?
Update:
I just read this answer by #jamessan which provides a few ideas. He shows the following code snippet:
vim --servername foo somefile.txt
:shell
<do stuff in your shell>
vim --servername foo --remote otherfile.txt
fg
However, I'd have to think about how to make it easier to use perhaps with some aliases.
Would this be a good approach?
How could it be made efficient to use?
This is also what I need. I found this thread, though no satisfying approach, happy to see people having same requirement like me.
My approach is
add below to .bashrc
v() {
vim_id=`jobs|sed -n "/vim/s/\[\([0-9]\)\]+.*/\1/p"`
if [ -n "$vim_id" ]; then
echo "tabedit $#" > ~/.vim_swap/e.vim && fg $vim_id
else
vim $#
fi
}
add below to .vimrc
nnoremap <silent> <space>e :source $HOME/.vim_swap/e.vim<Bar>:call writefile([], $HOME."/.vim_swap/e.vim")<CR>
Then v foo.c to open first file, editing..., ctrl-z to suspend vim, do shell stuff, v bar.h to bring vim foreground.
And in VIM, press <Space>e to tabedit bar.h.
So the idea is to generate vim command from shell command, save them to a temp .vim file. In VIM, map key to source the .vim file and clear it.
Instead of running vim again, you need to bring your current vim process to the foreground (with fg) and open the file in vim.
I have not used it much, but you may find the "vim server" feature (see --remote*, --servername, etc. options) lets you open the file from your shell into an existing, backgrounded vim. However, ctrl-z suspends the process instead of allowing it to continue to run in the background, and you will need to put that vim into the background so it can respond as a "vim server". Use the shell's bg command to do that.
I would just call vim from fg and open new file inside vim since its just seems to be faster (although it may be just faster to me). To work with multiple files inside vim you need to use command edit (in vim): :e [filepath/]filename and you walk true buffers (all files will be as vim buffers) with ^I (ctrl+I) and ^O (ctrl+o)
It works on both GTK and shell versions. There is no such a huge difference on workflow. I prefer shell version since i do most of commands there (compiling launching etc.).
If you use tmux, and if you always have your vim instance running as the first job in background, you can setup alias like below in csh.
alias v 'tmux send-keys fg Space +1 Enter :e Space `realpath \!:1` Enter'
then you can call it like this
v myfile.txt
If your vim instance is not the first background job, enrich the alias with jobs output.
In Bash, this can be done with a function.
function v() {
local job=$(jobs | perl -ne 'print $1 if /\[(\d+)\].*vim/')
if [[ -n $job ]]; then
tmux send-keys fg Space $job Enter
for f in $*; do
tmux send-keys :e Space `realpath $f` Enter
done
else
vim $*
fi
}

Resources