Add simple text pager for interactive list commands (alternative to #4729)#5015
Open
simonfaltum wants to merge 3 commits intosimonfaltum/list-json-pagerfrom
Open
Add simple text pager for interactive list commands (alternative to #4729)#5015simonfaltum wants to merge 3 commits intosimonfaltum/list-json-pagerfrom
simonfaltum wants to merge 3 commits intosimonfaltum/list-json-pagerfrom
Conversation
Approval status: pending
|
Depends on #5016. Extends the interactive pager introduced in #5016 to commands that register a row template (jobs, clusters, apps, pipelines, etc.). Reuses the shared plumbing from that PR — raw-mode key reader, crlfWriter, prompt helpers, SupportsPager capability — and adds only the template-specific rendering on top. Shape of the new code: - paged_template.go: the template pager. Executes the header + row templates into an intermediate buffer per batch, splits by tab, locks visual column widths from the first batch, and pads every subsequent batch to those widths. The output matches the non-paged tabwriter path byte-for-byte for single-page results and stays aligned across pages for longer ones. - render.go: `RenderIterator` now routes to the template pager when a row template is set, and to the JSON pager otherwise. Covers the subtle rendering bugs that come up when you drop into raw mode and page output: - `term.MakeRaw` clears OPOST, disabling '\n'→'\r\n' translation; the already-shared crlfWriter fixes the staircase effect. - Header and row templates must parse into independent *template.Template instances so the second Parse doesn't overwrite the first (otherwise every row flush re-emits the header text). - An empty iterator still flushes the header. - Column widths are locked from the first batch so a short final batch doesn't visibly compress vs the wider batches above it. Co-authored-by: Isaac
15b0327 to
8003087
Compare
Mirrors the fix in the base PR (#5016). go mod tidy promoted golang.org/x/term from indirect to a direct dependency, and the repo's TestRequireSPDXLicenseComment in internal/build rejects direct dependencies without an SPDX identifier comment — failing `make test` on every platform. Move the dependency into the main require block with the correct `// BSD-3-Clause` comment. This commit is independent from #5016 so 5015 can land on top of main; once the base PR merges, git will resolve this trivially on rebase. Co-authored-by: Isaac
TestNoticeFileCompleteness cross-checks the BSD-3-Clause section of NOTICE against the go.mod require block. Adding golang.org/x/term as a direct dependency (for raw-mode stdin) also requires adding its attribution to NOTICE. Mirror the existing entries for golang.org/x/sys and golang.org/x/text. Co-authored-by: Isaac
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Follow-up to #5016 (JSON pagination). Extends the same interactive pager to commands that register a row template —
jobs list,clusters list,apps list,pipelines list,workspace list, etc. — so the first page renders immediately, then you control when to fetch more.Depends on #5016. Base branch is
simonfaltum/list-json-pager. The shared plumbing (raw-mode key reader,crlfWriter,SupportsPager, prompt helpers) lives in that PR; this one only adds the template-specific rendering on top.This PR is an alternative to #4729 (the Bubble Tea TUI):
spacepage,enterdrain,q/esc/Ctrl+Cquit/search,n/Nmatch nav,qquitlibs/cmdio/onlylibs/tableview/and 15+ override filesTableConfig,ColumnDef,Col[T],Optional, etc.charmbracelet/bubbles,bubbletea,lipglossChanges
Before:
databricks <resource> listwith a row template drained the full iterator and rendered every row up front through the existingrenderUsingTemplatepipeline.Now: when stdin, stdout, and stderr are all TTYs, the CLI streams the first 50 rows and prompts on stderr:
SPACEfetches and renders the next page.ENTERdrains the remaining iterator (still interruptible byq/esc/Ctrl+Cbetween pages).q/esc/Ctrl+Cstop immediately. Piped output and--output jsonkeep the existing behavior. Commands without a row template use the JSON pager from #5016.Rendering reuses the existing
Annotations["template"]andAnnotations["headerTemplate"]: colors, alignment, and row format come from the same code path as today's non-pagedjobs list. No newTableConfig, no newColumnDef, no changes to any override files.Implementation (one new file in
libs/cmdio/):paged_template.go— the template pager. Executes the header + row templates into an intermediate buffer per batch, splits by tab, computes visual column widths (stripping ANSI SGR so colors don't inflate), locks those widths from the first page, and pads every subsequent page to them. Output is visually indistinguishable from tabwriter for single-page results and stays aligned across pages for longer ones.render.go—RenderIteratorroutes to the template pager when a row template is set and to the JSON pager (from Add interactive pagination for JSON list output #5016) otherwise.paged_template_test.go— unit tests: page size, SPACE, ENTER, quit keys, Ctrl+C-mid-drain,--limitintegration, empty iterator, header + rows regression, cross-batch column stability, and byte-for-byte equivalence to the non-paged path for single-page lists.Subtle rendering bugs caught along the way (regression tests included):
term.MakeRawclears the TTY'sOPOSTflag, which disables\n→\r\ntranslation — newlines become bare LF and output staircases down the terminal. The sharedcrlfWriterfrom Add interactive pagination for JSON list output #5016 puts the\rback.*template.Templateinstances. Sharing one receiver causes the secondParseto overwrite the first, which madeapps listrender the header in place of every data row.Test plan
go test ./libs/cmdio/...(passes)make checkspassesmake lintfullpasses (0 issues)apps list,jobs list,clusters list,workspace list /— first page renders immediately, SPACE fetches next, ENTER drains, Ctrl+C/Esc/q all quit (and interrupt a drain).--output json: output unchanged frommain.