aux4/paginate

Page through data one screen at a time and render each page however you like. paginate owns the navigation loop, never the data — you give it a command that returns one page and a command that renders it, so the same pager works for a local file and a paginated HTTP endpoint. Nothing is ever loaded in full, so a file larger than memory pages exactly as cheaply as a small one.

Installation

aux4 aux4 pkger install aux4/paginate

Quick Start

# A local file, three rows at a time, drawn as a table
aux4 paginate 'cat orders.json | aux4 json page --offset {offset} --limit {limit}' \
  --render 'aux4 render table "id,name,total"' \
  --limit 3

# A paginated endpoint that wraps its rows in an envelope
aux4 paginate 'aux4 curl "https://api.example.com/items?page={page}&limit={limit}"' \
  --data '$.data' \
  --totalPages '$.pagination.totalPages' \
  --render 'aux4 render table "id,name"'

How it works

The pager keeps one piece of state: the current page index and the page size. Everything a fetch command might need is derived from those, so offset-style and page-style APIs are both served without a mode flag — your command names whichever it wants.

| Placeholder | Value | |---|---| | {page} | current page, 1-based | | {pageIndex} | current page, 0-based | | {offset} | pageIndex * limit | | {limit}, {pageSize} | records per page |

Placeholders use single braces. ${page} would not survive: aux4 expands ${...} in parameter values before the command reaches the pager, so a simple ${page} arrives empty. Replacement matches whole tokens only, so a JSON body such as -d '{"page":1}' is left alone.

Keys

| Key | Action | |---|---| | > . n space → | next page | | < , p ← | previous page | | [ g Home | first page | | ] G End | last page — only when the total is known | | q Ctrl-C | quit |

Boundaries are clamped: < on the first page stays put rather than requesting a negative offset, and > will not move past the end.

] works only when --total or --totalPages resolves. The pager never guesses a total, and it hides the ] last hint when there is none — so "there is no last page" stays distinguishable from "the key did nothing".

Responses with an envelope

Most APIs wrap their rows:

{
  "data": [],
  "pagination": {
    "page": 1,
    "total": 240,
    "totalPages": 24
  }
}

--data points at the array, using the same path syntax as aux4 json get ($, $.data, $.results.0, $.page[0].items). The renderer only ever receives the extracted array, never the envelope — so aux4 render table gets exactly what it expects without knowing pagination happened.

--total, --totalPages and --hasMore point at the metadata. With metadata the status line reads:

 page 3 of 24 · 240 items   < prev  > next  [ first  ] last  q quit

and without it, simply page 3.

--hasMore is worth setting even though it does not enable ]: without it the only way to detect the end is fetching an empty page.

With no --data, the fetch output is passed to the renderer untouched, so sources that are not JSON still work.

Options

aux4 paginate <fetch> [--render <cmd>] [--data <path>] [--limit <n>]
  • fetch — command that returns one page (required)
  • --render — command each page is piped through. Default: print the page as-is
  • --data — path to the array in the response. Default: $
  • --limit — records per page. Default: 10
  • --total — path to the total record count, e.g. $.pagination.total
  • --totalPages — path to the total page count, e.g. $.pagination.totalPages
  • --hasMore — path to a boolean saying whether more pages follow
  • --page — page to start on. Default: 1

Without a terminal

Piped, redirected, or running in CI, paginate prints the starting page once and exits instead of waiting for keys. It never blocks a script.

aux4 paginate 'cat orders.json | aux4 json page --offset {offset} --limit {limit}' --limit 2 > page1.json

Renderers

Any command that reads JSON on stdin works — the renderer never knows it is being paginated:

--render 'aux4 render table "id,status,total"'
--render 'aux4 render list "id" --secondary "customer.name"'
--render 'aux4 render kv'
--render 'aux4 json select "id,status"'

Each renderer takes its own arguments — render table and render list both take the field spec positionally, and render list requires one.

License

Apache-2.0