src/lesster

lesster – a less-like interactive text pager library for Nim.

Exports the public API for embedding the pager in other Nim programs:

  • viewText – display an in-memory sequence of lines.
  • viewFile – display a file path, or "-" to read from stdin.

Keybindings

KeyAction
↑ /↓ Scroll one line up / down
PgUp /PgDn Scroll one page up / down
SpaceScroll one page down
gJump to the top
GJump to the bottom
/Enter case-insensitive regex search mode
nNext search match
NPrevious search match
mToggle minimal Markdown rendering on / off
sToggle word-wrap on / off
tToggle markdown table formatting on / off
TabCycle through colour themes
qQuit

Types

Theme = object
  titleBg*: iw.BackgroundColor ## Title bar background
  titleFg*: iw.ForegroundColor ## Title bar foreground
  bodyBg*: iw.BackgroundColor ## Content area background
  bodyFg*: iw.ForegroundColor ## Content area foreground
  statusBg*: iw.BackgroundColor ## Status bar background (normal mode)
  statusFg*: iw.ForegroundColor ## Status bar foreground (normal mode)
  searchBg*: iw.BackgroundColor ## Search prompt bar background
  searchFg*: iw.ForegroundColor ## Search prompt bar foreground
  matchBg*: iw.BackgroundColor ## Search-match line highlight background
  matchFg*: iw.ForegroundColor ## Search-match line highlight foreground
  mdHeaderBg*: iw.BackgroundColor ## Markdown header background (same as body background).
  mdHeaderFg*: iw.ForegroundColor ## Markdown header foreground (bright/accent color).
  mdCodeBg*: iw.BackgroundColor ## Markdown code-block background (contrasts with body background).
  mdCodeFg*: iw.ForegroundColor ## Markdown code-block foreground.
  mdEmphasisBg*: iw.BackgroundColor ## Markdown emphasis background (same as body background).
  mdEmphasisFg*: iw.ForegroundColor ## Markdown emphasis foreground (same accent as header).
  mdInlineCodeBg*: iw.BackgroundColor ## Markdown inline-code background.
  mdInlineCodeFg*: iw.ForegroundColor ## Markdown inline-code foreground.
Colour configuration for every visual element drawn on screen. Set bodyBg / bodyFg to bgNone / fgWhite to let the terminal's own theme shine through (the "terminal" preset).

Lets

