// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later 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. type LibreOfficeContext struct { InSpreadsheet bool Cell bool CellEditor bool EditorParent ObjectID ContainerFocused bool CellText string Coordinates string Formula string Selection *LibreOfficeSelection } // LibreOfficeSelection never expands a sheet. Complete small selections carry // at most 64 positions; larger selections carry counts and boundary samples. // Kind is cells, rows, columns, or all. Count is a lower bound when // CountLimited is true. type LibreOfficeSelection struct { Kind string Count int CountLimited bool Complete bool Cells []LibreOfficeCell // Boundary samples distinguish equal-sized large selections. They do // not prove that every cell between the endpoints is selected. First, Last LibreOfficeCell } type LibreOfficeCell struct{ Row, Column int } const libreOfficeSelectionLimit = 64 // IsLibreOfficeProcess uses /proc identity verified by the adapter. An // accessible name or document title must never enable application policy. 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) }