// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package app import ( "strings" "unicode" "git.stormux.org/storm/cthulhu/internal/input" "git.stormux.org/storm/cthulhu/internal/presentation" "git.stormux.org/storm/cthulhu/internal/review" ) // Shared by review spelling and learn mode, matching Python Cthulhu's names. func phoneticLetter(letter rune) string { words := [...]string{"alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india", "juliet", "kilo", "lima", "mike", "november", "oscar", "papa", "quebec", "romeo", "sierra", "tango", "uniform", "victor", "whiskey", "xray", "yankee", "zulu"} letter = unicode.ToLower(letter) if letter < 'a' || letter > 'z' { return "" } return words[letter-'a'] } func flat_review_speech(command input.Command) review.FlatSpeech { switch command { case input.ReviewSpellWord: return review.FlatSpell case input.ReviewPhoneticWord, input.ReviewPhoneticCharacter: return review.FlatPhonetic } return review.FlatSpeak } // Preserve blank/whitespace announcements. Otherwise spell Unicode runes as // separate utterances, retaining repeated letters and character-mode speech. func set_review_spelling(request *speechRequest, text string, style review.FlatSpeech) { if style == review.FlatSpeak || strings.TrimSpace(text) == "" { return } request.Character = style == review.FlatSpell for _, letter := range text { kind := "" part := presentation.FlatReviewText(string(letter), true) if style == review.FlatPhonetic { if unicode.IsUpper(letter) { kind = "uppercase" } if name := phoneticLetter(letter); name != "" { part = name } else if unicode.IsLetter(letter) { part = string(unicode.ToLower(letter)) } } request.Spelling = append(request.Spelling, part) request.SpellingVoices = append(request.SpellingVoices, kind) } }