PSPG(1)

๐Ÿ’– pspg(1) โ€” the pspg manual, bestie edition ๐Ÿ’–

okay so this is the manual page for pspg, from the pspg manual. yes the title is literally just the name twice, don't ask. anyway. sit down, grab a strawberry ๐Ÿ“, we're learning a pager.


โœจ NAME โœจ

pspg โ€” Postgres Pager. that's it, that's the name. it's giving "simple but iconic" ๐Ÿ’…


๐ŸŒธ DESCRIPTION ๐ŸŒธ

so here's the lore: everybody who uses psql also uses the less pager. and like, less works well, no shade, but it has zero special support for tabular data. none. it looks at a table and just sees text. tragic honestly ๐Ÿ˜ญ

the author found a few projects that tried to fix this, but none of them was good enough for this purpose. so obviously the only logical move was to write a small specialized pager to use as a psql pager. main character energy fr fr ๐Ÿ‘‘

and this pager can be used from these command line clients too, not just psql:

like, the range?? we love a versatile icon ๐Ÿ’–


๐ŸŽฏ Main target

so what is this pager actually about? bestie. let me tell you.

frozen headers AND clipboard copy AND cute themes? she ate and left no crumbs ๐Ÿ”ฅ


๐Ÿงš Installation and basic configuration

the pspg can be simply installed from Debian (Ubuntu) repositories. RedHat (Fedora) repositories contains pspg too, so nobody's left out:

# Debian (Ubuntu)
sudo apt-get install pspg

# RedHat (Fedora)
sudo dnf install pspg

basic configuration is very simple - just set the system environment variable PSQL_PAGER:

export PSQL_PAGER='pspg'

or, if you want some common options (-b means blackwhite theme, -X preserve content after exit):

export PSQL_PAGER='pspg -X -b'
โš ๏ธ Attention: options used in command line has higher priority than options specified in configuration file (~/.pspgconf). so like, the command line is the boss here. periodt.

native installation on MS Windows is not supported, but pspg works well inside wsl2. inside wsl2 environment, the installation is same like on used Linux system. so basically: windows girlies, go through wsl2, it's fine ๐Ÿซถ

installation on macOS/homebrew is simple by brew install pspg.


๐ŸŽฌ Video presentation

https://www.youtube.com/watch?v=JyxuEkoYDQk

like, actual moving pictures of it working. go watch, i'll wait ๐Ÿ’…


๐Ÿ“ธ Screenshots

(yes bestie, there are screenshots on the real page โ€” this is the part where they live ๐Ÿ–ผ๏ธโœจ)


๐Ÿ‘‘ Options

okay this next bit is the whole --help output, so buckle up. here's what it looks like when you run it:

[pavel@localhost ~]$ pspg --help
pspg is a Unix pager designed for table browsing.

and the usage is literally:

pspg [OPTION] [file]

now the actual options, organized cute so you don't get lost ๐ŸŒˆ

โœจ General options

  • --about โ€” about authors (the lore, the credits, the icons behind the icon)
  • --help โ€” show this help
  • -V, --version โ€” show version
  • --info โ€” show info about libraries and system
  • --direct-color โ€” force direct-color terminal mode
  • -f, --file=FILE โ€” open file
  • -F, --quit-if-one-screen โ€” quit if content is one screen
  • --clipboard-app=NUM โ€” specify app used by copy to clipboard (1, 2, 3, 4)
  • --esc-delay=NUM โ€” specify escape delay in ms (-1 inf, 0 not used, )
  • --interactive โ€” force interactive mode
  • --ignore_file_suffix โ€” don't try to deduce format from file suffix
  • --ni โ€” not interactive mode (only for csv and query)
  • --no-watch-file โ€” don't watch inotify event of file
  • --no-mouse โ€” don't use own mouse handling
  • --no-progressive-load โ€” don't use progressive data load
  • --no-sigint-search-reset โ€” without reset searching on sigint (CTRL C)
  • --no-sleep โ€” without waits against flickering
  • --no_xterm_mouse_mode โ€” don't use optional xterm mouse mode
  • --only-for-tables โ€” use std pager when content is not table
  • --on-sigint-exit โ€” exit on sigint(CTRL C or Escape)
  • --pgcli-fix โ€” try to fix some pgcli related issues
  • --querystream โ€” read queries from stream forever
  • --quit-on-f3 โ€” exit on F3 like mc viewers
  • --rr=ROWNUM โ€” rows reserved for specific purposes
  • --stream โ€” read input forever
  • -X, --reprint-on-exit โ€” preserve content after exit

