diff --git a/backlog/tasks/task-24 - Optimize-worktree-info-caching-in-wt-recent.md b/backlog/tasks/task-24 - Optimize-worktree-info-caching-in-wt-recent.md index 36eaeef..4513988 100644 --- a/backlog/tasks/task-24 - Optimize-worktree-info-caching-in-wt-recent.md +++ b/backlog/tasks/task-24 - Optimize-worktree-info-caching-in-wt-recent.md @@ -1,7 +1,8 @@ --- id: task-24 title: Optimize worktree info caching in wt recent -status: To Do +status: Won't Do +updated_date: '2025-07-11' assignee: [] created_date: '2025-07-11' labels: [] @@ -19,3 +20,19 @@ The updateWorktreeInfo function in wt recent could be expensive with many worktr - [ ] Only update worktree info when displaying branches with worktrees - [ ] Measure performance improvement with many worktrees - [ ] Ensure cache invalidation when worktrees change + +## Implementation Notes + +**Decision: Won't implement** + +Based on performance benchmarks from task-22, caching is not needed: + +- Branch filtering performance is excellent (< 0.2ms for 10,000 branches) +- The bottleneck is git operations (`git for-each-ref`, `git worktree list`), not our Go code +- Caching worktree info in memory wouldn't help since: + - We still need to call git commands each time + - The Go processing is already extremely fast + - Most users won't have hundreds of worktrees (typical usage is < 10) +- Adding caching would increase complexity without meaningful performance gains + +The real bottleneck is git command execution time, which caching cannot improve. diff --git a/backlog/tasks/task-25 - Improve-multi-line-format-alignment-in-wt-recent.md b/backlog/tasks/task-25 - Improve-multi-line-format-alignment-in-wt-recent.md new file mode 100644 index 0000000..32f2cc3 --- /dev/null +++ b/backlog/tasks/task-25 - Improve-multi-line-format-alignment-in-wt-recent.md @@ -0,0 +1,42 @@ +--- +id: task-25 +title: Improve multi-line format alignment in wt recent +status: Done +assignee: [] +created_date: '2025-07-11' +updated_date: '2025-07-11' +labels: + - high-priority + - formatting +dependencies: [] +--- + +## Description + +Fix alignment issues in the multi-line display format. The star should be directly attached to the branch name, and subsequent lines should align with the branch name, not the index. Add blank lines between entries for better readability. + +## Acceptance Criteria + +- [x] Star directly next to branch name (0: *branch) +- [x] Second/third lines align with branch name +- [x] Blank line between entries +- [x] No truncation in multi-line mode + +## Implementation Plan + +1. Modify displayBranches function to show star directly after colon +2. Ensure proper indentation for second and third lines +3. Add blank lines between all entries (except after last) +4. Update tests to match new format + +## Implementation Notes + +Successfully improved the multi-line format alignment: + +- Star is now directly attached to branch name: `0: *branch-name` +- Second and third lines are indented with 3 spaces to align with branch name +- Blank lines added between all entries for better readability +- No truncation in multi-line mode (full branch names shown) +- Tests updated to verify the new format + +The format is now much cleaner and easier to scan, especially with long branch names. diff --git a/backlog/tasks/task-26 - Add-configuration-management-commands-to-wt.md b/backlog/tasks/task-26 - Add-configuration-management-commands-to-wt.md new file mode 100644 index 0000000..3ab1966 --- /dev/null +++ b/backlog/tasks/task-26 - Add-configuration-management-commands-to-wt.md @@ -0,0 +1,26 @@ +--- +id: task-26 +title: Add configuration management commands to wt +status: To Do +assignee: [] +created_date: '2025-07-11' +updated_date: '2025-07-11' +labels: + - high-priority + - config +dependencies: [] +--- + +## Description + +Implement a set of commands to manage wt configuration without manually editing config files. This improves usability by providing quick access to configuration values and the ability to edit them from the command line. + +## Acceptance Criteria + +- [ ] wt config list - show all config values +- [ ] wt config get - get specific value +- [ ] wt config set - set value +- [ ] wt config edit - open in editor +- [ ] wt config path - show file path +- [ ] wt config dir - navigate to config dir +- [ ] Editor selection (wt.editor then then ) diff --git a/backlog/tasks/task-27 - Improve-compact-mode-wrapping-and-truncation-behavior.md b/backlog/tasks/task-27 - Improve-compact-mode-wrapping-and-truncation-behavior.md new file mode 100644 index 0000000..f2d0b93 --- /dev/null +++ b/backlog/tasks/task-27 - Improve-compact-mode-wrapping-and-truncation-behavior.md @@ -0,0 +1,23 @@ +--- +id: task-27 +title: Improve compact mode wrapping and truncation behavior +status: To Do +assignee: [] +created_date: '2025-07-11' +updated_date: '2025-07-11' +labels: + - low-priority + - formatting +dependencies: [] +--- + +## Description + +The current truncation in compact mode doesn't make sense when terminals already wrap text naturally. Improve the behavior to either wrap properly or make truncation configurable, especially for narrow terminal windows. + +## Acceptance Criteria + +- [ ] Remove or make truncation optional in compact mode +- [ ] Consider terminal width for smart wrapping +- [ ] Add --no-truncate flag for scripts +- [ ] Make truncation width configurable diff --git a/backlog/tasks/task-28 - Add-terminal-width-detection-for-smart-formatting.md b/backlog/tasks/task-28 - Add-terminal-width-detection-for-smart-formatting.md new file mode 100644 index 0000000..d12a49e --- /dev/null +++ b/backlog/tasks/task-28 - Add-terminal-width-detection-for-smart-formatting.md @@ -0,0 +1,23 @@ +--- +id: task-28 +title: Add terminal width detection for smart formatting +status: To Do +assignee: [] +created_date: '2025-07-11' +updated_date: '2025-07-11' +labels: + - low-priority + - enhancement +dependencies: [] +--- + +## Description + +Detect terminal width to make intelligent decisions about when to truncate or wrap text. This would improve the display on various terminal sizes without manual configuration. + +## Acceptance Criteria + +- [ ] Detect terminal width using appropriate system calls +- [ ] Use width to determine truncation behavior +- [ ] Graceful fallback when width cannot be detected +- [ ] Work correctly with terminal resizing diff --git a/backlog/tasks/task-29 - Implement-worktree-setup-automation.md b/backlog/tasks/task-29 - Implement-worktree-setup-automation.md new file mode 100644 index 0000000..1e756d2 --- /dev/null +++ b/backlog/tasks/task-29 - Implement-worktree-setup-automation.md @@ -0,0 +1,24 @@ +--- +id: task-29 +title: Implement worktree setup automation +status: To Do +assignee: [] +created_date: '2025-07-11' +updated_date: '2025-07-11' +labels: + - future + - automation +dependencies: [] +--- + +## Description + +Add the ability to define and run automatic setup steps when creating new worktrees. This could include running npm install, syncing env files, and other project-specific initialization tasks. + +## Acceptance Criteria + +- [ ] Define setup steps in project config +- [ ] Run setup automatically on wt new +- [ ] Support various command types +- [ ] Handle setup failures gracefully +- [ ] Optional manual trigger with wt setup diff --git a/backlog/tasks/task-30 - Add-port-management-for-parallel-worktree-development.md b/backlog/tasks/task-30 - Add-port-management-for-parallel-worktree-development.md new file mode 100644 index 0000000..f0f0758 --- /dev/null +++ b/backlog/tasks/task-30 - Add-port-management-for-parallel-worktree-development.md @@ -0,0 +1,24 @@ +--- +id: task-30 +title: Add port management for parallel worktree development +status: To Do +assignee: [] +created_date: '2025-07-11' +updated_date: '2025-07-11' +labels: + - future + - enhancement +dependencies: [] +--- + +## Description + +When working with multiple worktrees in parallel, port conflicts are common. Implement a system to track and allocate unique ports for each worktree to enable true parallel development. + +## Acceptance Criteria + +- [ ] Track ports in use per worktree +- [ ] Allocate unique ports on setup +- [ ] Configure services with allocated ports +- [ ] Show port allocation with wt ports +- [ ] Free ports when worktree removed diff --git a/cmd/wt/main.go b/cmd/wt/main.go index 4b2fd79..7f6fc78 100644 --- a/cmd/wt/main.go +++ b/cmd/wt/main.go @@ -76,8 +76,8 @@ wt() { elif [[ "$line" == "EXEC:"* ]]; then exec_cmd="${line#EXEC:}" else - # Print non-command lines - [ -n "$line" ] && echo "$line" + # Print non-command lines (including empty lines) + echo "$line" fi done <<< "$output" @@ -288,7 +288,11 @@ func handleRecentCommand(args []string) { } // Display branches - displayBranches(branches, flags.count) + if flags.compact { + displayBranchesCompact(branches, flags.count) + } else { + displayBranches(branches, flags.count) + } // Display summary of skipped branches if verbose mode is enabled displaySkippedBranchesIfVerbose(branchResult.skipped, flags.verbose) @@ -1138,7 +1142,8 @@ Smart commands (with fuzzy branch matching): list, ls List all worktrees recent Show YOUR recently active branches (default: your branches only) Navigate directly: 'wt recent 2' → go to your 3rd recent branch - Options: --all, --others, -n + Default: multi-line format for better readability + Options: --all, --others, -n , --compact, --verbose new Smart worktree creation - handles all branch states: • Branch doesn't exist → Create branch + worktree + switch • Branch exists, no worktree → Create worktree + switch @@ -1351,6 +1356,7 @@ type recentFlags struct { count int navigateIndex int verbose bool + compact bool } // parseRecentFlags parses command line flags for the recent command @@ -1373,6 +1379,9 @@ func parseRecentFlags(args []string) recentFlags { case arg == "--verbose" || arg == "-v": flags.verbose = true i++ + case arg == "--compact" || arg == "-c": + flags.compact = true + i++ case arg == "-n" && i+1 < len(args): flags.count = parseAndValidateCount(args[i+1]) i += 2 @@ -1603,7 +1612,7 @@ func navigateToBranch(branches []branchCommitInfo, index int, gitClient git.Clie } } -// displayBranches shows the list of branches with formatting +// displayBranches shows the list of branches in multi-line format (default) func displayBranches(branches []branchCommitInfo, count int) { displayCount := len(branches) if displayCount > count { @@ -1614,6 +1623,40 @@ func displayBranches(branches []branchCommitInfo, count int) { return } + for i := 0; i < displayCount; i++ { + branch := branches[i] + + // First line: index with proper spacing, then branch name with star + if branch.hasWorktree { + fmt.Printf("%d: *%s\n", i, branch.branch) + } else { + fmt.Printf("%d: %s\n", i, branch.branch) + } + + // Second line: commit subject (indented to align with branch name) + fmt.Printf(" %s\n", branch.subject) + + // Third line: author and date (indented to align with branch name) + fmt.Printf(" %s, %s\n", branch.author, branch.relativeDate) + + // Add blank line between entries (but not after the last one) + if i < displayCount-1 { + fmt.Println() + } + } +} + +// displayBranchesCompact shows the list of branches in compact single-line format +func displayBranchesCompact(branches []branchCommitInfo, count int) { + displayCount := len(branches) + if displayCount > count { + displayCount = count + } + + if displayCount == 0 { + return + } + // Calculate dynamic column widths based on actual content maxBranchLen := 15 // minimum width maxDateLen := 10 // minimum width diff --git a/cmd/wt/recent_test.go b/cmd/wt/recent_test.go index b10d0a6..e0d93c7 100644 --- a/cmd/wt/recent_test.go +++ b/cmd/wt/recent_test.go @@ -70,6 +70,7 @@ func TestParseRecentFlags(t *testing.T) { wantCount int wantNavigate int wantVerbose bool + wantCompact bool wantError bool }{ { @@ -164,6 +165,28 @@ func TestParseRecentFlags(t *testing.T) { wantCount: 15, wantNavigate: -1, }, + { + name: "compact flag long form", + args: []string{"--compact"}, + wantCompact: true, + wantCount: 10, + wantNavigate: -1, + }, + { + name: "compact flag short form", + args: []string{"-c"}, + wantCompact: true, + wantCount: 10, + wantNavigate: -1, + }, + { + name: "compact with other flags", + args: []string{"--all", "-c", "-n", "5"}, + wantAll: true, + wantCompact: true, + wantCount: 5, + wantNavigate: -1, + }, } for _, tt := range tests { @@ -196,6 +219,10 @@ func TestParseRecentFlags(t *testing.T) { if flags.verbose != tt.wantVerbose { t.Errorf("verbose flag: got %v, want %v", flags.verbose, tt.wantVerbose) } + + if flags.compact != tt.wantCompact { + t.Errorf("compact flag: got %v, want %v", flags.compact, tt.wantCompact) + } }) } } @@ -773,8 +800,98 @@ func TestTruncateWithEllipsis(t *testing.T) { } } -// TestDisplayBranchesFormatting tests the dynamic width calculation -func TestDisplayBranchesFormatting(t *testing.T) { +// TestDisplayBranchesMultiline tests the multi-line display format +func TestDisplayBranchesMultiline(t *testing.T) { + t.Run("multi-line format", func(t *testing.T) { + branches := []branchCommitInfo{ + { + branch: "feature/very-long-branch-name-with-issue-123", + commitHash: "abc123", + relativeDate: "2 hours ago", + subject: "Implement the new feature for handling long branch names", + author: "Tobias Engelhardt", + timestamp: time.Now().Add(-2 * time.Hour), + hasWorktree: true, + }, + { + branch: "fix/issue-456", + commitHash: "def456", + relativeDate: "1 day ago", + subject: "Fix critical bug in authentication", + author: "Jane Smith", + timestamp: time.Now().Add(-24 * time.Hour), + hasWorktree: false, + }, + } + + // Capture output + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + displayBranches(branches, 10) + + w.Close() + output, _ := io.ReadAll(r) + os.Stdout = oldStdout + + outputStr := string(output) + lines := strings.Split(strings.TrimSpace(outputStr), "\n") + + // Check that we have correct number of lines + // 2 branches * 3 lines each + 1 blank line between = 7 lines + if len(lines) != 7 { + t.Errorf("Expected 7 lines of output, got %d", len(lines)) + t.Logf("Output:\n%s", outputStr) + } + + // Check first branch format + if !strings.HasPrefix(lines[0], "0: *feature/very-long-branch-name-with-issue-123") { + t.Errorf("First line doesn't match expected format: %s", lines[0]) + } + + // Check indentation on second and third lines + if !strings.HasPrefix(lines[1], " ") { + t.Error("Second line should be indented") + } + if !strings.HasPrefix(lines[2], " ") { + t.Error("Third line should be indented") + } + + // Check that there's a blank line after first entry + if lines[3] != "" { + t.Error("Expected blank line after first entry") + } + + // Check second branch doesn't have star (no worktree) + if !strings.HasPrefix(lines[4], "1: fix/issue-456") { + t.Errorf("Fifth line doesn't match expected format: %s", lines[4]) + } + }) + + t.Run("empty branch list", func(t *testing.T) { + var branches []branchCommitInfo + + // Capture output + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + displayBranches(branches, 10) + + w.Close() + output, _ := io.ReadAll(r) + os.Stdout = oldStdout + + // Should produce no output + if len(output) != 0 { + t.Errorf("Expected no output for empty branch list, got: %s", string(output)) + } + }) +} + +// TestDisplayBranchesCompactFormatting tests the compact format +func TestDisplayBranchesCompactFormatting(t *testing.T) { t.Run("branches with varying lengths", func(t *testing.T) { branches := []branchCommitInfo{ { @@ -811,7 +928,7 @@ func TestDisplayBranchesFormatting(t *testing.T) { r, w, _ := os.Pipe() os.Stdout = w - displayBranches(branches, 10) + displayBranchesCompact(branches, 10) w.Close() output, _ := io.ReadAll(r) @@ -846,7 +963,7 @@ func TestDisplayBranchesFormatting(t *testing.T) { r, w, _ := os.Pipe() os.Stdout = w - displayBranches(branches, 10) + displayBranchesCompact(branches, 10) w.Close() output, _ := io.ReadAll(r) diff --git a/internal/help/help.go b/internal/help/help.go index 9f6f855..b25f661 100644 --- a/internal/help/help.go +++ b/internal/help/help.go @@ -375,7 +375,7 @@ var commandHelpMap = map[string]CommandHelp{ "recent": { Name: "recent", Usage: "wt recent [index] [options]", - Description: "Show and navigate to your recently active branches (default: only your branches)", + Description: "Show and navigate to your recently active branches (default: only your branches, multi-line format)", Examples: []string{ "wt recent # List your 10 most recent branches", "wt recent -n 20 # List your 20 most recent branches", @@ -406,6 +406,12 @@ var commandHelpMap = map[string]CommandHelp{ Description: "Show detailed information about skipped branches", Example: "wt recent --verbose", }, + { + Flag: "--compact", + ShortFlag: "-c", + Description: "Use compact single-line format instead of multi-line", + Example: "wt recent --compact", + }, }, SeeAlso: []string{"wt list", "wt go", "wt new"}, },