8

I would find it useful to open several files at the same time on specific lines.

I know I can open a single file on a specific line with:

vi +123 ~/.zshrc

And I can open multiple files with:

vi ~/.zshrc ~/.profile 

But how can I open both files on specific lines in each file, e.g: (this does not work):

vi +123 ~/.zshrc +10 ~/.profile 

To open zshrc on line 123 and profile at line 10.

Thanks for your help in advance.

Jim

4
  • 2
    I think you'll just need to do it "the hard way", e.g. vim +123 ~/.zshrc -c 'e ~/.profile | 10'
    – B Layer
    Commented Dec 13, 2021 at 14:57
  • Yep that works, I thought as much ;-)
    – Jim
    Commented Dec 13, 2021 at 15:38
  • If this were something I wanted to do frequently I'd probably create a wrapper script that would allow something like vimn ~/.zshrc:123 ~/.profile:10. (Assuming no one comes up with anything better than my first comment.)
    – B Layer
    Commented Dec 13, 2021 at 16:29
  • Possibly vim files ... +'argdo 10 | first' if you want the same number. Or use the quickfix list.
    – D. Ben Knoble
    Commented Dec 13, 2021 at 23:52

2 Answers 2

5

Native

With native Vim there's no pretty way to do it. You'll have to submit a couple Ex commands using the -c or + command-line flag:

vim +123 ~/.zshrc -c 'e ~/.profile | 10'

That is, after startup the command :e ~/.profile will open ~/.profile and the next command :10 will take you to line 10.

You can, of course, do this with as many files as you'd like.

One thing worth noting is that after startup the current buffer will be the last one specified on the command line rather than the first as is normally the case. As a workaround you can add -c first to the end of the command line (as is done in the wrapper script, below). For example:

vim foo.txt +10 -c 'e bar.txt | 20' -c 'e baz.txt | 30' -c first

The current buffer in this case will be foo.txt (with the cursor on line 10).

Plugin

If you don't mind installing a plugin you can use vim-fetch which allows a command line like:

vim ~/.zshrc:123 ~/.profile:10

It works but it's a little wonky, in my opinion. It seems that it loads a (non-existent) file named, for example, ~/zshrc:123 and only upon navigating to that buffer does the plugin parse out the line number and load the actual file. You may or may not notice this happening. (I noticed it because I saw the temporary file:line name in my tab line.)

Wrapper

Before I found that plugin I had whipped up a wrapper script for Vim that uses the same parameter format. The script name is substituted for vim. (If you really wanted to you could name it vim and put it in your PATH ahead of Vim itself.) I'm posting it just in case anyone's interested:

#!/bin/bash

for arg; do
    # If an existing, regular file is followed by ':' and a number...
    if [[ $arg =~ ^[^:]*:[[:digit:]]+$ && -f ${arg%%:*} ]]; then
        cmds+=(-c "e ${arg%%:*} | ${arg##*:}")
    else
        other+=($arg)
    fi
done

/bin/vim "${other[@]}" "${cmds[@]}" -c first

I did this quickly as a little Bash exercise so it may not work perfectly for every conceivable set of command line arguments...caveat emptor. :)

0

Depending on what you're trying to do, a viable alternative might be running the system command inside Vim to generate the locations and populating the quickfix list with the result. See How to create qf or location list from results of shell command for some ideas. Here's a Neovim/Lua example for inspiration:

vim.api.nvim_create_user_command('TorgleFlidgets',
    function()
        vim.cmd.cclose()
        print('🐰 torgling the flidgets ...')
        local out = vim.fn.systemlist("torgle ./flidgets.txt")
        if vim.v.shell_error == 0 then
            print('nothing to see here')
            return
        end
        local files = {}
        for _, file in pairs(out) do
            local parts = {}
            for part in string.gmatch(file, "%S+") do
                table.insert(parts, part)
            end
            table.insert(files, {filename = parts[1], lnum = parts[2], col = parts[3]})
        end
        vim.fn.setqflist(files)
        vim.cmd.copen()
    end,
    {nargs = 0}
)

In this notional example, the output of torgle ./flidgets.txt looks like:

/path/to/file1.txt 25 19
/path/to/file2.txt 44 37

(In my actual case, I used some combination of awk and sed to massage the output of my system command into this format. This particular example won't work if filenames may contain whitespace.)

1
  • If you’re going to this effort, it’s probably easier to write a compiler script that sets makeprg and errorfmt so that :make does this for you
    – D. Ben Knoble
    Commented Mar 23 at 13:43

Your Answer

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

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