๐ŸŽจ Output format options

  • -a, --ascii โ€” force ascii
  • -b, --blackwhite โ€” black-white style
  • -s, --style=N โ€” set color style number (0..22)
  • --bold-labels โ€” row, column labels use bold font
  • --bold-cursor โ€” cursor use bold font
  • --border โ€” type of borders (0..2)
  • --double-header โ€” header separator uses double lines
  • --force-uniborder โ€” replace ascii borders by unicode borders
  • --highlight-odd-rec โ€” highlights odd records (when it is supported by style)
  • --hide-header-line โ€” hides header line (between column names and data)
  • --ignore-short-rows โ€” rows with wrong column numbers are ignored
  • --null=STRING โ€” STRING used instead NULL

๐Ÿ” Searching options

  • -g --hlite-search, -G --HILITE-SEARCH โ€” don't highlight lines for searches
  • -i --ignore-case โ€” ignore case in searches that do not contain uppercase
  • -I --IGNORE-CASE โ€” ignore case in all searches

๐Ÿ–ฑ๏ธ Interface options:

  • -c, --freezecols=N โ€” freeze N columns (0..9)
  • --less-status-bar โ€” status bar like less pager
  • --line-numbers โ€” show line number column
  • --menu-always โ€” show top bar menu every time
  • --no-bars, --no-commandbar, --no-topbar โ€” don't show bottom, top bar or both
  • --no-cursor โ€” row cursor will be hidden
  • --no-last-row-search โ€” don't use the last pattern when starting a new search
  • --no-scrollbar โ€” don't show scrollbar
  • --no-sound โ€” don't use beep when scroll is not possible
  • --tabular-cursor โ€” cursor is visible only when data has table format
  • --vertical-cursor โ€” show vertical column cursor

๐Ÿ“ฅ Input format options:

  • --csv โ€” input stream has csv format
  • --csv-separator โ€” char used as field separator
  • --csv-header [on/off] โ€” specify header line usage
  • --skip-columns-like="SPACE SEPARATED STRING LIST" โ€” columns with substr in name are ignored
  • --csv-trim-width=NUM โ€” trim value after NUM chars
  • --csv-trim-rows=NUM โ€” trim value after NUM rows
  • --tsv โ€” input stream has tsv format

๐Ÿšช On exit options:

  • --on-exit-reset โ€” sends reset terminal sequence "\33c"
  • --on-exit-clean โ€” sends clean terminal sequence "\033[2J"
  • --on-exit-erase-line โ€” sends erase line terminal sequence "\33[2K\r"
  • --on-exit-sgr0 โ€” sends sgr0 terminal sequence "\033[0;10m"

๐Ÿ‘€ Watch mode options:

  • -q, --query=QUERY โ€” execute query
  • -w, --watch time โ€” the query (or read file) is repeated every time (sec)

๐Ÿ”Œ Connection options:

  • -d, --dbname=DBNAME โ€” database name
  • -h, --host=HOSTNAME โ€” database server host (default: "local socket")
  • -p, --port=PORT โ€” database server port (default: "5432")
  • -U, --username=USERNAME โ€” database user name
  • -W, --password โ€” force password prompt

๐Ÿ› Debug options:

  • --log=FILE โ€” log debug info to file
  • --wait=NUM โ€” wait NUM seconds to allow attach from a debugger

pspg shares a lot of key commands with the less pager or the vi editor. so if you already know those, you're lowkey already home ๐Ÿ โœจ

options can also be passed within the PSPG environment variable. and here's the processing order, listen up because this matters: configuration file is processed first. options from the PSPG variable are processed afterwards step and command line options are processed at the end. one option can be processed multiple times, and the last value wins. so like, last one in wins the crown ๐Ÿ‘‘


๐ŸŒˆ Environment variables

the original page puts these in a cute little table, but we're doing bullets because we're built different:

  • PSPG โ€” can hold same options like command line
  • PSPG_CONF โ€” path to configuration file
  • PSPG_HISTORY โ€” path to file pspg's readline history file

๐ŸŽ€ Example of config file

the default path of config file is ~/.pspgconf.

and heads up bestie: the fields names can be different than from related command line options. so don't come for me when they don't match, that's just how it is:

ascii_menu = false
bold_labels = false
bold_cursor = false
ignore_case = false
ignore_lower_case = false
no_cursor = false
no_sound = false
no_mouse = false
less_status_bar = false
no_highlight_search = false
no_highlight_lines = false
force_uniborder = false
show_rownum = false
without_commandbar = false
without_topbar = false
vertical_cursor = false
on_sigint_exit = false
no_sigint_search_reset = false
double_header = false
quit_on_f3 = false
pgcli_fix = false
xterm_mouse_mode = true
show_scrollbar = true
menu_always = false
empty_string_is_null = true
last_row_search = true
progressive_load_mode = true
highlight_odd_rec = false
hide_header_line = false
on_exit_reset = false
on_exit_clean = false
on_exit_erase_line = false
on_exit_sgr0 = false
direct_color = false
theme = 16
border_type = 2
default_clipboard_format = 0
clipboard_app = 0
hist_size = 500
esc_delay = -1

