2

I have a bash command that will align text into a tabular form. If I have input such as this:

A | B | C
Alpha | Beta | Gamma
12 | 34.56 | 78.9

I can run cat test.txt | sed -e 's/|/'$'\001''|/g' | column -t -s $'\001' to get:

A       | B       | C
Alpha   | Beta    | Gamma
12      | 34.56   | 78.9

The \001 is a delimiter I use with column since I want to retain the | in the text.

I can run this command inside vim by first visually selecting lines and then :'<,'>!sed ... with command exactly as above, without the cat.

I want to turn this into a vim map so that I can visually highlight a bunch of rows, or use text objects, and do the same alignment. Unfortunately, the following:

vnoremap <leader>t :'<,'>!sed -e 's/|/'$'\001''|/g' | column -t -s $'\001'

gives me the error E486: Pattern not found: '$'\001''| for the first $'\001'.

How to resolve this?

5
  • 1
    not solving your problem, but you can consider making this into a bash script
    – Mass
    Feb 9, 2021 at 20:58
  • wow, I'm stoked to learn that this combination of visually-selected text + external command to update it is even possible!!!
    – alec
    Feb 9, 2021 at 21:28
  • 1
    @alex :help filter :) For the OP, probably :help map-bar and How to debug a mapping (sorry, wrong link earlier)
    – D. Ben Knoble
    Feb 9, 2021 at 21:44
  • fwiw... vimwiki has a neat table feature that you might find handy
    – alec
    Feb 9, 2021 at 21:48
  • The \001 is a delimiter What's wrong with column -t -s\| -o\| ??
    – Matt
    Feb 10, 2021 at 8:55

2 Answers 2

4

The main issue that needs fixing here is that the | character is special here, it is used as a separator for Ex commands and is not passed verbatim to your mapping.

In order to fix it, you need to either use <Bar> or \| here.

See :help map-bar for more details.

Additionally, you'll probably want to add a <CR> at the end, to actually execute the command when the mapping is activated.

Finally, you might want to use xnoremap here, since vnoremap affects both Visual and Select mode. (Select mode is not used very often, but mapping Visual mode only is typically the more correct choice here.)

Putting it all together:

xnoremap <leader>t :'<,'>!sed -e 's/<Bar>/'$'\001''<Bar>/g' <Bar> column -t -s $'\001'<CR>
2

Like @Mass's comment suggested, you can create a columnize.sh file...

#!/usr/bin/env bash

set -euo pipefail

sed -e 's/|/'$'\001''|/g' | column -t -s $'\001'

(Make it executable of course chmod +x columnize.sh.)

And then in .vimrc map it:

vnoremap <leader>t :!columnize.sh<CR>
5
  • 1
    I don't see why invoking a script would be slower than the individual commands... In both cases you're spawning a shell, then sed and column. Other than reading the script file (which is negligible), the two are essentially he same.
    – filbranden
    Feb 10, 2021 at 12:46
  • I tiried both ways and there was a very significant delay when the sed | column commands were in a separate script file. I have no idea why. But it I tried a few times and it was consistent.
    – alec
    Feb 10, 2021 at 15:16
  • 1
    Maybe some problem with $PATH? Perhaps a network directory in there, or a directory with too many entries, that is slowing down lookup? But this would affect most of any commands that you run... Does it also happen if you call columnize.sh with an explicit path from Vim? Such as :!./columnize.sh<CR> (assuming it resides on the current directory)
    – filbranden
    Feb 10, 2021 at 17:57
  • 1
    Nice! Using the full path to the script works just as fast, thanks :)
    – alec
    Feb 11, 2021 at 0:12
  • 1
    Also: "Make it writable" the +x is actually executable, not writable... Can you fix it?
    – filbranden
    Feb 11, 2021 at 1:17

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.