a90b7443e4
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
108 lines
4.6 KiB
Bash
108 lines
4.6 KiB
Bash
#!/usr/bin/env bash
|
|
# save_onlyoffice_file — fuerza el guardado (Ctrl+S) de un documento abierto en una
|
|
# instancia de ONLYOFFICE Desktop Editors en Linux/X11 y confirma que el archivo se
|
|
# escribio a disco observando el cambio de mtime.
|
|
#
|
|
# Para que existe: OnlyOffice mantiene los cambios en memoria hasta que el usuario
|
|
# guarda. Cualquier proceso que regenere el .xlsx leyendo del disco (por ejemplo un
|
|
# build que refresca hojas) perderia el trabajo manual no guardado. Esta funcion
|
|
# vuelca ese trabajo a disco ANTES de tocar el archivo, de modo que el paso de
|
|
# actualizacion pueda preservarlo. Es el primer paso del flujo seguro:
|
|
# save_onlyoffice_file -> (actualizar el archivo) -> reload_onlyoffice_file
|
|
#
|
|
# La ventana se localiza por el basename del archivo (OnlyOffice titula la ventana
|
|
# "<basename> — ONLYOFFICE"), igual que open_onlyoffice_file. Si no hay ventana
|
|
# abierta para ese basename no hay nada que guardar: se devuelve status "no_window"
|
|
# con exit 0 (el disco ya es la unica fuente de verdad).
|
|
#
|
|
# Funcion impura: envia eventos de teclado a X11 (xdotool) y lee el estado del
|
|
# sistema de archivos. Imprime una linea JSON con el resultado a stdout.
|
|
#
|
|
# No usamos `set -e`: los pipelines de busqueda de ventanas (xdotool|head) pueden no
|
|
# matchear y no deben abortar el script. Mantenemos -u y pipefail con guardas.
|
|
set -uo pipefail
|
|
|
|
save_onlyoffice_file() {
|
|
local file_path="${1:-}"
|
|
local instance="${2:-demo}"
|
|
|
|
# --- 1. Validacion de dependencias del sistema ---
|
|
local dep
|
|
for dep in xdotool stat; do
|
|
if ! command -v "$dep" >/dev/null 2>&1; then
|
|
echo "error: dependencia ausente: '$dep' (instala xdotool, coreutils)" >&2
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
# --- 2. Validacion de argumentos ---
|
|
if [ -z "$file_path" ]; then
|
|
echo "error: uso: save_onlyoffice_file <file_path> [instance]" >&2
|
|
return 1
|
|
fi
|
|
if [ ! -f "$file_path" ]; then
|
|
echo "error: el archivo no existe: '$file_path'" >&2
|
|
return 1
|
|
fi
|
|
local abs_path
|
|
abs_path="$(cd "$(dirname "$file_path")" && pwd)/$(basename "$file_path")"
|
|
local base
|
|
base="$(basename "$abs_path")"
|
|
|
|
# --- 3. Localizar la ventana de OnlyOffice por basename ---
|
|
local wid=""
|
|
wid="$(xdotool search --name "$base" 2>/dev/null | head -1 || true)"
|
|
if [ -z "$wid" ]; then
|
|
printf '{"instance":"%s","file":"%s","wid":null,"status":"no_window"}\n' \
|
|
"$instance" "$abs_path"
|
|
return 0
|
|
fi
|
|
local hex
|
|
hex="$(printf '0x%08x' "$wid" 2>/dev/null || echo "$wid")"
|
|
|
|
# --- 4. mtime antes de guardar ---
|
|
local mtime_before
|
|
mtime_before="$(stat -c %Y "$abs_path" 2>/dev/null || echo 0)"
|
|
|
|
# --- 5. Enfocar la ventana y enviar Ctrl+S ---
|
|
xdotool windowactivate --sync "$wid" >/dev/null 2>&1 || true
|
|
xdotool key --clearmodifiers --window "$wid" ctrl+s >/dev/null 2>&1 || true
|
|
|
|
# --- 6. Esperar el guardado; auto-confirmar el dialogo de formato si aparece ---
|
|
# OnlyOffice puede mostrar un dialogo modal ("mantener formato") al guardar. Si el
|
|
# mtime no cambia en ~1.2s asumimos que hay un modal esperando y le enviamos Return:
|
|
# acepta la opcion por defecto, que es mantener el formato actual del archivo. Si no
|
|
# habia dialogo, el Return va al editor y solo mueve de celda (inofensivo: no altera
|
|
# datos). El intento se repite mientras el guardado no se confirme.
|
|
local mtime_after="$mtime_before" i=0 confirmed=0
|
|
local max=27 # ~8s a 0.3s por iteracion
|
|
until [ "$mtime_after" -gt "$mtime_before" ] || [ "$i" -ge "$max" ]; do
|
|
read -r -t 0.3 _ </dev/null 2>/dev/null || true
|
|
mtime_after="$(stat -c %Y "$abs_path" 2>/dev/null || echo "$mtime_before")"
|
|
i=$((i + 1))
|
|
# A partir de ~1.2s sin guardar, confirmar el dialogo modal con Return.
|
|
if [ "$i" -ge 4 ] && [ "$mtime_after" -le "$mtime_before" ]; then
|
|
local dlg
|
|
dlg="$(xdotool getactivewindow 2>/dev/null || true)"
|
|
if [ -n "$dlg" ]; then
|
|
xdotool key --clearmodifiers --window "$dlg" Return >/dev/null 2>&1 || true
|
|
confirmed=1
|
|
fi
|
|
fi
|
|
done
|
|
|
|
local status="saved"
|
|
if [ "$mtime_after" -le "$mtime_before" ]; then
|
|
# Sin cambio de mtime: no habia nada pendiente que guardar.
|
|
status="no_change"
|
|
fi
|
|
printf '{"instance":"%s","file":"%s","wid":"%s","status":"%s","dialog_confirmed":%s,"mtime_before":%s,"mtime_after":%s}\n' \
|
|
"$instance" "$abs_path" "$hex" "$status" "$confirmed" "$mtime_before" "$mtime_after"
|
|
return 0
|
|
}
|
|
|
|
# Ejecutable directo: `bash save_onlyoffice_file.sh <file> [instance]`.
|
|
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|
save_onlyoffice_file "$@"
|
|
fi
|