Skip to content

feat: Add shell autocompletion support for bash and zsh#43

Open
stjuan627 wants to merge 1 commit intojohnlindquist:mainfrom
stjuan627:feat/autocompletion
Open

feat: Add shell autocompletion support for bash and zsh#43
stjuan627 wants to merge 1 commit intojohnlindquist:mainfrom
stjuan627:feat/autocompletion

Conversation

@stjuan627
Copy link

@stjuan627 stjuan627 commented Feb 10, 2026

Add wt completion bash/zsh command that outputs shell completion scripts, and a hidden wt __complete command for dynamic candidate generation. Completions include worktree branches for merge/remove/open, git branches for new/setup/extract, and static subcommands for config.

Summary by CodeRabbit

  • New Features

    • Added shell autocompletion support for bash and zsh shells, providing intelligent suggestions for subcommands, branches, and configuration options during CLI usage.
  • Documentation

    • Added shell autocompletion setup instructions, enabling users to enable completion in their shells both for the current session and permanently via shell profile files.

Add `wt completion bash/zsh` command that outputs shell completion scripts,
and a hidden `wt __complete` command for dynamic candidate generation.
Completions include worktree branches for merge/remove/open, git branches
for new/setup/extract, and static subcommands for config.
@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

Adds comprehensive shell autocompletion support for bash and zsh shells to the CLI. Includes a new completion command that generates shell scripts, dynamic __complete command that provides context-aware suggestions for subcommands and git branches, and integration with git utilities to fetch branch and worktree data.

Changes

Cohort / File(s) Summary
Documentation
README.md
Adds usage instructions for shell autocompletion with commands to enable bash/zsh completion in current session and persist via shell profiles; documents completion coverage scope.
Shell Completion Scripts
src/completions/bash.ts, build/completions/bash.js, src/completions/zsh.ts, build/completions/zsh.js
New modules exporting bashCompletionScript() and zshCompletionScript() functions that return shell scripts for bash and zsh integration; scripts invoke wt __complete to dynamically fetch and register completions.
Completion Command Handler
src/commands/completion.ts, build/commands/completion.js
New modules defining completionHandler(shell) to output appropriate completion scripts and getCompletions(words) to provide context-aware completion candidates; handles subcommands, worktree branches, git branches, and config subcommands with error-tolerant behavior.
Git Utility Enhancement
src/utils/git.ts, build/utils/git.js
New exported getBranches(cwd) function that executes git branch --format=%(refname:short) to retrieve local branch names; returns empty array on error.
CLI Integration
src/index.ts, build/index.js
Wires new completion and __complete commands into CLI; imports and exports completion handler and getCompletions functions; __complete is hidden and parses words after -- delimiter for dynamic completion queries.
Test Suite
test/completion.test.ts
Comprehensive test coverage for completion logic with mocked git utilities; validates subcommand completion, worktree branch suggestions, git branch filtering, config subcommand completion, and edge cases; uses stdout capture helper for assertion.

Sequence Diagram

sequenceDiagram
    participant User as User/Shell
    participant CLI as CLI (wt)
    participant Complete as __complete Handler
    participant Logic as getCompletions
    participant Git as Git Utils
    participant Shell as Shell Registration

    User->>CLI: Start typing 'wt new [TAB]'
    CLI->>Complete: Invokes __complete with words
    Complete->>Logic: Calls getCompletions(['new', 'partial'])
    Logic->>Git: Detects 'new' command, calls getBranches()
    Git-->>Logic: Returns ['main', 'feature-x', 'feature-y']
    Logic-->>Complete: Filters and returns matching branches
    Complete-->>CLI: Outputs candidates to stdout
    CLI->>Shell: Returns completion suggestions
    Shell-->>User: Displays matching branches for [TAB]

    rect rgba(100, 150, 200, 0.5)
    Note over User,Shell: Initial Shell Setup
    User->>CLI: Run 'wt completion bash'
    CLI->>Complete: completionHandler('bash')
    Complete-->>User: Outputs bash completion script
    User->>Shell: Evaluates script, registers _wt_completions
    Shell-->>User: Completion ready for future use
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Whiskers twitching with glee,
Shell completion flows wild and free,
Bash and Zsh now dance with delight,
Tab completion shines so bright!
Git branches bloom at command's call, 🌿✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and concisely summarizes the main change: adding shell autocompletion support for bash and zsh, which is the primary focus of all file modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
build/commands/completion.js (2)

62-82: Completions offered for extra positional arguments where commands accept only one.

For commands like merge, remove, and open (which take a single branch argument), if the user has already typed one branch and presses Tab again (e.g., wt merge branch1 <TAB>), the completion logic will still suggest more branches. Consider guarding with completed.length === 1 similar to how config is handled, to avoid suggesting spurious candidates.

♻️ Suggested fix
         // Worktree branch commands: merge, remove/rm, open
         if (WORKTREE_BRANCH_COMMANDS.has(command)) {
+            if (completed.length !== 1) return;
             const worktrees = await getWorktrees();

Apply the same guard for GIT_BRANCH_COMMANDS:

         // Git branch commands: new, setup, extract
         if (GIT_BRANCH_COMMANDS.has(command)) {
+            if (completed.length !== 1) return;
             const branches = await getBranches();

1-18: Verify that the SUBCOMMANDS list stays in sync with the actual CLI commands.

The SUBCOMMANDS constant is a manually maintained list. If commands are added/removed/renamed in src/index.ts, this list will silently go stale. Consider adding a comment noting this coupling, or extracting command names programmatically in a future iteration.

src/commands/completion.ts (2)

38-43: Use colored console output for the error message.

The error message for unsupported shells uses plain console.error without colored formatting. Other commands in this project use chalk for error messages.

Proposed fix
+import chalk from "chalk";
+
 ...
         default:
-            console.error(
-                `Unsupported shell: ${shell}. Supported shells: bash, zsh`
-            );
+            console.error(
+                chalk.red(`Unsupported shell: ${shell}. Supported shells: bash, zsh`)
+            );
             process.exit(1);

As per coding guidelines, src/commands/*.ts: "Provide clear, colored console feedback for success and error messages in CLI commands."


75-84: Consider whether locked/prunable worktrees should be excluded from completions.

Currently all non-main worktrees with a branch are suggested. A locked or prunable worktree might fail certain operations (e.g., remove). This is minor since the user will get a clear error from the actual command, but you could optionally filter out prunable/locked entries for remove/rm.

test/completion.test.ts (2)

1-1: Unused import: beforeEach.

beforeEach is imported but never used in this file.

Proposed fix
-import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { describe, it, expect, vi } from 'vitest';

50-63: Consider using vi.spyOn instead of monkey-patching console.log.

Vitest provides vi.spyOn(console, 'log') which is more idiomatic and eliminates the need for manual save/restore. The current approach works but is more fragile.

Suggested alternative
-async function captureCompletions(words: string[]): Promise<string[]> {
-    const lines: string[] = [];
-    const originalLog = console.log;
-    console.log = (...args: any[]) => {
-        const output = args.join(' ');
-        lines.push(...output.split('\n'));
-    };
-    try {
-        await getCompletions(words);
-    } finally {
-        console.log = originalLog;
-    }
-    return lines.filter(l => l !== '');
-}
+async function captureCompletions(words: string[]): Promise<string[]> {
+    const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
+    try {
+        await getCompletions(words);
+    } finally {
+        spy.mockRestore();
+    }
+    return spy.mock.calls
+        .map(args => args.join(' '))
+        .flatMap(line => line.split('\n'))
+        .filter(l => l !== '');
+}

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 and usage tips.

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.

1 participant