copy that whole block into ~/.pspgconf and you're so set ๐Ÿ’…โœจ


(part 1 done bestie, more incoming ๐Ÿฆ‹)

โœจ Themes โœจ

okay so pspg literally ships with a whole built-in theme menu, and the codes are numbered 0 through 23. no cap, here's every single one with the exact names so you can match them up ๐Ÿ’…

  • 0 โ€” black & white
  • 1 โ€” Midnight Commander like
  • 2 โ€” FoxPro like
  • 3 โ€” Pdmenu like
  • 4 โ€” White theme
  • 5 โ€” Mutt like
  • 6 โ€” PCFand like
  • 7 โ€” Green theme
  • 8 โ€” Blue theme
  • 9 โ€” Word Perfect like
  • 10 โ€” Low contrast blue theme
  • 11 โ€” Dark cyan/black mode
  • 12 โ€” Paradox like
  • 13 โ€” dBase IV retro style
  • 14 โ€” dBase IV retro style (Magenta labels)
  • 15 โ€” Red white theme
  • 16 โ€” Simple theme
  • 17 โ€” Solarized dark theme
  • 18 โ€” Solarized light theme
  • 19 โ€” Gruvbox light theme
  • 20 โ€” Tao Light theme
  • 21 โ€” FlatWhite theme
  • 22 โ€” Relational pipes theme
  • 23 โ€” Paper Color theme

see http://okbob.blogspot.cz/2017/07/i-hope-so-every-who-uses-psql-uses-less.html

๐ŸŽ€ Custom themes ๐ŸŽ€

you can customize over the base and menu templates while referencing the built-in themes. save your custom theme file in the directory with pspg configuration, and name it .pspg_theme_xxx. select it with the command line option --custom-style=name or with the command \ctheme name. obsessed ๐Ÿซถ

here's an example of a custom theme file (named .pspg_theme_mc2, and yes it can be activated by the command \ctheme mc2):

template = 1
template_menu = 3

background = black, white
data = black, white
label = black, white, italic, bold
border = #000000, white
footer = lightgray, white
cursor_data = blue, white, italic, bold, dim, reverse
cursor_border = blue, blue , italic, bold, dim, reverse
cursor_label = blue, white, italic, bold, dim, reverse
cursor_footer = blue, white, italic, bold, dim, reverse
cursor_bookmark = red, white, italic, bold, dim, reverse
cross_cursor = white, blue, italic, bold
cross_cursor_border = brightblue, blue
status_bar = black, lightgray
title = black, lightgray
scrollbar_arrows = black, white
scrollbar_background = lightgray, white
scrollbar_slider = white, gray

some keys can be marked with the symbol *, and those marked keys are used for odd records:

data* = black, lightgray
label* = black, lightgray, italic, bold
border* = #000000, lightgray

So like, template and template_menu are your safety nets bestie ๐Ÿ’– โ€” they set fallback values for any keys you didn't bother specifying in your custom theme. And template_menu specifically? That's currently the only way to customize how the F9 menu looks. That's it. That's the whole vibe. ๐ŸŽ€

