Skip to content

feat: add dot commands, result truncation and pager to repl - #36

Merged
esadek merged 15 commits into
mainfrom
pager
Oct 14, 2026
Merged

esadek merged 15 commits into
mainfrom
pager

Conversation

@esadek

@esadek esadek commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator
  • Add DuckDB-style dot commands to the interactive shell.
  • Truncate large results to fit the terminal. Results can be shown through an external pager.

@esadek
esadek requested a review from ianmcook October 12, 2026 21:27
@ianmcook

Copy link
Copy Markdown
Member

Issues (none blocking):

  1. The .last example in the docs doesn't match real output. It shows use .last to show entire result for SELECT * FROM range(1000), but the actual footer is 1000 rows (40 shown) 1 column. The hint only appears when there's room for it, so narrow results never mention .last.
  2. .maxrows docs say "Show at most COUNT rows", which isn't quite true. Rows are only hidden when that saves lines (more than max + 3 rows), so .maxrows 5 on 8 rows shows all 8. That behavior makes sense, but the docs should say so.
  3. .maxwidth docs say "Limit tables to WIDTH columns". In a table context "columns" reads as table columns; "characters" would be clearer.
  4. The Windows code is never compiled in CI. CI runs only on Ubuntu, but releases build Windows wheels.
    • The SetConsoleCtrlHandler call matches the windows-sys 0.61.2 signature.
    • Separately, cmd /C gets its argument through .args(), and Rust's quoting may break pager commands that contain quotes, such as "C:\Program Files\...\less.exe" -S. CommandExt::raw_arg is the usual fix. Not tested on Windows.
  5. .help alignment: the long .pager usage pushes every description out to column 60, so they wrap on terminals up to 100 columns wide.
  6. Nits:
    • last_result is only replaced after the next query finishes, so memory briefly holds two full results.
    • .pager on extra becomes a pager command named on extra.
    • .pager 'a' 'b' has its outer quotes stripped, leaving a' 'b.

Scope question:

Truncation only applies in the REPL. Output from --query, --file and stdin is deliberately left alone (and the docs say so), so databow --query in a terminal still wraps long values the old way. That's arguably where truncation would help most, since output there can't be paged or re-shown with .last. Is it planned for a follow-up?

@ianmcook

Copy link
Copy Markdown
Member

Thanks for the fixes — items 1, 2, 3, 5, and the three nits all look good. Two things still open before this can merge, plus the earlier scope question.

1. Drop the tmp: commits. 9036413 and 3ab7740 add a module-level zz_probe_exit_codes test that panics unconditionally, so the Windows CI job is red.

2. Windows missing-pager detection doesn't work. The probe output shows why: on windows-latest, cmd /C <missing-command> exits with code 1 in every variant tried (/S /C quoted, /C unquoted, .args, cmd.exe, stdin piped or null), never 9009. So COMMAND_NOT_FOUND = 9009 never matches, a missing pager is treated as success, the output is lost, and the "Printing to stdout instead" fallback never runs. That's what test_run_pager_missing_command is catching.

Suggestion: don't infer "not found" from the shell's exit code at all. Resolve the first token of the pager command (honoring a leading quoted path) against PATH — and PATHEXT on Windows — before spawning, and return NotFound if it isn't there. That also removes the dependency on 127 from sh.

Related Windows-only edge case, untested: .pager "C:\Program Files\less.exe" with no arguments is a single quoted word, so unquote strips the quotes and cmd receives an unquoted path with a space.

Minor: the Linux job runs plain cargo clippy while the Windows job runs cargo clippy --all-targets -- -D warnings, so Windows is stricter than Linux. Probably worth making them match.

3. Scope question from the first review — truncation only applies in the REPL, and --query / --file / stdin in a terminal still wrap long values the old way. Is non-interactive truncation planned as a follow-up?

@esadek

esadek commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

On scope, leaving --query/--file/stdin untruncated is intentional as those modes are mostly used by scripts and agents which need the full result.

@ianmcook

Copy link
Copy Markdown
Member

One regression from dropping the exit-status check entirely, plus a minor follow-on.

program_name returns None for commands that need the shell (~, $VAR, quoted expansions) and runs them unchecked, which is fine. But run_pager now also ignores the exit status, so when such a pager is missing the result is lost. Verified on macOS with .pager on:

  • .pager ~/databow-no-such-pager → sh: ...: No such file or directory, no table, no fallback message.
  • .pager $DATABOW_MISSING_PAGER (var names a missing program) → sh: ...: command not found, same.
  • .pager "$HOME/databow-no-such-pager" → same.
  • .pager $UNSET_VAR → nothing printed at all, since sh -c '' exits 0.

Before 83864dd, sh's exit code 127 turned these into NotFound and the fallback printed the table. Suggest keeping the exit-code check as a second line of defence on Unix, where POSIX guarantees 127 (not found) and 126 (not executable). The PATH lookup is the only thing that works on Windows, but on Unix both should apply. The empty-expansion case can't be caught by exit code; probably fine to leave.

Minor: a quoted path that doesn't exist or isn't executable loses its quotes. unquote keeps them only when is_program_path succeeds, so .pager "/opt/my pager/plain.txt" (mode 0644) or a typo'd path is stored unquoted. The fallback still fires, but the error names the first whitespace-split word (.../my not found instead of .../my pager/plain.txt), and .pager shows the command without quotes. A non-executable file could also say "not executable" rather than "not found".

@esadek
esadek merged commit f44c685 into main Oct 14, 2026
2 checks passed
@esadek
esadek deleted the pager branch October 14, 2026 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants