Cuaderno de GNUtas

Proteger contra escritura bloques de código en Org

En muchos documentos de Org suelo incluir bloques de código con funciones en Elisp que se evalúan durante el proceso de exportación, y siempre cabe el escrúpulo de prevenir cualquier edición accidental de ese código valioso. Por supuesto, usando un sistema de control de versiones cualquier desaguisado es revertible, felizmente. Pero tampoco está de más la posibildad de asegurar fácilmente esos bloques y protegerlos contra escritura, y ser capaces también de liberarlos con pareja agilidad. Se me ocurrió, para ello, escribir estas funciones que comento a continuación, y que sacan buen provecho de la herramienta org-element-map, incluida en la biblioteca org-element.

Para empezar, necesitamos definir una función que nos añada la propiedad de texto read-only a todos los bloques de código en un búfer dado:

(defun protege-bloques ()
    (interactive)
    (org-element-map (org-element-parse-buffer) 'src-block
      (lambda (bloque)
        (let ((desde (org-element-property :begin bloque))
               (hasta (org-element-property :end bloque)))
          (add-text-properties desde hasta '(read-only t))))))

Seguida por esta otra función que los desprotege. Eso sí, ojo, con el añadido de la variable local inhibit-read-only con valor non-nil, ya que Emacs se habrá tomado demasiado al pie de la letra lo de «read only», a la manera del guardian de exagerado celo que no nos deja entrar en nuestra propia casa.

(defun desprotege-bloques ()
    (interactive)
    (org-element-map (org-element-parse-buffer) 'src-block
      (lambda (bloque)
        (let* ((desde (org-element-property :begin bloque))
               (hasta (org-element-property :end bloque))
               (inhibit-read-only t))
          (remove-text-properties desde hasta '(read-only t))))))

Pero, claro, con lo anteror no vamos a ningún sitio, ya que lo que pretendemos es proteger ciertos bloques (por ejemplo, los que llevan el encabezado :protegido) y no todos los que tenemos en nuestro documento. Para ello, es necesario esta tercera función, que es la que realmente nos hará la criba:

(defun bloque-solo-lectura ()
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (while
          (re-search-forward ":protegido" nil t)
        (save-restriction
          (org-narrow-to-block)
          (protege-bloques)))))

Por último, la función la podemos anclar al hook de Org Mode:

(add-hook 'org-mode-hook 'bloque-solo-lectura)

Aunque yo sería más partidario de evaluarla como simple variable local en los documentos donde queramos que actúe. Por ejemplo, poniendo en la primera línea de cada fichero:

# -*- eval: (bloque-solo-lectura) -*-

(Y siempre que queramos eliminar la resticción del bloque podremos evaluar la función desprotege-bloques).

Publicado: 12/02/20

Última actualización: 21/01/22


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

© Juan Manuel Macías
Creado con esmero en
GNU Emacs