search: dedup detail renderers behind a shared detailWriter · Entire

Search: Dedup Detail Renderers Behind a Shared DetailWriter

aadf0b9 → main ·

alishakawaguchi · 1mo ago · 1 file · +136 added/-197 removed

The three per-type detail renderers (checkpoint/commit/session) each redefined identical label/field/wrapped-field/section helpers plus the Match-with-score and author-with-username blocks. Extract a detailWriter type that owns the shared layout so each renderer reads as a field list. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

5c1f6e660501 View transcript

Changes

  1. cmd/entire/cli
    • Msearch_tui.go +136/-197
// detailWriter accumulates a label/value detail body. It owns the shared
// layout (label column width, value wrap width, section spacing) so the
// per-type renderers below differ only in which fields they emit.
type detailWriter struct {
    b            strings.Builder
    styles       searchStyles
    labelWidth   int
    valueWidth   int
    showSections bool
}

func (m searchModel) newDetailWriter(title string, contentWidth int, showSections bool) *detailWriter {
    const labelWidth = 12
    valueWidth := contentWidth - labelWidth - 1
    if valueWidth < 20 {
        valueWidth = 0
    }
    w := &detailWriter{
        styles:       m.styles,
        labelWidth:   labelWidth,
        valueWidth:   valueWidth,
        showSections: showSections,
    }
    w.b.WriteString(w.styles.render(w.styles.detailTitle, title) + "\n")
    return w
}

func (w *detailWriter) label(label string) string {
    return w.styles.render(w.styles.label, fmt.Sprintf("%-*s", w.labelWidth, label+":"))
}

func (w *detailWriter) field(label, value string) {
    w.b.WriteString(w.label(label) + " " + value + "\n")
}

func (w *detailWriter) wrappedField(label, value string) {
    if w.valueWidth == 0 || len(value) <= w.valueWidth {
        w.field(label, value)
        return
    }
    indent := strings.Repeat(" ", w.labelWidth+1)
    lines := strings.Split(wrapText(value, w.valueWidth), "\n")
    w.b.WriteString(w.label(label) + " " + lines[0] + "\n")
    for _, line := range lines[1:] {
        w.b.WriteString(indent + line + "\n")
    }
}

func (w *detailWriter) section(title string) {
    if w.showSections {
        w.b.WriteString("\n" + w.styles.render(w.styles.detailTitle, title) + "\n")
    } else {
        w.b.WriteString("\n")
    }
}

func (w *detailWriter) matchField(meta search.Meta) {
    value := meta.MatchType
    if meta.Score > 0 {
        value += " " + w.styles.render(w.styles.dim, fmt.Sprintf("(score: %.3f)", meta.Score))
    }
    w.field("Match", value)
}

func (w *detailWriter) authorField(author string, username *string) {
    value := author
    if username != nil && *username != "" {
        value = *username + " " + w.styles.render(w.styles.dim, "("+author+")")
    }
    w.field("Author", value)
}

func (w *detailWriter) String() string {
    return strings.TrimRight(w.b.String(), "\n")
}