More work on LibreOffice support.
This commit is contained in:
1 parent
e0c8c6198c
commit
4ac59d4ced
25 files changed
+392
-57
No files matched your search
@@ -4,6 +4,11 @@
|
||||
|
||||
package atspi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// LibreOfficeContext is bounded, copied metadata from the native owner. It
|
||||
// describes Calc's cell and temporary editor objects, without native handles.
|
||||
// Presentation and application policy must not query the provider themselves.
|
||||
@@ -15,6 +20,7 @@ type LibreOfficeContext struct {
|
||||
ContainerFocused bool
|
||||
CellText string
|
||||
Coordinates string
|
||||
Formula string
|
||||
}
|
||||
|
||||
// IsLibreOfficeProcess uses /proc identity verified by the adapter. An
|
||||
@@ -22,3 +28,16 @@ type LibreOfficeContext struct {
|
||||
func IsLibreOfficeProcess(process string) bool {
|
||||
return process == "soffice.bin"
|
||||
}
|
||||
|
||||
// Preserve spaces inside formula string literals and keep the beginning when
|
||||
// bounding long expressions. Text context's default suffix is for caret lines.
|
||||
func sanitizeLibreOfficeFormula(value string) string {
|
||||
value = strings.ToValidUTF8(value, "�")
|
||||
if len(value) > maxSnapshotFieldLength {
|
||||
value = value[:maxSnapshotFieldLength]
|
||||
for !utf8.ValidString(value) {
|
||||
value = value[:len(value)-1]
|
||||
}
|
||||
}
|
||||
return sanitizeTextContext(value)
|
||||
}
|
||||
@@ -120,6 +120,9 @@ func captureLibreOfficeContext(source *C.AtspiAccessible, snapshot *Snapshot) {
|
||||
grandparentRole == C.ATSPI_ROLE_DOCUMENT_SPREADSHEET
|
||||
if context.Cell {
|
||||
context.Coordinates = snapshot.Name
|
||||
// Orca requests uncached attributes: editing can replace a formula
|
||||
// without replacing the accessible cell.
|
||||
C.atspi_accessible_clear_cache_single(source)
|
||||
attributes := C.atspi_accessible_get_attributes(source, nil)
|
||||
if attributes != nil {
|
||||
columnKey, rowKey := C.CString("colindextext"), C.CString("rowindextext")
|
||||
@@ -130,6 +133,16 @@ func captureLibreOfficeContext(source *C.AtspiAccessible, snapshot *Snapshot) {
|
||||
if column != "" && row != "" {
|
||||
context.Coordinates = sanitizeSnapshotField(column + row)
|
||||
}
|
||||
// Current providers use lowercase; Orca also accepts Formula.
|
||||
for _, key := range []string{"formula", "Formula"} {
|
||||
name := C.CString(key)
|
||||
value := C.g_hash_table_lookup(attributes, C.gconstpointer(name))
|
||||
C.free(unsafe.Pointer(name))
|
||||
if value != nil {
|
||||
context.Formula = sanitizeLibreOfficeFormula(C.GoString((*C.gchar)(value)))
|
||||
break
|
||||
}
|
||||
}
|
||||
C.g_hash_table_unref(attributes)
|
||||
}
|
||||
text := C.atspi_accessible_get_text_iface(source)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package atspi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func TestLibreOfficeFormulaPreservesLiteralSpacesAndBoundedPrefix(t *testing.T) {
|
||||
formula := `="two spaces"`
|
||||
if got := sanitizeLibreOfficeFormula(formula); got != formula {
|
||||
t.Fatalf("formula literal changed: %q", got)
|
||||
}
|
||||
formula += strings.Repeat("猫", maxSnapshotFieldLength)
|
||||
got := sanitizeLibreOfficeFormula(formula)
|
||||
if len(got) > maxSnapshotFieldLength || !utf8.ValidString(got) || !strings.HasPrefix(formula, got) {
|
||||
t.Fatalf("invalid bounded formula prefix: bytes=%d", len(got))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user