package tui import ( "strings" "albedo/cli/internal/daemon" "charm.land/bubbles/v2/textinput" tea "charm.land/bubbletea/v2" ) // SessionRenameMsg asks the app to save a session's name. A blank name hands // the title back to the daemon, which takes it from the latest message. type SessionRenameMsg struct{ ID, Name, ETag string } // sessionRenamedMsg is the daemon's answer to a SessionRenameMsg: the // session as it is now listed. type sessionRenamedMsg struct { Err error Session daemon.Session SessionRenameMsg } // renameField edits one session's name in place. While it is open its owner // hands it every key, so typing never reaches search or navigation. type renameField struct { id, was, etag string input textinput.Model // selected holds until the first key: typing replaces the opening // draft, which a message title can fill to the limit; other keys edit it. selected bool } // renameLimit matches the daemon, which keeps 80 characters of a name. const renameLimit = 80 // open starts a draft of current, prompting with placeholder once emptied. func (f *renameField) open(id, current, placeholder string) { in := newField() in.CharLimit = renameLimit in.Placeholder = placeholder st := in.Styles() st.Focused.Text = DefaultStyles.Bold st.Focused.Placeholder = DefaultStyles.Faint in.SetStyles(st) in.SetValue(current) in.CursorEnd() in.Focus() f.id, f.was, f.input, f.selected = id, current, in, current != "" } func (f renameField) active() bool { return f.id != "" } // key edits the draft. Enter saves a changed name and esc drops it; both // close the field. func (f *renameField) key(msg tea.KeyPressMsg) tea.Cmd { switch msg.String() { case "esc", "ctrl+c": f.id = "" return nil case "enter": id, name := f.id, strings.TrimSpace(f.input.Value()) f.id = "" if name == strings.TrimSpace(f.was) { return nil } return func() tea.Msg { return SessionRenameMsg{ID: id, Name: name, ETag: f.etag} } } if f.selected && msg.Text != "" { f.input.SetValue("") } f.selected = false var cmd tea.Cmd f.input, cmd = f.input.Update(msg) return cmd } // view is the draft in exactly width cells. func (f renameField) view(width int) string { f.input.SetWidth(max(1, width-1)) if f.selected { st := f.input.Styles() st.Focused.Text = DefaultStyles.Cursor f.input.SetStyles(st) } return svFit(f.input.View(), width) } // renameHints stand in for a screen's key hints while a name is being edited. func renameHints(blank string) string { return keyHints(hint{"enter", "save"}, hint{"esc", "cancel"}, hint{"", "empty " + blank}) }