---
name: save_onlyoffice_file
kind: function
lang: bash
domain: shell
purity: impure
version: 1.1.0
description: "Fuerza el guardado (Ctrl+S) de un documento abierto en una instancia de OnlyOffice Desktop en Linux/X11 y confirma que llego a disco por cambio de mtime. Primer paso del flujo seguro guardar -> actualizar -> recargar; evita perder cambios no guardados cuando un build regenera el archivo leyendo del disco."
signature: "save_onlyoffice_file(file_path: string, [instance: string]) -> json"
error_type: error_go_core
tags: [onlyoffice, desktop, x11, gui, save, persist]
uses_functions: []
uses_types: []
file_path: bash/functions/shell/save_onlyoffice_file.sh
params:
  - name: file_path
    desc: "ruta al documento abierto en OnlyOffice cuyo guardado se quiere forzar. Debe existir. Se normaliza a ruta absoluta y se usa su basename para localizar la ventana."
  - name: instance
    desc: "nombre del slot/instancia para etiquetar la salida JSON (default: 'demo'). Usar el MISMO valor que en open/reload/close del mismo documento por coherencia."
output: "linea JSON a stdout: {\"instance\":\"<i>\",\"file\":\"<abs>\",\"wid\":\"<hex>|null\",\"status\":\"saved\"|\"no_change\"|\"no_window\",\"dialog_confirmed\":0|1[,\"mtime_before\":N,\"mtime_after\":N]}. dialog_confirmed=1 si se envio Return para cerrar el dialogo modal de formato. Exit 0 salvo error de dependencia o archivo inexistente (exit 1)."
---

Fuerza el guardado (Ctrl+S) de un documento abierto en una instancia de ONLYOFFICE
Desktop Editors en Linux/X11 y confirma que el guardado llegó a disco observando el
cambio de `mtime` del archivo.

Existe para cerrar una ventana de pérdida de datos: OnlyOffice mantiene los cambios
en memoria hasta que el usuario guarda. Cualquier proceso que regenere el archivo
leyendo del disco (un build que refresca hojas, un script de sincronización)
perdería el trabajo manual no guardado. Esta función vuelca ese trabajo a disco
ANTES de tocar el archivo, de modo que el paso de actualización pueda preservarlo.

Es el primer paso del flujo seguro de refresco:

```
save_onlyoffice_file  ->  (actualizar el archivo en disco)  ->  reload_onlyoffice_file
```

## Ejemplo

```bash
# Forzar el guardado de un xlsx abierto en la instancia "afiliados"
bash bash/functions/shell/save_onlyoffice_file.sh \
  /home/enmanuel/afiliados/programas_afiliados.xlsx afiliados
# {"instance":"afiliados","file":"/home/enmanuel/afiliados/programas_afiliados.xlsx","wid":"0x0a20002a","status":"saved","mtime_before":1718380000,"mtime_after":1718380042}

# Via fn run (tras fn index)
./fn run save_onlyoffice_file /home/enmanuel/afiliados/programas_afiliados.xlsx afiliados

# Encadenado con la actualización y la recarga (flujo seguro completo)
bash bash/functions/shell/save_onlyoffice_file.sh "$XLSX" afiliados
python build_xlsx.py                      # regenera solo las hojas gestionadas
./fn run reload_onlyoffice_file "$XLSX" afiliados
```

## Cuando usarla

Llámala SIEMPRE justo antes de regenerar o modificar en disco un archivo que el
usuario pueda tener abierto en OnlyOffice, para no pisar sus cambios sin guardar.
Es el primer eslabón del flujo guardar -> actualizar -> recargar. Si no hay ventana
abierta para ese archivo, es un no-op seguro (status `no_window`).

## Gotchas

- **Orden crítico**: guarda ANTES de actualizar el archivo. Si actualizas primero y
  guardas OnlyOffice después, OnlyOffice sobrescribe tu actualización con su copia
  en memoria (vieja). El flujo correcto es save -> update -> reload.
- **status `no_change`**: el `mtime` no cambió. Normalmente significa que no había
  cambios pendientes (no es un error).
- **Auto-confirmación del diálogo de formato (v1.1.0)**: si tras Ctrl+S el guardado no
  se completa en ~1.2s, la función asume que OnlyOffice mostró un diálogo modal
  ("mantener formato") y le envía Return, que acepta la opción por defecto (mantener el
  formato actual). El campo `dialog_confirmed` indica si se envió. Si no había diálogo,
  el Return va al editor y solo mueve de celda (no altera datos). Para suprimir el
  diálogo de forma permanente, desmárcalo en OnlyOffice: Configuración avanzada →
  desactivar el aviso de formato al guardar.
- **status `no_window`**: no hay ninguna ventana cuyo título contenga el basename del
  archivo. No hay nada que guardar; el disco ya es la única fuente de verdad.
- **Detección por basename**: dos archivos con el mismo nombre en rutas distintas
  colisionan al localizar la ventana (igual que open/reload).
- **X11 obligatorio**: depende de `xdotool` (y `stat` de coreutils). No funciona en
  Wayland puro sin XWayland.
- **Foco**: la función activa la ventana (`windowactivate --sync`) para que Ctrl+S
  llegue al editor. Roba el foco un instante; es esperable.

## Capability growth log

- v1.1.0 (2026-06-15) — auto-confirma el diálogo modal "mantener formato" enviando
  Return a la ventana activa cuando el guardado no se completa en ~1.2s; añade el campo
  `dialog_confirmed` a la salida JSON.
