github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/hud/edits.go (about) 1 package hud 2 3 import ( 4 "fmt" 5 "path" 6 7 "github.com/tilt-dev/tilt/internal/rty" 8 "github.com/tilt-dev/tilt/pkg/model" 9 ) 10 11 type EditStatusLineComponent struct { 12 bs buildStatus 13 } 14 15 var _ rty.Component = &EditStatusLineComponent{} 16 17 func NewEditStatusLine(buildStatus buildStatus) rty.Component { 18 return &EditStatusLineComponent{ 19 bs: buildStatus, 20 } 21 } 22 23 func (esl *EditStatusLineComponent) Size(availWidth, availHeight int) (int, int, error) { 24 return availWidth, 1, nil 25 } 26 27 func (esl *EditStatusLineComponent) makeEditsComponents(width int) (rty.Component, rty.Component) { 28 var filenames, filenamesEtAl rty.Component 29 30 // fit as many filenames as possible into `width` 31 if len(esl.bs.edits) > 0 { 32 // technically this might be a multi-digit number and could lose digits as we make more filenames explicit, 33 // but close enough 34 spaceForFilenames := width - len(fmt.Sprintf(" (+%d more)", len(esl.bs.edits))) 35 36 edits := esl.bs.edits 37 s := "" 38 for len(edits) > 0 { 39 next := path.Base(edits[0]) 40 if s != "" { 41 next = " " + next 42 } 43 if len(next) <= spaceForFilenames { 44 spaceForFilenames -= len(next) 45 s += next 46 edits = edits[1:] 47 } else { 48 break 49 } 50 } 51 52 filenames = rty.TextString(s) 53 54 if len(edits) > 0 { 55 if len(s) == 0 { 56 filenamesEtAl = rty.TextString(fmt.Sprintf("%d files", len(edits))) 57 } else { 58 filenamesEtAl = rty.TextString(fmt.Sprintf(" (+%d more)", len(edits))) 59 } 60 } 61 } 62 return filenames, filenamesEtAl 63 } 64 65 func (esl *EditStatusLineComponent) buildStatusText() rty.Component { 66 return buildStatusCell(esl.bs) 67 } 68 69 func (esl *EditStatusLineComponent) buildAgeText() rty.Component { 70 return deployTimeCell(esl.bs.deployTime, esl.bs.defaultTextColor()) 71 } 72 73 func (esl *EditStatusLineComponent) rightPane() rty.Component { 74 l := rty.NewConcatLayout(rty.DirHor) 75 l.Add(esl.buildStatusText()) 76 l.Add(middotText()) 77 l.Add(esl.buildAgeText()) 78 return l 79 } 80 81 func (esl *EditStatusLineComponent) Render(w rty.Writer, width, height int) error { 82 offset := 0 83 allocated := 0 84 sb := rty.NewStringBuilder() 85 bs := esl.bs 86 87 if len(bs.edits) == 0 { 88 if bs.reason.Has(model.BuildReasonFlagInit) { 89 sb.Fg(cLightText).Text("FIRST BUILD ") 90 } 91 } else { 92 sb.Fg(cLightText).Text("EDITED FILES ") 93 } 94 95 lhs := sb.Build() 96 97 lhsW, _, err := lhs.Size(width, 1) 98 if err != nil { 99 return err 100 } 101 allocated += lhsW 102 103 rhs := esl.rightPane() 104 rhsW, _, err := rhs.Size(width, 1) 105 if err != nil { 106 return err 107 } 108 allocated += rhsW 109 110 filenames, filenamesEtAl := esl.makeEditsComponents(width - allocated) 111 var filenamesW, filenamesEtAlW int 112 if filenamesEtAl != nil { 113 filenamesEtAlW, _, err = filenamesEtAl.Size(width, 1) 114 if err != nil { 115 return err 116 } 117 allocated += filenamesEtAlW 118 } 119 120 if filenames != nil && allocated < width { 121 filenamesW, _, err = filenames.Size(width-allocated, 1) 122 if err != nil { 123 return err 124 } 125 } 126 127 { 128 w, err := w.Divide(0, 0, width, 1) 129 if err != nil { 130 return err 131 } 132 w.RenderChild(lhs) 133 offset += lhsW 134 } 135 136 if filenames != nil && filenamesW > 0 { 137 w, err := w.Divide(offset, 0, filenamesW, 1) 138 if err != nil { 139 return err 140 } 141 w.RenderChild(filenames) 142 offset += filenamesW 143 } 144 145 if filenamesEtAl != nil { 146 w, err := w.Divide(offset, 0, filenamesEtAlW, 1) 147 if err != nil { 148 return err 149 } 150 w.RenderChild(filenamesEtAl) 151 } 152 153 { 154 w, err := w.Divide(width-rhsW, 0, rhsW, 1) 155 if err != nil { 156 return err 157 } 158 w.RenderChild(rhs) 159 } 160 161 return nil 162 }