70 lines
2.9 KiB
Go
70 lines
2.9 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"git.stormux.org/storm/cthulhu/internal/atspi"
|
|
"git.stormux.org/storm/cthulhu/internal/input"
|
|
"git.stormux.org/storm/cthulhu/internal/presentation"
|
|
"git.stormux.org/storm/cthulhu/internal/review"
|
|
)
|
|
|
|
func (handler *eventReviewHandler) current_line(command input.Command) {
|
|
if handler.focusGate.Locked() || handler.focusGate.Suspended() {
|
|
return
|
|
}
|
|
handler.syncForeground()
|
|
if handler.focusGate.Locked() || handler.focusGate.Suspended() || handler.objectReview == nil || !handler.state.current.ID().Valid() {
|
|
return
|
|
}
|
|
handler.state.pending.terminalFocus.clear()
|
|
handler.state.pending.terminalDeletion.clear()
|
|
handler.state.pending.terminalRepaint.clear()
|
|
style := review.FlatSpeak
|
|
if command == input.SpellCurrentLine {
|
|
style = review.FlatSpell
|
|
} else if command == input.PhoneticCurrentLine {
|
|
style = review.FlatPhonetic
|
|
}
|
|
browse := handler.browser != nil && handler.browser.ready && handler.browser.mode == review.BrowseMode
|
|
if err := handler.objectReview.ReadCurrentLine(browse, style); err != nil {
|
|
handler.logger.Warn("queue current line", "error", err)
|
|
}
|
|
}
|
|
|
|
func (handler *eventReviewHandler) present_current_line(result review.Result) {
|
|
if !handler.objectReview.CurrentDocumentResult(result) || result.DocumentFocus != handler.objectReview.Focus() || handler.focusGate.Locked() || handler.focusGate.Suspended() {
|
|
return
|
|
}
|
|
if result.CurrentLineBrowse && (handler.browser == nil || !handler.browser.acceptsDocumentResult(review.Result{
|
|
DocumentFocus: result.DocumentFocus, DocumentPosition: result.DocumentPosition, DocumentCaretCommand: review.CaretReadLine, Err: result.Err,
|
|
})) {
|
|
return
|
|
}
|
|
request := speechRequest{Text: "Could not read current line.", Role: "system", Cause: "current-line"}
|
|
if result.Err == nil {
|
|
// Native reports require the matching focused source and an unbroken
|
|
// capture through the application. Missing privacy data stays local.
|
|
context := result.DocumentCaretContext
|
|
nativeSource := len(context) > 0 && result.DocumentFocus.Valid() &&
|
|
result.DocumentPosition.Snapshot.ID() == result.DocumentFocus && context[0].ID() == result.DocumentFocus &&
|
|
context[len(context)-1].Role == "application"
|
|
if result.CurrentLineBrowse || nativeSource {
|
|
sources := atspi.DocumentLine{Contents: []atspi.DocumentContent{{Snapshot: result.DocumentPosition.Snapshot}},
|
|
SourceContexts: [][]atspi.Snapshot{result.DocumentCaretContext}}
|
|
request.origin = document_line_speech_origin(sources)
|
|
if result.DocumentCaretLine != nil {
|
|
if origin := document_line_speech_origin(*result.DocumentCaretLine); origin != speechOriginLocal {
|
|
request.origin = origin
|
|
}
|
|
}
|
|
}
|
|
text := result.DocumentCaretText
|
|
request.Text = presentation.FlatReviewText(text, false)
|
|
request.Role = result.DocumentPosition.Snapshot.Role
|
|
set_review_spelling(&request, text, result.FlatSpeech)
|
|
}
|
|
handler.speech.Enqueue(request)
|
|
}
|