// Fenrir console screen reader. // Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package interaction import ( "strings" "unicode" "git.stormux.org/storm/fenrir/internal/i18n" ) // Lists use Text as a prefix search without filtering or activating items. func (s *Session) list(control *Control, key Key) Result { if key.Ctrl && key.Name != "backspace" { return Result{} } if key.Name == "backspace" || (key.Name == "" || key.Name == "space") && key.Text != "" && !key.Ctrl { prefix := []rune(control.Text) if key.Name == "backspace" { if key.Ctrl { prefix = nil } else if len(prefix) > 0 { prefix = prefix[:len(prefix)-1] } } else { for _, char := range key.Text { if !unicode.IsPrint(char) { return Result{} } } if len(prefix)+len([]rune(key.Text)) > 4096 { return Result{} } prefix = append(prefix, []rune(key.Text)...) } query := strings.ToLower(string(prefix)) for index, item := range control.Items { if strings.HasPrefix(strings.ToLower(item), query) { control.Text, control.Selected = string(prefix), index return Result{Speech: item} } } // Reject unmatched input so a typo leaves the last valid search intact. return Result{Speech: i18n.T("No matches")} } switch key.Name { case "up": control.Selected = (control.Selected + len(control.Items) - 1) % len(control.Items) case "down": control.Selected = (control.Selected + 1) % len(control.Items) case "enter": return Result{Action: control.Action} default: return Result{} } control.Text = "" return Result{Speech: control.Items[control.Selected]} }