Skip to content

feat(shell): bash-style multi-column tab completion with custom pager#318

Merged
F16shen merged 2 commits into
AI-Shell-Team:mainfrom
F16shen:feat/bash-tab-completion-list
Jun 29, 2026
Merged

feat(shell): bash-style multi-column tab completion with custom pager#318
F16shen merged 2 commits into
AI-Shell-Team:mainfrom
F16shen:feat/bash-tab-completion-list

Conversation

@F16shen

@F16shen F16shen commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add CompletionEngine to route local path tokens through FilenameCompleter and everything else through PTY query_completions (no forward_readline_tab probe in the shell layer).
  • Implement bash-like multi-column completion listing with a custom --More-- pager (Space/y next page, Enter next line, q/n/Backspace/Ctrl+C stop).
  • Intercept double-Tab within 800ms to print the list ourselves and return Cmd::Repaint so ANSI prompts are not corrupted by manual stdout redraw.

Test plan

  • make format-check && make lint
  • cargo test -p aish-shell completion
  • cargo test -p aish-pty readline_tab
  • Manual: ls /usr/bin → Tab Tab → multi-column list appears
  • Manual: Space to page, q / Ctrl+C to stop without extra blank line
  • Manual: ls /usr Tab → LCP extends to /usr/… (not r/)
  • Manual: systemctl rest Tab → completes without timeout

Summary by CodeRabbit

  • New Features
    • Added a tab CompletionEngine that chooses local filesystem completion or PTY-backed completion, improving behavior around cursor position and word detection.
    • Double-pressing Tab now displays a Bash-style, paged multi-column completion list.
    • Local path completion is disabled for quoted and remote-style paths (e.g., user@host:/path, host:/path).
  • Bug Fixes
    • Prevents redundant suggestions by filtering exact-match candidates and avoids duplicate/conflicting completion output.
  • Chores
    • Enabled an additional rustyline feature for directory-aware behavior.

Replace rustyline's built-in completion list with a bash-like multi-column
pager (Space/Enter/q/Ctrl+C), route local paths through FilenameCompleter,
and use double-Tab to show candidates while Repaint keeps ANSI prompts intact.
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the pull request. A maintainer will review it when available.

Please keep the PR focused, explain the why in the description, and make sure local checks pass before requesting review.

Contribution guide: https://github.com/AI-Shell-Team/aish/blob/main/CONTRIBUTING.md

@github-actions

Copy link
Copy Markdown
Contributor

This pull request description looks incomplete. Please update the missing sections below before review.

Missing items:

  • User-visible Changes
  • Compatibility
  • Testing
  • Change Type
  • Scope

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2b53bbcc-5f69-47bd-ba02-571d85356a2c

📥 Commits

Reviewing files that changed from the base of the PR and between 255a451 and 8f809ab.

📒 Files selected for processing (2)
  • crates/aish-pty/src/readline_tab.rs
  • crates/aish-shell/src/completion_list.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/aish-pty/src/readline_tab.rs
  • crates/aish-shell/src/completion_list.rs

📝 Walkthrough

Walkthrough

Adds shared shell completion, paged completion-list output, and double-Tab readline handling. It also updates PTY path-token detection, re-exports the local-path helper, and enables rustyline directory completion support.

Changes

Completion and readline tab flow

Layer / File(s) Summary
Path rules
Cargo.toml, crates/aish-pty/src/lib.rs, crates/aish-pty/src/readline_tab.rs
rustyline gains with-dirs; should_complete_path_locally is re-exported, is_path_like_token becomes private, and path completion excludes quoted and remote-style tokens.
Completion engine
crates/aish-shell/src/lib.rs, crates/aish-shell/src/completion.rs
Adds CompletionEngine, routes completion between local filesystem and PTY candidates, filters exact matches, and exports the new shell completion modules.
Completion list UI
crates/aish-shell/src/completion_list.rs
Adds display-string normalization, terminal sizing, column layout, pager prompting, raw key handling, and completion-list tests.
Readline integration
crates/aish-shell/src/readline.rs
Refactors ShellHelper to use CompletionEngine, adds double-Tab state and handler wiring, and resets tab state and terminal size before each read.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • AI-Shell-Team/aish#219: Also changes crates/aish-shell/src/readline.rs completion behavior and readline key handling.
  • AI-Shell-Team/aish#238: Provides the PTY completion protocol and query_completions flow consumed by CompletionEngine.
  • AI-Shell-Team/aish#248: Also updates Tab-completion flow and token/path classification in readline.rs and readline_tab.rs.

