renderEntry renders a single PRD entry line.
(entry PRDEntry, selected bool, width int)
| 530 | |
| 531 | // renderEntry renders a single PRD entry line. |
| 532 | func (p *PRDPicker) renderEntry(entry PRDEntry, selected bool, width int) string { |
| 533 | var line strings.Builder |
| 534 | |
| 535 | // Current indicator |
| 536 | if entry.Name == p.currentPRD { |
| 537 | line.WriteString(lipgloss.NewStyle().Foreground(SuccessColor).Render("● ")) |
| 538 | } else { |
| 539 | line.WriteString(" ") |
| 540 | } |
| 541 | |
| 542 | // Name |
| 543 | nameStyle := lipgloss.NewStyle().Foreground(TextColor) |
| 544 | if selected { |
| 545 | nameStyle = nameStyle.Bold(true).Foreground(TextBrightColor) |
| 546 | } |
| 547 | name := entry.Name |
| 548 | maxNameLen := 12 |
| 549 | if len(name) > maxNameLen { |
| 550 | name = name[:maxNameLen-2] + ".." |
| 551 | } |
| 552 | line.WriteString(nameStyle.Render(fmt.Sprintf("%-12s", name))) |
| 553 | line.WriteString(" ") |
| 554 | |
| 555 | if entry.Orphaned && entry.LoadError != nil { |
| 556 | // Orphaned worktree with no PRD - show orphaned indicator |
| 557 | orphanedStyle := lipgloss.NewStyle().Foreground(WarningColor) |
| 558 | line.WriteString(orphanedStyle.Render("[orphaned worktree]")) |
| 559 | // Show worktree path if space allows |
| 560 | remaining := width - 32 - 18 // account for indicator + name + orphaned label |
| 561 | if remaining > 10 && entry.WorktreeDir != "" { |
| 562 | pathStyle := lipgloss.NewStyle().Foreground(MutedColor) |
| 563 | displayPath := p.worktreeDisplayPath(entry) |
| 564 | line.WriteString(pathStyle.Render(" " + displayPath)) |
| 565 | } |
| 566 | } else if entry.LoadError != nil { |
| 567 | // Show error indicator |
| 568 | errorStyle := lipgloss.NewStyle().Foreground(ErrorColor) |
| 569 | line.WriteString(errorStyle.Render("[error]")) |
| 570 | } else { |
| 571 | // Progress bar |
| 572 | progressWidth := 8 |
| 573 | percentage := float64(0) |
| 574 | if entry.Total > 0 { |
| 575 | percentage = float64(entry.Completed) / float64(entry.Total) * 100 |
| 576 | } |
| 577 | filledWidth := int(float64(progressWidth) * percentage / 100) |
| 578 | emptyWidth := progressWidth - filledWidth |
| 579 | |
| 580 | progressBar := progressBarFillStyle.Render(strings.Repeat("█", filledWidth)) + |
| 581 | progressBarEmptyStyle.Render(strings.Repeat("░", emptyWidth)) |
| 582 | line.WriteString(progressBar) |
| 583 | line.WriteString(" ") |
| 584 | |
| 585 | // Count |
| 586 | countStyle := lipgloss.NewStyle().Foreground(MutedColor) |
| 587 | line.WriteString(countStyle.Render(fmt.Sprintf("%d/%d", entry.Completed, entry.Total))) |
| 588 | |
| 589 | // Loop state indicator |