Emacs: Mi fichero de configuración 2021

34 minutos de lectura

Al igual que hice con las extensiones que utilizo en Gnome Shell, voy a repasar mi actual fichero de configuración que utilizo en Emacs en este año 2021.

Como suele ser habitual cuando empiezas en Emacs, cuando necesitamos una determinada características recurrimos a copiar trozos de otros ficheros de configuración de otros usuarios, buscas lo que necesitas, copias y pegas.

Normalmente esto suele funcionar pero presenta un problema, y es que sabes que funciona pero no sabes porqué funciona y además muchas veces, por lo menos en mi caso, terminas copiando funciones o características que no necesitas.

Así que este es un fichero de configuración sencillo, ya que no utilizo Emacs para programar, simplemente está pensado para llevar mi agenda, diario, listas de tareas (TODO) y también para hacer este blog mediante org-static-blog, todo ello gracias a org-mode, por que no esperes encontrar un gran fichero de configuración, además mis conocimientos sobre Emacs y org-mode se limitan a lo que he comentado.

Después de soltarte todo el rollo, veamos mi fichero de configuración, bueno realmente son dos, config.org e init.el

init.el

Este fichero básicamente se encarga de instalar el paquete use-package, necesario para poder instalar los paquetes que vamos a configurar en el archivo config.org, leer el archivo ~/.emacs.d/config.org y gracias a la magia de org-mode, cargar los bloques de código lisp, que contienen las variables de configuración y los paquetes a instalar para Emacs.

 1(require 'package)
 2(setq package-enable-at-startup nil)
 3(add-to-list 'package-archives
 4'("melpa" . "https://melpa.org/packages/"))
 5(package-initialize)
 6
 7;; Bootstrap `use-package'
 8(unless (package-installed-p 'use-package)
 9(package-refresh-contents)
10(package-install 'use-package))
11
12(org-babel-load-file (expand-file-name "~/.emacs.d/config.org"))
13(custom-set-variables
14 ;; custom-set-variables was added by Custom.
15 ;; If you edit it by hand, you could mess it up, so be careful.
16 ;; Your init file should contain only one such instance.
17 ;; If there is more than one, they won't work right.
18 '(initial-frame-alist '((fullscreen . maximized)))
19 '(package-selected-packages
20   '(aggressive-indent flyspell-correct-ivy auto-package-update nimbus-theme use-package)))
21(custom-set-faces
22 ;; custom-set-faces was added by Custom.
23 ;; If you edit it by hand, you could mess it up, so be careful.
24 ;; Your init file should contain only one such instance.
25 ;; If there is more than one, they won't work right.
26 )

config-org

En este fichero vamos a configurar las variables que nos permitirán modificar el entono de Emacs e instalar los paquetes que vamos a utilizar.

Introducción

Esta configuración pasa por ser una configuración simple, que se adapta a mi día a día, es decir, TODOS, notas, diario, organización de agenda y blog

Otras configuraciones las he sacado de los respectivos sitios de los paquetes que configuro.

** Información del usuario

1;;
2;; with this variable set the name and e-mail of user
3;;
4(setq user-full-name "Carlos M."
5      user-mail-address "hefistion.arroba.mail.com"
6      calendar-latitude 40.2375052
7      calendar-longitude -3.6967718
8      calendar-location-name "Pinto, Madrid")

Fuentes de Paquetes

Las fuentes de paquetes que vamos a necesitar para las instalaciones.

 1;;;
 2;;;;; install the melpa repository
 3;;
 4
 5(setq package-archives (append package-archives
 6			       '(("gnu" . "https://elpa.gnu.org/packages/")
 7				 ("melpa" . "https://melpa.org/packages/")
 8				 ("org" . "https://orgmode.org/elpa/"))))
 9
10;;("org" . "http://orgmode.org/elpa/") necesario para instalar org-mode nesario
11;; para org-contacts, si no lo vas a utilizar lo puedes borrar

Puesta en marcha

Ficheros a usar para la autenticación

Pongo mi archivo authinfo.gpg en una carpeta que luego sincronizo para poder usar fácilmente mi configuración en otros dispositivos.

1(setq auth-sources '("~/.gnupg/shared/authinfo"))

Mis valores por defecto

Desactiva las barras de menús y desplazamiento, arranca Emacs en pantalla completa y algunos otros cambios para los valores por defecto.

 1
 2(tool-bar-mode -1)                                            ; disable bar-mode
 3(toggle-scroll-bar -1)                                        ; disablescroll-mode
 4(tooltip-mode -1)                                             ; Desactiva tooltips
 5(menu-bar-mode -1)                                            ; desactiva barra menu
 6(fset 'yes-or-no-p 'y-or-n-p)                                 ; sustituye yes/no por y/n
 7(display-time)                                                ; muestra el rekoj
 8(line-number-mode t)                                          ;;
 9(column-number-mode t)                                        ;; mode line settings
10(size-indication-mode t)                                      ;;
11(add-to-list 'default-frame-alist '(fullscreen . maximized))  ; pantalla completa
12(global-set-key (kbd "C-+") 'text-scale-increase)             ; Incrementa el tamaño de la funete
13(global-set-key (kbd "C--") 'text-scale-decrease)             ; Decrementa el tamaño de la funete
14(size-indication-mode t)                                      ; Muestra el tamaño del archivo
15(custom-set-variables
16 '(initial-frame-alist (quote ((fullscreen . maximized)))))   ; Fullscreen
17(setq
18 inhibit-startup-screen t                                     ; disable startup screen
19 display-time-24hr-format t                                   ; Muestra el reloj en formato 24 hrs
20 display-time-format "%H:%M"                                  ; Le da formato a la hora
21 ring-bell-function 'ignore                                   ; Elimina el sonido de la campana
22 load-prefer-newer t                                          ; Prefiere la versión más reciente de un archivo.
23 select-enable-clipboard t                                    ; Sistema de fusión y portapapeles de Emacs.
24 use-package-always-ensure t                                  ; Evita la clave :ensure para cada paquete
25 vc-follow-symlinks t                                         ; Siempre sigue los enlaces simbólicos.
26 make-backup-files nil                                        ; No realiza backups de ficheros
27 auto-save-default nil                                        ; Deshabilita #file#
28 ;org-footnote-section "Referencias:"                         ; cambio footnotes por referencias
29 global-hl-line-mode t                                        ; Highlight current line
30 kill-ring-max 128                                            ; Longitud máxima del anillo de matar
31 create-lockfiles nil                                         ; Impido la creación de ficheros .#
32 )

Recogida de basura

1;; reduce the frequency of garbage collection by making it happen on
2;; each 50MB of allocated data (the default is on every 0.76MB)
3(setq gc-cons-threshold 50000000)
4;; warn when opening files bigger than 100MB
5(setq large-file-warning-threshold 100000000)

ibuffer

Ibuffer es un programa que mejora el manejo de los buffers por parte de Emacs.

1;; replace buffer-menu with ibuffer
2(use-package ibuffer
3  :ensure t
4  :config
5  (global-set-key (kbd "C-x C-b") #'ibuffer))

Vamos a añadir un pequeño código con algunas mejoras donde principalmente haremos que los buffers se agrupen en ciertos grupos dependiendo de lo que contengan unas pequeñas mejoras más.

 1  (setq ibuffer-saved-filter-groups
 2	(quote (("default"
 3		 ("dired" (mode . dired-mode))
 4		 ("org" (name . "^.*org$"))
 5		 ("web" (or (mode . web-mode) (mode . js2-mode)))
 6		 ("shell" (or (mode . eshell-mode) (mode . shell-mode)))
 7		 ("mu4e" (name . "\*mu4e\*"))
 8		 ("programming" (or
 9				 (mode . python-mode)
10				 (mode . c++-mode)))
11		 ("emacs" (or
12			   (name . "^\\*scratch\\*$")
13			   (name . "^\\*Messages\\*$")))
14		 ))))
15  (add-hook 'ibuffer-mode-hook
16	    (lambda ()
17	      (ibuffer-auto-mode 1)
18	      (ibuffer-switch-to-saved-filter-groups "default")))
19
20;; don't show these
21;;(add-to-list 'ibuffer-never-show-predicates "zowie")
22
23;; Don't show filter groups if there are no buffers in that group
24(setq ibuffer-show-empty-filter-groups nil)
25
26;; Don't ask for confirmation to delete marked buffers
27(setq ibuffer-expert t)

Configuraciones estéticas

  • Cambiando el tema

    1(use-package nimbus-theme
    2  :ensure t
    3  :config
    4  (load-theme 'nimbus t))
    
  • Fuente

    1;; cambio la fuente
    2(set-face-attribute 'default nil
    3            :height 130
    4            :weight 'normal
    5            :width 'normal)
    

Actualiza automáticamente paquetes

Actualiza los paquetes cada 4 días, sustituye antiguas versiones por la nuevas

1(use-package auto-package-update
2  :ensure t
3  :config
4  (setq auto-package-update-delete-old-versions t
5	auto-package-update-interval 4)
6  (auto-package-update-maybe))

Ortografía

  • Corrector ortográfico

    Añado el corrector de ortografía en español, has de tener instalado aspell en el sistema

    1(setq ispell-program-name "aspell")
    2(setq ispell-local-dictionary "espanol")
    3(setq ispell-local-dictionary-alist
    4      '(("espanol" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil nil nil utf-8)))
    
  • Fly Spell

    flyspell habilita la revisión ortográfica sobre la marcha en Emacs.

     1(use-package flyspell
     2  :defer 1
     3  :delight
     4  :custom
     5  (flyspell-abbrev-p t)
     6  (flyspell-issue-message-flag nil)
     7  (flyspell-issue-welcome-flag nil)
     8  (flyspell-mode 1))
     9
    10(use-package flyspell-correct-ivy
    11  :after flyspell
    12  :bind (:map flyspell-mode-map
    13          ("C-;" . flyspell-correct-word-generic))
    14  :custom (flyspell-correct-interface 'flyspell-correct-ivy))
    15
    16;; Activar Flyspell en modo texto y modos relacionados
    17(add-hook 'text-mode-hook
    18      '(lambda () (flyspell-mode 1)))
    
  • Alternar entre diccionario en español e ingles

    Habitualmente necesito cambiar entre el diccionario English y Spanish, uso esta función:

    1(defun fd-switch-dictionary()
    2  (interactive)
    3  (let* ((dic ispell-current-dictionary)
    4     (change (if (string= dic "espanol") "english" "espanol")))
    5    (ispell-change-dictionary change)
    6    (message "Dicionario cambiado desde %s a %s" dic change)
    7    ))
    8(global-set-key (kbd "<f6>")   'fd-switch-dictionary)
    

Hacer/deshacer

En lugar de tratar el deshacer/rehacer como una secuencia lineal de cambios, el modo undo-tree-mode trata el historial de deshacer como una rama de cambios, similar a la forma en que Vim lo maneja.

1(use-package undo-tree
2  :delight
3  :bind ("C-d" . undo-tree-redo)
4  :init (global-undo-tree-mode 1)
5  :custom
6  (undo-tree-visualizer-timestamps t)
7  (undo-tree-visualizer-diff t))

Espacios en Blanco

 1(use-package whitespace
 2  :ensure
 3  :defer 1
 4  :hook (before-save . delete-trailing-whitespace))
 5
 6(use-package hungry-delete
 7  :ensure t
 8  :defer 0.7
 9  :delight
10  :config (global-hungry-delete-mode))

Paréntesis

Muestra el padre y colorea los grupos de paréntesis de diferente color

 1(show-paren-mode 1)           ; Mostrar al padre
 2(use-package rainbow-delimiters
 3  :defer 1
 4  :hook (prog-mode . rainbow-delimiters-mode))
 5
 6  (use-package smartparens
 7    :defer 1
 8    :delight
 9    :custom (sp-escape-quotes-after-insert nil)
10    :config (smartparens-global-mode 1))

Autorevert

Recarga los archivos al ser modificados

1(use-package autorevert
2  :ensure nil
3  :diminish
4  :hook (after-init . global-auto-revert-mode))

Usando el propio navegador de Emacs por defecto

Por defecto, Emacs que se adapta muy bien al entorno donde estés trabajando abrirá el navegador que tengas configurado en tu escritorio por defecto cuando quieras abrir un enlace. Si en vez de que abra el navegador por defecto quieres que no salga de Emacs y use su propio navegador en modo texto añadiremos la siguiente línea de configuración a nuestro fichero de configuración

1(setq browse-url-browser-function 'eww-browse-url)

Emojify

Representación de los emojis

1(use-package emojify
2  :ensure t)

Añadiendo números de líneas

En emacs tenemos mucha información en el mini-buffer como el nombre del archivo, el modo en el que está, los modos menores y la línea en la que estamos, pero hay que reconocer que muchas veces es más cómodo tener los números de línea a la izquierda del documento, junto a las líneas del documento. Para ello tenemos el paquete nlinum

Así que tendremos que instalarlo y añadirlo a nuestra configuración. Asignado a la tecla de función F9

1(use-package nlinum
2  :ensure t
3  :config
4  (global-set-key (kbd "<f9>") #'nlinum-mode))

Archivos recientes

Proporciona un acceso rápido a los archivos recientes.

 1(use-package recentf
 2  :defer 2
 3  :bind ("C-c r" . recentf-open-files)
 4  :init (recentf-mode)
 5  :custom
 6  (recentf-max-menu-items 10)
 7  (recentf-max-saved-items 50)
 8  (recentf-exclude (list "COMMIT_EDITMSG"
 9			 "~$"
10			 "/scp:"
11			 "/ssh:"
12			 "/sudo:"
13			 "diario.*"
14			 "recentf*"
15			 "bookmark*"
16			 "/archivo*"
17			 "birthday*"
18			 "*elpa/*"
19			 "/tmp/"
20			 "public/*"
21			 "~/.emacs.d/s*"))
22  :config (run-at-time nil (* 5 60) 'recentf-save-list))

Buffer

No pregunta antes de matar un buffer.

1(global-set-key [remap kill-buffer] #'kill-this-buffer)
2(kill-buffer "*scratch*")

Ditaa

Convierte texto ASCII a grafico, ubicacion del binario

1(setq org-ditaa-jar-path "/usr/bin/ditaa")

Complementos

Paquetes complementarios para facilitar mi trabajo en Emacs

Control de Versión

Magit es una interfaz para el sistema de control de versiones Git, implementado como un paquete Emacs. Mientras no podamos (todavía) afirmar que Magit envuelve y mejora todos y cada uno de los comandos de Git, es lo suficientemente completo como para permitir que incluso los usuarios experimentados de Git realicen casi todos sus tareas diarias de control de versiones directamente desde Emacs

git-gutter Además de eso, me gusta ver las líneas que se están modificando en el archivo mientras lo estoy editando.

Finalmente, git-timemachine~ lo utilizo para ver fácilmente los cambios realizados en commits anteriores.

 1(use-package magit
 2  :ensure
 3  :bind
 4  ("C-x g" . magit-status))
 5
 6
 7(use-package git-gutter
 8  :ensure t
 9  :defer 0.3
10  :delight
11  :init (global-git-gutter-mode))
12
13(use-package git-timemachine
14  :defer 1
15  :delight)

Autopair y company

Vamos a instalar dos paquetes muy intersantes para escribir código. El autopair que sirve para que nos termine paréntesis, llaves, etc, y el paqute company para el autocompletado. Podemos ir primeramente a las webs de autopair y company.

 1(use-package autopair
 2  :ensure t
 3  :config (autopair-global-mode))
 4
 5(use-package company
 6  :ensure t
 7  :config
 8   (setq company-idle-delay 0)
 9   (setq company-minimum-prefix-length 3)
10   (global-company-mode t))
11
12(add-hook 'after-init-hook 'global-company-mode)

Ivy y counsel

Ahora vamos a instalar una serie de paquetes que nos van a hacer la vida más fácil a la hora de trabajar con Emacs.

Por un lado tenemos a Ivy. Ivy es un sistema que autocompletado en diversos contextos como son menús, en el mini-buffer, código, etc. Lo mejor es verlo funcionar y ver como nos ayuda mucho a trabajar con Emacs.

Al mismo tiempo que Ivy vamos a instalar dos paquetes más que son swiper y counsel. Ambos ayudan mucho al trabajo con Emacs. Swiper ayuda a la búsqueda de texto dentro de un fichero y counsel ayuda a la búsqueda de comandos dentro del mini-buffer.

 1
 2(use-package ivy
 3:ensure t
 4:config
 5 (setq ivy-use-virtual-buffers t)
 6 (setq ivy-count-format "(%d/%d) "))
 7
 8(use-package swiper
 9:ensure t
10:config
11(global-set-key (kbd "C-s") 'swiper))
12
13
14(use-package counsel
15:ensure t
16:config
17 (global-set-key (kbd "M-x") 'counsel-M-x)
18 (global-set-key (kbd "C-x C-f") 'counsel-find-file)
19 (global-set-key (kbd "<f1> f") 'counsel-describe-function)
20 (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
21 (global-set-key (kbd "<f1> l") 'counsel-find-library)
22 (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
23 (global-set-key (kbd "<f2> u") 'counsel-unicode-char))

Añadiendo neo-tree para la navegación a través de los ficheros

Aunque es muy cómodo usar el programar dired para navegar entre los ficheros es muy práctico usar programas como neo-tree que es una versión para Emacs del neovim. Yo lo tengo configurado para que se active con la tecla .

1(use-package neotree
2  :ensure t
3  :config
4  (setq neo-theme 'icons)
5  (global-set-key [f2] 'neotree-toggle))

Instalando projectile

Projectile es un gestor de proyectos. Lo instalamos ya que lo pide dashboard.

1(use-package projectile
2  :ensure t
3  :config
4  (define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
5  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
6  (projectile-mode +1))

Añadiendo dashboard para un inicio bonito

Para ponerle una pantalla de inicio bonito usaremos el paquete dashboard que es un paquete que usa Spacemacs en el inicio solo que adaptado para poder ser usado en cualquier Emacs aunque no usemos Spacemacs. Lo activo con la tecla F10. Mi configuración:

 1;; instala iconos para dashboard
 2(use-package all-the-icons
 3  :ensure t
 4  :init
 5  (unless (member "all-the-icons" (font-family-list))
 6    (all-the-icons-install-fonts t)))
 7
 8(use-package dashboard
 9  :ensure t
10  :custom
11  (dashboard-banner-logo-title (format "Buen día %s" user-full-name))
12  (dashboard-startup-banner 'logo)
13   (dashboard-items '((recents . 4)
14		      (projects . 3)
15		      (agenda . 3)
16		      ))
17   :config
18   (setq dashboard-set-heading-icons t
19	 dashboard-set-file-icons t
20	 dashboard-set-init-info t
21	 dashboard-set-navigator t)
22
23   (setq dashboard-navigator-buttons
24	 `((
25	    (,(when (display-graphic-p)
26		(all-the-icons-octicon "home" :height 1.1 :v-adjust 0.0))
27	     "Página web" "El Blog de Lázaro"
28	     (lambda (&rest _) (browse-url "https://elblogdelazaro.org")))
29	    (,(when (display-graphic-p)
30		(all-the-icons-material "home" :height 1.35 :v-adjust -0.24))
31	     "Localhost" "Abrir Hugo localhost"
32	     (lambda (&rest _) (browse-url "http://localhost:8080/")))
33	    (,(when (display-graphic-p)
34		(all-the-icons-octicon "tools" :height 1.0 :v-adjust 0.0))
35	     "Configuración" "Abrir configuración de emacs (.org)"
36	     (lambda (&rest _) (find-file (expand-file-name  "~/.emacs.d/config.org"))))
37	    (,(when (display-graphic-p)
38		(all-the-icons-octicon "calendar" :height 1.0 :v-adjust 0.0))
39	     "Agenda" "Agenda personal"
40	     (lambda (&rest _)
41	       (interactive)
42	       (if (get-buffer "*Org Agenda*")
43		   (progn
44		     (switch-to-buffer-other-window "*Org Agenda*")
45		     (kill-buffer "*Org Agenda*")
46		     (org-agenda-list))
47		 (split-window-right)
48		 (org-agenda-list))))
49	    )))
50   :hook
51   (after-init . dashboard-setup-startup-hook))
52 (global-set-key (kbd "<f10>") 'open-dashboard) ;F10 para ir al Dashboard

1(defun open-dashboard ()
2  "Open the *dashboard* buffer and jump to the first widget."
3  (interactive)
4  (delete-other-windows)
5  ;; Refresh dashboard buffer
6  (if (get-buffer dashboard-buffer-name)
7      (kill-buffer dashboard-buffer-name))
8  (dashboard-insert-startupify-lists)
9  (switch-to-buffer dashboard-buffer-name))

Instalando Smex y which-key

Finalmente instalaremos dos paquetes que son muy útiles. El primero de ellos es smex el cual consigue que cuando empecemos a escribir un comando tras pulsar M-x los comandos que nos pongan primero gracias a counsel sean los que más hemos usado.

El segundo paquete es which-key y éste vale para cuando empecemos a usar las combinacionesde teclas. Este paquete lo que hace es que a la vez que vamos ejecutando las combinaciones de teclas se nos muestra una lista de qué siguiente combinación de teclas sigue y qué comando ejecutará.

 1;; iniciamos Smex
 2(use-package smex
 3  :ensure t
 4  :config
 5  (smex-initialize))
 6;; iniciamos el paquete which-key
 7(use-package which-key
 8  :defer 10
 9  :ensure t
10  :config
11  (which-key-setup-minibuffer)
12  (which-key-mode 1))

eshell

Eshell es el emulador de consola de texto que lleva incorporado Emacs. En Emacs podemos ejecutar cualquier shell, sea bash, zsh, tcs, etc, pero lo que hace a Eshell único es que además de las funciones propias de un emulador de consola como comandos unix, alias, etc, también puedes ejecutar ordenes escritas en elisp.

El código

Vamos a añadir un pequeño código para mejorar el aspecto y la usabilidad de Eshell

 1;;; eshell ;;;;;;;;;;;;;;,
 2
 3(eval-after-load "em-ls"
 4  '(progn
 5     (defun ted-eshell-ls-find-file-at-point (point)
 6       "RET on Eshell's `ls' output to open files."
 7       (interactive "d")
 8       (find-file (buffer-substring-no-properties
 9		   (previous-single-property-change point 'help-echo)
10		   (next-single-property-change point 'help-echo))))
11
12     (defun pat-eshell-ls-find-file-at-mouse-click (event)
13       "Middle click on Eshell's `ls' output to open files.
14 From Patrick Anderson via the wiki."
15       (interactive "e")
16       (ted-eshell-ls-find-file-at-point (posn-point (event-end event))))
17
18     (let ((map (make-sparse-keymap)))
19       (define-key map (kbd "RET")      'ted-eshell-ls-find-file-at-point)
20       (define-key map (kbd "<return>") 'ted-eshell-ls-find-file-at-point)
21       (define-key map (kbd "<mouse-2>") 'pat-eshell-ls-find-file-at-mouse-click)
22       (defvar ted-eshell-ls-keymap map))
23
24     (defadvice eshell-ls-decorated-name (after ted-electrify-ls activate)
25       "Eshell's `ls' now lets you click or RET on file names to open them."
26       (add-text-properties 0 (length ad-return-value)
27			    (list 'help-echo "RET, mouse-2: visit this file"
28				  'mouse-face 'highlight
29				  'keymap ted-eshell-ls-keymap)
30			    ad-return-value)
31       ad-return-value)))
32(add-hook 'eshell-preoutput-filter-functions  'ansi-color-apply)

Sugerencias para Eshell

Con el paquete esh-autosuggest nos crea Sugerencias basadas en nuestro historial al igual que fish

1(use-package esh-autosuggest
2  :hook (eshell-mode . esh-autosuggest-mode)
3  ;; If you have use-package-hook-name-suffix set to nil, uncomment and use the
4  ;; line below instead:
5  ;; :hook (eshell-mode-hook . esh-autosuggest-mode)
6  :ensure t)

Usándolo con Ivy

Si usamos Ivy podemos combinarlo de la siguiente forma:

 1(setq ivy-do-completion-in-region t) ; this is the default
 2
 3(defun setup-eshell-ivy-completion ()
 4  (define-key eshell-mode-map [remap eshell-pcomplete] 'completion-at-point)
 5  ;; only if you want to use the minibuffer for completions instead of the
 6  ;; in-buffer interface
 7  (setq-local ivy-display-functions-alist
 8	      (remq (assoc 'ivy-completion-in-region ivy-display-functions-alist)
 9		    ivy-display-functions-alist)))
10
11(add-hook 'eshell-mode-hook #'setup-eshell-ivy-completion)

Org

Configuraciones básicas para Orgmode

Org mode es una de las mejores maravillas que tiene Emacs. Se le suele llamar una skill app dentro de Emacs. Darían muchos documentos para explicar todo lo que se puede hacer con org-mode pero al menos para empezar podemos hacer que sea agradable a la vista y más cómodo de usar. Para ellos nos basaremos en un artículo de Howard Abrams llamado org-mode como un procesador de texto que podemos encontrar aquí.

De ese artículo podemos sacar la siguiente configuración:

Para que cuando usemos * / o _ para resaltar texto, estos símbolos no aparezcan:

1(use-package org
2  :ensure org-plus-contrib
3  :delight "Θ "
4  :config
5  (setq org-hide-emphasis-markers t))

Para mejorar los bullets y que sean más bonitos

1(font-lock-add-keywords 'org-mode
2			'(("^ +\\([-*]\\) "
3			   (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))

Mejorando aún más el aspecto de los bullets gracias al paquete org-bullets

1(use-package org-bullets
2  :ensure t
3  :config
4  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

Adaptando el texto a la ventana

Finalmente haremos que cuando se visualice un fichero con extensión .org éste se adapte a la ventana y cuando la línea llegue al final de ésta haga un salto de carro. Para ellos añadiremos la línea

1(add-hook 'org-mode-hook 'visual-line-mode);

Autocompletado para Org-mode

Para activar el autocompletado en org instalremos el paquete org-ac y añadiremos la siguiente configuración:

1(use-package org-ac
2  :ensure t
3  :config
4  (org-ac/config-default))

Org-general

Org mode es una navaja suiza para Emacs en particular y para la vida en general, para muchos es una killer app que tiene Emacs,de hecho, algunas personas solo usan Emacs por Org mode.

Este solo es uno de los muchos ficheros de configuración que haremos para org mode ya que tiene tantas cosas que si lo hicieramos todo en uno nos saldría un fichero tremendamente largo.

Ficheros a usar

Inicialmente solo vamos a configurar algunas cosas relacionadas con la gestión de tareas y el con org mode.

Vamos a definir qué ficheros van a llevar los ficheros de la agenda y de las notas.

 1;; definiendo ficheros de agenda
 2(setq org-agenda-files (quote ("~/.personal/agenda/personal.org"
 3			       "~/.personal/agenda/trabajo.org"
 4			       "~/.personal/agenda/diario.org"
 5			       "~/.personal/agenda/diario-ibx.org")))
 6;; utilizo mi propio diario para a la agenda, asi que deshabilito el de emacs
 7(setq org-agenda-include-diary nil)
 8(setq org-agenda-diary-file "~/.personal/agenda/diario.org")
 9;; ubicacion de los ficheros cuando son archivados, organizados por fecha
10(setq org-archive-location "~/.personal/archivo/%s_archivo.org.gpg::datetree/")
11:; exportar
12(setq org-export-backends '(ascii html latex md org texinfo))
13;; Refile a otros ficheros de la agenda
14(setq org-refile-targets (quote (("personal.org" :maxlevel . 1) ("trabajo.org" :level . 1))))
15;;(setq org-refile-targets '((org-agenda-files :maxlevel . 1)))

Aspecto y etiquetas de las tareas

Ahora vamos a definir nuestras etiquetas de tareas para que además de los TODO, DONE, que tiene por defecto tenga otros y además le definiremos distintos colores

 1;; Define a kanban style set of stages for todo tasks
 2(setq org-todo-keywords
 3      '((sequence "PORHACER(p!)"
 4		  "ENPROCESO(e!)"
 5		  "BLOQUEADO(b!)"
 6		  "|" "HECHO(h!)" "ARCHIVAR(a!)")))
 7;; Setting Colours (faces) for todo states to give clearer view of work
 8(setq org-todo-keyword-faces
 9      '(("PORHACER" . org-warning)
10	("ENPROCESO" . "yellow")
11	("BLOQUEADO" . "red")
12	("HECHO" . "green")
13	("ARCHIVAR" .  "blue")))
14;; etiquetas que utilizo para mis notas
15(setq org-tag-alist '(("@nota" . ?n)
16		      ("@casa" . ?c)
17		      ("@dinero" . ?d)
18		      ("@fecha" . ?f)
19		      ("@salud" . ?s)
20		      ("@tarea" . ?t)
21		      ("@coche" . ?h)
22		      ("@trabajo" . ?b)
23		      ("crypt" . ?C)))
24(setq org-tags-exclude-from-inheritance '("crypt" "project"))
25;; Progress Logging
26;; When a TODO item enters DONE, add a CLOSED: property with current date-time stamp and into drawer
27(setq org-log-done 'time)
28(setq org-log-into-drawer "LOGBOOK")
29;; Alinea etiquetas
30(setq org-tags-column 80)

Teclas rápidas para tareas

Teclas rapidas para gestionar las tareas. Te debes de posicionar al inicio del encabezado y pulsar la tecla rapìda para que la tarea cambie de estado. Se encesita la funcion org-use-speed-commands-for-headings-and-lists definida en el apartado Funciones propias.

Cuando inicamos el reloj la tarea cambia al estado ENPROCESO y cuando paremos el reloj a BLOQUEADO.

 1(setq org-use-speed-commands 'my/org-use-speed-commands-for-headings-and-lists)
 2(add-to-list 'org-speed-commands-user '("$" call-interactively 'org-archive-subtree))
 3(add-to-list 'org-speed-commands-user '("i" call-interactively 'org-clock-in))
 4(add-to-list 'org-speed-commands-user '("p" call-interactively 'org-clock-out))
 5(add-to-list 'org-speed-commands-user '("d" call-interactively 'org-clock-display))
 6(add-to-list 'org-speed-commands-user '("s" call-interactively 'org-schedule))
 7(add-to-list 'org-speed-commands-user '("x" org-todo "HECHO"))
 8(add-to-list 'org-speed-commands-user '("a" org-todo "ARCHIVAR"))
 9;; Cambiamos el estado de la tarea cuando inicia o para el reloj
10(setq org-clock-in-switch-to-state "ENPROCESO")
11(setq org-clock-out-switch-to-state "BLOQUEADO")

Personalizando el calendario

Aunque esto requiere un paquete extra, calfw-org, lo añadiré ahora porque con el tendremos un calendario muy resultón donde aparecerán nuestras tareas.

Para acceder a él escribiremos M-x: cfw-caledario o pulsando la f8

Además vamos a hacerle unos ajustes de aspecto, como poner que empiece el calendario en Lunes, por defecto lo hace en Domingo y además poner los meses y los días de la semana en español.

  • Personalizando los meses y semana

     1(setq calendar-month-name-array
     2      ["Enero" "Febrero" "Marzo" "Abril" "Mayo" "Junio"
     3       "Julio"    "Agosto"   "Septiembre" "Octubre" "Noviembre" "Diciembre"])
     4
     5(setq calendar-day-name-array
     6      ["Domingo" "Lunes" "Martes" "Miércoles" "Jueves" "Viernes" "Sábado"])
     7
     8(setq org-icalendar-timezone "Europe/Madrid") ;; timezone
     9(setq calendar-week-start-day 1) ;; la semana empieza el lunes
    10(setq european-calendar-style t) ;; estilo europeo
    
  • Festivos

    Lista de fechas importantes según mi país, España. Es muy probable que algunas fechas sean diferentes en tu país o Comunidad Autónoma, , por lo tanto, adapta la configuración como corresponda.

     1(setq calendar-holidays '((holiday-fixed 1 1 "Año Nuevo")
     2              (holiday-fixed 1 6 "Reyes Magos")
     3              (holiday-fixed 4 18 "Jueves Santo")
     4              (holiday-fixed 4 19 "Viernes Santo")
     5              (holiday-fixed 5 1 "Dia del Trabajo")
     6              (holiday-fixed 5 2 "Comunidad de Madrid")
     7              (holiday-fixed 5 15 "San Isidro")
     8              (holiday-fixed 8 15 "Asunción")
     9              (holiday-fixed 10 02 "Día de la Policía")
    10              (holiday-fixed 10 12 "Día de la Hispanidad")
    11              (holiday-fixed 11 01 "Todos los Santos")
    12              (holiday-fixed 11 09 "Almudena")
    13              (holiday-fixed 12 06 "Constitución")
    14              (holiday-fixed 12 08 "Inmaculada")
    15              (holiday-fixed 12 25 "Navidad")
    16              ))
    
  • Poniendo una vista chula al calendario

    1(use-package calfw
    2  :ensure t
    3  :bind ([f8] . my/mi-calendario)
    4  :custom
    5  (cfw:org-overwrite-default-keybinding t)) ;; atajos de teclado de la agenda org-mode
    6;(setq cfw:display-calendar-holidays nil) ;; esconder fiestas calendario emacs
    7
    8(use-package calfw-org
    9  :ensure t)
    
  • Sincronización con Caldav

    Para terminar vamos a utilizar org-caldav para la sincronización bidireccional del calendario con servidores CalDav. :files son las ficheros que contienen los eventos que se sincronizaran con el calendario remoto, :inbox es el fichero donde se descargan los eventos del calendario remoto

     1
     2(use-package org-caldav
     3  :ensure t
     4  :bind ([f4] . org-caldav-sync)
     5  :preface
     6  :custom
     7  ;; Calendarios a utilizar
     8  (org-caldav-url "https://servidor_caldav/caldav/carlos")
     9  (org-caldav-calendars
    10   '((:calendar-id "lfxlzur"
    11           :files ("~/.personal/agenda/diario.org")
    12           :inbox "~/.personal/agenda/diario-ibx.org")
    13     ))
    14  (org-caldav-backup-file "~/.personal/calendario/org-caldav-backup.org.gpg")
    15  (org-caldav-save-directory "~/.personal/calendario/")
    16  (org-icalendar-alarm-time 1)
    17  )
    
  • Sincronizando con vdirsyncer

    Utilizo vdirsyncer para sincronizar calendario y agenda ya que tengo problemas con caldav y mi servidor, la tecla de funcoin f3 llama a la función sync-my-diary

    En el fichero diario.org he añadido una variable local para que cuando se guarde el fichero, al mismo tiempo se exporte en formato .ics para poder utilizarlo con vdirsyncer. Debe ir colocada al inicio del fichero.

    1-*- eval: (add-hook 'after-save-hook 'org-icalendar-export-to-ics nil t) -*-
    

    1(global-set-key [f3] 'sync-my-diary)
    

Babel

Configuración de babel para distintos lenguajes, org-babel permitirá evaluar código fuente de varios lenguajes interpretados, para introducirlo en documentos que podemos crear con org-mode y exportarlos en múltiples formatos.

 1(setq org-confirm-babel-evaluate nil
 2      org-src-fontify-natively t
 3      org-src-tab-acts-natively t)
 4
 5(org-babel-do-load-languages
 6 'org-babel-load-languages
 7 '((dot . t)
 8   (emacs-lisp . t)
 9   (shell . t)
10   (python . t)
11   (latex . t)
12   (ditaa . t)
13   (org . t)))

Org-indent

Aspecto mejorado al identar

1(add-hook 'org-mode-hook 'org-indent-mode)

Funciones propias

Ahora vamos a crear unas funciones muy simples que simplemente nos van a ayudar a acceder fácilmente a nuestros ficheros de Actividades, tareas y notas, escribiéndolo en el mini-buffer con M-x

 1;;
 2(defun my/org-use-speed-commands-for-headings-and-lists ()
 3  "funcion para que las teclas rapidas trabajen en los encabezados"
 4  "Activa los comandos de velocidad también en los elementos de la lista."
 5  (or (and (looking-at org-outline-regexp) (looking-back "^\**"))
 6      (save-excursion (and (looking-at (org-item-re)) (looking-back "^[ \t]*")))))
 7;;
 8(defun my/mi-calendario ()
 9  "calendarios a mostrar en calfw-org cuando pulso f8"
10  (interactive)
11  (cfw:open-calendar-buffer
12   :contents-sources
13   (list
14    (cfw:org-create-source)
15    )))
16;;
17(defun sync-my-diary ()
18  "Sync diario.ics file with vdirsyncer external script and delete .ics."
19  (interactive)
20  (shell-command "vdirsyncer sync diario_sync")
21  (shell-command "rm ~/.personal/agenda/*.ics"))

Org-agenda

Vamos a configurar las vistas de agenda y los contactos para poder captura

Contactos

La mejor solución para mantener tus contactos. Suelo usar org-contacts está disponible en org-plus-contrib. Los contactos se guuardan en el fichero contactos.ord

1(use-package org-contacts
2  :ensure nil
3  :after org
4  :custom
5  (org-contacts-files '("~/.personal/agenda/contactos.org.gpg")))

Agenda

Es importante tomarte tu tiempo para hacer una configuración que sea fácil de usar y que haga tu vida más fácil con una buena organización.

org-agenda me permite ser organizado con las tareas diarias. Como resultado, puedo usar mi tiempo al máximo

Sincronizo mis archivos org mediante Syncthing para poder revisar mi agenda y actualizarla desde varios ordenadores y dispositivos móviles.

La vista de agenda se activa la tecla F7 y tiene asociada dos vistas a las teclas (o) para el trabajo y (p) para la personal.

Las vistas están organizadas por estados

 1(use-package org-agenda
 2  :ensure nil
 3  :after org
 4  :bind ([f7] . org-agenda)
 5  :custom
 6  (org-agenda-dim-blocked-tasks t)
 7  (org-agenda-include-diary nil)
 8  (org-agenda-inhibit-startup t)
 9  (org-agenda-show-log t)
10  (org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled)
11  (org-agenda-span 4)
12  (org-agenda-start-on-weekday 1)
13  (org-deadline-warning-days 7)
14  (org-agenda-sticky nil)
15  (org-agenda-window-setup 'current-window) ; Sobrescribe la ventana actual con la agenda
16  (org-agenda-tags-column -100)
17  (org-agenda-time-grid '((daily today require-timed)))
18  (org-agenda-use-tag-inheritance t)
19  (org-enforce-todo-dependencies t)
20  (org-habit-show-habits-only-for-today nil)
21  (org-track-ordered-property-with-tag t)
22  (org-agenda-custom-commands
23   '(("h" "Habitos" tags-todo "STYLE=\"habit\""((org-agenda-overriding-header "Habitos")
24						(org-agenda-sorting-strategy
25						 '(todo-state-down effort-up category-keep))))
26     ("o" "Trabajo"
27      ((agenda "" )
28       (tags-todo "trabajo/PORHACER"
29		  ((org-agenda-overriding-header "Tareas por Hacer")
30		   (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled))
31		   (org-tags-match-list-sublevels t)))
32       (tags-todo "trabajo/ENPROCESO"
33		  ((org-agenda-overriding-header "Tareas en Proceso")
34		   (org-tags-match-list-sublevels t)))
35       (tags-todo "trabajo/BLOQUEADO"
36		  ((org-agenda-overriding-header "Tareas Paradas o Esperando")
37		   (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled))
38		   (org-tags-match-list-sublevels t)))
39       (tags "trabajo/HECHO"
40	     ((org-agenda-overriding-header "Tareas Hechas")
41	      (org-tags-match-list-sublevels t)))
42       (tags "trabajo/ARCHIVADO"
43	     ((org-agenda-overriding-header "Tareas terminadas sin Archivar")
44	      (org-tags-match-list-sublevels t)))
45       (tags "reubicar"
46	     ((org-agenda-overriding-header "Reubicar")
47	      (org-tags-match-list-sublevels t)))
48       nil))
49     ;; Reportes personales
50     ("p"  "Personal"
51      ((agenda "" )
52       (tags-todo "personal/PORHACER"
53		  ((org-agenda-overriding-header "Tareas por Hacer")
54					;(org-agenda-skip-function '(org-agenda-skip-deadline-if-not-today))
55		   (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled))
56		   (org-tags-match-list-sublevels t)))
57       (tags-todo "personal/ENPROCESO"
58		  ((org-agenda-overriding-header "Siguientes en Proceso")
59		   (org-tags-match-list-sublevels t)))
60       (tags "personal/BLOQUEADO"
61	     ((org-agenda-overriding-header "Tareas Paradas o Esperando")
62	      (org-tags-match-list-sublevels t)))
63       (tags "personal/HECHO"
64	     ((org-agenda-overriding-header "Tareas Hechas")
65	      (org-agenda-todo-ignore-deadlines 'future)
66	      (org-agenda-todo-ignore-scheduled 'future)
67	      (org-agenda-tags-todo-honor-ignore-options t)
68	      (org-tags-match-list-sublevels t)))
69       (tags "personal/ARCHIVAR"
70	     ((org-agenda-overriding-header "Tareas terminadas sin Archivar")
71	      (org-tags-match-list-sublevels t)))
72       (tags "reubicar"
73	     ((org-agenda-overriding-header "Reubicar")
74	      (org-tags-match-list-sublevels t)))
75       nil))
76     )))

Notificaciones

Muestra notificaciones de otros paquetes de diversas formas. Por ahora solo lo uso para mostrar notificaciones de escritorio desde el código del paquete.

 1(require 'appt)
 2(appt-activate 1)
 3
 4(use-package notifications
 5  :demand t)
 6(add-hook 'org-finalize-agenda-hook 'org-agenda-to-appt) ;; update appt list on agenda view
 7
 8(setq appt-display-format 'window
 9      appt-message-warning-time '5)
10(setq appt-disp-window-function
11      (lambda (nmins curtime msg)
12	(notifications-notify :title "Recordatorio!!"
13			      :body (format "Tienes una cita %s en %d minutos" msg (string-to-number nmins))
14			      :app-name "Emacs: Org"
15			      :sound-name "alarm-clock-elapsed")))
16(display-time)                   ;; activate time display
17(run-at-time "24:01" 3600 'org-agenda-to-appt)           ;; update appt list hourly
18(setq org-agenda-finalize-hook 'org-agenda-to-appt)

Captura

Las plantillas para org-capture ahorran mucho tiempo al agregar nuevas entradas. yo las suelo usar para registrar rápidamente tareas, entradas de libro mayor, notas y otra información.

 1(use-package org-capture
 2  :ensure nil
 3  :after org
 4  :bind ("C-c c" . org-capture)
 5  :preface
 6  (defvar my/org-basic-task-template "* PORHACER %?
 7   Añadido: %U" "Plantilla básica de tareas.")
 8
 9  (defvar my/org-meeting-template "* Cita con %^{CON}
10   :PROPERTIES:
11   :SUMMARY: %^{DESCRIPCION ....}
12   :NOMOBRE: %^{NOMBRE ....}
13   :LUGAR: %^{DONDE ....}
14   :DIRECCION: %^{CALLE ....}
15   :TELEFONO: %^{123-456-789}
16   :NOTA: %^{NOTAS}
17   :AÑADIDA: %U
18   :END:
19   Fecha de la reunión: %?%T" "Plantilla para programar reuniones.")
20
21  (defvar my/org-contacts-template "* %(org-contacts-template-name)
22   :PROPERTIES:
23   :EMAIL: %(org-contacts-template-email)
24   :PHONE: %^{123-456-789}
25   :HOUSE: %^{123-456-789}
26   :ALIAS: %^{nick}
27   :NICKNAME: %^{hefistion}
28   :IGNORE:
29   :NOTE: %^{NOTA}
30   :ADDRESS: %^{Calle Ejemplo 1 2D, 28320, Pinto, Madrid, España}
31   :BIRTHDAY: %^{yyyy-mm-dd}
32   :END:" "Plantilla para org-contacts.")
33  :custom
34  (org-capture-templates
35   `(("c" "Contactos" entry (file+headline "~/.personal/agenda/contactos.org.gpg" "Amigos"),
36      my/org-contacts-template)
37
38     ("f" "Fecha" entry (file+headline "~/.personal/agenda/reubicar.org" "Fechas"),
39      my/org-basic-task-template)
40
41     ("n" "Nota" entry (file+headline "~/.personal/agenda/reubicar.org" "Nota"),
42      my/org-basic-task-template)
43
44     ("i" "Cita" entry (file+datetree "~/.personal/agenda/diario.org"),
45      my/org-meeting-template)
46
47     ("b" "Blog" entry (file+headline "~/.personal/agenda/reubicar.org.gpg" "Blog"),
48      my/org-basic-task-template)
49
50     ("t" "Tarea" entry (file+headline "~/.personal/agenda/reubicar.org.gpg" "Tareas"),
51      my/org-basic-task-template))))

Cifrado / Descifrado

Para poder habilitar el cifrado y descifrado de archivos .gpg con org-mode, necesitaremos instalar gnupg2.

Una vez hecho esto, simplemente configuramos org-crypt para aceptar nuestro identificador de clave pública para permitir el cifrado asimétrico.

NOTA: necesitas modificar la variable org-crypt-key para reemplazar mi identificador de clave por el tuyo (o nil para permitir el cifrado simétrico).

org-crypt cifra el texto de una entrada, pero no el título o las propiedades

1(use-package org-crypt
2  :ensure nil
3  :after org)
4(org-crypt-use-before-save-magic)
5(setq org-tags-exclude-from-inheritance (quote ("crypt")))
6(setq org-crypt-key "carlos70@protonmail.com")
7(setq org-crypt-disable-auto-save nil)

Funciones propias

 1(defun org-agenda-skip-deadline-if-not-today ()
 2  "If this function returns nil, the current match should not be skipped.
 3Otherwise, the function must return a position from where the search
 4should be continued."
 5  (ignore-errors
 6    (let ((subtree-end (save-excursion (org-end-of-subtree t)))
 7	  (deadline-day
 8	   (time-to-days
 9	    (org-time-string-to-time
10	     (org-entry-get nil "DEADLINE"))))
11	  (now (time-to-days (current-time))))
12      (and deadline-day
13	   (not (= deadline-day now))
14	   subtree-end))))

TOC

toc-org mantendrá una tabla de contenido en el primer encabezado que tiene una etiqueta :TOC:.

1(use-package toc-org
2  :after org
3  :hook (org-mode . toc-org-enable))

Programación-Web

Lenguajes de programación y paquete0s necesarios para la creación de blogs

Markdown

Tienes que tener instalado markdown en tu equipo

1(use-package markdown-mode
2  :ensure t
3  :commands (markdown-mode gfm-mode)
4  :mode (("README\\.md\\'" . gfm-mode)
5	 ("\\.md\\'" . markdown-mode)
6	 ("\\.markdown\\'" . markdown-mode))
7  :init (setq markdown-command "markdown"))

Marcador ancho columna

1(use-package fill-column-indicator
2  :ensure t
3  :init
4  (setq fci-rule-color "purple")
5  (setq fill-column 79)
6  (setq fci-rule-column 79)
7  (add-hook 'python-mode-hook 'fci-mode)
8  (add-hook 'emacs-lisp-mode-hook 'fci-mode)
9  (add-hook 'sh-mode-hook 'fci-mode))

Flycheck

 1 (use-package flycheck
 2   :config
 3   ;; (setq flycheck-global-modes '(python-mode))
 4   ;; (global-flycheck-mode)
 5   (add-hook 'after-init-hook #'global-flycheck-mode)
 6   :diminish flycheck-mode
 7   :ensure t)
 8
 9
10 (use-package flycheck
11   hook
12   ((org-mode
13     makdown-mode
14;    python-mode
15     text-mode) . turn-on-flyspell))

Htmlize

 1(use-package htmlize
 2  :defer t
 3  :config
 4  (progn
 5
 6    ;; It is required to disable `fci-mode' when `htmlize-buffer' is called;
 7    ;; otherwise the invisible fci characters show up as funky looking
 8    ;; visible characters in the source code blocks in the html file.
 9    ;; http://lists.gnu.org/archive/html/emacs-orgmode/2014-09/msg00777.html
10    (with-eval-after-load 'fill-column-indicator
11      (defvar modi/htmlize-initial-fci-state nil
12	"Variable to store the state of `fci-mode' when `htmlize-buffer' is called.")
13
14      (defun modi/htmlize-before-hook-fci-disable ()
15	(setq modi/htmlize-initial-fci-state fci-mode)
16	(when fci-mode
17	  (fci-mode -1)))
18
19      (defun modi/htmlize-after-hook-fci-enable-maybe ()
20	(when modi/htmlize-initial-fci-state
21	  (fci-mode 1)))
22
23      (add-hook 'htmlize-before-hook #'modi/htmlize-before-hook-fci-disable)
24      (add-hook 'htmlize-after-hook #'modi/htmlize-after-hook-fci-enable-maybe))
25
26    ;; `flyspell-mode' also has to be disabled because depending on the
27    ;; theme, the squiggly underlines can either show up in the html file
28    ;; or cause elisp errors like:
29    ;; (wrong-type-argument number-or-marker-p (nil . 100))
30    (with-eval-after-load 'flyspell
31      (defvar modi/htmlize-initial-flyspell-state nil
32	"Variable to store the state of `flyspell-mode' when `htmlize-buffer' is called.")
33
34      (defun modi/htmlize-before-hook-flyspell-disable ()
35	(setq modi/htmlize-initial-flyspell-state flyspell-mode)
36	(when flyspell-mode
37	  (flyspell-mode -1)))
38
39      (defun modi/htmlize-after-hook-flyspell-enable-maybe ()
40	(when modi/htmlize-initial-flyspell-state
41	  (flyspell-mode 1)))
42
43      (add-hook 'htmlize-before-hook #'modi/htmlize-before-hook-flyspell-disable)
44      (add-hook 'htmlize-after-hook #'modi/htmlize-after-hook-flyspell-enable-maybe))))

Org-Static-Blog

Configuración del blog con org-static-blog

 1(use-package org-static-blog
 2  :ensure t
 3  :init
 4  (setq org-static-blog-publish-title "el blog de lázaro"
 5	org-static-blog-publish-url "https://elblogdelazaro.org/"
 6	org-static-blog-publish-directory "~/Documentos/proyectos/elblogdelazaro.org/public/"
 7	org-static-blog-posts-directory "~/Documentos/proyectos/elblogdelazaro.org/posts"
 8	org-static-blog-drafts-directory "~/Documentos/proyectos/elblogdelazaro.org/drafts"
 9	org-static-blog-rss-file "index.xml"
10	org-static-blog-rss-max-entries 16
11	org-static-blog-langcode "es"
12	org-export-with-toc nil
13	org-static-blog-enable-tags t
14	org-export-with-section-numbers nil
15	org-static-blog-preview-ellipsis "(ver más..)"
16	org-static-blog-preview-link-p t
17	org-static-blog-preview-convert-titles nil
18	org-static-blog-use-preview t)
19
20  (setq org-static-blog-rss-extra
21	(concat
22	 "<generator>"
23	 (format "Emacs %d.%d" emacs-major-version emacs-minor-version) " "
24	 "Org-mode " (org-version) " "
25	 "org-static-blog 1.4.0"
26	 "</generator>\n"
27	 "<webMaster>" user-full-name " (" user-mail-address ") " "</webMaster>\n"
28	 "<image>\n"
29	 "<url>" org-static-blog-publish-url "static/favicon.ico" "</url>\n"
30	 "<title>" org-static-blog-publish-title "</title>\n"
31	 "<link>" org-static-blog-publish-url "</link>\n"
32	 "</image>\n"))
33
34  ;; This header is inserted into the <head> section of every page:
35  ;;   (you will need to create the style sheet at
36  ;;    ~/projects/blog/static/style.css
37  ;;    and the favicon at
38      ;;    ~/projects/blog/static/favicon.ico)
39  (setq org-static-blog-page-header
40	"<meta name=\"author\" content=\"Carlos M.\">
41	 <meta name=\"generator\" content=\"org-blog-static\">
42	 <meta name=\"viewport\" content=\"initial-scale=1,width=device-width,minimum-scale=1\">
43	 <link rel=\"shortcut icon\" href=\"static/favicon.ico\" type=\"image/x-icon\">
44	 <link rel=\"icon\" href=\"static/favicon.ico\" type=\"image/x-icon\">
45	 <link href= \"static/style.css\" rel=\"stylesheet\" type=\"text/css\">"
46	)
47
48  ;; This preamble is inserted at the beginning of the <body> of every page:
49  ;;   This particular HTML creates a <div> with a simple linked headline
50
51  (setq org-static-blog-page-preamble
52	"<header>
53	    <p id=\"blogname\">
54		<a href=\"index.html\">El Blog de Lázaro</a>
55	    <p/>
56		<p id=\"catchphrase\">
57		    \"Mis notas sobre tecnolog&iacute;a\"
58		</p>
59	    <div id=\"nav\">
60		<a href=\"about.html\">Acerca de</a> <span class=\"sep\">|</span>
61		<a href=\"archive.html\">Archivo</a> <span class=\"sep\">|</span>
62		<a href=\"tags.html\">Tags</a> <span class=\"sep\">|</span>
63		<a href=\"index.xml\">Rss</a>
64	    </div>")
65
66  ;; This postamble is inserted at the end of the <body> of every page:
67  ;; This particular HTML creates a <div> with a link to the archive page
68  ;; and a licensing stub.
69  (setq org-static-blog-page-postamble
70	"<footer id=\"footer\">
71	  Creado por <a href=\"https://elblogdelazaro.org\">el blog de l&aacute;zaro</a> bajo licencia <a rel=\"license\"  href=\"http://creativecommons.org/licenses/by-sa/4.0/\"> CC BY-SA 4.0</a>
72	   generado con <a rel=\"org-static-blog\" href=\"https://github.com/bastibe/org-static-blog/\"> org-static-blog</a>
73	   y <a rel=\"Emacs\" href=\"https://www.gnu.org/software/emacs/\">emacs</a>
74       </footer>"))

Espero que te haya gustado, pasa un gran día…