Here's every key you can theme, no gatekeeping:

  • background โ€” the background color, the canvas of your whole aesthetic โœจ
  • data โ€” text in data cells (aka anything that's not a header and not a frozen column)
  • border โ€” the border color, the ~frame~ around things ๐Ÿ–ผ๏ธ
  • label โ€” text for labels (headers and frozen columns, iykyk)
  • row_number โ€” the line numbers
  • record_number โ€” (the manual literally leaves this one blank, so no tea to spill ๐Ÿ™ˆ)
  • selected_area โ€” (blank in the original too, bestie, I'm not making stuff up ๐Ÿ’€)
  • footer โ€” the results footer, i.e. the non-tabular bit like a rowcount
  • cursor_data โ€” text in the highlighted data cell (again: non-header, non-frozen-column)
  • cursor_border โ€” the border color when it's highlighted ๐Ÿ‘‘
  • cursor_label โ€” the highlighted label text (header or frozen column)
  • cursor_row_number โ€” the highlighted line numbers
  • cursor_record_number โ€” (also blank in the original, we love an empty cell ๐ŸŒธ)
  • cursor_selected_area โ€” (blank again, iconic ๐Ÿ’…)
  • cursor_footer โ€” the highlighted results footer (non-tabular, e.g. rowcount)
  • scrollbar_arrows โ€” the scrollbar's up and down arrows โฌ†๏ธโฌ‡๏ธ
  • scrollbar_background โ€” the scrollbar's "empty" background
  • scrollbar_slider โ€” the scrollbar slider sitting over that background
  • scrollbar_active_slider โ€” the slider when it's grabbed by the mouse ๐Ÿ–ฑ๏ธ
  • title โ€” the results headline (you'll see it in the psql describe commands)
  • status_bar โ€” the top query + cursor location info
  • prompt_bar โ€” (blank in the original, keeping it 100 with you ๐Ÿซถ)
  • info_bar โ€” info text, like "Not found" when you're searching and it's giving nothing ๐Ÿ˜ญ
  • input_bar โ€” the input prompt and text (search, for example)

  • error_bar โ€” the manual doesn't spell this one out, it's just listed with a blank description ๐Ÿ™ˆ
  • bookmark โ€” same deal, listed with no description attached
  • bookmark_border โ€” also listed bare, no description given
  • cursor_bookmark โ€” bare again, no description
  • cross_cursor โ€” Highlighted cell at intersection of horizontal and vertical cursors
  • cross_cursor_border โ€” Borders at intersection of horizontal and vertical cursors
  • matched_pattern โ€” Search result match text
  • matched_pattern_nohl โ€” listed with no description, so that's all the manual gives us ๐Ÿซถ
  • matched_line โ€” Line containing search result
  • matched_line_border โ€” Borders in search result line
  • matched_pattern_cursor โ€” Highlighted search result match text
  • matched_line_vertical_cursor โ€” Vertically highlighted search result match text
  • matched_line_vertical_cursor_border โ€” Borders of vertically highlighted cell with search result match
  • error โ€” blank description in the docs, bestie, that's literally all it says

Okay so about the actual colors ๐ŸŒˆ โ€” the ANSI colors Black, Red, Green, Brown, Blue, Magenta, Cyan, LightGray, Gray, BrightRed, BrightGreen, Yellow, BrightBlue, BrightMagenta, BrightCyan, White, and Default will display as your terminal emulator configures them. Not as pspg decides, as your terminal decides. iykyk.

Alternatively โ€” and this is the fun part, bestie โ€” you can specify hex RGB values like #FF00FF. Custom colors, main character energy. ๐Ÿ’…


Styles โœจ are any combination of: bold, italic, underline, reverse, standout, dim. Mix and match, go off, stack 'em.

If the format of some key is not correct, then this row is ignored. Like, silently. It just doesn't apply. ๐Ÿ’€

For debugging of custom theme it's good to start pspg with option --log. An information about broken definitions are stored in log file. So when your beautiful lil theme isn't doing what you want, that's your move โ€” fire up the log, read what broke, fix it. ๐ŸŽ€

โŒจ๏ธ Keyboard commands โŒจ๏ธ

okay bestie, this is the full keybind rundown โ€” every single shortcut, no skipping, all the facts staying exactly where they belong ๐Ÿ’…โœจ

  • 0, 1, 2, 3, .., 9 โ€” freeze first N columns.
  • KEY_UP, k โ€” navigate backward by one line.
  • KEY_DOWN, j โ€” navigate forward by one line.
  • KEY_LEFT, h โ€” scroll to left.
  • KEY_RIGHT, l โ€” scroll to right.
  • Ctrl+KEY_LEFT โ€” scroll one char left.
  • Ctrl+KEY_RIGHT โ€” scroll one char right.
  • Shift+KEY_LEFT โ€” scroll one column left.
  • Shift+KEY_RIGHT โ€” scroll one column right.
  • Ctrl+Home, g โ€” go to the start of file.
  • Ctrl+End, G โ€” go to the end of file.
  • Alt+l โ€” go to line number.
  • H โ€” go to first line of current window.
  • M โ€” go to half of current window.
  • L โ€” go to end of current window.
  • PPAGE, Ctrl+b โ€” backward one window.
  • NPAGE, Ctrl+f, space โ€” forward one window.
  • HOME, ^ โ€” go to begin of line, first column.
  • END, $ โ€” go to end of line, last column.
  • Ctrl+e โ€” scroll a window down.
  • Ctrl+y โ€” scroll a window up.
  • Ctrl+d โ€” forward a half window.
  • Ctrl+u โ€” backward a half window.
  • s โ€” save content to file.
  • / โ€” search for a pattern which will take you to the next occurrence ๐Ÿ”
  • ? โ€” search for a pattern which will take you to the previous occurrence (same energy, opposite direction, we love a backtracking queen)
  • n โ€” for next match
  • N โ€” for next match in reverse direction
  • c โ€” column search
  • Alt+/ โ€” search for a pattern inside selected area
  • Alt+? โ€” backward search for a pattern inside selected area
  • Alt+c โ€” switch (on, off) drawing line cursor
  • Alt+m โ€” switch (on, off) own mouse handler
  • Alt+n โ€” switch (on, off) drawing line numbers
  • Alt+v, double click on column header โ€” switch (on, off) drawing column cursor
  • Mouse button wheel โ€” scroll vertical
  • Alt+Mouse button wheel โ€” scroll horizontal
  • F9 โ€” show menu
  • q, F10, Esc 0 โ€” quit (three whole ways to say goodbye, pick your fighter ๐Ÿ’…)
  • Alt+q โ€” quit and print raw (unformatted) content
  • Alt+k, Alt+double click โ€” switch bookmark
  • Alt+j โ€” go to next bookmark
  • Alt+i โ€” go to previous bookmark
  • Alt+o โ€” flush bookmarks
  • a โ€” sort ascendent
  • d โ€” sort descendent
  • u โ€” unsorted (sorted in origin order)
  • Space โ€” stop/continue in watch mode
  • R โ€” Repaint screen and refresh input file
  • Ins โ€” export row, column or cell to default target

Okay bestie, real talk for a sec: that last one, Ins? That's your export button and it lowkey does the most โ€” it can ship out a whole row, a whole column, or just a single cell, and it drops it onto the default target. So before you mash it, know what your target is set to, iykyk ๐ŸŽฏ

And yeah, Alt+q is the sneaky icon move ๐Ÿซถ โ€” normal q / F10 / Esc 0 bails out, but Alt+q bails out and hands you the raw (unformatted) content on the way. Different vibe, different output, both valid.

  • shift+cursor up, down โ€” defines the row range ๐ŸŽฏ like you're drawing the boundaries of your lil selection kingdom
  • Ctrl+Shift+cursor left, right โ€” defines the column range, so now you're boxing in columns too ๐Ÿ“ฆ
  • F3 โ€” start/finish of selection rows, press it to open the row-selection era and press it again to close it โœจ
  • Shift+F3 โ€” start/finish of selection block, same energy but for a whole block this time ๐Ÿงฑ
  • Ctrl+drag mouse โ€” defines rows selection, and if you do it on a column header it defines column selection instead ๐Ÿ–ฑ๏ธ lowkey iconic how one gesture does two jobs
  • Ctrl+o โ€” shows the primary screen, then press any key to return to the pager again ๐Ÿ‘€ yes literally any key, it's giving "no thoughts just vibes"
  • %, Ctrl+a โ€” select all ๐Ÿ’… the "I want everything" button, no notes

๐Ÿซถ BACKSLASH COMMANDS ๐Ÿซถ

okay bestie, these are the little backslash spells you can type at the pager. every single one is here, no skips, no cap:

  • \N โ€” go to line number
  • \+N โ€” go to N lines forward
  • \-N โ€” go to N lines backward
  • \N+ โ€” go to line number
  • \N- โ€” go to line number from end
  • \theme N โ€” set theme number
  • \copy [all\|selected] [nullstr "str"] [csv\|tsv\|insert\|text\|pipesep\|sqlvalues] โ€” copy data to clipboard
  • \save [all\|selected] [nullstr "str"] [csv\|tsv\|insert\|text\|pipesep\|sqlvalues] โ€” copy data to clipboard
  • \order [N\|column name] โ€” sort by column
  • \orderd [N\|column name] โ€” desc sort by column
  • \sort [N\|column name] โ€” sort by column
  • \sortd [N\|column name] โ€” desc sort by column
  • \dsort [N\|column name] โ€” desc sort by column (alias)
  • \rsort [N\|column name] โ€” desc sort by column (alias)
  • \asc [N\|column name] โ€” sort by column (alias)
  • \desc [N\|column name] โ€” desc sort by column (alias)
  • \search [back] [selected] [column name] [string\|"string"] โ€” search string in data

The output can be redirected to any command when the name starts with pipe symbol:

\copy csv | less

๐Ÿ’€ ENDING ๐Ÿ’€

The pager can be ended by pressing keys q or F10 or Esc 0. With option --on-sigint-exit then the pager is closed by pressing keys Ctrl+c or Esc Esc.


๐Ÿฆ‹ USE Escape, key INSTEAD Alt + key ๐Ÿฆ‹

pspg supports a possibility to use a sequence of keys Esc, key instead of an Alt+key combination. The interval between pressing Esc and key is limited by interval specified by option esc-delay or by configuration's option esc_delay. This is max delay time in ms. After this interval, the single pressing Esc is interpreted as Escape. -1 means unlimited, 0 disables this feature.


Column search is case insensitive every time. Searched column is marked by vertical cursor. Last non empty string searching pattern is used when current searching pattern is empty string. Searching is starting after visible vertical column or on first visible not freezed columns (after some horizontal scrolling) or on first column. After last column searching starts from first again.


๐Ÿ“ EXPORT & CLIPBOARD ๐Ÿ“

For clipboard support the clipboard application should be installed: 1. wl-clipboard (Wayland), 1. xclip (xwindows), 3. pbcopy (MacOS) or 4. clip.exe (WSL2).

pspg try to translate unicode symbol โˆ… to NULL every time. If you don't use special setting by \pset null ..., then psql displays empty string instead NULL. pspg hasn't any special detection (in export routines) for this case. You should to check and enable or disable menu item Empty string is NULL.

pspg has automatic detection of clipboard application. Unfortunately, this detection should not to work for same cases. You can specify the application by specify number (1,2,3,4) to --clipboard-app option.

Formats make a difference! pspg copies records in CSV format by default, which uses comma separators and trims initial and trailing whitespace. Use "formatted text" to copy query output exactly, or choose one of the other available options.


๐Ÿ‘‘ STATUS LINE DESCRIPTION ๐Ÿ‘‘

  • V: [d/d d..d] โ€” vertical cursor: (column number)/(columns) (char positions from) .. (char positions to)
  • FC: d โ€” freezed columns length in chars
  • C: d..d/d โ€” unfreezed visible data in chars (from .. to)/(total)
  • L:[d + d d/d] โ€” lines (number of first visible line) + (number of line of display), (current line)/(lines)
  • d% โ€” percent of already displayed data

๐Ÿš Usage as csv viewer

okay so real talk โ€” pspg lowkey slays as a csv viewer too, and it plays so nice with miller (http://johnkerl.org/miller/doc/index.html). Bestie combo:

mlr --icsv --opprint --barred put '' obce.csv | pspg --force-uniborder

โœจ New version has integrated csv support โ€” just use the --csv option and you're literally done.

It can also be integrated into mc ๐Ÿ’…:

  • copy the file from /etc/mc/mc.ext to your ~/.config/mc directory
  • insert this in there:
##csv

regex/\.csv
    View=pspg -f %f --csv
  • restart mc

๐Ÿซ  Known issues

  • When you use pspg on Cygwin, some temporary freezing of scrolling was reported ๐Ÿ˜ญ In this case, please, use an option --no-sleep. I see slow scrolling (via scrollbar) inside konsole (KDE terminal). The option --no-sleep helps too.

๐Ÿ‘€ Usage in watch mode

The result of the query can be refreshed every n seconds โœจ pspg remembers the cursor row, possible vertical cursor, possible ordering. The refreshing should be paused by pressing the space key โ€” and repeated pressing of this key enables refreshing again. Cute, right?

pspg uses the inotify API when it is available, and when the input file is changed, then pspg rereads the file immediately ๐Ÿ”ฅ That behaviour can be disabled by the option --no-watch-file or by specifying watch time with the option --watch.


๐ŸŒŠ Streaming modes

pspg can read a continuous stream of tabular data from a pipe, named pipe or from a file (with an option --stream), or it can read a stream of queries from a pipe or from a file (with an option --querystream). In stream mode, only data in table format can be processed, because pspg uses an empty line as the separator between tables ๐Ÿ“‹

The query stream mode is a sequence of SQL statements separated by the char GS (Group separator โ€” 0x1D) on a separated line.

pavel@localhost ~]$ cat < /dev/pts/3 > ~/pipe
select 10
^]
select 20
^]
select *
from
pg_class
^]

