Archivo de configuración de Emacs desde un fichero org-mode.
 
Go to file
Notxor 534e419ca4 Elimina la carga del paquete de OpenStreetMap, por no usarlo. 2023-12-04 10:30:41 +01:00
LICENSE Initial commit 2022-08-26 10:47:15 +02:00
README.org Elimina la carga del paquete de OpenStreetMap, por no usarlo. 2023-12-04 10:30:41 +01:00
init.el Elimina la carga del paquete de OpenStreetMap, por no usarlo. 2023-12-04 10:30:41 +01:00
mi-custom-var.el Establece la previsualización de imágenes y fragmentos LaTeX 2023-10-23 10:10:42 +02:00

README.org

init-emacs

Archivo de configuración de Emacs desde un fichero org-mode. Lo ideal es tener agrupadas las opciones por conceptos y no, como hace por defecto Emacs en custom-set-variables, alfabéticamente.

Inicio de la configuración

La configuración comienza estableciendo las variables necesarias para la configuración de paquetes. Estoy utilizando el modo use-package.

Los paquetes los buscará en los repositorios GNU y melpa. Al iniciar refresca los paquetes, comprueba si está instalado use-package, si no lo está lo instala y comienza el proceso.

  ;;; package --- init.el
  ;;; Commentary:
  ;;; Este es mi fichero init.el para configurar Emacs
  (require 'package)
  ;;; Code:
  (setq package-archives
        '(("elpa"   . "https://elpa.gnu.org/packages/")
          ;;("devel"  . "https://elpa.gnu.org/devel/")
          ("nongnu" . "https://elpa.nongnu.org/nongnu/")
          ("melpa"  . "https://melpa.org/packages/")))
  (package-initialize)

  (unless (package-installed-p 'use-package)
    (package-refresh-contents)
    (package-install 'use-package))
  (eval-and-compile
    (setq use-package-always-ensure t
          use-package-expand-minimally t))

También puede haber algunos paquetes bajados a mano o desarrollados por mí, que los busca en diferentes sitios.

  ;; lugar para los paquetes bajados a mano
  (add-to-list 'load-path "~/.emacs.d/site-packages")
  (add-to-list 'load-path "~/.emacs.d/notxor-blog/")

Primero cargar el Dracula-Theme, que es mi tema oscuro favorito.

  (use-package dracula-theme
    :ensure t)

Ajuste de variables

El apartado de custom-set-variables lo genera automáticamente Emacs cuando se utiliza el modo gráfico de configuración. Avisa de que seamos cuidadosos si lo modificamos a mano.

Lo que no me gusta de esta generación automática es que ordena las variables alfabéticamente y prefiero agruparlas por concepto. Pero por concepto es posible que nos encontremos con algunas variables que se queden solas.

Cabecera

  (setq custom-file "~/.emacs.d/mi-custom-var.el")
  (load custom-file)

Ajustes de calendario y agenda

  (custom-set-variables
   ;; custom-set-variables was added by Custom.
   ;; If you edit it by hand, you could mess it up, so be careful.
   ;; Your init file should contain only one such instance.
   ;; If there is more than one, they won't work right.

  '(browse-url-secondary-browser-function 'browse-url-w3)
  ;; Estilos de cabeceras
  '(calendar-date-style 'iso)
  '(calendar-day-header-array ["Do" "Lu" "Ma" "Mi" "Ju" "Vi" "Sa"])
  '(calendar-day-name-array
    ["domingo" "lunes" "martes" "miércoles" "jueves" "viernes" "sábado"])
  '(calendar-month-abbrev-array
    ["Ene" "Feb" "Mar" "Abr" "May" "Jun" "Jul" "Ago" "Sep" "Oct" "Nov" "Dic"])
  '(calendar-month-name-array
    ["enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre"])
  '(calendar-week-start-day 1) ; La semana comienza en lunes

  '(org-agenda-diary-file "~/agenda/diario.org")
  '(org-agenda-files
    '("/home/notxor/agenda/agenda.org" "/home/notxor/agenda/personal.org"))
  '(org-agenda-include-diary t)
  '(org-archive-location "~/agenda/especiales/archive.org::* Desde %s")

  '(org-caldav-calendar-id "personal")
  '(org-caldav-files '("~/agenda/personal.org"))
  '(org-caldav-inbox "~/agenda/personal.org")
  '(org-caldav-url
    "https://nube.nueva-actitud.org/remote.php/dav/calendars/Notxor")
  '(org-icalendar-timezone "Europe/Madrid")
  '(org-todo-keywords
    '((sequence "PENDIENTE(p)" "ESPERANDO(e)" "|" "HECHO(h)" "CANCELADO(c)")))

  '(diary-entry-marker 'font-lock-variable-name-face)
  '(diary-file "~/agenda/diario.org")
  '(calendar-mark-diary-entries-flag t)

