90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/atspi"
|
|
"git.stormux.org/storm/cthulhu/internal/sound"
|
|
)
|
|
|
|
type speechLine struct {
|
|
Object atspi.ObjectID
|
|
Raw string
|
|
}
|
|
type indentationData struct {
|
|
signature string
|
|
columns int
|
|
}
|
|
type indentationHistory map[atspi.ObjectID]indentationData
|
|
|
|
func indentation_data(line string) indentationData {
|
|
var data indentationData
|
|
for _, value := range line {
|
|
switch value {
|
|
case ' ', '\u00a0':
|
|
data.columns++
|
|
value = ' '
|
|
case '\t':
|
|
data.columns += 4 - data.columns%4
|
|
default:
|
|
return data
|
|
}
|
|
data.signature += string(value)
|
|
}
|
|
return data
|
|
}
|
|
|
|
func (worker *speechWorker) line_text(text string, line *speechLine) string {
|
|
if line == nil || worker.reading == nil {
|
|
return text
|
|
}
|
|
data := indentation_data(line.Raw)
|
|
previous, known := worker.indentation[line.Object]
|
|
if worker.indentation == nil || len(worker.indentation) >= 128 && !known {
|
|
worker.indentation = make(indentationHistory)
|
|
}
|
|
worker.indentation[line.Object] = data
|
|
settings := worker.reading()
|
|
if !settings.EnableIndentation || settings.OnlySpeakDisplayedText || known && previous.signature == data.signature {
|
|
return text
|
|
}
|
|
mode := settings.IndentationPresentationMode
|
|
if (mode == "beeps" || mode == "both") && worker.indentationCue != nil {
|
|
frequency := min(2700, 200+data.columns*30)
|
|
if data.columns > previous.columns {
|
|
frequency += 50
|
|
} else if data.columns < previous.columns {
|
|
frequency = max(100, frequency-50)
|
|
}
|
|
worker.indentationCue(sound.Cue{Name: sound.IndentationCueName(frequency)})
|
|
}
|
|
if mode == "beeps" {
|
|
return text
|
|
}
|
|
word := "columns"
|
|
if data.columns == 1 {
|
|
word = "column"
|
|
}
|
|
return strings.TrimSuffix(fmt.Sprintf("indentation %d %s, %s", data.columns, word, text), ", ")
|
|
}
|
|
|
|
func document_speech_line(line atspi.DocumentLine) *speechLine {
|
|
if len(line.Contents) == 0 {
|
|
return nil
|
|
}
|
|
content := line.Contents[0]
|
|
if content.Snapshot.Role == "password text" {
|
|
return nil
|
|
}
|
|
raw := content.RawText
|
|
if raw == "" {
|
|
raw = content.Text
|
|
}
|
|
return &speechLine{Object: content.Snapshot.ID(), Raw: raw}
|
|
}
|