package plugins import ( "charm.land/bubbles/v2/key" tea "charm.land/bubbletea/v2" "github.com/anotherhadi/spilltea/internal/keys" "github.com/anotherhadi/spilltea/internal/util" ) func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Route non-key messages to textarea when editing so internal // textarea messages (e.g. clipboard paste) are handled correctly. if m.editing { if _, ok := msg.(tea.KeyPressMsg); !ok { var cmd tea.Cmd m.textarea, cmd = m.textarea.Update(msg) return m, cmd } } switch msg := msg.(type) { case tea.MouseWheelMsg: if !m.editing { util.HandleMouseWheel(msg, &m.detailViewport) } case tea.KeyPressMsg: pk := keys.Keys.Plugins g := keys.Keys.Global // Filtering mode: esc clears+closes, enter just closes, rest goes to filterInput. if m.filtering { switch { case key.Matches(msg, g.Escape): m.filtering = false m.filter = "" m.filterInput.SetValue("") m.filterInput.Blur() m.applyFilter() m.recalcSizes() case msg.String() == "enter": m.filtering = false m.filterInput.Blur() m.recalcSizes() default: var cmd tea.Cmd m.filterInput, cmd = m.filterInput.Update(msg) m.filter = m.filterInput.Value() m.applyFilter() return m, cmd } return m, nil } // Editing mode: only esc exits, everything else goes to textarea. if m.editing { if key.Matches(msg, g.Escape) { m.editing = false m.textarea.Blur() if info, ok := m.selected(); ok && m.manager != nil { val := m.textarea.Value() m.manager.SaveConfig(info.ID, val) // Update cached info. m.filtered[m.cursor].ConfigText = val for i := range m.items { if m.items[i].ID == info.ID { m.items[i].ConfigText = val break } } } return m, nil } var cmd tea.Cmd m.textarea, cmd = m.textarea.Update(msg) return m, cmd } switch { case key.Matches(msg, g.Escape): if m.filter != "" { m.filter = "" m.filterInput.SetValue("") m.applyFilter() } case key.Matches(msg, pk.Filter): m.filtering = true m.filterInput.Focus() m.recalcSizes() case key.Matches(msg, g.Up): if m.cursor > 0 { m.cursor-- m.recalcSizes() m.syncTextarea() m.detailViewport.GotoTop() } case key.Matches(msg, g.Down): if m.cursor < len(m.filtered)-1 { m.cursor++ m.recalcSizes() m.syncTextarea() m.detailViewport.GotoTop() } case key.Matches(msg, pk.Toggle): if info, ok := m.selected(); ok && m.manager != nil { m.manager.TogglePlugin(info.ID) m.filtered[m.cursor].Enabled = !info.Enabled for i := range m.items { if m.items[i].ID == info.ID { m.items[i].Enabled = !info.Enabled break } } m.refreshListViewport() } case key.Matches(msg, pk.EditConfig): if _, ok := m.selected(); ok && m.hasConfig() { m.editing = true m.textarea.Focus() } case key.Matches(msg, g.PrevPage): m.cursor = util.CursorMovePage(m.cursor, len(m.filtered), m.pager.PerPage, false) m.recalcSizes() m.syncTextarea() m.detailViewport.GotoTop() case key.Matches(msg, g.NextPage): m.cursor = util.CursorMovePage(m.cursor, len(m.filtered), m.pager.PerPage, true) m.recalcSizes() m.syncTextarea() m.detailViewport.GotoTop() case key.Matches(msg, g.ScrollUp): util.ScrollViewport(&m.detailViewport, -1) case key.Matches(msg, g.ScrollDown): util.ScrollViewport(&m.detailViewport, 1) case key.Matches(msg, g.Help): m.help.ShowAll = !m.help.ShowAll m.recalcSizes() } } return m, nil }