5

I would like to modify the behavior of one of my mapping but only when Vim is reading data which were piped to it by $ vipe.

The mapping closes/quits the current window/session depending on certain conditions. When Vim is reading data which were piped to it, I would like the mapping to execute :cquit, so that it reports an error to the shell and the output of the shell command is not displayed in the terminal when I quit (or the rest of the pipeline is not processed).

$ vipe is a shell utility, included in the moreutils package, whose man page contains this:

NAME
       vipe - edit pipe

SYNOPSIS
       command1 | vipe | command2

DESCRIPTION
       vipe allows you to run your editor in the middle of a unix pipeline and edit the data that is being piped
       between programs. Your editor will have the full data being piped from command1 loaded into it, and when you
       save, that data will be piped into command2.

ENVIRONMENT VARIABLES
       EDITOR
           Editor to use.

       VISUAL
           Also supported to determine what editor to use.

As an example, one could use it to count the number of files/directories in the current working directory with $ ls and $ wc -l, using Vim in the middle to interactively remove some entries:

$ ls | vipe | wc -l

But, I don't know how to detect that Vim has been invoked by $ vipe.

I tried to use the StdinReadPre and StdinReadPost event like this:

augroup standard_input
    autocmd!
    autocmd StdinReadPre * nno cd :echo 'hello'<cr>
    autocmd StdinReadPost * nno cd :echo 'hello'<cr>
augroup END

But it didn't work, when hitting cd, hello was not displayed.

The reason why it didn't worked is probably because Vim wasn't invoked with the - argument, because this works:

$ ls | vim -

And :h StdinReadPre and :h StdinReadPost seems to confirm this:

                            *StdinReadPost*
StdinReadPost           After reading from the stdin into the buffer,
                before executing the modelines.  Only used
                when the "-" argument was used when Vim was
                started |--|.
                            *StdinReadPre*
StdinReadPre            Before reading from stdin into the buffer.
                Only used when the "-" argument was used when
                Vim was started |--|.

I also tried to check the contents of the internal variables v:progname and v:progpath but they both report vim, not vipe.

Is there a way to detect whether Vim has been invoked by another shell command (vipe, git commit, ...)?

2
  • 2
    vipe and git open Vim with a temporary file, so stdin isn't involved.
    – muru
    Jan 5, 2017 at 10:49
  • For your particular problem, maybe alias vipe='vipe --suffix vipe'
    – CervEd
    Jan 26 at 15:39

2 Answers 2

5

Since vipe, git commit (and many other programs which invoke an editor) use the VISUAL and EDITOR variables (unless you specify an editor for git with git config core.editor), you can use that variable to invoke Vim in such a way that you can detect it:

export EDITOR='env called=1 vim'

Then, in Vim, $called will have a value of 1, which you can use to detect whether it was called by a command.

0
5

I don't know how reliable it is but I found how to get the PID of the parent of a process here:

ps -o ppid= -p <pid of the process>

And how to get the name of a process from its PID here:

ps -p 1337 -o comm=

One can get the pid of the Vim's process with the getpid() function, so combining the previous 2 commands, maybe this expression could get the name of the parent of Vim:

expand('`ps -p $(ps -o ppid= -p '.getpid().') -o comm=`')

I've tried to use it in my mapping like this:

if expand('`ps -p $(ps -o ppid= -p '.getpid().') -o comm=`') ==# 'vipe'
    cquit
else
    ...
endif

It seems to work.

5
  • 2
    I do something similar to determine whether vim has been invoked from gdb, but using the /proc file system and Vim's internal commands. let ppid = split(readfile("/proc/".getpid()."/stat")[0])[3] let pcmd = split(readfile("/proc/".ppid."/cmdline", "b")[0])[0] if fnamemodify(pcmd, ":t") =~ "gdb$" ...
    – garyjohn
    Jan 5, 2017 at 13:02
  • @garyjohn I've just tested it in my mapping, and it works too. I didn't know about the /proc folder and how we could use it to get the pid of processes. This is great, thanks for sharing! Jan 5, 2017 at 13:15
  • 1
    @garyjohn at least on Linux, you can eliminate the getpid() by reading /proc/self/stat directly
    – muru
    Jan 5, 2017 at 15:19
  • @muru: Thank you. That does make it cleaner and hopefully a little faster.
    – garyjohn
    Jan 5, 2017 at 15:52
  • @garyjohn let ppid = readfile("/proc/".getpid()."/ppid")[0] may also work
    – CervEd
    Jan 26 at 15:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.