you should add this to your profile ๐Ÿซถ:

#for Postgres 10 and older
export PAGER="pspg"

#for postgres 11 and newer
export PSQL_PAGER="pspg"

#or "\setenv PAGER pspg" to .psqlrc

and in .psqlrc:

\set QUIET 1
\pset linestyle unicode
\pset border 2
\pset null โˆ…
\unset QUIET

some possible configuration:

-- Switch pagers with :x and :xx commands
\set x '\\setenv PAGER less'
\set xx '\\setenv PAGER \'pspg -bX --no-mouse\''
:xx

LC_CTYPE should be correct ๐Ÿ‘‘ Mainly when you use unicode borders. ncurses doesn't display unicode borders (produced by psql) without a correct setting of this variable. It's possible to check the value 'C.UTF8'.


โš ๏ธ Attention

When you use the option --only-for-tables, then:

  • set PAGER to pspg and PSQL_PAGER to less or
  • set PAGER to less and PSQL_PAGER to pspg

๐Ÿฌ MySQL usage

MariaDB [sakila]> pager pspg -s 14 -X --force-uniborder --quit-if-one-screen
PAGER set to 'pspg -s 14 -X --force-uniborder --quit-if-one-screen'
MariaDB [sakila]> select now();
MariaDB [sakila]> select * from nicer_but_slower_film_list limit 100;

