sharkdp / bat

A cat(1) clone with wings.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MANPAGER won't work on Mandoc's man implementation

Bumbadawg opened this issue · comments

commented

What version of bat are you using?
0.15.4

Describe the bug you encountered:
Using export MANPAGER="sh -c 'col -bx | bat -l man -p'"
results in -bx: 1: Syntax error: Unterminated quoted string

Describe what you expected to happen?
paging with bat

How did you install bat?
Void Linux package manager

** The bug **
It was already reported here for Termux, and it coudl well be the case for Alpine and other Mandoc's man implementations cases.
See termux/termux-packages#4781 (comment)

** Lazy solution **
Instead of recompiling man from GNU (https://www.nongnu.org/man-db/development.html)
one can be using export MANPAGER='nvim +Man!'

Thank you for reporting this.

This is not a bug in bat. This implementation of man is currently not supported. This should probably be documented.

It does not work because mandoc does not do shell tokenization of the $MANPAGER string, it just splits it into a list of words and passes them to execvp. So the error comes from sh which complains about an unterminated quoted string from the word 'col.

bat itself does not have any problems displaying the output of mandoc's man command, you just have to configure the pager appropriately. This can be done by putting the following in a wrapper script and then export MANPAGER="your_wrapper":

#!/bin/sh
cat "$1" | col -bx | bat --language man --style plain
#!/bin/sh
cat "$1" | col -bx | bat --language man --style plain

Not that performance matters much for a shell script like this, but you can even cut out the cat invocation:

col -bx < "$1" | bat --language man -p
commented

If you don't have col installed, it's shipped as part of heirloom-doctools.

commented

col -bx < "$1" | bat --language man -p

Or:

#!/bin/sh
exec col -bx | bat -pl man

col -bx < "$1" | bat --language man -p

Or:

#!/bin/sh
exec col -bx | bat -pl man

These two commands are not equivalent - the former reads from a file denoted by $1 and the latter reads from stdin. The former is required for mandoc, the latter may be required for other things that use $MANPAGER (e.g. using the help function in an ipython shell). The following can be used as a universal solution (note that cat here is not as useless as in #1145 (comment)):

#!/bin/sh

# mandoc passes a file name, other tools write to stdout
# using `cat "$@"` we take care of both reading from file and stdin
exec cat "$@" | col -bx | bat --language man --style plain --pager "$PAGER"

@lahwaacz Thanks, this solution works wonderfully!

As part of my investigation into other man-related issues, I figured out why the mandoc implementation doesn't work:

It does extremely simple shell splitting for the MANPAGER variable, which makes it impossible to escape spaces.

image

@lahwaacz's approach of putting it in a separate script is the only solution to having this work with mandoc.

exec cat "$@" | col -bx | bat --language man --style plain --pager "$PAGER"

Or this for better performance:

#!/bin/sh
if [ -f "$1" ]; then
  col -bx < "$1" | bat --language man --plain
else
  col -bx | bat --language man --plain
fi

Or this for better performance:

Did you actually measure it?

In any case, [ -f "$1" ] seems like a wrong condition: if there is no file but stdin, there is no $1 itself.

In any case, [ -f "$1" ] seems like a wrong condition: if there is no file but stdin, there is no $1 itself.

what else is the else clause for?
The code means: if the input is a file then take the file, otherwise take the stdin

Did you actually measure it?

Do I have to? One must be processed through cat and then col, while the other just goes through col

In any case, [ -f "$1" ] seems like a wrong condition: if there is no file but stdin, there is no $1 itself.

what else is the else clause for? The code means: if the input is a file then take the file, otherwise take the stdin

You should not check if $1 is a file, but if there is actually any input. Find out what $# is... 😉

Did you actually measure it?

Do I have to? One must be processed through cat and then col, while the other just goes through col

And you have added one shell condition instead. What do you think is faster: cat or [ -f "$1" ]?

Hey, so you have so much free time in your life huh?

It just bothered me when you don't understand the code and saying it's wrong. It's not wrong. See, after you figure out what my code means, you already improve it. Good learning for you, right? 😉
I'll take your offer then

#!/bin/sh
if [ $# -eq 0 ]; then
  col -bx | "$BAT_BIN" --language man --plain
else
  col -bx < "$1" | "$BAT_BIN" --language man --plain
fi

And you have added one shell condition instead. What do you think is faster: cat or [ -f "$1" ]?

Isn't it obvious? But sure, have it your way.. I don't have much time and energy for something like this

For others: In ubuntu, bat is actually batcat, so set BAT_BIN to bat or batcat depends on your environment.

I don't have much time and energy for something like this

Yeah it is much easier to claim something without actually verifying that it is true. I can as easily claim that there is no actual benefit in terms of performance.

You are all the way right 😉