Unificando y afinando búsquedas con Helm
Del potente y versátil buscador interactivo y autocompletivo Helm ya hablamos algo aquí hace un tiempo. El caso es que yo hago un uso bastante intensivo —y hasta entusiasta— de esta completa herramienta, además de que me permití la osadía de escribirle esta extensión para gestionar las fuentes del sistema y ejecutar sobre el candidato que tiene el foco ciertas acciones relacionadas con LATEX. Pero con todo lo útil que resulta Helm, siempre podremos afinar un poco más, para alcanzar un grado superior de confort. No hablaremos aquí de modificaciones en el comportamiento y aspecto de la interfaz y el búfer de Helm (eso daría para otra GNUta), sino más bien de ciertas mejoras a la hora de unificar las búsquedas. Y es que la virtud de Helm, su prolijidad, puede ser a menudo uno de sus defectos, o al menos una de las barreras que suelen intimidar al recién llegado.
Veamos: usamos Helm para mil y una cosas, y cada instancia de éste extrae su información y
su lista de candidatos de una fuente diferente (lo que en la jerga helmiana llamaremos
«sources»). Y cada una de estas listas, además, puede incluir una serie de acciones a
llamar sobre el candidato escogido, aquel sobre el cual recae el foco. La acción por
defecto se activa con un simple ENTER
y al resto de acciones se accede mediante un menú
activado con la tecla tabulador o por un atajo de teclado. Ahora bien, en lugar de tener
varios atajos para varias instancias de Helm (buscar búferes abiertos, marcadores,
archivos recientes y demás), ¿por qué no incluir todas esas listas de fuentes en una única
instancia? Naturalmente, como el número de fuentes es exagerado, no parece buena idea
cargarlas todas de esa forma. Primero, porque se ralentizaría horriblemente la instancia
de Helm al tener que minar información de listas muy variopintas, generadas a partir de
presupuestos no menos variopintos; segundo, porque habrá fuentes que usemos con más
frecuencia que otras. A mí, por ejemplo, me resulta muy productivo y cómodo unificar las
siguientes fuentes:
- búferes
- marcadores
- locate (es decir, llama al comando de shell del mismo nombre)
- búferes o archivos recientes
y obtener, con sólo escribir unas letras, toda la información de búferes abiertos,
archivos indexados en la base de datos de locate
, marcadores y búferes recientemente
visitados. Un gran paso en el camino hacia la sencillez, incluso para una maquinaria tan
cargada de engranajes como es Helm.
helm-mini
Extraer información de múltiples fuentes de Helm se puede lograr de muchas formas, pero a
mi juicio la más sencilla es mediante la versión de Helm llamada helm-mini
. Así, nos
bastaría con configurar la siguiente variable con una lista de fuentes a nuestro gusto:
(setq helm-mini-default-sources '(helm-source-buffers-list
helm-source-recentf
helm-source-buffer-not-found
helm-source-bookmarks
helm-source-bookmark-set
helm-source-locate))
y asignar luego algún atajo de conveniencia a la función helm-mini
. Pero aún podemos
afinar un poco más las cosas si pensamos en los encabezados o árboles de Org que vamos
abriendo y visitando. Una de las cosas fascinantes, en efecto, que nos proporciona el modo
del Unicornio, es recordarnos la forma de actuar de las antiguas máquinas Lisp, donde lo
que primaba era el objeto, no el archivo o el directorio, como luego impuso la forma de
trabajar de Unix. En Org —que no deja de ser una interfaz de alto nivel para Elisp—
nos importa más el encabezado o árbol (el objeto), independientemente de en qué archivo se
encuentre y a qué nivel de cuál directorio. Esa forma de pensar supone una importante
liberación del encorsetamiento Unix, que tanto ha influido en la informática de los
últimos decenios.
Si hablamos de Org, por tanto, ese lugar donde casi siempre estamos moviéndonos, es más
productivo pensar en el concepto de encabezados recientes más que en el de archivos
recientes. Pero antes conviene hablar de otra herramienta maravillosa llamada org-ql
.
org-ql y helm-org-ql
org-ql
es una biblioteca para ejecutar una amplia batería de búsquedas a través de
nuestros documentos de Org, como si éstos fueran una suerte de base de datos.
helm-org-ql
, a su vez, es la interfaz de Helm para facilitar dichas búsquedas con la
potencia helmiana. Ambas bibliotecas están escritas por Adam Porter y pueden descargarse
tanto desde su repositorio de GitHub como desde Melpa. Desde luego merecen una GNUta
sólo para ellas cualquier día de estos, pero aquí nos bastará con centrarnos en un punto,
a saber, que cuando uno se habitúa a usarlas se convierten casi en el único medio para
acceder a los encabezados de los archivos Org, independientemente de dónde estén esos
archivos. Por tanto se me ocurrió que podrían ser un buen punto de partida para almacenar
todos los encabezados visitados como otra fuente para Helm.
Antes de seguir conviene señalar que existe un org-recent-headers
así como un
helm-org-recent-headers
, ambos también del mismo autor, pero a diferencia de la familia
org-ql
estas dos bibliotecas no me acababan de convencer tanto en su forma de proceder
como en la de entregar los resultados. Para mi uso personal necesitaba algo mucho más
simple pero también rápido y accesible, sin demasiadas complicaciones ni adornos. Así que
se me ocurrió ensayar el siguiente código Elisp.
Una fuente de Helm para los encabezados accedidos a través de helm-org-ql
Comenzamos por definir la siguiente variable, que va a ser una lista de listas, o una
alist o lista asociativa donde cada elemento es un cons cell, cuyo car es el nombre del
encabezado (pero precedido de la cadena visitado --
para que sea fácil de localizar
cuando lanzo helm-mini
), y el cdr es otro conscell que incluye el nombre del búfer y su
posición en dicho búfer:
(setq lista-helm-org-ql-visitados nil)
Sobreescribo la acción de helm-org-ql
(helm-org-ql-show-marker
) que salta al candidato
cuando lanzo helm-org-ql
. Simplemente, añade un nuevo elemento a la lista con cada
acción de visitar un encabezado:
(defun elemento-a-lista-visitados-helm-org-ql (marker) "Show heading at MARKER." (interactive) ;; This function is necessary because `helm-org-goto-marker' calls ;; `re-search-backward' to go backward to the start of a heading, ;; which, when the marker is already at the desired heading, causes ;; it to go to the previous heading. I don't know why it does that. (switch-to-buffer (marker-buffer marker)) (goto-char marker) (org-show-entry) (add-to-list 'lista-helm-org-ql-visitados `(,(concat "visitados --" (nth 4 (org-heading-components))) (,(buffer-name) ,(marker-position marker))))) (advice-add 'helm-org-ql-show-marker :override #'elemento-a-lista-visitados-helm-org-ql)
Esta función crea una lista de candidatos con los nombres de cada encabezado (serán los nombres que nos aparezcan en la lista de candidatos de Helm):
(defun candidatos-helm-org-ql-visitados () "Devuelve una lista con los encabezados visitados mediante `helm-org-ql'" (mapcar (lambda (x) (car x)) lista-helm-org-ql-visitados))
La lista de acciones. De momento, visitar el encabezado reciente:
(setq acciones-helm-org-ql-visitados (helm-make-actions "visitar el encabezado visitado" (lambda (x) (let* ((cons-destino (cdr (assoc x lista-helm-org-ql-visitados))) (buf (nth 0 (car cons-destino))) (marker-pos (nth 1 (car cons-destino)))) (switch-to-buffer buf) (goto-char marker-pos) (org-show-entry)))))
Y sólo queda definir la fuente para helm-mini:
(setq mi-helm-org-ql-encabezados-recientes '((name . "Encabezados de Org recientes") (candidates . candidatos-helm-org-ql-visitados) (action . acciones-helm-org-ql-visitados)))
que añadiremos a la lista de fuentes:
(setq helm-mini-default-sources '(helm-source-buffers-list
helm-source-recentf
helm-source-buffer-not-found
helm-source-bookmarks
helm-source-bookmark-set
helm-source-locate
mi-helm-org-ql-encabezados-recientes))
∞
Publicado: 26/04/21
Última actualización: 21/01/22
Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.