๐Ÿชถ SQLite

The SQLite native client doesn't produce well-formatted output, but it can be forced to generate CSV format โ€” and that format is well readable for pspg ๐Ÿ’–

sqlite3 -csv -header testdb.db 'select * from foo2' | pspg --csv --csv-header=on --double-header

๐Ÿ˜ pgcli

pgcli (https://github.com/dbcli/pgcli/) needs the following configuration options (~/.config/pgcli/config):

pager = /usr/bin/pspg --csv --rr=2 --quit-if-one-screen --ignore-case --csv-header on --pgcli-fix
table_format = csv

Older versions of pgcli had very slow output in tabular format ๐ŸŒ A workaround was using csv format. This should not be necessary on current versions, when the performance issue was fixed. The option --pgcli-fix fixed the import of partially broken csv format generated by pgcli. Modern versions of pgcli don't need csv format, and don't need the --pgcli-fix option.

pager = /usr/bin/pspg --rr=2 --quit-if-one-screen --ignore-case

๐Ÿงก sqlcl

As sqlcl doesn't currently support a pager option directly, you can either use a tool like qsh (https://github.com/muhmud/qsh) to work around this issue, or use the pspg.sql script (https://github.com/okbob/pspg/blob/master/scripts/sqlcl/pspg.sql) from this repo.

To use the script, start sqlcl as shown below (it's important to pass in the details of your current tty):

$ TTY=$(tty) sqlcl system/system @/path/to/pspg.sql

You can now have the results of a query sent to pspg like this:

SQL> pspg select * from user_tables;

๐ŸŸ nushell

pspg supports the default table_mode: rounded and table_mode: heavy ๐ŸŽ€

The conversion to csv can be used too:

sys | get cpu | to csv | pspg --csv

Note: footer_mode should be disabled.

nushell configuration:

$env.config.footer_mode = never
$env.config.table.header_on_separator = false
$env.config.ls.clickable_links = false
$env.config.table.mode = rounded

๐Ÿ–ฑ๏ธ Note โ€” mouse

pspg tries to use xterm mouse mode 1002, when the terminal and ncurses are not too antique. If there are problems with usage โ€” unwanted visual artefacts when you move with the mouse while some mouse button is pressed โ€” then 1. please, report the issue (please, attach the log file), 2. use the option --no-xterm-mouse-mode and pspg will not try to activate this mode ๐Ÿ™ˆ


๐ŸŒˆ Note โ€” true color themes on KDE konsole terminal

On my Fedora this terminal doesn't correctly display true color themes ๐Ÿ˜ญ The basic problem is in the default TERM setting, that is xterm-256color. Unfortunately, the konsole terminal is not fully compatible with xterm, and doesn't allow color changing. You can force direct colors by using the option --direct-color or by setting TERM=xterm-direct. The second option is the more correct setting of the TERM variable to konsole-256color. In this case pspg will map the true rgb colors to supported 256 colors โœจ


๐Ÿ› ๏ธ Note โ€” compilation issue

Some linker issues can be fixed by:

I changed
gcc -lncursesw pager.c -o pspg -ggdb
to
gcc pager.c -o pspg -ggdb -lncursesw

If you want to use pspg as a Postgres client, then you need to run configure --with-postgresql=yes. On Fedora with my own Postgres build I had to install the openssl-devel package and I had to set export PKG_CONFIG_PATH="/usr/local/pgsql/master/lib/pkgconfig/".

On FreeBSD you should use gmake instead of make ๐Ÿ‘‘


๐Ÿ“ฆ Note โ€” Installation details

When you compile code from source, run ./configure first. Sometimes ./autogen.sh first.

If you would like to display UTF-8 characters, then pspg should be linked with the ncursesw library. UTF-8 characters are displayed badly when the ncursesw library is used. You can see broken characters with an incorrect locale setting too ๐Ÿซ 

You can check wide chars support with pspg --version. A row ncurses with wide char support is expected. Re-run configure with the --with-ncursesw option. When this command fails, check if the development package for the ncursesw library is installed.

๐Ÿบ Homebrew (for Linux & MacOS)

# brew install pspg

You can compile pspg easily without brew, but you need the gnu readline library. MacOS uses by default readline emulated over libedit, but pspg requires the full gnu readline library.

LDFLAGS="-L/usr/local/opt/readline/lib" CPPFLAGS="-I/usr/local/opt/readline/include" ./configure
LDFLAGS="-L/usr/local/opt/readline/lib" CPPFLAGS="-I/usr/local/opt/readline/include" make

๐ŸŒ€ Debian

# apt-cache search pspg
# apt-get install pspg

๐ŸŽฉ Fedora (28 and later)

# dnf install pspg

๐Ÿ”ด RPM (CentOS/openSUSE/โ€ฆ)

pspg is available from the community repository https://yum.postgresql.org/packages.php

๐Ÿ”๏ธ Alpine Linux

# apk add pspg

๐ŸŒฟ Gentoo

# emerge -av dev-db/pspg

๐Ÿน Arch Linux

The Arch User Repository contains two versions:

Use the AUR helper of your choice, or git and makepkg, to install pspg ๐Ÿ’…

๐Ÿ˜ˆ FreeBSD

# pkg install pspg

๐Ÿก OpenBSD

# pkg_add pspg

More about it here: https://fluca1978.github.io/2021/10/28/pspgOpenBSD.html

๐ŸŽ Using MacPorts (MacOS only)

# port install pspg

๐ŸชŸ MS Windows

pspg can simply be used on MS Windows by using wsl2 โœจ I tested it, and it's working without problems.

  • In a terminal, execute wsl --install -d Ubuntu-22.04
  • In a terminal, open an Ubuntu session:
sudo apt-get update
sudo apt-get install pspg
sudo apt-get install postgresql postgresql-contrib

# set password for user postgres
sudo passwd postgres
su - postgres
psql postgres
>> create role pavel login;
\q
exit
touch ~/.psqlrc
mcedit .psqlrc
\pset linestyle unicode
\pset border 2
\setenv PSQL_PAGER 'pspg -b -X'
# press F2 and F10
psql postgres

there isn't any difference from installation and work on Ubuntu (Debian) ๐Ÿซถ

pspg is not ported to MS Windows yet. There's the dependency on ncurses and on a correctly (fully) implemented newterm function (pdcurses does this only on Unix platforms). It can work with WSL2 maybe (I didn't test it). An alternative can be using the less pager, which is ported to some MS Win environments. less depends on termcap, and it's a little bit more portable than pspg (termcap is the low layer of ncurses). less supports fixed rows and, with the --chop-long-lines option or just -S, can be used as a pager for pspg.

export PSQL_PAGER="less --chop-long-lines --header 1"

โ˜€๏ธ Solaris

There are a few issues requiring manual code changes for successful compilation โ€” we successfully tested pspg, but although pspg was linked with ncursesw libraries, the utf8 encoding support didn't work fully correctly โ€” probably due to some issues in the libc library ๐Ÿ˜ญ There are problems with chars encoded to 3 bytes โ€” unicode borders, etc. Two-byte unicode chars should be displayed well.

You can use pspg with usual accented chars, but unicode borders should not be used. Replacement of ascii borders by special border chars (by ncurses technology) works well โ€” look at the Options|Force unicode borders option.

  • Solaris make doesn't support conditional statements โ€” they should be removed. So, remove unsupported functionality from the Makefile (ifdef, endif), replace -include by include first.
  • After running configure, remove the link on the termcap library from config.make. It is garbage produced by the readline automake script. The combination with ncurses libraries makes some linking issues.

๐Ÿงš builtin libraries

export CURSES_CFLAGS="-I/usr/include/ncurses/"
export PANEL_LIBS="-lpanelw"
./configure

๐ŸŒŸ OpenCSW development

export CFLAGS="-m64 -I/opt/csw/include"
export LDFLAGS="-L/opt/csw/lib/64 -R/opt/csw/lib/64"
export PKG_CONFIG_PATH="/opt/csw/lib/64/pkgconfig"
./configure

๐ŸŒˆ POSSIBLE TODO (aka the "somebody please do this" list) ๐ŸŒˆ

Okay bestie, so these are the glow-up plans for the project โ€” not done yet, just vibing on the wishlist ๐Ÿ’ญโœจ

  • Store data in some column format (right now the data are stored like an array of rows). With this change it could be possible to operate over columns โ€” hide columns, change width, cyclic iteration over columns, change order of columns, mark columns, and export only selected columns (selected rows). That's a whole new level of main character energy for the data model, no cap ๐Ÿ‘‘
  • Replace printing document directly to ncurses window with some smarter structure. Internally there are a lot of checks and fixes to support complex dynamic layout. The possible views should remember first row, last row, current row. Right now, these data are in global variables or in DataDesc and ScrDesc structures โ€” lowkey a whole situation ๐Ÿซ 

๐ŸŽ€ ST_MENU ๐ŸŽ€

This project uses the st_menu library โ€” it's the implementation of CUA menubar and pulldown menu for ncurses, and it's iconic fr fr:

https://github.com/okbob/ncurses-st-menu

๐Ÿ’Œ NOTE (the part where she's being adorable) ๐Ÿ’Œ

If you like it, send a postcard from your home country to my address, please ๐Ÿซถ๐Ÿ“ฎ โ€” and yes she really means it, this is the sweetest thing ever:

Pavel Stehule
Skalice 12
256 01 Benesov u Prahy
Czech Republic

I invite any questions, comments, bug reports, patches on mail address pavel.stehule@gmail.com โ€” literally bring it all, the questions, the comments, the bugs, the patches, all of it ๐Ÿ’–


And that's the whole page, bestie โ€” you made it to the very end, slay ๐Ÿ’…โœจ This lil masterpiece is PSPG(1) from May 2025, and honestly? Iconic. Go forth and scroll with taste ๐Ÿฆ‹๐ŸŒธ

๐Ÿ“ฆ where this page comes from