Files
cthulhu/internal/app/browser_lists.go

99 lines
2.9 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"context"
"fmt"
"strconv"
"strings"
"unicode"
"git.stormux.org/storm/cthulhu/internal/input"
"git.stormux.org/storm/cthulhu/internal/interaction"
"git.stormux.org/storm/cthulhu/internal/review"
)
type documentListSource interface {
ListDocument(context.Context, review.DocumentTarget, int) (review.DocumentListSnapshot, error)
SelectDocumentList(review.DocumentListSnapshot, int) error
}
func (ui *internalUI) browserListMessage(message string) {
if ui.gate.Locked() || ui.gate.Suspended() {
return
}
ui.speech.Enqueue(speechRequest{Text: message, Role: "system", Cause: "browser-list"})
if ui.braille != nil {
ui.braille.EnqueueMessage(message)
}
}
func documentListTarget(binding input.DocumentListBinding) review.DocumentTarget {
switch binding.Command {
case input.DocumentListAnnotations:
return review.DocumentAnnotation
case input.DocumentListInternalFrames:
return review.DocumentInternalFrame
case input.DocumentListMath:
return review.DocumentMath
}
target, _, _ := documentReviewCommand(binding.Next)
return target
}
func (ui *internalUI) browserList(ctx context.Context, binding input.DocumentListBinding) (*interaction.Session, review.DocumentListSnapshot, error) {
if ui.documents == nil {
return nil, review.DocumentListSnapshot{}, review.ErrNoCurrent
}
list, err := ui.documents.ListDocument(ctx, documentListTarget(binding), binding.Level)
if err != nil {
return nil, list, err
}
if len(list.Entries) == 0 {
return nil, list, nil
}
items := make([]interaction.Item, 0, len(list.Entries))
for index, position := range list.Entries {
snapshot := position.Snapshot
label := position.Label
if label == "" {
label = snapshot.Name
}
if label == "" && snapshot.Role != "password text" {
label = snapshot.Text
}
if label == "" {
label = snapshot.Role
}
label = strings.Join(strings.FieldsFunc(label, func(r rune) bool { return unicode.IsControl(r) || unicode.IsSpace(r) }), " ")
// Keep the existing form label bound without splitting UTF-8.
labelRunes := []rune(label)
if len(labelRunes) > 225 {
label = string(labelRunes[:225])
}
if label == "" {
label = snapshot.Role
}
if snapshot.HeadingLevel > 0 {
label += fmt.Sprintf(", heading level %d", snapshot.HeadingLevel)
}
if snapshot.Role == "check box" || snapshot.Role == "radio button" || snapshot.Role == "toggle button" {
if snapshot.Checked {
label += ", checked"
} else {
label += ", not checked"
}
}
items = append(items, interaction.Item{ID: strconv.Itoa(index), Label: label})
}
title := fmt.Sprintf("%s: %d items found", binding.Title, len(items))
if len(items) == 1 {
title = binding.Title + ": 1 item found"
}
session, err := interaction.NewNavigationSession(title, items, list.Selected)
return session, list, err
}