Skip to content

Instantly share code, notes, and snippets.

@ernstki
Last active November 25, 2022 14:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ernstki/241630f72ad884bf8b56a36e3265d214 to your computer and use it in GitHub Desktop.
Save ernstki/241630f72ad884bf8b56a36e3265d214 to your computer and use it in GitHub Desktop.
Guide to centering 80-ish column plain text content within wider terminal windows (a work-in-progress)

Centering fixed-width plaintext files in widescreen terminals

How to pad out 80-ish column plain text documents such that they're placed in the center of a much wider terminal (or other application window), for better readability.

Plain text documents in your web browser

Simplest CSS that could possibly work, assuming an 80-column plain text document. Requires Stylus or a similar browser extension. I use "URLs matching the regexp" .*\.(|TXT|txt|rst|md|ME|me)$.

body {
  width: 80ch;
  margin: 0 auto;
}

Center a document based on the actual longest line, rather than just guessing 80ch. Only lightly tested. Requires a user script extension like Tampermonkey.

// ==UserScript==
// @name         Center plaintext docs
// @namespace    https://github.com/ernstki
// @version      0.1
// @description  Pad fixed-width text documents so they're centered within the window
// @author       Kevin Ernst
// @include      /.*\.(|TXT|txt|rst|md|ME|me)$/
// @icon         none
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    var max = 0;
    var style = document.createElement('style');

    document.body.textContent.split(/\n/).forEach((l) => {
        if (l.length > max) max = l.length;
    })

    // not sure why '+2' should be necessary, but it is in Firefox at least
    style.textContent = 'body { width: ' + (max+2) + 'ch; margin: 0 auto; }'
    document.head.appendChild(style);
})();

man7.org

Manual pages on man7.org are displayed in a fixed-width font, but left aligned. You can fix this with Stylus, or another user style manager:

body {
  width: 88ch;
  margin: 0 auto;
}

Anything less can display

source

cless() {
    local contentwidth=${WIDTH:-100}
    local termwidth=$(tput cols)

    sed "s/^/$(printf "%$(((termwidth-contentwidth)/2))s")/" ${1:+"$@"} \
      | less
}

alias lessc=cless  # for convenience, in case you forget

Markdown via ~/.lessfilter and rich-cli

Requires rich-cli. Put this in your ~/.lessfilter and mark it executable with chmod u+x ~/.lessfilter.

Note that ~/.lessfilter is not a feature of less. It's a convention that probably originated with Debian, and seems to be supported in CentOS/RHEL, but not the less from Macports, for example. In environments where ~/.lessfilter doesn't seem to do anything, try putting export LESSOPEN="|$HOME/.lessfilter '%s'" in your login scripts.

See the "INPUT PREPROCESSOR" section of less(1) for details.

#!/bin/bash
contentwidth=${WIDTH:-100}
termwidth=$(tput cols)

case "$1" in
    *.md|*.markdown)
        if type rich &>/dev/null; then
            command rich --force-terminal -d 0,$(((termwidth-contentwidth)/2)) "$@"
            exit 0
        else
            exit 1
        fi
        ;;
esac
exit 1

Anything rich can display

Requires rich-cli.

# source: https://github.com/Textualize/rich-cli/issues/19#issuecomment-1052873593
rich() {
    local contentwidth=${WIDTH:-100}
    local termwidth=$(tput cols)
    local stdin=-
    
    [[ -t 0 ]] && stdin=
    command rich -d 0,$(((termwidth-contentwidth)/2)) --force-terminal $stdin "$@" | less -XR
}

Man pages

source

cman() { 
    local DEFAULT_WIDTH=100
    local manpage margin pad
    local width=$DEFAULT_WIDTH
    local termwidth=$(tput cols)

    while (( $# )); do
        case $1 in
            -w*|--width*)
                if [[ $1 =~ --?w(idth=)?([1-9][0-9]*)$ ]];
                then
                    width=${BASH_REMATCH[2]}
                else
                    shift
                    if [[ -z ${1:-} || ! $1 =~ ^[1-9][0-9]*$ ]]; then
                        echo "ERROR: The -w / --width option expects an" \
                             "integer argument." >&2
                        return 1
                    fi
                    width=$1
                fi
                ;;
            -*)
                echo "ERROR: Unrecognized option '$1'." >&2
                return 1
                ;;
            *)
                if [[ ${manpage:-} ]]; then
                    echo "ERROR: One manual page at a time, please!" >&2
                    return 1
                fi
                manpage=$1
                ;;
        esac
        shift
    done

    if (( termwidth < width )); then
        echo "WARNING: '-w $width' is wider than the terminal." >&2
        width=$termwidth
    else
        margin=$(( (termwidth - width) / 2 ))
        pad=$(printf "%${margin}s")
    fi

    if [[ -z $manpage ]]; then
        echo "What manual page do you want?"
        return  # on macOS/BSD anyway, this *doesn't* return failure
    fi

    (
        (( ${DEBUG:-} )) && set -x
        set -eo pipefail

        manpath=$(man -w $manpage)
    
        { [[ ${manpath##*.} == gz ]] && gzip -dc $manpath || cat $manpath; } \
          | groff -Tascii -rLL=${width}n -man \
          | sed "s/^/$pad/" \
          | ${PAGER:-less -FRX}
    )
}

alias manc=cman  # for convenience, in case you forget

Vim buffers

Courtesy of @vcavallo, via this gist.

" source: https://gist.github.com/vcavallo/c3147fca261c78bd9c4a3648089b22e8
" centers the current pane as the middle 2 of 4 imaginary columns
" should be called in a window with a single pane

 function CenterPane()
   lefta vnew
   wincmd w
   exec 'vertical resize '. string(&columns * 0.75)
 endfunction

" optionally map it to a key:
"nnoremap <leader>e :call CenterPane()<cr>

License

Unless otherwise noted, I am the original author of the code snippets in this gist, and reuse is permitted under the terms of the MIT license.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment