Viewing man pages in Preview or VS Code

Posted

I stumbled upon a post entitled “Piping stdout and stderr to Preview” by Erica Sadun - the cool bit that caught my attention was about redirecting man pages (UNIX help) to Preview on macOS. But this got me thinking... to redirect the output to Visual Studio Code instead!

Output to Preview

Quoting Erica Sadun: “This allows you to keep the man page open, search it, and generally have a better user experience than struggling with more (or less) to navigate through the information provided there.”

The command is as below, where -t formats the output as Postscript (of course you should replace grep):

man -t grep | open -fa Preview

Man page in macOS Preview

This is really handy for those who do not have a touch bar, and who do not use the standard Terminal.app.

The output is similar to what you get when using the touch bar man page button:

macOS Terminal touch bar man page button

Man page from macOS Terminal touch bar

Output to VS Code

Personally, I prefer to live in VSCode and use its embedded terminal. So, rather than having the man page in Preview, I could just get it to open in VS Code. Easier to search and refer to the man page, although I would loose the formatting of course (bold and italics / underline).

col -bx is used to strip the man page of control codes and escape sequences with -b to “not output any backspaces” and -x to “output multiple spaces instead of tabs”.

The first way is as follows:

man grep | col -bx | open -fa /Applications/Visual\ Studio\ Code.app 

Man page in Visual Studio Code

Using open -f to “Read input from standard input” creates a temporary file in /tmp with the filename open_xxxxxxxx.txt. Over time, you will end up with a ton of them, which you will have to clean up manually!

The alternative is to pipe STDOUT directly to VS Code:

man grep | col -bx | /Applications/Visual\ Studio\ Code.app/Contents/Resources/app/bin/code - &

This creates an intermediate VS Code process to listen to the stream, and the process will remain running until the document is closed in VS Code. I add & to run it in the background so that I can get my terminal back.

From my testing, this also creates an intermediate file somewhere in /var/folders/xx/yyy...yyy/z. These files do get cleaned up if you close the document, but do not if you terminate the pipe via Ctrl+C. To avoid this I run code in the background with &.

Digression: Output as HTML

Ah, this is possible too and retains formatting, but is waaay too hard to use...

groff -Thtml -mandoc /usr/share/man/man1/grep.1 | open -fa /Applications/Visual\ Studio\ Code.app 

To go down the rabbit hole... Those Ctrl+H escape characters in man pages are backspaces (\x08 in hex) to go back one character. On a (dot matrix) line printer if you print a character, then backspace, and print the character again, you get bold. Print an underscore, then backspace, and print a character, you get underline! Wow, old stuff man!

This does not work to generate HTML files! It’s just an advanced example of sed...

The first expression replaces A\x08A with <b>A</b> the second replace _\0x8A with <u>A</u>. Note the syntax $'\x08' allows the shell to interpret the hex code.

man grep | sed -e 's/\(.\)'$'\x08''\1/<b>\1<\/b>/g' \
 -e 's/_'$'\x08''\(.\)/<u>\1<\/u>/g'

Conclusion

Man pages can be a pain to navigate, so these alternatives may help someone!

Bonus: For even more convenience, I add a function to .zshrc so that I can just use e.g. m grep! Either:

function m() { man -t "$1" | open -fa Preview }

or:

function m() { man "$1" | col -bx | open -fa /Applications/Visual\ Studio\ Code.app }

or:

function m() { man "$1" | col -bx | /Applications/Visual\ Studio\ Code.app/Contents/Resources/app/bin/code - & }