fix(interactive): correct Esc behavior and direct-exec for optional flags

This commit is contained in:
刘焱 2026-06-08 18:59:00 +08:00
parent 65a4e60d6d
commit 2596d1dc70
2 changed files with 30 additions and 11 deletions

View File

@ -176,14 +176,29 @@ func (m *paletteModel) filterItems(query string) {
m.list.ResetSelected()
}
// matchesQuery checks if title or description contains the query (case-insensitive).
// matchesQuery checks if the query is a subsequence (fzy-style fuzzy match)
// of either the title or the description, case-insensitively. An empty query
// matches everything.
func matchesQuery(title, description, query string) bool {
return subsequenceMatch(query, title) || subsequenceMatch(query, description)
}
// subsequenceMatch returns true if every character of query appears in target
// in the same order (not necessarily contiguously), ignoring case. An empty
// query always matches.
func subsequenceMatch(query, target string) bool {
query = strings.ToLower(query)
target = strings.ToLower(target)
if query == "" {
return true
}
q := strings.ToLower(query)
return strings.Contains(strings.ToLower(title), q) ||
strings.Contains(strings.ToLower(description), q)
i := 0
for j := 0; j < len(target) && i < len(query); j++ {
if target[j] == query[i] {
i++
}
}
return i == len(query)
}
// Update handles messages for the palette.
@ -196,8 +211,9 @@ func (m paletteModel) Update(msg tea.Msg) (paletteModel, tea.Cmd) {
m.backToGroups()
return m, nil
}
// levelGroup: signal the outer REPL to return to stateInput, not quit
m.quitting = true
return m, tea.Quit
return m, nil
case tea.KeyEnter:
selected := m.list.SelectedItem()

View File

@ -225,17 +225,19 @@ func (m replModel) updatePalette(msg tea.Msg) (tea.Model, tea.Cmd) {
result := m.palette.result
s := result.Shortcut
// Check if there are flags that need to be filled
// Only open the form when required flags are missing.
// Commands with only optional flags execute directly — users can pass
// flags via the direct-command syntax if needed.
missing := missingRequiredFlags(s, map[string]string{})
if len(missing) > 0 || len(s.Flags) > 0 {
if len(missing) > 0 {
m.form = newFormModel(result.Group, s, m.width, m.height, nil)
m.state = stateForm
return m, nil
}
// Execute directly
// No required flags missing → execute directly
m.state = stateExecuting
return m, m.executeCommand(result.Group, s, map[string]string{})
return m, tea.Batch(m.executeCommand(result.Group, s, map[string]string{}), m.spinner.Tick)
}
return m, cmd
@ -269,12 +271,13 @@ func (m replModel) updateExecuting(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case execResultMsg:
if msg.err != nil {
m.lastError = fmt.Sprintf("Error: %v", msg.err)
m.lastError = fmt.Sprintf("命令执行失败: %s", msg.err)
m.lastOutput = ""
m.state = stateError
return m, nil
}
m.lastOutput = msg.output
display := formatCommandDisplay(msg.group, msg.shortcut, msg.args)
m.lastOutput = fmt.Sprintf(" ✓ 执行: %s\n\n%s", display, msg.output)
m.lastError = ""
m.state = stateInput
m.input.Focus()