ThemesTable = toTable([("terminal", Theme(titleBg: bgNone, titleFg: fgWhite,
    bodyBg: bgNone, bodyFg: fgWhite, statusBg: bgNone, statusFg: fgWhite,
    searchBg: bgNone, searchFg: fgYellow, matchBg: bgNone, matchFg: fgYellow,
    mdHeaderBg: bgNone, mdHeaderFg: fgYellow, mdCodeBg: bgBlack,
    mdCodeFg: fgWhite, mdEmphasisBg: bgNone, mdEmphasisFg: fgYellow,
    mdInlineCodeBg: bgNone, mdInlineCodeFg: fgMagenta)), ("default", Theme(
    titleBg: bgBlue, titleFg: fgWhite, bodyBg: bgBlack, bodyFg: fgWhite,
    statusBg: bgCyan, statusFg: fgBlack, searchBg: bgYellow, searchFg: fgBlack,
    matchBg: bgYellow, matchFg: fgBlack, mdHeaderBg: bgBlack,
    mdHeaderFg: fgCyan, mdCodeBg: bgBlack, mdCodeFg: fgWhite,
    mdEmphasisBg: bgBlack, mdEmphasisFg: fgCyan, mdInlineCodeBg: bgBlack,
    mdInlineCodeFg: fgMagenta)), ("dark", Theme(titleBg: bgBlack,
    titleFg: fgCyan, bodyBg: bgBlack, bodyFg: fgWhite, statusBg: bgBlue,
    statusFg: fgWhite, searchBg: bgGreen, searchFg: fgBlack, matchBg: bgGreen,
    matchFg: fgBlack, mdHeaderBg: bgBlack, mdHeaderFg: fgCyan,
    mdCodeBg: bgBlack, mdCodeFg: fgWhite, mdEmphasisBg: bgBlack,
    mdEmphasisFg: fgCyan, mdInlineCodeBg: bgBlack, mdInlineCodeFg: fgMagenta)), (
    "light", Theme(titleBg: bgWhite, titleFg: fgBlue, bodyBg: bgWhite,
                   bodyFg: fgBlack, statusBg: bgBlue, statusFg: fgWhite,
                   searchBg: bgYellow, searchFg: fgBlack, matchBg: bgYellow,
                   matchFg: fgBlack, mdHeaderBg: bgWhite, mdHeaderFg: fgBlue,
                   mdCodeBg: bgGreen, mdCodeFg: fgBlack, mdEmphasisBg: bgWhite,
                   mdEmphasisFg: fgBlue, mdInlineCodeBg: bgWhite,
                   mdInlineCodeFg: fgMagenta)), ("matrix", Theme(
    titleBg: bgBlack, titleFg: fgGreen, bodyBg: bgBlack, bodyFg: fgGreen,
    statusBg: bgGreen, statusFg: fgBlack, searchBg: bgGreen, searchFg: fgBlack,
    matchBg: bgGreen, matchFg: fgBlack, mdHeaderBg: bgBlack,
    mdHeaderFg: fgGreen, mdCodeBg: bgBlack, mdCodeFg: fgWhite,
    mdEmphasisBg: bgBlack, mdEmphasisFg: fgGreen, mdInlineCodeBg: bgBlack,
    mdInlineCodeFg: fgMagenta)), ("mono", Theme(titleBg: bgWhite,
    titleFg: fgBlack, bodyBg: bgBlack, bodyFg: fgWhite, statusBg: bgWhite,
    statusFg: fgBlack, searchBg: bgWhite, searchFg: fgBlack, matchBg: bgWhite,
    matchFg: fgBlack, mdHeaderBg: bgBlack, mdHeaderFg: fgWhite,
    mdCodeBg: bgBlue, mdCodeFg: fgWhite, mdEmphasisBg: bgBlack,
    mdEmphasisFg: fgWhite, mdInlineCodeBg: bgBlack, mdInlineCodeFg: fgWhite))])

Consts

ThemeNames = ["default", "dark", "light", "matrix", "mono", "terminal"]
Ordered list used when cycling themes with Tab.

Procs

proc getMounted[T](node: T; ctx: var Context[State]): T
proc renderRoot(node: nw.Node; ctx: var Context[State]) {.
    ...raises: [Exception, KeyError], tags: [RootEffect], forbids: [].}
proc viewFile(path: string; title: string = ""; themeName: string = "default";
              markdownMode: bool = false) {.
    ...raises: [IOError, KeyError, IllwaveError, Exception],
    tags: [ReadIOEffect, RootEffect, ReadEnvEffect, WriteIOEffect, TimeEffect],
    forbids: [].}

Launch the interactive pager for a file path, or "-" for stdin.

When reading from stdin, fd 0 is reconnected to /dev/tty after all data has been buffered so that keyboard input still works.

proc viewText(lines: seq[string]; title: string = "lesster";
              themeName: string = "default"; markdownMode: bool = false) {.
    ...raises: [KeyError, IllwaveError, IOError, Exception],
    tags: [RootEffect, ReadEnvEffect, WriteIOEffect, TimeEffect], forbids: [].}

Launch the interactive pager with an in-memory sequence of text lines.

title is displayed centred in the title bar. themeName must be one of the keys in ThemesTable ("default", "dark", "light", "matrix", "mono", "terminal"); unknown names fall back to "default".

Methods

method mount(node: nw.Node; ctx: var Context[State]) {.base, locks: "unknown",
    ...raises: [], tags: [], forbids: [].}
method render(node: nw.Box; ctx: var Context[State]) {....raises: [Exception],
    tags: [RootEffect], forbids: [].}
method render(node: nw.Node; ctx: var Context[State]) {.base, locks: "unknown",
    ...raises: [], tags: [], forbids: [].}
method render(node: nw.Scroll; ctx: var Context[State]) {.
    ...raises: [Exception, KeyError], tags: [RootEffect], forbids: [].}
method render(node: nw.Text; ctx: var Context[State]) {.
    ...raises: [ValueError, Exception, KeyError], tags: [RootEffect], forbids: [].}
method unmount(node: nw.Node; ctx: var Context[State]) {.base, locks: "unknown",
    ...raises: [], tags: [], forbids: [].}