Suggested labels

size: XL

Poem

A rabbit tapped the shell by moon,
And paths marched out in column tune.
--More-- blinked, then hopped away,
While tabs made little lists obey.
🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main shell change: bash-style multi-column tab completion with a custom pager.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
crates/aish-shell/src/readline.rs (1)

109-116: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid querying completions twice on the first Tab.

The handler calls engine.complete(...) and then returns None, so rustyline immediately reaches ShellHelper::complete, which calls engine.complete(...) again. For PTY-backed completions, that can duplicate the timeout-bound query_completions round trip on every first Tab.

Consider making the handler only arm TAB_STATE on the first Tab, and query engine.complete(...) only when a pending second Tab is actually going to print the custom list.

Also applies to: 268-287

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-shell/src/readline.rs` around lines 109 - 116, The Tab handling
in ShellHelper::complete is triggering engine.complete(...) twice on the first
Tab because the pre-check returns None and rustyline then calls the completion
path again. Update the first-Tab logic so it only arms TAB_STATE.pending_list
and defers calling engine.complete(...) until the second Tab actually needs to
print the custom list, using the existing ShellHelper::complete and TAB_STATE
flow to avoid the duplicate completion query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aish-pty/src/readline_tab.rs`:
- Around line 61-68: The remote-path heuristic in looks_like_remote_path() is
missing the bare host:/path form, so should_complete_path_locally() still routes
scp-style remote targets to FilenameCompleter. Update looks_like_remote_path()
in readline_tab.rs to also पहचान bare host:/... tokens before local completion
is chosen, while preserving the existing URL and user@host:/... checks. Add a
regression test covering host:/etc/ (and similar) to verify it is treated as
remote and not handled by the local filename completer.

In `@crates/aish-shell/src/completion_list.rs`:
- Around line 100-120: The terminal size selection in completion_list should use
precedence instead of max, so stale cached or COLUMNS/LINES values do not
override the current tty size after a resize. Update the logic around
current_terminal_size, winsize_ioctl, and the env fallbacks to prefer a non-zero
ioctl result first, then the cached rustyline size, then environment/default
values, and treat zero ws_col/ws_row as unavailable rather than converting them
into sentinel dimensions. Also remove the behavior where winsize_ioctl turns
ws_row == 0 into u16::MAX, since the rows path later clamps it and page_size
never sees the intended unknown-size signal.
- Around line 229-234: The pager flow in the `for row in rows` loop is
discarding legitimate input by calling `drain_stdin_typeahead()` right after
rendering `MORE_PROMPT` in the `read_more_action()` path. Remove that
stdin-draining step from the `--More--` prompt handling so keys like Space or q
entered immediately after the prompt are preserved and processed normally.

---

Nitpick comments:
In `@crates/aish-shell/src/readline.rs`:
- Around line 109-116: The Tab handling in ShellHelper::complete is triggering
engine.complete(...) twice on the first Tab because the pre-check returns None
and rustyline then calls the completion path again. Update the first-Tab logic
so it only arms TAB_STATE.pending_list and defers calling engine.complete(...)
until the second Tab actually needs to print the custom list, using the existing
ShellHelper::complete and TAB_STATE flow to avoid the duplicate completion
query.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e8300e2-b114-462e-90fe-ccc378f71c76

📥 Commits

Reviewing files that changed from the base of the PR and between 3a9e093 and 255a451.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • Cargo.toml
  • crates/aish-pty/src/lib.rs
  • crates/aish-pty/src/readline_tab.rs
  • crates/aish-shell/src/completion.rs
  • crates/aish-shell/src/completion_list.rs
  • crates/aish-shell/src/lib.rs
  • crates/aish-shell/src/readline.rs

Comment thread crates/aish-pty/src/readline_tab.rs
Comment thread crates/aish-shell/src/completion_list.rs
Comment thread crates/aish-shell/src/completion_list.rs
Route scp-style host:/path tokens to PTY completion instead of FilenameCompleter,
and move typeahead draining ahead of the pager prompt so Space/q are not eaten.
@F16shen F16shen merged commit 18aee29 into AI-Shell-Team:main Jun 29, 2026
8 checks passed
@F16shen F16shen deleted the feat/bash-tab-completion-list branch June 29, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant