After commit c018f5fd29 Fenrir is being switched over to go. If you do not want to be part of the testing process, please switch to master.

This commit is contained in:
Storm Dragon committed 2026-10-27 20:30:55 -04:00
1 parent c018f5fd29
commit 0e50de4c76
1047 files changed
+58364 -63747

No files matched your search

+181
View File
@@ -0,0 +1,181 @@
// Fenrir console screen reader.
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
// Package emoji provides the bundled picker catalog and its internal UI form.
package emoji
import (
"sort"
"git.stormux.org/storm/fenrir/internal/interaction"
)
const MenuTitle = "Emoji Menu"
// Catalog values originate in Python Fenrir commands/vmenu-profiles/KEY/emoji.
// Duplicate aliases are omitted; names describe the stored Unicode sequence.
var categories = []struct {
id, label string
choices []interaction.Choice
}{
{"people", "People", []interaction.Choice{
{ID: "😠", Label: "Angry"},
{ID: "😁", Label: "Beaming"},
{ID: "😘", Label: "Blowing kiss"},
{ID: "😎", Label: "Cool"},
{ID: "😭", Label: "Crying"},
{ID: "😈", Label: "Devil"},
{ID: "😵", Label: "Dizzy"},
{ID: "🤯", Label: "Exploding head"},
{ID: "🤬", Label: "Face with symbols"},
{ID: "😀", Label: "Grinning"},
{ID: "😅", Label: "Grinning sweat"},
{ID: "😍", Label: "Heart eyes"},
{ID: "🥰", Label: "Hearts around"},
{ID: "👿", Label: "Imp"},
{ID: "😂", Label: "Laughing"},
{ID: "🤢", Label: "Nauseated"},
{ID: "🥺", Label: "Pleading"},
{ID: "💩", Label: "Poop"},
{ID: "🤣", Label: "Rolling laughing"},
{ID: "😢", Label: "Sad"},
{ID: "😋", Label: "Savoring food"},
{ID: "😱", Label: "Screaming"},
{ID: "😊", Label: "Smiling"},
{ID: "😏", Label: "Smirking"},
{ID: "👍", Label: "Thumbs up"},
{ID: "😉", Label: "Winking"},
}},
{"nature", "Nature", []interaction.Choice{
{ID: "🦋", Label: "Butterfly"},
{ID: "🐱", Label: "Cat"},
{ID: "🌸", Label: "Cherry blossom"},
{ID: "🐶", Label: "Dog"},
{ID: "🌙", Label: "Moon"},
{ID: "🌈", Label: "Rainbow"},
{ID: "🌹", Label: "Rose"},
{ID: "☀️", Label: "Sun"},
{ID: "🌻", Label: "Sunflower"},
{ID: "🌳", Label: "Tree"},
{ID: "🐺", Label: "Wolf"},
}},
{"food", "Food", []interaction.Choice{
{ID: "🍎", Label: "Apple"},
{ID: "🥑", Label: "Avocado"},
{ID: "🍺", Label: "Beer"},
{ID: "🎂", Label: "Birthday cake"},
{ID: "☕", Label: "Coffee"},
{ID: "🍩", Label: "Donut"},
{ID: "🍔", Label: "Hamburger"},
{ID: "🍕", Label: "Pizza"},
{ID: "🍓", Label: "Strawberry"},
{ID: "🌮", Label: "Taco"},
}},
{"holidays", "Holidays", []interaction.Choice{
{ID: "👾", Label: "Alien monster"},
{ID: "🦇", Label: "Bat"},
{ID: "🐈‍⬛", Label: "Black cat"},
{ID: "🐰", Label: "Bunny"},
{ID: "🎄", Label: "Christmas tree"},
{ID: "⚰️", Label: "Coffin"},
{ID: "🥚", Label: "Egg"},
{ID: "🎆", Label: "Fireworks"},
{ID: "👻", Label: "Ghost"},
{ID: "🎁", Label: "Gift"},
{ID: "🎃", Label: "Jack o'lantern"},
{ID: "🧙", Label: "Mage"},
{ID: "🎅", Label: "Santa"},
{ID: "☘️", Label: "Shamrock"},
{ID: "💀", Label: "Skull"},
{ID: "⛄", Label: "Snowman"},
{ID: "🕷", Label: "Spider"},
{ID: "🦃", Label: "Turkey"},
{ID: "🧛", Label: "Vampire"},
{ID: "🕸️", Label: "Web"},
{ID: "🧙‍♀️", Label: "Witch"},
{ID: "🧟", Label: "Zombie"},
}},
{"symbols", "Symbols", []interaction.Choice{
{ID: "🦴", Label: "Bone"},
{ID: "⛓️", Label: "Chains"},
{ID: "✅", Label: "Checkmark"},
{ID: "🗡️", Label: "Dagger"},
{ID: "🔥", Label: "Fire"},
{ID: "🙏", Label: "Folded hands"},
{ID: "❤️", Label: "Heart"},
{ID: "⚡", Label: "High voltage"},
{ID: "💯", Label: "Hundred points"},
{ID: "✌️", Label: "Peace"},
{ID: "🤘", Label: "Rock on"},
{ID: "☠️", Label: "Skull crossbones"},
{ID: "✨", Label: "Sparkles"},
{ID: "⭐", Label: "Star"},
{ID: "⚔️", Label: "Sword"},
}},
{"flags", "Flags", []interaction.Choice{
{ID: "🇦🇷", Label: "Argentina"},
{ID: "🇦🇺", Label: "Australia"},
{ID: "🇧🇪", Label: "Belgium"},
{ID: "🇧🇷", Label: "Brazil"},
{ID: "🇨🇦", Label: "Canada"},
{ID: "🇨🇳", Label: "China"},
{ID: "🇩🇰", Label: "Denmark"},
{ID: "🇫🇮", Label: "Finland"},
{ID: "🇫🇷", Label: "France"},
{ID: "🇩🇪", Label: "Germany"},
{ID: "🇬🇷", Label: "Greece"},
{ID: "🇮🇳", Label: "India"},
{ID: "🇮🇪", Label: "Ireland"},
{ID: "🇮🇱", Label: "Israel"},
{ID: "🇮🇹", Label: "Italy"},
{ID: "🇯🇵", Label: "Japan"},
{ID: "🇲🇽", Label: "Mexico"},
{ID: "🇳🇱", Label: "Netherlands"},
{ID: "🇳🇴", Label: "Norway"},
{ID: "🇵🇱", Label: "Poland"},
{ID: "🇵🇹", Label: "Portugal"},
{ID: "🇷🇺", Label: "Russia"},
{ID: "🇿🇦", Label: "South Africa"},
{ID: "🇰🇷", Label: "South Korea"},
{ID: "🇪🇸", Label: "Spain"},
{ID: "🇸🇪", Label: "Sweden"},
{ID: "🇨🇭", Label: "Switzerland"},
{ID: "🇹🇷", Label: "Turkey"},
{ID: "🇺🇦", Label: "Ukraine"},
{ID: "🇬🇧", Label: "United Kingdom"},
{ID: "🇺🇸", Label: "United States"},
}},
}
// New_session builds an independent draft. Search is local to each category;
// the first All tab searches the complete catalog.
func New_session() (*interaction.Session, error) {
form := interaction.Form{Type: interaction.TabForm, Title: MenuTitle}
var all []interaction.Choice
for _, category := range categories {
all = append(all, category.choices...)
}
sort.SliceStable(all, func(i, j int) bool { return all[i].Label < all[j].Label })
addTab := func(id, label string, choices []interaction.Choice) {
form.Tabs = append(form.Tabs, interaction.Tab{ID: id, Label: label, Controls: []interaction.Control{{
ID: "emoji", Label: "Emoji", Kind: interaction.Grid, Choices: choices, Columns: 6, Action: "copy_emoji",
}}})
}
addTab("all", "All", all)
for _, category := range categories {
addTab(category.id, category.label, category.choices)
}
return interaction.New_session(form)
}
// Selection returns the selected Unicode sequence and readable name. It never
// returns a selection from another tab or from an empty search.
func Selection(session *interaction.Session) (string, string, bool) {
control, ok := session.Focused_control()
if !ok || control.Kind != interaction.Grid || control.Selected < 0 || control.Selected >= len(control.Choices) {
return "", "", false
}
choice := control.Choices[control.Selected]
return choice.ID, choice.Label, true
}
+69
View File
@@ -0,0 +1,69 @@
// Fenrir console screen reader.
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package emoji
import (
"git.stormux.org/storm/fenrir/internal/i18n"
"strings"
"testing"
"git.stormux.org/storm/fenrir/internal/interaction"
)
func TestCategorySelectionAndIndependentSearches(t *testing.T) {
session, err := New_session()
if err != nil {
t.Fatal(err)
}
if _, _, ok := Selection(session); ok {
t.Fatal("tab strip has a selection")
}
session.Handle(interaction.Key{Name: "tab"})
session.Handle(interaction.Key{Text: "j"})
session.Handle(interaction.Key{Name: "right"})
if value, _, _ := Selection(session); value != "🇯🇵" {
t.Fatal("filtered All navigation", value)
}
session.Handle(interaction.Key{Name: "tab"})
session.Handle(interaction.Key{Name: "right"})
session.Handle(interaction.Key{Name: "right"})
session.Handle(interaction.Key{Name: "tab"})
session.Handle(interaction.Key{Text: "c"})
if value, _, _ := Selection(session); value != "🐱" {
t.Fatal("Nature selection came from another tab", value)
}
session.Handle(interaction.Key{Name: "tab", Shift: true})
session.Handle(interaction.Key{Name: "left"})
session.Handle(interaction.Key{Name: "left"})
session.Handle(interaction.Key{Name: "tab"})
if value, _, _ := Selection(session); value != "🇯🇵" {
t.Fatal("All search/selection not retained", value)
}
other, err := New_session()
if err != nil {
t.Fatal(err)
}
other.Handle(interaction.Key{Name: "tab"})
if value, _, _ := Selection(other); value != "👾" {
t.Fatal("new session inherited previous search", value)
}
}
func TestBundledTranslationSearchPreservesEmoji(t *testing.T) {
previous := i18n.Use(i18n.New(t.TempDir(), "de"))
t.Cleanup(func() { i18n.Use(previous) })
session, err := New_session()
if err != nil {
t.Fatal(err)
}
if got := session.Open(); !strings.HasPrefix(got, "Emoji-Menü. Alle Registerkarte") {
t.Fatal("untranslated picker", got)
}
session.Handle(interaction.Key{Name: "tab"})
session.Handle(interaction.Key{Text: "Schmetter"})
if value, label, ok := Selection(session); !ok || value != "🦋" || label != "Butterfly" {
t.Fatalf("localized search changed identity: %q %q %v", value, label, ok)
}
}