@@ -45,7 +45,8 @@ type REPL struct {
4545 completeState int
4646 completeOptions []string
4747 completePrefix string
48- completeIdx int // Current index in completion options
48+ completeIdx int // Current index in completion options
49+ lastTabInput string // last input text when Tab was pressed
4950 streamingEnabled bool
5051 systemPrompt string
5152 messages []Message
@@ -571,29 +572,19 @@ func (r *REPL) readLine() (string, error) {
571572}
572573
573574func (r * REPL ) handleTabCompletion (line * strings.Builder ) {
574- input := line .String ()
575-
576- // Only reset completion state if necessary
577- // This makes backspace handling simpler - if the user has modified
578- // the input so it's no longer related to our completion,
579- // we reset the completion state
580- if r .completeState != 0 {
581- // Reset if input has been modified to be unrelated to current completion
582- // but preserve state for proper cycling
583- if input != r .completePrefix {
584- var currentOption string
585- if r .completeIdx < len (r .completeOptions ) {
586- currentOption = r .completeOptions [r .completeIdx ]
587- }
588- // Check if input matches the option itself (for commands) or prefix+option (for @ path)
589- if r .completeIdx >= len (r .completeOptions ) ||
590- (input != currentOption && input != r .completePrefix + currentOption ) {
591- r .completeState = 0
592- r .completeIdx = 0
593- r .completeOptions = nil
594- r .completePrefix = ""
595- }
596- }
575+ // Capture original input and ensure lastTabInput is updated after completion
576+ origInput := line .String ()
577+ defer func () {
578+ r .lastTabInput = line .String ()
579+ }()
580+ input := origInput
581+
582+ // Fresh vs cycling: reset if first tab or input changed since last tab press
583+ if r .completeState == 0 || origInput != r .lastTabInput {
584+ r .completeState = 0
585+ r .completeIdx = 0
586+ r .completeOptions = nil
587+ r .completePrefix = ""
597588 }
598589
599590 // Check if input contains @ for file path completion
0 commit comments