okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
0b9f48f
main
1package tui 2 3import ( 4"fmt" 5"strconv" 6"strings" 7 8"github.com/charmbracelet/x/ansi" 9) 10 11// chipRows is the height of the strip of cards above the composer: the 12// thumbnail area and a border above and below it. 13const chipRows = thumbRows + 2 14 15// chip is one card of the strip: a title naming its marker, up to thumbRows 16// lines of content, and a caption. 17type chip struct { 18title ,caption string 19content []string 20} 21 22// chips are the attachments the composer still marks, in reading order. 23func (m ChatModel )chips () []chip { 24var chips []chip 25seen := make (map [string ]bool ) 26for _ ,match := range anyMarker .FindAllString (m .TextArea .Value (),- 1 ) { 27if seen [match ] { 28continue 29 } 30seen [match ]= true 31if found := imageMarker .FindStringSubmatch (match );found != nil { 32n ,_ := strconv .Atoi (found [1 ]) 33if image ,ok := m .Images .byNumber [n ];ok { 34chips = append (chips ,m .imageChip (n ,image )) 35 } 36 }else if found := pasteMarker .FindStringSubmatch (match );found != nil { 37n ,_ := strconv .Atoi (found [1 ]) 38if text ,ok := m .Pastes .byNumber [n ];ok { 39chips = append (chips ,m .pasteChip (n ,text )) 40 } 41 } 42 } 43return chips 44} 45 46func (m ChatModel )imageChip (n int ,image pastedImage )chip { 47content := []string {"" ,DefaultStyles .Faint .Render ("image" )} 48if image .thumb != nil { 49content = placeholderRows (* image .thumb ) 50 } 51return chip { 52title :"image #" + strconv .Itoa (n ), 53caption :fmt .Sprintf ("%d×%d" ,image .Width ,image .Height ), 54content :content , 55 } 56} 57 58func (m ChatModel )pasteChip (n int ,text string )chip { 59lines := strings .Split (text ,"\n" ) 60caption := "+" + strconv .Itoa (len (lines ))+ " lines" 61if len (lines )<= collapseLines { 62caption = strconv .Itoa (len ([]rune (text )))+ " chars" 63 } 64content := make ([]string ,0 ,thumbRows ) 65for _ ,line := range lines [:min (len (lines ),thumbRows )] { 66line = ansi .Truncate (strings .ReplaceAll (line ,"\t" ," " ),thumbCols ,"" ) 67// padded to the full width, so the card keeps the lines left-aligned 68content = append (content ,DefaultStyles .Faint .Render (line + strings .Repeat (" " ,thumbCols - ansi .StringWidth (line )))) 69 } 70return chip {title :"paste #" + strconv .Itoa (n ),caption :caption ,content :content } 71} 72 73// chipStrip lays the chips out side by side within width, chipRows rows 74// high, or returns nil when there are none. Cards that do not fit are 75// counted at the end instead. 76func (m ChatModel )chipStrip (width int ) []string { 77chips := m .chips () 78if len (chips )== 0 { 79return nil 80 } 81const cardWidth = thumbCols + 2 82shown := min (len (chips ), (width + 1 )/ (cardWidth + 1 )) 83if shown < len (chips )&& shown * (cardWidth + 1 )+ len ("+99" )> width { 84shown -- // room for the count of the rest 85 } 86rows := make ([]string ,chipRows ) 87for i ,c := range chips [:max (0 ,shown )] { 88for r ,line := range m .card (c ) { 89rows [r ]+= strings .Repeat (" " ,min (i ,1 ))+ line 90 } 91 } 92if hidden := len (chips )- max (0 ,shown );hidden > 0 { 93rows [chipRows / 2 ]+= DefaultStyles .Faint .Render (" +" + strconv .Itoa (hidden )) 94 } 95return rows 96} 97 98// card draws c in a rounded border thumbCols+2 cells wide, its content 99// centred, its title on the top edge and its caption on the bottom one. 100func (m ChatModel )card (c chip ) []string { 101edge := func (left ,label ,right string )string { 102label = ansi .Truncate (label ,thumbCols - 2 ,"…" ) 103fill := thumbCols - ansi .StringWidth (label )- 2 104return DefaultStyles .Decor .Render (left + strings .Repeat ("─" ,fill - fill / 2 )+ " " )+ 105DefaultStyles .Muted .Render (label )+ 106DefaultStyles .Decor .Render (" " + strings .Repeat ("─" ,fill / 2 )+ right ) 107 } 108side := DefaultStyles .Decor .Render ("│" ) 109rows := []string {edge ("╭" ,c .title ,"╮" )} 110top := (thumbRows - len (c .content ))/ 2 111for r := range thumbRows { 112line := "" 113if r >= top && r - top < len (c .content ) { 114line = c .content [r - top ] 115 } 116pad := thumbCols - ansi .StringWidth (line ) 117rows = append (rows ,side + strings .Repeat (" " ,pad / 2 )+ line + strings .Repeat (" " ,pad - pad / 2 )+ side ) 118 } 119return append (rows ,edge ("╰" ,c .caption ,"╯" )) 120}