@@ -22,46 +22,32 @@ type SendMsg struct {
2222 Content string
2323}
2424
25- // historyNavigation describes which direction we want to pull from history.
26- type historyNavigation int
27-
28- const (
29- NAVIGATEPREVIOUS historyNavigation = iota
30- NAVIGATENEXT
31- )
32-
3325// Editor represents an input editor component
3426type Editor interface {
3527 layout.Model
3628 layout.Sizeable
3729 layout.Focusable
3830 layout.Help
39- SetHistory (hist * history.History )
4031 SetWorking (working bool ) tea.Cmd
4132}
4233
4334// editor implements [Editor]
4435type editor struct {
4536 textarea * textarea.Model
37+ hist * history.History
4638 width int
4739 height int
4840 working bool
41+ // completions are the available completions
42+ completions []completions.Completion
4943
50- // history is the shared command store backing up/down navigation.
51- hist * history.History
52- // draftInput holds the user's unsent text while they browse history.
53- draftInput string
54- // historyBrowsing marks that we're currently showing history entries.
55- historyBrowsing bool
5644 // completionWord stores the word being completed
57- completionWord string
58- // completions are the available completions
59- completions []completions.Completion
45+ completionWord string
6046 currentCompletion completions.Completion
6147}
6248
6349// New creates a new editor component
64- func New (a * app.App ) Editor {
50+ func New (a * app.App , hist * history. History ) Editor {
6551 ta := textarea .New ()
6652 ta .SetStyles (styles .InputStyle )
6753 ta .Placeholder = "Type your message here..."
@@ -75,6 +61,7 @@ func New(a *app.App) Editor {
7561
7662 return & editor {
7763 textarea : ta ,
64+ hist : hist ,
7865 completions : completions .Completions (a ),
7966 }
8067}
@@ -123,24 +110,20 @@ func (e *editor) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
123110 }
124111 value := e .textarea .Value ()
125112 if value != "" && ! e .working {
126- // Treat enter as send: clear input and exit history browse state.
127113 e .textarea .Reset ()
128- e .endHistoryBrowse ()
129114 return e , core .CmdHandler (SendMsg {Content : value })
130115 }
131116 return e , nil
132117 case "ctrl+c" :
133118 return e , tea .Quit
134119 case "up" :
135- // Consume the key when we replace the buffer with an older command.
136- if e .navigateHistory (NAVIGATEPREVIOUS ) {
137- return e , nil
138- }
120+ e .textarea .SetValue (e .hist .Previous ())
121+ e .textarea .MoveToEnd ()
122+ return e , nil
139123 case "down" :
140- // Consume the key when we replace the buffer with a newer command.
141- if e .navigateHistory (NAVIGATENEXT ) {
142- return e , nil
143- }
124+ e .textarea .SetValue (e .hist .Next ())
125+ e .textarea .MoveToEnd ()
126+ return e , nil
144127 default :
145128 for _ , completion := range e .completions {
146129 if msg .String () == completion .Trigger () {
@@ -150,11 +133,6 @@ func (e *editor) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
150133 cmds = append (cmds , e .startCompletion (completion ))
151134 }
152135 }
153-
154- // Any other key exits history browsing so input becomes fresh text.
155- if e .historyBrowsing {
156- e .endHistoryBrowse ()
157- }
158136 }
159137 }
160138
@@ -244,88 +222,3 @@ func (e *editor) SetWorking(working bool) tea.Cmd {
244222 e .working = working
245223 return nil
246224}
247-
248- func (e * editor ) SetHistory (hist * history.History ) {
249- e .hist = hist
250- }
251-
252- func (e * editor ) navigateHistory (direction historyNavigation ) bool {
253- // Returning true tells Update to stop Bubble Tea's default cursor handling,
254- // because we've already replaced the textarea content for this key press.
255- if ! e .canBrowseHistory () {
256- return false
257- }
258-
259- if ! e .historyBrowsing {
260- e .beginHistoryBrowse ()
261- }
262-
263- var entry string
264- switch direction {
265- case NAVIGATEPREVIOUS :
266- // Up arrow walks toward older commands.
267- entry = e .hist .Previous ()
268- case NAVIGATENEXT :
269- // Down arrow walks toward newer commands.
270- entry = e .hist .Next ()
271- if entry == "" {
272- // Restore the draft when we step past the newest entry.
273- e .restoreDraftFromHistory ()
274- return true
275- }
276- default :
277- return false
278- }
279-
280- if entry == "" {
281- return true
282- }
283-
284- // Replace the input with the selected history entry.
285- e .textarea .SetValue (entry )
286- // Place the cursor at the end so the user can immediately append or send.
287- e .textarea .MoveToEnd ()
288- return true
289- }
290-
291- func (e * editor ) canBrowseHistory () bool {
292- // We only take over arrow keys when there's at least one history entry and
293- // the textarea is a single line (multi-line inputs retain normal movement).
294- return e .hist != nil && e .textarea .Value () == ""
295- }
296-
297- func (e * editor ) beginHistoryBrowse () {
298- if e .hist == nil {
299- return
300- }
301- // Capture the in-progress text so we can restore it after browsing.
302- e .draftInput = e .textarea .Value ()
303- e .historyBrowsing = true
304- // Start from the newest entry so the first "up" pulls the latest command.
305- e .moveHistoryCursorToLatest ()
306- }
307-
308- func (e * editor ) restoreDraftFromHistory () {
309- e .textarea .SetValue (e .draftInput )
310- e .textarea .MoveToEnd ()
311- e .endHistoryBrowse ()
312- }
313-
314- func (e * editor ) endHistoryBrowse () {
315- e .historyBrowsing = false
316- e .draftInput = ""
317- if e .hist == nil {
318- return
319- }
320- e .moveHistoryCursorToLatest ()
321- }
322-
323- func (e * editor ) moveHistoryCursorToLatest () {
324- if e .hist == nil {
325- return
326- }
327- // Advance until Next returns empty, which positions the cursor just after
328- // the most recent saved command.
329- for e .hist .Next () != "" {
330- }
331- }
0 commit comments