Pregunta:
Considere el siguiente código fuente de elisp dentro de un archivo .org
:
#+BEGIN_SRC elisp :results silent
(delete-other-windows)
(split-window-right)
(switch-to-buffer-other-window '"*Python*")
#+END_SRC
Este código está destinado a eliminar todas las demás ventanas, crear una nueva ventana a la derecha (trabajo con 2 ventanas una al lado de la otra) y luego cambiar a esa ventana y abrir un intérprete de Python que ya se está ejecutando allí.
Funciona si voy línea por línea y Cx Ce
para evaluar el código elisp. Sin embargo, ejecutar el bloque de código a través de Cc Cc
en modo org no produce el efecto deseado.
Pregunta: ¿Es posible modificar ese bloque de código para que ejecutarlo con Cc Cc
produzca el efecto deseado?
Respuesta:
El siguiente código lisp define el nuevo parámetro de bloque fuente emacs-lisp :keep-windows
. Puede modificar la configuración de la ventana a través del bloque fuente si establece este parámetro en t
.
Puede poner el código fuente en su archivo de inicio .
Reemplaza save-window-excursion
en org-babel-execute:emacs-lisp
por una macro recién definida save-window-excursion-if
. La nueva macro necesita un predicado como nuevo primer argumento. La configuración de la ventana solo se almacena si ese predicado no es nulo. Ahí es donde se prueba el nuevo parámetro de bloque fuente :keep-windows
.
La función replace-in-fundef
continuación necesita acceso al archivo fuente ob-emacs-lisp.el
.
(require 'ob-emacs-lisp)
(defun transform-tree (tree trafo)
"Transform TREE by TRAFO."
(let ((next tree))
(while next
(let ((this next))
(setq next (cdr next))
(if (consp (car this))
(transform-tree (car this) trafo)
(funcall trafo this)))))
tree)
(defun replace-in-fundef (fun sym &rest replacement)
"In function FUN perform REPLACEMENT."
(setq fun (or
(condition-case err
(let* ((pos (find-function-noselect fun t))
(buf (car pos))
(pt (cdr pos)))
(with-current-buffer buf
(save-excursion
(goto-char pt)
(read buf))))
(error nil))
(and (symbolp fun) (symbol-function fun))
fun))
(transform-tree fun
(lambda (this)
(when (eq (car this) sym)
(let ((copy-repl (cl-copy-list replacement)))
(setcdr (last copy-repl) (cdr this))
(setcdr this (cdr copy-repl))
(setcar this (car copy-repl)))))))
(defmacro save-window-excursion-if (pred &rest body)
"Act like `save-window-excursion' if PRED is non-nil."
(declare (indent 1) (debug t))
(let ((c (make-symbol "wconfig")))
`(let ((,c (and ,pred (current-window-configuration))))
(unwind-protect (progn ,@body)
(when ,c (set-window-configuration ,c))))))
(advice-remove 'org-babel-execute:emacs-lisp #'ad-org-babel-execute:emacs-lisp)
;; make sure we have access to the source code of `org-babel-execute:emacs-lisp'
(find-function-noselect 'org-babel-execute:emacs-lisp t)
;; (defun ad-org-babel-execute:emacs-lisp ...):
(eval (replace-in-fundef 'org-babel-execute:emacs-lisp 'org-babel-execute:emacs-lisp 'ad-org-babel-execute:emacs-lisp))
;; Use `save-window-excursion-if' in `ad-org-babel-execute:emacs-lisp':
(declare-function 'ad-org-babel-execute:emacs-lisp " ")
(eval (replace-in-fundef 'ad-org-babel-execute:emacs-lisp
'save-window-excursion 'save-window-excursion-if '(null (member (cdr (assoc :keep-windows params)) '("yes" "t")))))
;; Replace `org-babel-execute:emacs-lisp':
(advice-add 'org-babel-execute:emacs-lisp :override #'ad-org-babel-execute:emacs-lisp)
Su bloque fuente de ejemplo se puede aumentar con :keep-windows
siguiente manera:
#+BEGIN_SRC elisp :results silent :keep-windows t
(delete-other-windows)
(split-window-right)
(switch-to-buffer-other-window '"*Python*")
#+END_SRC
Algunos detalles sobre el código fuente:
Queremos reemplazar save-window-excursion
en org-babel-execute:emacs-lisp
. save-window-excursion
es una macro. Eso significa que necesitamos el código fuente para reemplazar la macro antes de su expansión. Buscamos org-babel-execute:emacs-lisp
con find-function
y lo leemos a través del lector elisp. La definición de la función se puede interpretar como un árbol construido a partir de listas lisp (si la función no está compilada por bytes). Modificar esa definición es una transformación de árbol.