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

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
}

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()

How to run Vim commands from Terminal

My questions is one that I haven't seen answered, the usual question is how to run certain commands to a file.
My question is how to run Vim commands or functions, from outside Vim (i.e. Terminal), these wouldn't affect any file, just Vim itself. Is this is even possible? If so, how?
If this is not possible like this, is there a way to go into Vim, run a command automatically, and then exit when that ends? Or run another command and then exit?
Thanks for your help!
Use
vim --cmd 'Command launched before vimrc' \
-c 'Command launched after vimrc' \
-c 'qa!' # Quit vim
. For running a command in an existing vim session you have to use +clientserver feature: run one vim with
vim --servername vim
and others with
vim --remote-send '<C-\><C-n>:Command<CR>'

how to automatically make new file with mvim

When I run mvim . it opens NERDTree but doesnt open a new file/buffer.
How might I accomplish this? Ideally when you type mvim . from terminal it would open MacVim, close NERDtree, and open a new buffer
I'm not sure if this is possible but is there a way that if I run mvim . from the command line multiple times it wouldn't open vim in a new window each time?
As for your second question, vim allows you to send a file to an already running instance with --remote arguments, if vim is compiled with +clientserver. MacVim should be - if :echo has("clientserver") prints 1 in the command-line, then this should work. This will work for any vim compiled with +clientserver, including vim running within a terminal window.
When vim is using clientserver you can run mvim so that it sends the new file(s) to an already-running instance of vim, e.g.:
$ mvim --remote-silent file2.txt
Make an alias for mvim that always passes --remote-silent.
See :help remote for more details.
1.You are asking it to open your directory viewer, right? If not, why do you start vim passing the current directory (.) as argument? Leave it off and it will start with an empty buffer.
$ mvim
2.Take a look in the vim manual (man vim). You probably want the --remote-silent option.
$ mvim --remote-silent file
I personally use this so often that I've created an alias for it in my .profile:
alias v='mvim --remote-silent'

using xargs vim with gnu screen

I've got a weird problem where if i do something like this in a gnu screen window, that window starts responding in weird ways
ls *.cpp | xargs vim
After I exit from vim, the screen window doesn't echo any command. It even does not echo CR.
Any suggestions?
Piping changes vim's stdin and causes problems. Try this instead (for bash, zsh, etc.):
vim $(find . -name "*.cpp")
How about vim *.cpp?
Maybe for file in *.cpp; do vim "$file"; done could work too. Edit each file and exit.
Or start vim and add all cpp files with following command: :argadd *.cpp
When using Vim in a pipe like this, you'll probably notice the following warning:
Vim: Warning: Input is not from a terminal
That's Vim telling you that it cannot function as it's supposed to be (i.e. in interactive mode; you can still use it in "batch mode" by feeding it Ex commands to process). That explains the weirdness you experience after Vim quits.

reuse vim instance from linux terminal

By making use of the remote feature in vim, is it possible to reuse an instance of vim to load up multiple files as needed.
It will be nice to have that facility from within the same terminal instance.
I am more keen to have a tab based interface, which available in vim 7+
The scenario should be
Open terminal
vim file1.cpp
Edit - Save - Ctrl+Z to get to prompt
open another file
vim file2.cpp
Now we have file1.cpp and file2.cpp open in the same editor
Is that possible?!
I'm not sure if this can be done in exactly the manner that you're specifying, but something very similar can probably be done using a vim server running on your local machine.
Look into the :help remote.txt in Vim.
If your version of vim was compiled with +clientserver you can use vim to create a vim server, and then execute commands on it, e.g. opening another file.
The --servername switch can create a new server, and the --remote switch can send additional commands or files to it.
e.g.
vim --servername test file1.txt
vim --servername test --remote file2.txt
I've had a look, and the vim I'm using as standard on xubuntu on one of my computers doesn't have it, but there are some instructions here that may help if yours has it compiled. If it isn't, installing gvim and symlinking is apparently an option (as gvim has it included by default), or compiling the binaries from source.
Edit:
I've had more of a play with gvim and this doesn't look possible to do this within the terminal. Control-Z suspends the job at the process level. I thought it might work with screen, but no communication seems to take place unless gvim has launched in a graphical window,
This is easy to do if you compiled VIM with +clientserver, as Andy suggested in a previous answer.
I did the following:
I started up VIM as a server:
vim --servername abc
I suspended it with CTRL+Z and did:
vim --servername abc --remote ~/.cshrc
fg
Now VIM had ~/.cshrc open.
Then I did:
vim --servername abc --remote ~/.aliases
fg
Now VIM had one buffer with ~/.cshrc and another with ~/.aliases.
Then I did:
vim --servername abc --remote-tab ~/foo_bar
fg
And now I VIM had one tab with the two previous buffers open and another tab with ~/foo_bar open.
In call cases VIM was running in the terminal, not as a GUI.
I have a couple suggestions for you, though neither is exactly what you're talking about. The first is NERD Tree, which gives you a nice tree-based file browser for opening other files. Very handy. I also set up a hot key (ctrl+o) to open NERD Tree for me. I keep an alias of whatever project I'm on in ~/curr/trunk, so this always works for me:
map <C-O> :NERDTreeToggle ~/curr/trunk/<CR>
The other thing that I would suggest is to do away with ctrl+z. It's somewhat clunky, and everyone I know who uses that method tends to get lost and end up with 3 or 4 vim's running in the background. Take a look at how to open a shell for yourself. I use a map for ;s to execute a shell script:
map ;s :!~/.vim/shell.sh<CR>
Which executes:
#!/bin/sh
/usr/local/bin/bash -l;
I also have a bit of magic in my .profile for making it obvious I'm in VIM:
if [ "$VIMRUNTIME" != "" ] ; then
export PS1="\u#\h \W \t$ vim> "
fi
</2 cents>
You can split the current screen and open two (or more) files in the following way:
For a horizontal split, do:
:sp 'filename'
and for a vertical split, do:
:vsp 'filename'
To tab between the two, hit ctrl+w, then use an arrow key to navigate to whichever file you want to edit.
Also, if you want to just switch files (and only have one open), you can do this:
:e 'filename'
G'day,
Or if you want to have multiple files but use the whole vim window for one file at a time you can just enter
:e 'filename'
to open the new file. You can do this multiple times. To see what you've currently got open, enter
:ls
To bounce between the files you've got open you can use cntl-^ (shift-cnt-6) and that will alternate between the main and secondary files (shown with a % and # in the file list)
Or you can enter
:n b
where n is the number at the beginning of the file you want in the list shown by the 'ls'command.
HTH
cheers,
You can set the hidden feature on vim, to allow it to have multiple files open:
:set hidden
Then you can open as many files as you want, without bothering to save them every time you want to switch a "buffer":
:e 'filename'
You have several commands to navigate the buffers:
:bnext
:bprev
:buffers
Of course, as mentioned by samoz, you can split your screen to see multiple buffers on the same window.
I'd suggest to read this for a good introduction about vim, it will save you a lot of time.
Good luck!

Resources