Why does "locate filename | xargs vim" cause strange terminal behaviour? - vim

When I do "locate 50local.policy | xargs vim", I get the error "Vim: Warnung: Die Eingabe kommt nicht von einem Terminal" (translation: Vim: Warning: The input does not come from a terminal).
I can edit successfully with vim but after I close it my terminal behaves strangely (I can't type letters and when I hit enter the shell prompt simply gets repeated.
When I do it with "xargs gedit" it does not create those problems.
I use Ubuntu 11.10 with Gnome 3 and Gnome-Terminal 3.0.1.

Vim expects to be connected to a real terminal and sends codes appropriate to that.
Reset the terminal with
reset
The easiest workaround:
locate 50local.policy | xargs gvim
Rationale gui vim doesn't require a terminal
Otherwise:
vim $(locate 50local.policy)
Rationale vim is started directly connected to the terminal (instead of as a child process under xargs which in turn runs in a subshell with stdin/stdout connected to pipes instead of a terminal). It is like saying
vim /usr/some/dir/50local.policy /usr/local/some/dir/50local.policy
Alternatively
You can dodge the issue by not starting vim with the arguments, but adding the arguments from vim! Vim is in fact a lot better at running shells than shells are at running vim.
Whilst in vim:
:args `locate 50local.policy`
:rewind
This sets the argument list to the files returned from the shell command between the ticks; :rewind then goes to the first file from that list.
If you were editing multiple matches, try this:
:w|next
This sequence of commands (separated by |) writes the current buffer to file, then goes to the next file in the args list.

An other alternative is to execute xargs with the -o option. From the man page:
-o Reopen stdin as /dev/tty in the child process before executing
the command. This is useful if you want xargs to run an interac-
tive application.
Note, -o is a BSD extension to xargs.
A more portable means to achieve the same effect is:
xargs sh -c 'vim "$#" < /dev/tty' vim

While 'reset' fixes the problem, you can also explicitely re-activate the echo behaviour with:
stty echo

Related

how to make gvim hold terminal until it ends?

I am trying to find and replace over file hierarchy using gvim like this:
find . | xargs grep -l pattern | xargs -n 1 gvim -c "%s/pattern/replacement/gc" -c "wq"
I could probably try to make it work properly without the n flag, but I could have theoretically many, many files with matches. What happens now is that gvim dettaches from terminal, so xargs starts all instances of gvim one after another with little delay. If I could force gvim to hold terminal, xargs would wait for gvim to finish, thus there would ever only be one instance of gvim running.
Unfortunately I can't use vim in the environment that this is relevant to. I obtained a working binary for gvim from a colleague, but they did not have a vim binary and I failed to compile vim myself and gave up on it for now.
You're looking for the -f command-line option:
-f GUI: Do not disconnect from the program that started Vim.
'f' stands for "foreground". If omitted, the GUI forks a new
process and exits the current one. "-f" should be used when
gvim is started by a program that will wait for the edit
session to finish (e.g., mail or readnews). If you want gvim
never to fork, include 'f' in 'guioptions' in your |gvimrc|.

Cygwin terminal input disappearing after quitting vim

Using Cygwin, I tried creating and editing a file in Vim:
touch test | vim
This is obviously a mistake; something like vim "$(touch test)" has a better chance of actually working. Nevertheless, this command throws the error:
Vim: Warning: Input is not from a terminal.
And after this, Vim opens and I exit the program with :q. Any subsequent commands I enter into the terminal are hidden from view until I restart Cygwin.
Why is this?
You don't understand what does a pipe | do in shell.
Pipe will take the pervious command's stdout as stdin to next command, in a subshell.
Your touch foo doesn't generate any output, what do you expect to happen? same for vim "$(touch test)".
If you want to create a file and open it in vim in one shot, you can try:
touch foo && vim foo
If you want to edit it with vim anyway, actually, you can simply just:
vim foo
then save the buffer after your editing.

Why doesn't "history | vim" work?

I want to use the Vim to see the result of history (not in the shell). I think history | vim will work (use the result of history as the input of vim), but it returns with:
$history | vim
Vim: Warning: Input is not from a terminal
Vim: Error reading input, exiting...
Vim: Finished.
Can anybody explain this?
By piping into vim, you are changing the standard input stream. Because vim is an interactive program, it requires the standard input to be the console.
If you want to view in vim, you should tell it you are reading the file from stdin (by supplying the argument -):
history | vim -
Alternatively, you could just use more or less:
history | more
history | less
These latter two are preferable. If you pipe into vim, it will see your "file" as having modifications, and so you can't quit with a straight :q command. Instead you have to force quit by :q!, which is a bit clunky.
On the other hand, you can exit more or less just by typing q. Have a look at the man-page for these two programs. You'll use them a lot.
As recommended by Russell Silva in the comments, you can open vim in read-only mode when you read from stdin. Just supply the -R argument. Then you can quit normally without needing the override:
history | vim -R -
Apart of vim -, you may try bash command substitution like:
vim <(history)
See also:
How to write whole buffer to standard output from the command line? at Vim SE
How to edit files non-interactively (e.g. in pipeline)? at Vim SE
This happend to me trying to send it to background console (&)
One script used:
...
vi "$file" &
...
# change to just:
vi "$file"
removing &, problem went away.

Is there a way to configure Vim grepprg option to avoid waiting until the external tool has finished searching?

I am a long time Vimmer. However, I keep switching to shell to make searches. This avoids me to use the quickfix functionality.
The main reason for switching to shell is that when I use grep from inside Vim (with :grep), I cannot follow progress.
Because the code base I search is usually wide, I really appreciate immediate feedback.
It gives me a chance to find out that my search expression is wrong before the full results have been displayed.
This allow me to cancel the search, refine the expression then relaunch the search.
Any hint how to reproduce this pattern inside Vim would be appreciated.
I don't see the same vim behaviour as you. When I run :grep, I still see the results in vim (not in the quickfix) before the search completes (but I cannot do anything until the search is done).
I even tried using no vim settings or plugins:
gvim -u NONE -U NONE
If that's not your behaviour, check your grepprg. Mine is the default:
:verbose set grepprg
grepprg=grep -n $* /dev/null
When I use run grep -e "score" -R /etc I see this output in vim:
:!grep -n -e "score" -R /etc /dev/null 2>&1| tee /tmp/voLcaNS/232
It's possible that your system is missing tee or your vim doesn't use it (I'm using Vim 7.2 on Ubuntu 10.10). tee takes the text passed to it and writes it to a file and to stdout.
If you're looking for a way to have the quickfix get updated with your search results and have vim not block while you're searching, then you could write a script that:
searches with grep as a background process and redirects to a file
every second until grep completes, have vim load the file in quickfix (cgetfile) (you can tell vim to do something from another process with --remote-expr)
You can try my AsyncCommand plugin to get your code started. It does the above, except that it only loads the file when the search is complete.
Are you familiar with ack.vim at all? It doesn't use the quickfix window, but uses a separate buffer in a split. However, it's rather faster results come right back to the vim frame.
This may be due to buffering between grep and tee, not vim itself. To test this theory, run grep from the command-line and pipe the output through tee (i.e. grep <pattern> <files> | tee temp.out). If it behaves the same as you observe within vim, then buffering is occurring.
To work around, install expect (sudo apt-get install expect-dev on Ubuntu 10.10) and grepprg to unbuffer grep -n $* /dev/null. (See Turn off buffering in pipe).
Take a look at :vimgrep in the online documentation. It displays the file name being searched and updates as it goes.
There are three ways to do a search in entire projects.
System command grep(fast, but not working well with Ouickfix list)
=>$ grep -n Example *
Vim internal grep(slow, but have a strong pattern support)
:vim[grep] /{pattern}/[g][j] {file} ...
System plugin ack(perfect)
1 install ack
brew install ack
2 add below configs to your .vimrc
:set grepprg=ack\ --nongroup\ --column\ $*
:set grepformat=%f:%l:%c:%m
3 then you can use grep to call ack in vim like
:grep "object\." app/**/*.rb

How do I launch an editor from a shell script?

I would like my tcsh script to launch an editor (e.g., vi, emacs):
#!/bin/tcsh
vi my_file
This starts up vi with my_file but first displays a warning "Vim: Warning: Output is not to a terminal" and my keystrokes don't appear on the screen. After I kill vi, my terminal window is messed up (no newlines), requiring a "reset". I tried "emacs -nw", "xemacs -nw", and pico with similar results. "xemacs" works but launches a separate window. I want to reuse the same terminal window.
Is there a way to launch an editor from a script so that it reuses the same terminal window?
I answered my own question! You have to redirect terminal input and output:
#!/bin/tcsh
vi my_file < `tty` > `tty`
The reason you're getting the error is that when you start a shell in your environment, it's starting in a subshell that has STDIN and STDOUT not connected to a TTY — probably because this is in something like a pipeline. When you redirect, you're opening a new connection directly to the device. So, for example, your command line turns
$ vi < `tty` > `tty`
into
$ vi < /dev/ttys000 > /dev/ttys000
So you're not really using your old STDIN/STDOUT, you're creating two new files and mapping them to your vi process's STDIN/STDOUT.
Now, tell us what you're doing with this and we'll tell you how to avoid this kludge.
I wanted to do something similar. I wanted an alias that would find the last file I was working on, and open it in vi(1) for editing. Anyway, I couldn't figure out how to do it as a readable alias (in tcsh) so I just created an ugly shell script (csh because I'm old) instead:
#!/bin/csh
set DIR = "~/www/TooMuchRock/shows/"
set file = $DIR`ls -t $DIR | head -1`
set tty = `tty`
vi $file <$tty >$tty
(1) kraftwerk:bin> which vi
vi: aliased to /usr/local/bin/vim -u ~/.exrc
Absolutely. :-)
Write your script and have it call the EDITOR environment variable, which you will have set to "emacsclient". Then start up Emacs, execute M-x server-start, switch to a shell buffer (M-x shell) and execute your script. Emacsclient will pop up the thing to be edited and C-x # will act as a "done" command and take you back to your script with edits completed or aborted, as you choose.
Enjoy.
Edit: I meant to add that these days Emacs IS my terminal program. I have dozens of shell buffers and never have to worry about losing output and can use all the power of Emacs to manipulate and analyse the terminal output. And have Emacs scripts generate input to the shells. Awesome actually. For example, watching Tomcat output scroll by in a shell buffer while editing sources or processing mail or doing most any Emacs thing is very convenient. When a Tomcat stack trace appears I can quickly respond to it.
Had the same trouble with 'pinfo' in a shell script 'while' loop. The line can be used in the script, it uses 'ps' to find the tty of the current process number, "$$", and stores that tty in $KEY_TTY:
KEY_TTY=/dev/`ps | grep $$ | tr -s '[:blank:]' | cut -d " " -f 3`
Later in the script, just call the tty-only proggie, with $KEY_TTY as input, in my case it was:
pinfo -m $s $page < $KEY_TTY
For 'vi' it'd be:
vi $a < $KEY_TTY > $KEY_TTY
The advantage is that the script as a whole can still accept STDIN input, and 'vi' (or whatever) should work fine -- without having to remember to set any environmental variables before running the script.
Set your terminal tty to a variable, and then redirect the editor i/o through that variable.
In your script:
#!/bin/sh
ls | while read a; do vi $a < $MYTTY >$MYTTY; done
And then execute the script with:
$ MYTTY=`tty` ./myscript >/tmp/log
I was able to get the desired behavior under bash+Cygwin+Terminator:
#!/bin/bash
vim foo
Run the script, vim loads, no error messages, behaves as normal. There are undoubtedly dozens of variations between our setups, however, so I can't hazard a guess as to what makes the difference. I'm curious what it is, but you got it working, which is the important part.

Resources