using xargs vim with gnu screen - vim

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.

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

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&

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
}

Executing vim commands without interactive mode

I need to execute vim commands on thousands of files without suffering from interactive mode slowness. I tried :
find ... | xargs vim '+set fileencoding=utf-8 | x'
and
for file in ... ; do
vim '+set fileencoding=utf-8 | x' $file
done
but it's too slow and I have warnings
Vim : Warning : Output is not to a terminal
Is it impossible to avoid interactive mode in vim ?
ps: I can otherwise use iconv, but it causes errors with files > 32 ko
iconv --from-code=ISO-8859-1 --to-code=UTF-8 $file -o $file
I would do:
find .... -print0 | xargs -0 vim -c 'argdo set fenc=utf8' -c 'wqa'
Filetype, syntax and indent plugins are probably what's slowing you down.
These are specified in your ~/.vimrc with a line that looks typically like:
filetype plugin indent on
You could try commenting that out, or
You can start Vim without your plugins and ~/.vimrc but staying in nocompatible mode by doing:
vim -Nu NONE

Open all files that match a certain pattern in Vim

I’m in ~/src. I can do git grep _pattern_ and get a list of all *.cpp or *.hpp files that match this pattern.
Now I would like to go through all the files that match the pattern and make edits on them. How do I do this in Vim? (Basically, I want Vim to go through my directory like git grep does, and jump me to the right files.)
You can use the single inverted commas (also a unix shell feature), something like:
vim `git grep --name-only <your expression>`
In bash, you could do
vim $(grep -l _pattern_ *.cpp *.hpp)
but that's a bash feature, not a vim feature.
you can use the args ex command:
:args *.cpp *.hpp
This will open all cpp and hpp files in the current directory.
You can use any file path expansions available to :grep as well.
You could possibly set the grepprg and grepformat options to run git grep... and interpret the result. This would then let you run the command :grep and read the results into the quickfix buffer - see :h quickfix for more information. You can then step through them with :cnext and :cprev, or :copen to open a separate window with the list of files - putting the cursor on a filename and pressing return will open that file for editing.
The advantage of this over Zoran's and ammoQ's suggestions is that it will not read the files into memory until you want to edit them. Their suggestion will load possibly hundreds of files into memory at once, and can be a nightmare to manage. It is also cross platform so should work on Windows without having to use a third-party shell such as cygwin bash.
By properly using the quickfix list, you can even go immediately to the the right line (using the :help quickfix commands, eg. :cn or :cw). So, if you are using bash or zsh:
vim -q &lt(git grep foo)

Resources