Un punto importante es la captura de citas y otros asuntos mediante el sistema de captura de org-mode. La captura suele ser una de las dificultades que se nos plantea cuando queremos tomar notas rápido. Las siguientes plantillas facilitan que con pocas pulsaciones de teclas muestre una estructura según el tipo de anotación que quiero hacer.

    '(org-capture-templates
      ;; Es una lista de listas así que vamos por partes
      '(("t" "Tarea Pendiente")
        ("tt" "Tarea Simple    (t) trabajo" entry (file "~/agenda/agenda.org")
         "* PENDIENTE %? \t :trabajo:
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
          ("ta" "Tarea Simple    (a) asociación" entry (file+headline "~/agenda/agenda.org" "Asociación")
           "* PENDIENTE %? \t :pica:
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
          ("tp" "Tarea Simple    (p) personal" entry (file+headline "~/agenda/agenda.org" "Personal")
           "* PENDIENTE %? \t :personal:
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
   ;;; Capturar tareas que pasan a estar a la espera
          ("e" "Tarea a la espera")
          ("et" "Tarea a la espera    (t) trabajo" entry (file "~/agenda/agenda.org")
           "* ESPERANDO %? \t :trabajo:
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"ESPERANDO\"            from \"\"      %U
     :END:" :empty-lines 1)
          ("ea" "Tarea a la espera    (a) asociación" entry (file+headline "~/agenda/agenda.org" "Asociación")
           "* ESPERANDO %? \t :pica:
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"ESPERANDO\"            from \"\"      %U
     :END:" :empty-lines 1)
          ("ep" "Tarea Simple    (p) personal" entry (file+headline "~/agenda/agenda.org" "Personal")
           "* ESPERANDO %? \t :personal:
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"ESPERANDO\"            from \"\"      %U
     :END:" :empty-lines 1)
   ;;; Capturas que tienen «deadline» asociada
          ("l" "Tarea con fecha límite")
          ("lt" "Tarea    (t) trabajo" entry (file "~/agenda/agenda.org")
           "* PENDIENTE %? \t :trabajo:
     DEADLINE: %(substring (call-interactively 'org-deadline) 12)
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
          ("la" "Tarea    (a) asociación" entry (file+headline "~/agenda/agenda.org" "Asociación")
           "* PENDIENTE %? \t :pica:
     DEADLINE: %(substring (call-interactively 'org-deadline) 12)
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
          ("lp" "Tarea    (p) personal" entry (file+headline "~/agenda/agenda.org" "Personal")
           "* PENDIENTE %? \t :personal:
     DEADLINE: %(substring (call-interactively 'org-deadline) 12)
     :PROPERTIES:
     :CREATE:      %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
   ;;; Templates de captura para cosas que no son para la agenda
          ("n" "Capturas no para agenda")
          ("nc" "Anotar (c) contacto" entry (file+headline "~/agenda/especiales/personal.org.gpg" "Sin ordenar")
           "** %^{Nombre} %^{Apellidos}%?
     :PROPERTIES:
     :Nombre:     %\\1
     :Apellidos:  %\\2
     :Alias:      %^{Alias}
     :Grupo:      %^{Grupo}
     :F-nacim:    %^{F-nacim}u
     :Móvil:      %^{Móvil}
     :Teléfono:
     :Email:      %^{Email}
     :Web:
     :Dirección:  %^{Dirección}
     :Ciudad:     %^{Ciudad}
     :Provincia:  %^{Provincia}
     :Cód.Pos:    %^{Código Postal}
     :Compañía:
     :Notas:
     :END:" :empty-lines 1)
          ("nd" "Anotar (d) diario" entry (file+headline "~/agenda/bitacora.org" "Diario")
           "** %U
  %?" :empty-lines 1)
          ("ni" "Anotar (i) idea" entry (file+headline "~/agenda/bitacora.org" "Ideas")
           "** Idea para %^{Tema}
     :PROPERTIES:
     :Tema:      %\\1
     :fecha:     %U
     :END:
  %?" :empty-lines 1)
      ("np" "Anotar (p) presupuesto" entry (file+headline "~/agenda/cuentas.org" "Presupuestos")
       "** Presupuesto para %^{Cliente}
     :PROPERTIES:
     :Cliente:       %\\1
     :fecha:         %U
     :END:
  %T

  | Concepto                              | Precio (€) | Cantidad  | Total (€) |
  | <30>                                  | <9>        | <9>       | <9>       |
  |---------------------------------------+------------+-----------+-----------|
  | %?                                    |            |           |           |
  |                                       |            |           |           |
  |---------------------------------------+------------+-----------+-----------|
  | Total                                 |            |           |           |
  ,#+TBLFM: $4=$2*$3;%.2f::@>$4=vsum(@3..@-1);%.2f
  " :empty-lines 1)
  ;;; Lista de templates de captura para Frateco
          ("f" "Tareas para Frateco Esperanto")
          ("ff" "Tarea    (f) Frateco" entry (file+headline "~/agenda/agenda.org" "Esperanto")
           "* PENDIENTE %? \t :personal:
     DEADLINE: %(substring (call-interactively 'org-deadline) 12)
     :PROPERTIES:
     :CREATE:       %U
     :END:
     :LOGBOOK:
     - State  \"PENDIENTE\"            from \"\"      %U
     :END:" :empty-lines 1)
          ))

Lector de feeds

Para leer las noticias que suelen interesarme utilizo elfeed, que es la herramienta de Emacs para RSS.

    '(elfeed-feeds
      '("https://trasteandoconjess.es/feed"
        "https://write.privacytools.io/c3po/feed/"
        "https://56k.es/rss"
        "https://ciberpatrulla.com/blog/feed"
        "https://victorhckinthefreeworld.com/feed/"
        "https://jordila.librebits.info/feed/"
        "https://notxor.nueva-actitud.org/rss.xml"
        "https://pfctelepathy.wordpress.com/feed/"
        "https://ondahostil.wordpress.com/feed/"
        "https://priioajn.wordpress.com/feed/"
        "https://izaroblog.com/feed/"
        "https://elpinguinotolkiano.wordpress.com/feed/"
        "http://www.lapipaplena.org/feed/"
        "http://www.infocop.es/AreaRSS/"
        "http://www.copmadrid.org/wp/feed/"
        "https://lamiradadelreplicante.com/feed/"
        "https://mamalinuxera.wordpress.com/feed/"
        "https://zagueros.noblogs.org/feed/"
        "https://colaboratorio.net/feed/"
        "https://maxxcan.codeberg.page/rss.xml"
        "https://mierda.tv/feed/"
        "http://rufianenlared.com/feed/"
        "https://lwn.net/headlines/newrss"
        "https://luluvonflama.wordpress.com/feed/"
        "https://lamaldiciondelescritor.blogspot.com/feeds/posts/default"
        "https://www.atareao.es/feed/"
        "https://elbinario.net/feed/"
        "https://linuxenmovimiento.es/feed/"
        "https://www.muylinux.com/feed/"
        "http://asociacionpica.org/feed"
        "https://nueva-actitud.org/feed/"
        "https://fatimenia.wordpress.com/feed/"
        "https://clarosenelbosque.com/feed/"
        "http://worldbuildingschool.com/feed/"
        "https://ugeek.github.io/feed.xml"
        "http://lapiedradesisifo.com/feed/"
        "http://elblogdeiulius.es/feed/page:feed.xml"
        "http://planet.emacs-es.org/rss20.xml"
        "http://ruifigueiredo.me/rss.xml"
        "https://gnutas.juanmanuelmacias.com/rss.xml"
        "https://quijotelibre.com/feed/"
        "https://ciberpatrulla.com/feed/"
        "https://ekaitz.elenq.tech/feeds/all.atom.xml"
        "https://ebzzry.io/sitemap.xml"
        "http://muzaiko.info/public/podkasto/podkasto.rss"
        "https://unesperante.wordpress.com/feed/"
        "http://feeds.feedburner.com/VarsoviaVentoPodkasto"
        "http://www.esperanto.es/hef/index.php?format=feed&type=rss"
        "https://teokajlibroj.wordpress.com/feed/"
        "http://www.liberafolio.org/feed/"
        "https://eo.globalvoices.org/feed"
        "http://revuoesperanto.org/rss.xml"
        "http://eo.mondediplo.com/?page=backend"
        "https://bertilow.com/bertiloblogo/?feed=rss2"
        "https://scivolemo.wordpress.com/feed/"
        "http://feeds.feedburner.com/CuadernoDeCulturaCientfica"
        "https://lacienciaysusdemonios.com/feed/"
        "https://www.linux.com/feeds/rss"
        "http://planetkde.org/rss20.xml"
        "http://planet.kde-espana.org/atom.xml"
        "https://jordila.librebits.info/feed"
        "https://casatiajulia.com/blog/feed"
        "http://feeds.feedburner.com/blogelhackernet.xml"
        "https://elblogdelazaro.gitlab.io/index.xml"
        "https://www.davidrevoy.com/feed/rss"
        "https://adrianperales.com/feed/"
        "https://pedrolr.es/blog/feed/"))

Ajustes varios

Lo primero es ajustar algunos directorios donde Emacs puede buscar información para el sistema de ayuda Info o páginas de manual de erlang.

  '(Info-default-directory-list
    '("/usr/share/info/" "/usr/local/share/info/" "~/opt/share/info/"))
  '(edts-man-root "/home/notxor/.emacs.d/edts/doc/R7B")

Otros ajustes se refieren al sistema de corrección ortográfica al vuelo.

  '(ispell-dictionary "espanol")
  '(ispell-program-name "aspell")
  '(ispell-list-command "--list")

También los lenguajes con los que podemos ejecutar bloques de código dentro de org-mode. La función principal es utilizar la llamada programación literaria, del que el presente fichero es sólo un pequeño ejemplo.

  '(org-babel-load-languages
    '((dot . t)
      (plantuml . t)
      (org . t)
      (ledger . t)
      (python . t)
      (emacs-lisp . t)
      (scheme . t)
      (latex . t)
      (gnuplot . t)
      (sqlite . t)
      (shell . t)
      (awk . t)
      (sed . t)
      (tcl . t)
      (julia . t)
      (lua . t)))

Las dos líneas finales de este apartado son decirle a Emacs dónde encontrar el ejecutable (java) de la aplicación plantuml y la combinación de teclas C-M-p para que la establezca como teclas básicas de perspective. Por algún motivo, no deja que se defina en otro sitio que no sea en el bloque custom-variables y además con un formato críptico.

Establece que se visualicen las imágenes enlazadas y el código LaTeX embebido dentro del modo org-mode.

  '(org-plantuml-jar-path "~/opt/bin/plantuml.jar")
  '(persp-mode-prefix-key (kbd "C-x c"))
  '(org-startup-with-inline-images t)
  '(org-startup-with-latex-preview t)

Ajustes de aspecto y comportamiento

Algunos valores más para modificar el aspecto y/o comportamiento de Emacs cuando trabajamos con él.

  '(abbrev-suggest t)
  '(delete-selection-mode nil)
  '(display-line-numbers-type 'visual)
  '(face-font-family-alternatives
    '(("Monospace" "Deja Vu Mono" "Fira Code" "fixed")
      ("Monospace Serif" "Fire Code" "Consolas" "Deja Vu Sans" "FreeMono" "Nimbus Mono L" "courier" "fixed")
      ("courier" "CMU Typewriter Text" "fixed")
      ("Sans Serif" "helv" "helvetica" "arial" "fixed")
      ("helv" "helvetica" "arial" "fixed")))
  '(ansi-color-faces-vector
    [default default default italic underline success warning error])
  '(ansi-color-names-vector
    ["black" "red3" "ForestGreen" "yellow3" "blue" "magenta3" "DeepSkyBlue" "gray50"])
  '(column-number-mode t)
  '(custom-enabled-themes '(dracula))
  '(httpd-host 'local)
  '(indent-tabs-mode nil)
  '(pdf-view-midnight-colors '("#232629" . "#f8f8f2"))
  ;; Cuestiones `estéticas'
  '(inhibit-startup-screen t)             ;No muestra la pantalla de inicio por defecto de `Emacs'
  '(scroll-bar-mode nil)                  ;Elimina las barras de scroll
  '(tool-bar-mode nil)                    ;Elimina la barra de herramientas
  '(menu-bar-mode nil)                    ;Elimina el menú (accesible desde `<f10>')
  '(global-prettify-symbols-mode t)       ;Activa la sustitución de símbolos de manera global

  '(electric-pair-mode t)                 ;Activar el modo de autocierre de paréntesis
  '(truncate-lines t)                     ;Las líneas en una línea sin saltos
  '(show-paren-mode t)                    ;Remarca la pareja de un paréntesis (corchete, llave)
  '(which-key-mode t)                     ;Activa la sugerencia de teclas
  '(word-wrap t)
  '(org-fontify-emphasized-text t))       ;Activar la visualización de estilos de fuente
  ;; Establecer el tamaño de inicio de la ventana
  (add-to-list 'default-frame-alist '(width . 200)) ;Son valores en caracteres, dependen del tamaño de fuente
  (add-to-list 'default-frame-alist '(height . 58))
  (save-place-mode t)         ; Guarda la posición del cursor al cerrar un archivo
  (global-auto-revert-mode t) ; Recarga el contenido del buffer si ha cambiado el archivo en disco.
  (setq global-auto-revert-non-file-buffers t) ; recarga buffers como el de dired si ha cambiado

Envía los ficheros de backup a un directorio temporal.

  ;; Centralizando los ficheros temporales en el directorio temporal
  (setq backup-directory-alist
        `((".*" . ,temporary-file-directory)))
  (setq auto-save-file-name-transforms
        `((".*" ,temporary-file-directory t)))

Configuraciones de teclas generales y ganchos

En este apartado se establecen las teclas generales disponibles en todos los modos. Aunque es posible que alguna quede sobrescrita por alguna tecla local del modo utilizado. En general, se utiliza la convención de C-c, como tecla base.

  ;; Asignación de combinaciones de teclas globales
  (global-set-key (kbd "C-v")     'iedit-mode)
  (global-set-key (kbd "C-c a")   'org-agenda)
  (global-set-key (kbd "C-c b")   'ibuffer-sidebar-toggle-sidebar)
  (global-set-key (kbd "C-c c")   'org-capture)
  (global-set-key (kbd "C-c d")   'org-date-from-calendar)
  (global-set-key (kbd "C-c e")   'elfeed)
  (global-set-key (kbd "C-c g")   'glasses-mode)
  (global-set-key (kbd "C-x g")   'magit-status)
  (global-set-key (kbd "C-c i")   'org-caldav-sync)
  (global-set-key (kbd "C-c h")   'hl-line-mode)
  (global-set-key (kbd "C-c l")   'display-line-numbers-mode)
  (global-set-key (kbd "C-c r")   'swiper)
  (global-set-key (kbd "C-c s")   'dired-sidebar-toggle-sidebar)
  (global-set-key (kbd "C-c t")   'toggle-truncate-lines)
  (global-set-key (kbd "C-c w")   'whitespace-mode)
  (global-set-key (kbd "<C-return>") 'hs-toggle-hiding)
  (global-set-key (kbd "M-/")     'hippie-expand)
  ;; Configuración de auto-complete
  (global-set-key (kbd "M-TAB") 'auto-complete)

Los ganchos (hooks) sirven para establecer automáticamente modos según se activen o no otros.

  ;; Hooks asignados automáticamente a modos
  (add-hook 'text-mode-hook 'turn-on-auto-fill)
  (add-hook 'text-mode-hook 'turn-on-flyspell)
  (add-hook 'text-mode-hook 'hl-line-mode)
  (add-hook 'dired-mode-hook 'all-the-icons-dired-mode)
  (add-hook 'dired-mode-hook 'dired-git-mode)
  (add-hook 'dired-mode-hook 'auto-revert-mode) ; refresco de dired
  (add-hook 'ledger-mode-hook 'display-line-numbers-mode)
  (add-hook 'prog-mode-hook 'display-line-numbers-mode)
  (add-hook 'prog-mode-hook 'hs-minor-mode) ; para poder plegar funciones
  (add-hook 'prog-mode-hook 'hl-line-mode)
  (add-hook 'gdscript-mode 'whitespace-mode)
  (add-hook 'org-mode-hook 'org-superstar-mode) ; activar modo de visualización de cabeceras de un punto
  (add-hook 'ediff-prepare-buffer-hook #'show-all)
  (add-hook 'prog-mode-hook 'electric-pair-mode) ; activar pareja de paréntesis, llaves, etc.
  (add-hook 'xref-backend-functions #'dumb-jump-xref-activate) ; activar «jump to definition»

Instalación de paquetes

Preparadas todas las variables llega el turno a los paquetes que necesito instalar para mi trabajo. Algunos paquetes están instalados pero son de uso esporádico, habría que hacerles una limpia.

Paquetes de aspecto y comportamiento

El paquete org-caldav actualiza la agenda desde un servicio caldav como el Nextcloud particular mío:

  (use-package org-caldav
    :ensure t
    :defer t)

El paquete org-superstar es el sustituto de org-bullets que ha dejado de ser continuado. Hace la misma función de poner las cabeceras con caracteres más visuales.

  (use-package org-superstar
    :ensure t
    :defer t)

El paquete editorconfig cubre un estándar establecido para varios editores. Proporciona soporte para varias propiedades, como indente_style, charset, end_of_line o tab_width. Dichas propiedades se establecen en un archivo .editorconfig y serían comunes para todos los editores que soportan dicho esquema.

  (use-package editorconfig
    :ensure t
    :config
    (editorconfig-mode t))

En dicho fichero de configuración común para los distintos lenguajes, se puede establecer un comportamiento distinto para cada lenguaje o tipo de archivo. Por ejemplo, en mi sistema tengo el siguiente, sacado del ejemplo de la página web aunque retocado un poco a mi conveniencia:

  # EditorConfig is awesome: https://EditorConfig.org

  # top-most EditorConfig file
  root = true

  # Unix-style newlines with a newline ending every file
  [*]
  end_of_line = lf
  insert_final_newline = true
  charset = utf-8
  trim_trailing_whitespace = false

  # 4 space indentation
  [*.py]
  indent_style = space
  indent_size = 4

  # Tab indentation (no size specified)
  [Makefile]
  indent_style = tab

  # Indentation override for all JS under lib directory
  [lib/**.js]
  indent_style = space
  indent_size = 2

  # Matches the exact files either package.json or .travis.yml
  [{package.json,.travis.yml}]
  indent_style = space
  indent_size = 2

El paquete beacon remarca la posición del cursor cuando entras en un buffer. Hace un vistoso guiño que te permite descubrir de un sólo vistazo dónde está. A parte de la vistosidad, viene muy bien cuando trabajas con muchos buffers abiertos.

  ;; Resalte de la posición del cursor al cambiar de `buffer'
  (use-package beacon
    :ensure t
    :config
    (beacon-mode t))

El paquete powerline embellece la linea de estado de Emacs haciéndola más vistosa.

  ;; Mejorando la visualización de la línea de estado
  (use-package powerline
    :ensure t
    :config
    (powerline-default-theme)
    (setq powerline-default-separator 'rounded))

El paquete heaven-and-hell permite tener definidos un par de temas, uno claro y uno oscuro, e intercambiarlos con la pulsación de una tecla. A veces, trabajando fuera al aire libre, los temas oscuros no se ven con claridad y necesito cambiar a un tema claro. Como tema claro utilizo el famoso dracula y como tema claro uno de los que ya viene instalado por defecto: tsdh-light. También se puede cambiar al tema claro que se establece por defecto al arrancar Emacs:

  • C-c <F6>: cambia al tema por defecto de Emacs
  • <F6>: intercambia los temas, el claro y el oscuro.

Ambas teclas no llaman directamente a las funciones de heaven-and-hell sino que llaman a las funciones definidas en este archivo de configuración para restablecer powerline después de haber cambiado el tema de color.

  (use-package heaven-and-hell
    :ensure t
    :init
    (setq heaven-and-hell-theme-type 'dark) ;; Omit to use light by default
    (setq heaven-and-hell-themes
          '((light . tsdh-light)
            (dark . dracula))) ;; Se puede sustituir por (dark . (tsdh-dark wombat))
    ;; Optionall, load themes without asking for confirmation.
    (setq heaven-and-hell-load-theme-no-confirm t)
    :hook ((after-init . heaven-and-hell-init-hook)))

  (defun ajuste-powerline-theme ()
    "Hace un reset de la powerline tras cambiar el tema."
    (interactive)
    (heaven-and-hell-toggle-theme)
    (powerline-reset))

  (defun ajuste-powerline-default-theme ()
    "Hace un reset de la powerline tras cambiar al tema por defecto."
    (interactive)
    (heaven-and-hell-load-default-theme)
    (powerline-reset))

  (global-set-key (kbd "C-c <f6>") 'ajuste-powerline-default-theme)
  (global-set-key (kbd "<f6>")     'ajuste-powerline-theme)

El código para hacer el fondo de Emacs transparente está comentado para desactivarlo. Queda vistoso pero es molesto para trabajar, alguna vez lo activo, pero sólo en modo presentación.

  ;; Fondo de Emacs transparente
  ;;(set-frame-parameter (selected-frame) 'alpha '(92 . 90))
  ;;(add-to-list 'default-frame-alist '(alpha . (92 . 90)))

Establecer y activar el plegado de código con hs-minor-mode asignándole las teclas necesarias, partiendo de M-p.

  ;; Activar plegado de código con hs-minor-mode
  ;; HIDE
  (global-set-key (kbd "M-p t") 'hs-hide-all)
  (global-set-key (kbd "M-p d") 'hs-hide-block)
  (global-set-key (kbd "M-p c") 'hs-hide-comment-region)
  (global-set-key (kbd "M-p l") 'hs-hide-level)
  ;; SHOW
  (global-set-key (kbd "M-p a") 'hs-show-all)
  (global-set-key (kbd "M-p s") 'hs-show-block)
  ;; TOGGLE
  (global-set-key (kbd "M-p e") 'hs-toggle-hiding)
  ;; JUMP
  (global-set-key (kbd "M-p i") 'imenu)

All-the-icons proporciona iconos gráficos para usarse en otros paquetes.

  (use-package all-the-icons
    :ensure t)

Dashboard es un paquete que sustituye la página inicial de Emacs proporcionando información sobre aspectos habituales: abrir algún fichero que hemos abierto hace poco, o proyecto. También nos muestra una lista de las actividades de la agenda más cercanas… y es un arranque vistoso.

  (use-package dashboard
    :ensure t
    :config
    (dashboard-setup-startup-hook))

  (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
  ;; Establece el título
  (setq dashboard-banner-logo-title "Bienvenido a Emacs Dashboard")
  ;; Establece la cartelera
  (setq dashboard-startup-banner 'logo)
  (setq dashboard-items '((recents  . 5)
                          (bookmarks . 5)
                          (projects . 5)
                          (agenda . 10)
                          (registers . 5)))

  ;; Centra el contenido de la pantalla
  (setq dashboard-center-content t)

  ;; Mostar el atajo de salto al lado de la cabecera
  (setq dashboard-show-shortcuts nil)

Paquetes de utilidad

El paquete ivy es un entrometido que lo quiere gestionar y mover todo, pero resulta muy útil porque lo muestra de manera más clara y sencilla de entender que el comportamiento por defecto. Nos muestra alternativas del comando que estamos tecleando, tiene autocompletado y otras funciones que nos hacen la vida más sencilla.

Counsel

  (use-package counsel
    :ensure t)

Ivy

Hay dos grandes paquetes de ayuda (completados, listados, sugerencias) para el usuario de Emacs uno es helm, pero yo utilizo ivy pues lo noto más ligero y agradable que el anterior.

  ;; Configurar ivy
  ;; add recentf-mode and bookmarks to ivy-switch-buffer.
  (use-package ivy
    :ensure t
    :init
    (setq ivy-use-virtual-buffers t
          ivy-height 15                             ; muestra 15 líneas de información (por defecto son 10)
          ivy-count-format ""                       ; no mostrar el contador
          ivy-initial-inputs-alist nil)
    :config
    (ivy-mode t))
  (use-package all-the-icons-ivy
    :init (add-hook 'after-init-hook 'all-the-icons-ivy-setup))
  (use-package all-the-icons-ivy-rich
    :ensure t
    :init (all-the-icons-ivy-rich-mode t))
  (use-package ivy-rich
    :ensure t
    :config
    (ivy-rich-mode t))

  (defun ivy-rich-switch-buffer-icon (candidate)
    (with-current-buffer
        (get-buffer candidate)
      (let ((icon (all-the-icons-icon-for-mode major-mode)))
        (if (symbolp icon)
            (all-the-icons-icon-for-mode 'fundamental-mode)
          icon))))
  (setq ivy-rich-display-transformers-list
        '(ivy-switch-buffer
          (:columns
           ((ivy-rich-switch-buffer-icon (:width 2))
            (ivy-rich-candidate (:width 30))
            (ivy-rich-switch-buffer-size (:width 7))
            (ivy-rich-switch-buffer-indicators (:width 4 :face error :align right))
            (ivy-rich-switch-buffer-major-mode (:width 12 :face warning))
            (ivy-rich-switch-buffer-project (:width 15 :face success))
            (ivy-rich-switch-buffer-path (:width (lambda (x) (ivy-rich-switch-buffer-shorten-path x (ivy-rich-minibuffer-width 0.3))))))
           :predicate
           (lambda (cand) (get-buffer cand)))))
  (setq all-the-icons-ivy-rich-icon t)
  (setq all-the-icons-ivy-rich-color-icon t)
  (setq all-the-icons-ivi-rich-icon-size 1.0)
  (setq all-the-icons-ivy-rich-field-width 80)

Gestión de proyectos

La gestión de proyectos la realiza projectile. La instalación es muy básica: se le dice un directorio donde los guardamos y también se activa el completado con ivy.

  ;; Configuración para projectile
  (use-package projectile
    :ensure t
    :bind-keymap (("C-c p" . projectile-command-map))
    :init
    (setq projectile-project-search-path '("~/proyectos/"))
    (setq projectile-completion-system 'ivy)
    (projectile-mode t))
  ;; autocompletado para `projectile'
  (use-package flycheck-projectile
    :ensure t
    :defer t)

Yasnippet

El paquete yasnippet permite gestionar pequeños trozos de texto, plantillas de programación y lo que se quiera introducir para ahorrar tiempo y quebraderos de cabeza cuando trabajamos.

  ;; gestión de plantillas yasnippet
  (use-package yasnippet
    :ensure t
    :defer t)

  (use-package ivy-yasnippet
    :ensure t
    :defer t)

  ;; colección de plantillas para yasnippet
  (use-package yasnippet-snippets
    :ensure t
    :defer t)

  ;; activar yasnippet donde es necesario
  (add-hook 'org-mode-hook 'yas-minor-mode)
  (add-hook 'prog-mode-hook 'yas-minor-mode)

  ;; asociar tecla con mostrar lista de snippets
  (global-set-key (kbd "C-c & y") 'ivy-yasnippet)

eldoc-box

Este paquete muestra en un frame hijo la información del elemento sobre el que se encuentra el cursor:

  (use-package eldoc-box
    :ensure t
    :defer t
    :init (setq eldoc-box-hover-mode t))

Which key

El paquete which-key muestra en el minibuffer las combinaciones de teclas disponibles después de haber pulsado una. Por ejemplo, cuando pulsamos C-x nos muestra todas las posibles opciones con una lista de tecla--comando.

  (use-package which-key
    :ensure t
    :init
    (which-key-setup-minibuffer)
    (which-key-mode))

Presentaciones

   (use-package org-tree-slide
    :defer t)
  (setq org-tree-slide-indicator
    '(:next "Siguiente >>" :previous "<<  Anterior" :content "<<  Contenido  >>"))

  (when (require 'org-tree-slide nil t)
    (define-key org-mode-map (kbd "<f8>") 'org-tree-slide-mode)
    (define-key org-mode-map (kbd "S-<f8>") 'org-tree-slide-skip-done-toggle)
    (define-key org-tree-slide-mode-map (kbd "C->")
      'org-tree-slide-move-previous-tree)
    (define-key org-tree-slide-mode-map (kbd "C-<")
      'org-tree-slide-move-next-tree)
    (define-key org-tree-slide-mode-map (kbd "C-x s c")
      'org-tree-slide-content)
    (setq org-tree-slide-skip-outline-level 4)
    (org-tree-slide-narrowing-control-profile)
    (setq org-tree-slide-skip-done nil))

Utilización de perspectivas

El paquete perspective proporciona espacios de trabajo separados en Emacs, parecido a cómo se trabaja en diferentes escritorios en los gestores de ventanas. Muestra las etiquetas de cada espacio de trabajo en la línea de estado, remarcando el que esté activo.

  (use-package perspective
    :ensure t
    :init
    (persp-mode t))

Navegador

w3m es un navegador para consola externo a Emacs. Este paquete proporciona la funcionalidad necesaria para utilizarlo dentro de un buffer de Emacs.

  (use-package w3m
    :ensure t
    :defer t)

Base de datos de contactos

Es una base de datos poco intuitiva. La guardo cifrada con GPG aunque Emacs la abre directamente sin preguntar nada, tiene accesible la clave. Eso me permite guardar las copias de seguridad e incluso enviar(me)la sin afectar a la seguridad.

  ;; Preparando la base de datos bbdb
  (use-package bbdb
    :init
    (setq bbdb-file "~/agenda/especiales/bbdb.gpg"
          bbdb-phone-style nil)
    :defer t
    :config
    (bbdb-initialize))

Paquetes añadidos a org

Este paquete tiene un compendio amplio de utilidades para org-mode. En particular lo instalo por la utilidad de exportación ox-bibtex y la de embellecimiento org-bullet-mode.

  (use-package org-contrib
    :defer t
    :after org
    :config
    (require 'ox-extra)
    (ox-extra-activate '(ignore-headlines)))

Contabilidad

Para la contabilidad utilizo la aplicación ledger. El paquete de autocompletado de ledger lleva un tiempo dando errores, por eso lo pongo aquí comentado.

  ;;configuración para contabilidad
  (use-package ledger-mode
    :ensure t
    :defer t
    :config
    (setq ledger-reconcile-default-commodity "€"
          ledger-default-date-format "%Y-%m-%d"))
  (autoload 'ledger-mode "ledger-mode" "Modo mayor para Ledger" t)
  (add-to-list 'auto-mode-alist '("\\.ledger$" . ledger-mode))
  (add-hook 'ledger-mode-hook
            (lambda ()
              (setq-local tab-always-indent 'complete)
              (setq-local completion-cycle-threshold t)
              (setq-local ledger-complete-in-steps t)))

  (use-package company-ledger
     :ensure t
     :defer t
     :after company)

  (use-package flycheck-ledger
    :ensure t
    :defer t
    :after flycheck)

Lector de feeds

También utilizo Emacs como lector de feeds. El paquete que me lo facilita es elfeed.

  (use-package elfeed
    :defer t
    :ensure t)

Paquete del blog

  (load-file "~/.emacs.d/notxor-blog/notxor-blog.el")
  ;; (use-package notxor-blog
  ;;   :load-path "~/.emacs.d/notxor-blog/"
  ;;   :defer t
  ;;   :ensure t)

Lector de libros electrónicos

Para utilizar Emacs como lector de archivos .epub

  ;;(use-package visual-line-mode
  ;;  :defer t)

  (use-package nov
    :defer t
    :config
    (setq nov-text-width 70
          visual-fill-column-center-text t))
  (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
  (add-hook 'nov-mode-hook 'visual-line-mode)
  (add-hook 'nov-mode-hook 'visual-fill-column-mode)

Gestión de anotaciones

La captura de notas la puse más arriba en la definición de variables. Esas notas, capturadas al vuelo, se guardan en ficheros aparte de la gestión de notas más científica que mantengo después. Activo un registro para acceder directamente a la apertura de un fichero de notas para después clasificarlas y pasarlas al sistema de anotaciones.

Registro para notas rápidas

Establece un registro de acceso directo para anotar directamente sin necesidad de buscar dónde.

  ;; Guardar en un registro el fichero de bitácora para abrirlo en cualquier momento
  (set-register ?a '(file . "~/agenda/bloc-notas.org"))
Paquete de notas y Zettelkasten

Sistema de toma de notas estandarizado con los principios del Zettelkasten. Si no sabes de lo que estoy hablando echa un ojo a mi blog y lo sabrás, encontrarás una entrada donde explico todo el proceso y lo que significa cada línea de este apartado.

  ;; Tomar notas
  (use-package deft
    :ensure t
    :bind ("<f5>" . deft)
    :commands (deft deft-refresh)
    :config (setq deft-directory "~/Nextcloud/Notes"
                  deft-extensions '("org" "md" "txt")
                  deft-use-filename-as-title t))

  (use-package zetteldeft
    :ensure t
    :after deft
    :config (zetteldeft-set-classic-keybindings))

  (setq zetteldeft-title-suffix "\n#+tags: #")
  (setq deft-default-extension "org")
  (setq zetteldeft-backlink-prefix "- Backlink: ")

  ;; Cambio de directorio Deft
  (defun deft-cambio-dir (dir)
    "Cambiar de directorio Deft al `DIR' de forma interactiva."
    (interactive "DNuevo directorio Deft: ")

    (message (format "Se cambia def-directory a: %s" dir))
    (setq deft-directory (expand-file-name dir))
    (deft-refresh))

  (defun deft-recursivo ()
    "Establece que `deft' busque también en subdirectorios."
    (interactive)
    (setq deft-recursive t)
    (deft-refresh))

  (defun deft-no-recursivo ()
    "Hace que `deft' no busque en subdirectorios."
    (interactive)
    (setq deft-recursive nil)
    (deft-refresh))

  (global-set-key (kbd "C-<f5>") #'deft-cambio-dir)
  (global-set-key (kbd "M-<f5>") #'deft-recursivo)
  (global-set-key (kbd "S-<f5>") #'deft-no-recursivo)

Se han añadido tres funciones para controlar qué notas aparecen en el listado de deft. La primera deft-cambio-dir modifica el directorio que se cargará. Por defecto se establece a ~/Nextcloud/Notes, pero se puede establecer a cualquier otro. Al cambiar de directorio se refresca el listado de notas. También se puede hacer que busque en subdirectorio o no. Las teclas mapeadas para estas funciones son:

  • C-<f5> cambia el directorio.
  • M-<f5> hace la búsqueda de notas recursiva en subdirectorios.
  • S-<f5> restringe la búsqueda al directorio seleccionado.

Notas con org-roam de prueba

De momento mantengo las notas en el sistema anterior… estoy estudiando la viabilidad de mudarlas a org-mode, que pinta se un trabajo largo y tedioso después de años tomando notas.

Primero instalamos las dependencias a sqlite y magit:

  (use-package emacsql
    :ensure t)
  (use-package emacsql-sqlite
    :ensure t
    :after 'emacsql)

Después el paquete org-roam:

  (use-package org-roam
  :ensure t
  :custom
  (org-roam-directory (file-truename "~/Notas"))
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         :map org-mode-map
         ("C-M-i" . completion-at-point)
         ;; Dailies
         ("C-c n j" . org-roam-dailies-capture-today))
  :config
  ;; If you're using a vertical completion framework, you might want a more informative completion interface
  (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
  (org-roam-db-autosync-mode)
  ;; If using org-roam-protocol
  (require 'org-roam-protocol))

Después del paquete base es recomendable instalar el UI, por aquello de la vistosidad:

  (use-package websocket
    :after org-roam)

  (use-package org-roam-ui
    :after org-roam
    :config
    (setq org-roam-ui-sync-theme t
          org-roam-ui-follow t
          org-roam-ui-update-on-save t
          org-roam-ui-open-on-start t))

También configuro denote para probarlo.

  ;;; instalación de denote

  (use-package denote
    :defer t
    :config
    (setq denote-directory (expand-file-name "~/denotas/")
          denote-known-keywords '("emacs" "cie-11" "blog")
          denote-infer-keywords t
          denote-sort-keywords t
          denote-prompts '(title keywords)
          denote-date-prompt-use-org-read-date t
          denote-backlinks-show-context t))

  (add-hook 'find-file-hook #'denote-link-buttonize-buffer)

  ;;(require 'denote-journal-extras.el)
  (setq denote-journal-extras-directory "~/denotas/diario")
  (setq denote-journal-extras-title-format 'day-date-month-year)

  ;; Keybindings para denote
  (let ((map global-map))
    (define-key map (kbd "C-c z j") #'denote-journal-extras-new-or-existing-entry) ; entrada a diario
    (define-key map (kbd "C-c z n") #'denote)
    (define-key map (kbd "C-c z N") #'denote-type)
    (define-key map (kbd "C-c z o") #'denote-open-or-create)
    (define-key map (kbd "C-c z d") #'denote-date)
    (define-key map (kbd "C-c z z") #'denote-signature) ; "zettelkasten" mnemonic
    (define-key map (kbd "C-c z s") #'denote-subdirectory)
    (define-key map (kbd "C-c z t") #'denote-template)
    ;; If you intend to use Denote with a variety of file types, it is
    ;; easier to bind the link-related commands to the `global-map', as
    ;; shown here.  Otherwise follow the same pattern for `org-mode-map',
    ;; `markdown-mode-map', and/or `text-mode-map'.
    (define-key map (kbd "C-c z i") #'denote-link) ; "insert" mnemonic
    (define-key map (kbd "C-c z l") #'denote-link-or-create)
    (define-key map (kbd "C-c z I") #'denote-add-links)
    (define-key map (kbd "C-c z b") #'denote-backlinks)
    (define-key map (kbd "C-c z f f") #'denote-find-link)
    (define-key map (kbd "C-c z f b") #'denote-find-backlink)
    ;; Note that `denote-rename-file' can work from any context, not just
    ;; Dired bufffers.  That is why we bind it here to the `global-map'.
    (define-key map (kbd "C-c z r") #'denote-rename-file)
    (define-key map (kbd "C-c z R") #'denote-rename-file-using-front-matter))

  ;; Key bindings specifically for Dired.
  (let ((map dired-mode-map))
    (define-key map (kbd "C-c C-d C-i") #'denote-link-dired-marked-notes)
    (define-key map (kbd "C-c C-d C-r") #'denote-dired-rename-marked-files)
    (define-key map (kbd "C-c C-d C-R") #'denote-dired-rename-marked-files-using-front-matter))

El paquete denote-menu muestra las notas de denote en forma de tabla:

  (use-package denote-menu
    :defer t)

  (global-set-key (kbd "C-c z m") #'denote-menu-list-notes)

Paquetes de programación

auto-tangle

El paquete org-auto-tangle se utiliza para que al guardar un archivo org que estamos editando, automáticamente haga el tangle del código a sus correspondientes ficheros. Si se usa la programación literaria es un paquete muy útil que nos ahorra tiempo (y nos evita errores).

  (use-package org-auto-tangle
    :defer t)
    ;; :hook (org-mode . org-auto-tangle-mode)
    ;; :config
    ;; (setq org-auto-tangle-default t))

Comprobación de código

El paquete flycheck comprueba el código al vuelo detectando errores y avisando de posibles problemas. Hay que instalar también los paquetes para cada lenguaje de programación utilizado.

  ;; configuración para flycheck
  (use-package flycheck
    :ensure t
    :init (global-flycheck-mode))

Control de versiones

Otras herramientas importantes son las destinadas al control de versiones: magit y va-fossil. Cada una de estas aportan facilidades para el uso de git y de fossil respectivamente.

  ;;magit
  (use-package magit
    :ensure t)
  (use-package magit-stats
    :ensure t)
  ;; fossil
  (use-package vc-fossil
    :defer t)

Cursores múltiples

El paquete iedit permite modificar el nombre de una variable en todas las apariciones que haga en un buffer a la vez. En la configuración de teclas generales utilizo la combinación C-v para activarlo y desactivarlo. El procedimiento es muy sencillo:

  1. Situar el punto sobre la variable cuyo nombre queremos modificar.
  2. Activar iedit. Mostrará el nombre remarcado a lo largo del buffer.
  3. Modificar el texto resaltado. Veremos cómo se van cambiando también el resto de apariciones del nombre.
  ;; Configurar iedit
  (use-package iedit
    :ensure t)

Árbol de directorios

Mientras programo o escribo me gusta tener la barra de directorios situada a la izquierda del frame y poder acceder a toda la funcionalidad que proporciona dired sin necesidad de abrir toda una sucesión de buffers. Además, utilizo la integración de git con dired y la utilización de iconos más vistosos con el paquete all-the-icons.

  ;; Ajustes de dired-sidebar
  ;;(setq dired-sidebar-subtree-line-prefix "->")
  (use-package dired-sidebar
    :ensure t
    :defer t
    :commands (dired-sidebar-toggle-sidebar)
    :init
    (setq dired-sidebar-theme 'nerd)
    (setq dired-sidebar-use-term-integration t)
    (setq dired-sidebar-use-custom-font t))

  (use-package dired-git
    :ensure t)

  (use-package all-the-icons
    :ensure t)
  (use-package all-the-icons-dired
    :ensure t)
  (use-package all-the-icons-ibuffer
    :ensure t
    :init (all-the-icons-ibuffer-mode t))

Lista de buffers

El siguiente paquete me permite abrir una lista de buffers en la sidebar, compartiéndola con el anterior dired-sidebar.

  (use-package ibuffer-sidebar
    :defer t)

Utilidad de shell

El siguiente paquete permite tener un terminal rápido e integrado con eshell en varios buffers de Emacs.

  ;; Proporciona terminal flexible
  (use-package eat
    :ensure t
    :defer t)

Soporte para autocompletado

Es el modo general de autocompletado de Emacs. Para algunos lenguajes se deben instalar los paquetes específicos.

  ;; Activar autocompletado general
  (use-package company
    :ensure t
    :init
    (setq company-tooltip-align-annotations t)
    :config
    (global-company-mode t))
  ;;(use-package corfu
    ;; Optional customizations
    ;; :custom
    ;; (corfu-cycle t)                ;; Enable cycling for `corfu-next/previous'
    ;; (corfu-auto t)                 ;; Enable auto completion
    ;; (corfu-separator ?\s)          ;; Orderless field separator
    ;; (corfu-quit-at-boundary nil)   ;; Never quit at completion boundary
    ;; (corfu-quit-no-match nil)      ;; Never quit, even if there is no match
    ;; (corfu-preview-current nil)    ;; Disable current candidate preview
    ;; (corfu-preselect-first nil)    ;; Disable candidate preselection
    ;; (corfu-on-exact-match nil)     ;; Configure handling of exact matches
    ;; (corfu-echo-documentation nil) ;; Disable documentation in the echo area
    ;; (corfu-scroll-margin 5)        ;; Use scroll margin

    ;; Enable Corfu only for certain modes.
    ;; :hook ((prog-mode . corfu-mode)
    ;;        (shell-mode . corfu-mode)
    ;;        (eshell-mode . corfu-mode))

    ;; Recommended: Enable Corfu globally.
    ;; This is recommended since Dabbrev can be used globally (M-/).
    ;; See also `corfu-excluded-modes'.
  ;;  :init
  ;;  (global-corfu-mode))

  ;;(setq tab-always-indent 'complete)

Soporte para la comprobación de sintaxis

  (use-package flycheck
    :ensure t
    :defer t)

Citas bibliográficas para org-mode

El paquete citar permite la gestión de una base de datos de citas bibliográficas estilo bibtex e incluir citas en org-mode y anotaciones.

  (use-package citar
    :no-require
    :custom
    (org-cite-global-bibliography '("~/denotas/referencias.bib"))
    (org-cite-insert-processor 'citar)
    (org-cite-follow-processor 'citar)
    (org-cite-activate-processor 'citar)
    (citar-bibliography org-cite-global-bibliography)
    :bind
    (("C-c k c o" . citar-open)
     (:map org-mode-map
           :package org
           ("C-c k C" . #'org-cite-insert))))

La combinación de teclas para insertar una nota en org-mode es C-c C-x C-@. Además se utiliza el paquete que permite la interacción entre citar y denote.

  (use-package citar-denote
    :custom
    ;; Use package defaults
    (citar-open-always-create-notes nil)
    (citar-denote-file-type 'org)
    (citar-denote-subdir nil)
    (citar-denote-keyword "bib")
    (citar-denote-use-bib-keywords nil)
    (citar-denote-title-format "title")
    (citar-denote-title-format-authors 1)
    (citar-denote-title-format-andstr "and")
    :init
    (citar-denote-mode)
    ;; Bind all available commands
    :bind (("C-c k c c" . citar-create-note)
           ("C-c k c n" . citar-denote-open-note)
           ("C-c k c d" . citar-denote-dwim)
           ("C-c k c e" . citar-denote-open-reference-entry)
           ("C-c k c a" . citar-denote-add-citekey)
           ("C-c k c k" . citar-denote-remove-citekey)
           ("C-c k c r" . citar-denote-find-reference)
           ("C-c k c f" . citar-denote-find-citation)
           ("C-c k c l" . citar-denote-link-reference)))

Lenguajes de marcado de texto

Soporte para asciidoc

No lo uso mucho… hace un tiempo colaboré con un proyecto que utilizaba como lenguaje de formateo el asciidoc y aún no lo he quitado… por si lo vuelvo a necesitar.

  ;; Paquete para asciidoc
  (use-package adoc-mode
    :defer t)
  (add-to-list 'auto-mode-alist '("\\.asciidoc\\'" . adoc-mode))

Soporte para LaTeX

Configuración para LaTeX. El soporte de TeX en general viene con la instalación base de Emacs. Lo único que hago en esta configuración es ajustar algunos comportamientos. También tuve un tiempo instalado el paquete ox-tufte, que proporciona la posibilidad de exportar un documento para el paquete de LaTeX tufte. Los documentos que genera ese paquete son realmente vistosos, si se trata de maquetar un libro: una columna con un amplio margen donde mostrar notas, gráficos y tablas pequeñas. Realmente interesante.

  (use-package auctex
    :defer t)
  ;; Ajustes para AUCTeX
  (setq TeX-view-program-selection
        '(((output-dvi has-no-display-manager)
           "dvi2tty")
          ((output-dvi style-pstricks)
           "dvips and gv")
          (output-dvi "xdvi")
          (output-pdf "xdg-open")
          (output-html "xdg-open")))
  (add-hook 'LaTeX-mode-hook (lambda ()(TeX-electric-math t)))
  (add-hook 'LaTeX-mode-hook 'turn-on-cdlatex)               ;Activar CDLaTeX
  (add-hook 'LaTeX-mode-hook (lambda ()(company-mode 1)))    ;Activar Autocompletado
  (company-auctex-init)
  (add-hook 'LaTeX-mode-hook (lambda ()(TeX-fold-mode 1)))   ;Activar el plegado
  (add-hook 'LaTeX-mode-hook 'latex-extra-mode)
  (add-hook 'LaTeX-mode-hook 'display-line-numbers-mode)

  ;; (use-package ox-tufte
  ;;   :defer t)

  ;; Soporte de autocompletado para LaTeX
  (use-package company-auctex
    :ensure t
    :after auctex)

Gestión de citas bibliográficas

  ;; Managing Bibliographies
  (use-package bibtex
    :custom
    (bibtex-dialect 'BibTeX)
    (bibtex-user-optional-fields
     '(("Etiquetas" "Etiquetas para describir la entrada" "")
       ("archivo" "Enlace a un documento." "" )))
    (bibtex-align-at-equal-sign t))

Normalmente gestiono las citas bibliográficas en formato bib con la aplicación JabRef. Sin embargo, me he encontrado en ocasiones la necesidad de gestionarlas en CSL (Citation Style Language). El paquete citeproc permite dicha gestión y para hacerlo desde org-mode se necesita el paquete citeproc-org

  (use-package citeproc
    :defer t
    :ensure t)
  (use-package citeproc-org
    :defer t
    :ensure t
    :after citeproc)

Soporte para PlantUML

Uno de los paquetes más útiles para hacer gráficos, desde org-mode también, es PlantUML. Como su nombre indica su especialidad son los esquemas gráficos UML, pero también realiza multitud de diagramas no UML, como los ditaa, Gantt, mapas mentales, etc. El la configuración de variables se ajusta la localización del ejecutable jar (es una herramienta Java).

  (use-package plantuml-mode
    :defer t)

Soporte para ficheros gráficos pikchr

El sistema de generación de gráficos pikchr es heredero de la herramienta pic de U*ix y su versión libre gpic. En mi blog hay una explicación más extensa sobre la herramienta.

  (use-package pikchr-mode
    :defer t)

web-mode

Este modo viene por defecto instalado con Emacs, tan solo añado algunas extensiones de archivo a la lista que se deben tratar con el modo.

  ;; Configurar web-mode
  (use-package web-mode)
  (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.js[x]?\\'" . web-mode))

Montar un servidor local para pruebas

Poder montar un servidor de pruebas para visualización de la página. Por defecto, está configurado para visualizar el directorio donde se carga el blog y se sirva por el puerto 8080.

  (use-package simple-httpd
    :ensure t
    :defer t
    :config (setq httpd-port 8080
                  httpd-root "~/public_html"))

Lenguajes de programación

gnuplot

GNUplot es una aplicación que permite dibujar gráficos a partir de tablas de datos.

  (use-package gnuplot
    :ensure t
    :defer t)
  (autoload 'gnuplot-mode "gnuplot" "Gnuplot major mode" t)
  (autoload 'gnuplot-make-buffer "gnuplot" "open a buffer in gnuplot-mode" t)
  (setq auto-mode-alist (append '(("\\.gp$" . gnuplot-mode)) auto-mode-alist))

scheme

Entorno de programación para scheme.

  (use-package geiser
    :ensure t
    :defer t)

  (use-package geiser-guile
    :after geiser
    :defer t)

  (use-package geiser-mit
    :after geiser
    :defer t)

  (use-package geiser-chibi
    :after geiser
    :defer t)

  (use-package geiser-chicken
    :after geiser
    :defer t)

  (use-package flycheck-guile
    :defer t)

lisp

Entorno de programación para lisp.

  (load (expand-file-name "~/quicklisp/slime-helper.el"))

  (use-package slime
    :defer t
    :config
    (setq inferior-lisp-program "/usr/bin/sbcl"))

  (use-package slime-company
    :defer t
    :after slime)

Clojure

Entorno de programación para Clojure.

  (use-package clojure-mode
    :defer t)
  (use-package cider
    :defer t)
  (use-package flycheck-clojure
    :defer t)
  (use-package clojure-snippets
    :ensure t)
  (use-package ivy-clojuredocs
    :ensure t)
  (use-package clj-refactor
    :defer t)
  (use-package cljr-ivy
    :defer t)

Además se puede instalar información sobre el lenguaje para consultarlo directamente desde Emacs

  (use-package clojure-essential-ref
    :defer t
    :bind (
           :map cider-mode-map
           ("C-h F" . clojure-essential-ref)
           :map cider-repl-mode-map
           ("C-h F" . clojure-essential-ref)))

lua

Paquetes para la programación con el lenguaje lua. También hay un paquete para gestionar lua-rocks, la herramienta de control de paquetes del lenguaje, pero que instalo porque tampoco utilizo demasiado éste.

  (use-package lua-mode
    :defer t)
  ;; autocompletado para `lua'
  (use-package company-lua
    :defer t)
  (use-package flymake-lua
    :defer t)

Tcl/Tk

El lenguaje Tcl/Tk es otro de los soportados por Emacs sin necesidad de instalar nada. Lo único que hago es añadir a la lista de extensiones automáticas la extensión .test para que la admita como propia de Tcl y facilitarme la edición de las pruebas unitarias.

  ;; Añadir extensión `.test' para `tcl-mode'
  (add-to-list 'auto-mode-alist '("\\.test\\'" . tcl-mode))

Soporte C++

  (use-package modern-cpp-font-lock
    :ensure t
    :init
    (add-hook 'c++-mode-hook #'modern-c++-font-lock-mode))

Programación en Python

Últimamente no utilizo demasiado el lenguaje Python. Dicho lenguaje cuenta con paquete instalado con la base de Emacs pero sólo colorea sintaxis y poco más. El paquete elpy proporciona las herramientas necesarias para trabajar con Python en Emacs. También puedes configurar elpy llamando a elpy-config, pero exige tener instalada la aplicación pip para poder instalar los paquetes de Python que se necesiten.

Otra opción sería instalar lsp y el soporte para este lenguaje.

  ;; Configuración del entorno elpy para Python
  (use-package elpy
    :ensure t
    :defer t
    :config
    (setq python-shell-interpreter "python3")
    (setq elpy-rpc-python-command "python3")
    :init
    (advice-add 'python-mode :before 'elpy-enable))

Programación en erlang

El paquete edts proporciona todas las herramientas necesarias para programar en erlang en Emacs. También se puede recurrir a la instalación del paquete lsp y el servidor específico de erlang para hacerlo. Pero esto es mucho más simple.

  ;; Configurar el sitio de erlang
  (use-package edts
    :defer t)

Programación en julia

  (use-package julia-mode
    :defer t)
  (use-package julia-repl
    :defer t
    :init
    (add-hook 'julia-mode-hook 'julia-repl-mode))
  (use-package flycheck-julia
    :defer t)

Programación en Janet

  (use-package janet-mode
    :defer t)
  (add-to-list 'auto-mode-alist '("\\.janet\\'" . janet-mode))

Programación en Nim

  (use-package nim-mode
    :defer t)
  (use-package flycheck-nim
    :defer t)
  (use-package flycheck-nimsuggest
    :defer t)
  (use-package ob-nim
    :defer t)
  (add-hook 'nim-mode-hook 'nimsuggest-mode)

Programación con PicoLisp

No está en la lista de paquetes de Melpa, se añade temporalmente incluyéndolo desde la descarga directa del repositorio. Puede desaparecer en un futuro próximo, dependiendo de si me termina convenciendo picolisp o no.

OpenStreetMap en Emacs

(use-package osm :bind (("C-c m h" . osm-home) ("C-c m s" . osm-search) ("C-c m v" . osm-server) ("C-c m t" . osm-goto) ("C-c m x" . osm-gpx-show) ("C-c m j" . osm-bookmark-jump)) :custom (osm-server 'default) (osm-copyright t) :init (with-eval-after-load 'org (require 'osm-ol)))

Fin

Modificación de tipos de letra

Se modifica el aspecto de algunos tipos de letra, concretamente el tipo por defecto será DejaVu Sans Mono.

También se cambian los tamaños de los encabezados cuando Emacs se encuentre en modo presentación con org-tree-slide, para hacerlos más grandes y más similares a lo que la gente espera en una presentación.

También se modifica el color de la etiqueta de la perspectiva seleccionada. Se establece el color a amarillo utilizando la tipografía normal. Por defecto es rojo y negrita y me resulta fea.

  ;; Ajustes de fuentes y tipos de letra
  (custom-set-faces
   ;; custom-set-faces was added by Custom.
   ;; If you edit it by hand, you could mess it up, so be careful.
   ;; Your init file should contain only one such instance.
   ;; If there is more than one, they won't work right.
   ;;'(default ((t (:family "DejaVu Sans Mono" :foundry "PfEd" :slant normal :weight normal :height 98 :width normal))))
   '(default ((t (:family "Fira Code" :foundry "CTDB" :slant normal :weight normal :height 98 :width normal))))
   '(org-tree-slide-heading-level-1 ((t (:inherit outline-1 :weight bold :height 3.5))))
   '(org-tree-slide-heading-level-2 ((t (:inherit outline-2 :weight bold :height 2.5))))
   '(org-tree-slide-heading-level-3 ((t (:inherit outline-3 :weight bold :height 1.5))))
   '(persp-selected-face ((t (:foreground "yellow" :weight normal)))))

Instalo el modo ligature-mode pero en lugar de activarlo siempre en modo programación, le asigno la tecla <F7> para activar/desactivar el modo. Tiene que estar configurada el tipo de letra Fira Code para que funcionen las ligaduras.

  (use-package ligature
    :ensure t
    :config
    ;; Enable the "www" ligature in every possible major mode
    (ligature-set-ligatures 't '("www"))
    ;; Enable traditional ligature support in eww-mode, if the
    ;; `variable-pitch' face supports it
    (ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
    ;; Enable all Cascadia and Fira Code ligatures in programming modes
    (ligature-set-ligatures 'prog-mode
                          '(;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~
                            ;; =:= =!=
                            ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "="))))
                            ;; ;; ;;;
                            (";" (rx (+ ";")))
                            ;; && &&&
                            ("&" (rx (+ "&")))
                            ;; !! !!! !. !: !!. != !== !~
                            ("!" (rx (+ (or "=" "!" "\." ":" "~"))))
                            ;; ?? ??? ?:  ?=  ?.
                            ("?" (rx (or ":" "=" "\." (+ "?"))))
                            ;; %% %%%
                            ("%" (rx (+ "%")))
                            ;; |> ||> |||> ||||> |] |} || ||| |-> ||-||
                            ;; |->>-||-<<-| |- |== ||=||
                            ;; |==>>==<<==<=>==//==/=!==:===>
                            ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]"
                                            "-" "=" ))))
                            ;; \\ \\\ \/
                            ("\\" (rx (or "/" (+ "\\"))))
                            ;; ++ +++ ++++ +>
                            ("+" (rx (or ">" (+ "+"))))
                            ;; :: ::: :::: :> :< := :// ::=
                            (":" (rx (or ">" "<" "=" "//" ":=" (+ ":"))))
                            ;; // /// //// /\ /* /> /===:===!=//===>>==>==/
                            ("/" (rx (+ (or ">"  "<" "|" "/" "\\" "\*" ":" "!"
                                            "="))))
                            ;; .. ... .... .= .- .? ..= ..<
                            ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\."))))
                            ;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-|
                            ("-" (rx (+ (or ">" "<" "|" "~" "-"))))
                            ;; *> */ *)  ** *** ****
                            ("*" (rx (or ">" "/" ")" (+ "*"))))
                            ;; www wwww
                            ("w" (rx (+ "w")))
                            ;; <> <!-- <|> <: <~ <~> <~~ <+ <* <$ </  <+> <*>
                            ;; <$> </> <|  <||  <||| <|||| <- <-| <-<<-|-> <->>
                            ;; <<-> <= <=> <<==<<==>=|=>==/==//=!==:=>
                            ;; << <<< <<<<
                            ("<" (rx (+ (or "\+" "\*" "\$" "<" ">" ":" "~"  "!"
                                            "-"  "/" "|" "="))))
                            ;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>>
                            ;; >> >>> >>>>
                            (">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-"))))
                            ;; #: #= #! #( #? #[ #{ #_ #_( ## ### #####
                            ("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_"
                                         (+ "#"))))
                            ;; ~~ ~~~ ~=  ~-  ~@ ~> ~~>
                            ("~" (rx (or ">" "=" "-" "@" "~>" (+ "~"))))
                            ;; __ ___ ____ _|_ __|____|_
                            ("_" (rx (+ (or "_" "|"))))
                            ;; Fira code: 0xFF 0x12
                            ("0" (rx (and "x" (+ (in "A-F" "a-f" "0-9")))))
                            ;; Fira code:
                            "Fl"  "Tl"  "fi"  "fj"  "fl"  "ft"
                            ;; The few not covered by the regexps.
                            "{|"  "[|"  "]#"  "(*"  "}#"  "$>"  "^="))
    ;; Enables ligature checks globally in all buffers. You can also do it
    ;; per mode with `ligature-mode'.
    ;;(global-ligature-mode t)
    :bind ("<f7>" . ligature-mode))

Finalización del archivo con las instrucciones que mandan las buenas formas de elisp. Si no se usan el init.el funcionaría igual, pero quedan así mejor.

Finalización correcta del fichero

  (provide 'init)
  ;;; init.el ends here