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
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).
  
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)), (
    "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: bgBlue, mdCodeFg: fgWhite, mdEmphasisBg: bgBlack,
                     mdEmphasisFg: fgCyan)), ("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: bgBlue,
    mdCodeFg: fgWhite, mdEmphasisBg: bgBlack, mdEmphasisFg: fgCyan)), ("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: bgCyan, mdCodeFg: fgBlack,
    mdEmphasisBg: bgWhite, mdEmphasisFg: fgBlue)), ("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: bgBlue, mdCodeFg: fgWhite,
    mdEmphasisBg: bgBlack, mdEmphasisFg: fgGreen)), ("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))])

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: [].}