Ir al contenido
  1. Publicaciones/

Emacs: Mi fichero configuración 2023

··5727 palabras·27 mins

Cuando se empieza a utilizar Emacs, la mayoría de las veces copiamos código de aquí y de allí, funciones que realmente no sabemos que hacen o si las vamos a utilizar, poco a poco, según empiezas a utilizar Emacs vas desechando código, añadiendo nuevas funciones o paquetes, en definitiva, tienes un fichero de configuración que va cambiando constantemente.

Creo haber alcanzado un cierto nivel de estabilidad en Emacs, como para tener un fichero de configuración más o menos estable, solo utilizo lo que necesito, es decir, organizo mi día a día con Org Mode ( agenda, calendario y notas), creo y publico los artículos del blog ( ox-hugo), utilizo el lector rss ( elfeed) para estar al día, interactuo en Mastodon ( mastodn.el) y Telegram ( telega.el) y gestiono mi correo electrónico ( mu4e), además suelo utilizar el navegador EWW con bastante frecuencia.

He dejado de jugar con Python, por lo que he borrado todos los paquetes relacionados con él aligerando bastante el fichero de configuración. Asi qeu si buscas un fichero de configuración simple, esperoq ue este te puedda ser de utiliddad.

Introducción #

Esta configuración tiene como base la serie de artículos escritos en el sitio Emacs From Scratch. La primera vez que cargues este archivo puedes generar el fichero init.el con la combinación de teclas C-c C-v t, después, cada vez que modifiques el archivo y lo guardes, se genera de forma automática.

Consejos de uso #

En este documento, hay enlaces en muchos lugares que llevan a la documentación de los distintos paquetes que utilizo. Si estás viendo este archivo en Emacs, puedes colocar el cursor en un enlace y presionar C-c C-o o ejecutar M-x org-open-at-point para abrir el enlace en el navegador web.

UTF-8 #

;; Codificación UTF-8 por defecto
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(if (boundp 'buffer-file-coding-system)
    (setq-default buffer-file-coding-system 'utf-8)
  (setq default-buffer-file-coding-system 'utf-8))
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))

Configuración del sistema de paquetes #

Emacs tiene un administrador de paquetes integrado, pero no facilita la instalación automática de paquetes en un nuevo sistema la primera vez que despliega su configuración. use-package es un paquete realmente útil que se utiliza en esta configuración para facilitar la automatización de la instalación y configuración de todo lo que vamos a usar.

;; Initialize package sources
(require 'package)

(setq package-archives '(("melpa" . "https://melpa.org/packages/")
                           ("gnu" . "https://elpa.gnu.org/packages/")
                           ("nongnu" . "https://elpa.nongnu.org/nongnu/")))

;;("org" . "https://orgmode.org/elpa/")))

(package-initialize)
(unless package-archive-contents
  (package-refresh-contents))

;; Initialize use-package on non-Linux platforms
(unless (package-installed-p 'use-package)
  (package-install 'use-package))

(require 'use-package)
(setq use-package-always-ensure t)

Configuración básica de la interfaz de usuario #

En esta sección configuro las configuraciones básicas de la interfaz de usuario que eliminan los elementos innecesarios para hacer que Emacs se vea mucho más minimalista y moderno. Si estás comenzando en Emacs, la barra de menú puede ser útil, si la quieres visualizar elimina la línea (menu-bar-mode -1).

(setq user-full-name "Carlos M.")
(setq inhibit-startup-message t)

(scroll-bar-mode -1)        ; Disable visible scrollbar
(tool-bar-mode -1)          ; Disable the toolbar
(tooltip-mode -1)           ; Disable tooltips
(set-fringe-mode 10)        ; Give some breathing room

(menu-bar-mode -1)          ; Disable the menu bar

;; Set up the visible bell
(setq visible-bell t)

(column-number-mode)
(global-display-line-numbers-mode t)

;; Set frame transparency
(set-frame-parameter (selected-frame) 'alpha '(95 .95 ))
(add-to-list 'default-frame-alist `(alpha . (95 . 95)))
(set-frame-parameter (selected-frame) 'fullscreen 'maximized)
(add-to-list 'default-frame-alist '(fullscreen . maximized))

;; sustituye yes/no por y/n
(fset 'yes-or-no-p 'y-or-n-p)

;; Disable line numbers for some modes
(dolist (mode '(org-mode-hook
                treemacs-mode-hook
                shell-mode-hook
                mastodon-mode-hook
                telega-root-mode-hook
                telega-chat-mode-hook
                elfeed-show-mode-hook
                elfeed-search-mode-hook
                mu4e-main-mode-hook
                vterm-mode-hook
                wallabag-search-mode-hook))
  (add-hook mode (lambda () (display-line-numbers-mode 0))))

;; Dislay Clock
(display-time)

(setq
 display-time-24hr-format t              ; Muestra el reloj en formato 24 hrs
 display-time-format "%H:%M"             ; Le da formato a la hora
 load-prefer-newer t                     ; Prefiere la versión más reciente de un archivo.
 select-enable-clipboard t               ; Sistema de fusión y portapapeles de Emacs.
 vc-follow-symlinks t                    ; Siempre sigue los enlaces simbólicos.
  make-backup-files nil                ; No realiza backups de ficheros
 auto-save-default nil                   ; Deshabilita #file#
 ;; org-footnote-section "Referencias:"  ; cambio footnotes por referencias
 ;; global-hl-line-mode t                ; Highlight current line
 kill-ring-max 128                       ; Longitud máxima del anillo de matar
 create-lockfiles nil                    ; Impido la creación de ficheros .#
 )

Configuración de la fuente #

Uso las fuentes Fira Code para esta configuración, lo más probable es que sea necesario instalarla en tu máquina. Generalmente se puede encontrar en los diversos administradores de paquetes de distribución Linux o se pueden descargar desde los enlaces anteriores.

(set-face-attribute 'default nil :font "Fira Code" :height 120)

;; Set the fixed pitch face
(set-face-attribute 'fixed-pitch nil :font "Fira Code" :height 120)

Ligaduras #

La GUI predeterminada de Emacs no admite ligaduras de programación. Si estás usando una versión >= 28 de Emacs , el método más fácil es usar ligature.el de Mickey Petersen ( de “Mastering Emacs”)

(setq master-font-family "FiraCode")
(use-package ligature
  :config
  (ligature-set-ligatures 't '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
                                                         ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
                                                         "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
                                                         "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
                                                         "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
                                                         "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
                                                         "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
                                                         "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
                                                         ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
                                                         "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
                                                         "##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
                                                         "?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
                                                         "\\\\" "://"))
  (global-ligature-mode t)
  )

Configuración combinación de teclas #

;; ESC para salr de los prompts
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)

;; Incrementa el tamaño de la fuente
(global-set-key (kbd "C-+") 'text-scale-increase)

;; Disminuye el tamaño de la fuente
(global-set-key (kbd "C--") 'text-scale-decrease)

;; Mover entre ventanas con teclas dirección
(global-set-key (kbd "C-c <left>")  'windmove-left)
(global-set-key (kbd "C-c <right>") 'windmove-right)
(global-set-key (kbd "C-c <up>")    'windmove-up)
(global-set-key (kbd "C-c <down>")  'windmove-down)

Configuración UI #

Color Theme #

ef-themes son una colección de temas claros y oscuros para GNU Emacs cuyo objetivo es proporcionar opciones coloridas (“bastante”) pero legibles. son ocho temas: https://protesilaos.com/codelog/2022-08-18-ef-themes-demo/.


;; Make customisations that affect Emacs faces BEFORE loading a theme
;; (any change needs a theme re-load to take effect).

;; (setq ef-themes-headings ; read the manual's entry or the doc string
;;       '((0 . (variable-pitch light 1.9))
;;         (1 . (variable-pitch light 1.8))
;;         (2 . (variable-pitch regular 1.7))
;;         (3 . (variable-pitch regular 1.6))
;;         (4 . (variable-pitch regular 1.5))
;;         (5 . (variable-pitch 1.4)) ; absence of weight means `bold'
;;         (6 . (variable-pitch 1.3))
;;         (7 . (variable-pitch 1.2))
;;         (t . (variable-pitch 1.1))))

;; They are nil by default...
(setq ef-themes-mixed-fonts t
      ef-themes-variable-pitch-ui t)

;; Disable all other themes to avoid awkward blending:
(mapc #'disable-theme custom-enabled-themes)

  (use-package ef-themes
    :config
    (load-theme 'ef-dark t))

Smex #

smex 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.

;; iniciamos Smex
(use-package smex
  :config
  (smex-initialize))

Which Key #

which-key es un panel de interfaz de usuario útil que aparece cuando comienza a presionar cualquier combinación de teclas en Emacs para ofrecerte todas las terminaciones posibles para el prefijo. Por ejemplo, si presiona C-c (mantén presionada la tecla control y presiona la letra c), aparecerá un panel en la parte inferior del marco que muestra todos los enlaces bajo ese prefijo y qué comando ejecutan. Esto es muy útil para aprender las posibles combinaciones de teclas en el modo de su búfer actual.

(use-package which-key
  :init (which-key-mode)
  :diminish which-key-mode
  :config
  (setq which-key-idle-delay 1))

Ivy y Counsel #

Ivy es un excelente framework de completado para Emacs. Proporciona un menú de selección mínimo pero poderoso que aparece cuando abres archivos, cambias de búfer y para muchas otras tareas en Emacs. Counsel es un conjunto personalizado de comandos para reemplazar `find-file` por` counsel-find-file`, etc., que proporcionan comandos útiles para cada uno de los comandos de finalización predeterminados.

ivy-rich agrega columnas adicionales a algunos de los comandos de Counsel para proporcionar más información sobre cada elemento.

(use-package ivy
  :diminish
  :bind (("C-s" . swiper)
         :map ivy-minibuffer-map
         ("TAB" . ivy-alt-done)
         ("C-l" . ivy-alt-done)
         ("C-j" . ivy-next-line)
         ("C-k" . ivy-previous-line)
         :map ivy-switch-buffer-map
         ("C-k" . ivy-previous-line)
         ("C-l" . ivy-done)
         ("C-d" . ivy-switch-buffer-kill)
         :map ivy-reverse-i-search-map
         ("C-k" . ivy-previous-line)
         ("C-d" . ivy-reverse-i-search-kill))
  :config
  (ivy-mode 1))

(use-package ivy-rich
  :init
  (ivy-rich-mode 1))

(use-package counsel
  :bind (("C-M-b" . 'counsel-switch-buffer)
         :map minibuffer-local-map
         ("C-r" . 'counsel-minibuffer-history))
  :custom
  (counsel-linux-app-format-function #'counsel-linux-app-format-function-name-only)
  :config
  (counsel-mode 1))

Perspective #

El paquete Perspective proporciona múltiples espacios de trabajo con nombre (o “perspectivas”) en Emacs, similar a múltiples escritorios en administradores de ventanas como Awesome y XMonad, y Spaces en Mac.

Perspective proporciona dos comandos para listar búferes usando Ivy y Counsel: persp-ivy-switch-buffer and persp-counsel-switch-buffer.

(use-package perspective
  :bind
  ("C-x C-b" . persp-list-buffers)
  ("C-x k" . persp-kill-buffer*)
  :custom
  (persp-mode-prefix-key (kbd "C-c C-p"))
  :init
  (persp-mode -1))

Complementos #

Ficheros a usar para la autenticación #

Ubicación del fichero authinfo.pgp para la autenticación en diversos servidores.

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

Actualizar automáticamente los paquetes #

Actualiza los paquetes cada 7 días a las 09:00 horas, sustituye antiguas versiones por la nuevas

(use-package auto-package-update
  :custom
  (auto-package-update-interval 7)
  (auto-package-update-delete-old-versions t)
  (auto-package-update-prompt-before-update t)
  (auto-package-update-hide-results t)
  :config
  (auto-package-update-maybe)
  (auto-package-update-at-time "09:00"))

Corrector ortográfico #

Corrector de ortografía en español, has de tener instalado aspell-es en el sistema

(setq ispell-program-name "aspell")
(setq ispell-local-dictionary "espanol")
(setq ispell-local-dictionary-alist
      '(("espanol" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil nil nil utf-8)))

FlySpell #

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

(use-package flyspell
  :defer 1
  :delight
  :custom
  (flyspell-abbrev-p t)
  (flyspell-issue-message-flag nil)
  (flyspell-issue-welcome-flag nil)
  (flyspell-mode 1))

(use-package flyspell-correct-ivy
  :after flyspell
  :bind (:map flyspell-mode-map
              ("C-;" . flyspell-correct-word-generic))
  :custom (flyspell-correct-interface 'flyspell-correct-ivy))

;; Activar Flyspell en modo texto y modos relacionados
(add-hook 'text-mode-hook
          #'(lambda () (flyspell-mode 1)))

Lingva #

El paquete lingva.el nos va a permitir hacer uso de lingva-translate pare realizar traducciones desde Emacs sin ser trakeados por Google.

(use-package lingva
  :config
  (setq lingva-source "auto"
        lingva-target "es"))

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.

(use-package undo-tree
:init
(global-undo-tree-mode 1)
:custom
      (undo-tree-visualizer-timestamps t)
      (undo-tree-visualizer-diff t)
      (undo-tree-auto-save-history nil))

Espacios en Blanco #

Elimina las lineas y espacion en blanco de manera automática.

(use-package whitespace
  :defer 1
  :hook (before-save . delete-trailing-whitespace))

(use-package hungry-delete
  :defer 0.7
  :delight
  :config (global-hungry-delete-mode))

Autorevert #

Recarga los archivos al ser modificados

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

Archivos recientes #

recentf es un modo menor en Emacs que crea una lista de archivos visitados recientemente, proporciona un acceso rápido a los archivos recientes mediante C-c r. Excluyo algunos archivos que nunca quiero volver a visitar, y también establezco el número máximo de elementos guardados en 50.

(use-package recentf
  :defer 2
  :bind ("C-c r" . recentf-open-files)
  :init (recentf-mode)
  :custom
  (recentf-max-menu-items 10)
  (recentf-max-saved-items 50)
  (recentf-exclude (list "COMMIT_EDITMSG"
                         "~$"
                         "/scp:"
                         "/ssh:"
                         "/sudo:"
                         "diario.*"
                         "recentf*"
                         "bookmark*"
                         "/archivo*"
                         "birthday*"
                         "*elpa/*"
                         "/tmp/"
                         "drafts/*"
                         "/.elfeed"
                         "/.telega"
                         "/.config"
                         "~/.emacs.d/s*"))
    :config (run-at-time nil (* 5 60) 'recentf-save-list))

Buffer #

No pregunta antes de matar un buffer.

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

Dashboard #

Una pantalla de inicio bonita, uso 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. Mi configuración:

(use-package all-the-icons)

(setq dashboard-icon-type 'all-the-icons) ;; use `all-the-icons' package
(use-package dashboard
  :custom
  (dashboard-startup-banner "~/Imágenes/mariposa.png")
  (dashboard-banner-logo-title (format "Buen día %s" user-full-name))
  (dashboard-items '((recents . 4)
                     (bookmarks . 4)
                     (agenda . 3)))
  :config
  (dashboard-setup-startup-hook)
  (setq dashboard-set-heading-icons t
        dashboard-set-file-icons t
        dashboard-set-init-info t
        dashboard-set-navigator t)
  (setq dashboard-navigator-buttons
        `((
           (,(when (display-graphic-p)
               (all-the-icons-octicon "home" :height 1.1 :v-adjust 0.0))
            "Página web" "El Blog de Lázaro"
            (lambda (&rest _) (browse-url "https://elblogdelazaro.org")))
           (,(when (display-graphic-p)
               (all-the-icons-material "home" :height 1.35 :v-adjust -0.24))
            "Localhost" "Abrir Hugo localhost"
            (lambda (&rest _) (browse-url "http://localhost:1313/")))
           (,(when (display-graphic-p)
               (all-the-icons-octicon "tools" :height 1.0 :v-adjust 0.0))
            "Configuración" "Abrir configuración de emacs (.org)"
            (lambda (&rest _) (find-file (expand-file-name  "~/.emacs.d/Emacs.org"))))
           (,(when (display-graphic-p)
               (all-the-icons-octicon "calendar" :height 1.0 :v-adjust 0.0))
            "Agenda" "Agenda personal"
            (lambda (&rest _)
              (interactive)
              (if (get-buffer "*Org Agenda*")
                  (progn
                    (switch-to-buffer-other-window "*Org Agenda*")
                    (kill-buffer "*Org Agenda*")
                    (org-agenda-list))
                (split-window-right)
                (org-agenda-list))))
           ))))
;; F10 para ir al Dashboard
(global-set-key (kbd "<f10>") 'open-dashboard)
(defun open-dashboard ()
  "Open the *dashboard* buffer and jump to the first widget."
  (interactive)
  (delete-other-windows)
  ;; Refresh dashboard buffer
  (if (get-buffer dashboard-buffer-name)
      (kill-buffer dashboard-buffer-name))
  (dashboard-insert-startupify-lists)
  (switch-to-buffer dashboard-buffer-name))

Ditaa #

Convierte texto ASCII a gráfico, ubicacion del binario, has de instalar ditaa en tu sistema.

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

Pdf-tools como visor PDF predeterminado #

PDF Tools es una biblioteca para archivos PDF y tiene muchas características como anotaciones, Yo sólo la uso para visualización, pero tiene muchas características que vale la pena explorar.

Algo importante es que esta biblioteca no funciona bien con linum-mode. Las siguiente línea de código desactivara este modo al renderizar .pdf: (add-hook 'pdf-view-mode-hook (lambda() (linum-mode -1)))

(use-package pdf-tools
  :config
  (pdf-tools-install)
  (setq-default pdf-view-display-size 'fit-width))

(add-hook 'pdf-view-mode-hook (lambda() (linum-mode -1)))

También hay pdf-view-themed-minor-mode que se ajusta automáticamente al tema que está usando, C-c C-r t

Eww como navegador por defecto #

Paso mucho tiempo dentro de Emacs, por que lo que me es útil abrir los enlaces url en el propio navegador de Emacs

(setq browse-url-browser-function 'eww-browse-url ) ; Use eww as the default browser

Org Mode #

Org Mode es una de las características distintivas de Emacs y por las que empecé a utilizar Emacs. Es un rico editor de documentos, planificador de proyectos, rastreador de tareas y de tiempo, generador de blogs y programación literaria, todo en un solo paquete.

Configuración Básica #

Esta sección contiene la configuración básica de org-mode, es decir, ficheros a tratar por la agenda, ubicación del archivo diario, etiquetas, etc.

(use-package org
  :ensure org-contrib
  :config
  (setq org-ellipsis " ▾")

  (setq org-agenda-start-with-log-mode t)
  (setq org-log-done 'time)
  (setq org-log-into-drawer t)

  (setq org-agenda-files
        '("~/.personal/agenda/personal.org"
          "~/.personal/agenda/trabajo.org"
          "~/.personal/agenda/diario.org"))
                                        ;"~/.personal/agenda/diario-ibx.org"))

  ;; utilizo mi propio diario para a la agenda, asi que deshabilito el de emacs
  (setq org-agenda-include-diary nil)
  ;; (setq diary-file "~/.personal/agenda/diario.org")
  (setq org-agenda-diary-file "~/.personal/agenda/diario.org")

  ;; ubicacion de los ficheros cuando son archivados, organizados por fecha
  (setq org-archive-location "~/.personal/archivo/%s_archivo.org::datetree/")

  (setq org-todo-keywords
        '((sequence "PORHACER(p!)"
                    "ENPROCESO(e!)"
                    "BLOQUEADO(b!)"
                    "|" "HECHO(h!)" "ARCHIVAR(a!)")))


  ;; Configuracion de colores (faces) para estados todo
   (setq org-todo-keyword-faces
         '(("PORHACER" . "red")
           ("ENPROCESO" . "yellow")
           ("BLOQUEADO" . "orange")
           ("HECHO" . "green")
           ("PUBLICADO" . "green")
           ("ARCHIVAR" .  "blue")))

   ;; Estados para el blog

       (setq org-todo-keyword-faces
         '(("BORRADOR" . "red")
           ("OCULTO" . "orange")
           ("PUBLICADO" .  "cyan")))

       (setq org-refile-targets
         '(("personal.org" :maxlevel . 1)
          ("trabajo.org" :maxlevel . 1)))

  ;; Save Org buffers after refiling!
  (advice-add 'org-refile :after 'org-save-all-org-buffers)

  ;; etiquetas que utilizo para mis notas
  (setq org-tag-alist '(("@nota" . ?n)
                        ("@casa" . ?c)
                        ("@finanzas" . ?d)
                        ("@fecha" . ?f)
                        ("@salud" . ?s)
                        ("@tarea" . ?t)
                        ("@coche" . ?h)
                        ("@trabajo" . ?b)
                        ("crypt" . ?C)))
  (setq org-tags-exclude-from-inheritance '("crypt"))

  ;; Progress Logging
  ;; When a TODO item enters DONE, add a CLOSED: property with current date-time stamp and into drawer
  (setq org-log-done 'time)
  (setq org-log-into-drawer "LOGBOOK")
  ;;
  ;; Alinea etiquetas
  (setq org-tags-column 70))

;; Aspecto mejorado al identar
(add-hook 'org-mode-hook 'org-indent-mode)


;; 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 esta, haga un salto de carro.
(add-hook 'org-mode-hook 'visual-line-mode)

Mejor Encabezado de Bullets #

org-bullets reemplaza las estrellas del encabezado en org-mode búfers con caracteres más agradables que puedes controlar. Otra opción para esto es org-superstar-mode.

(use-package org-bullets
  :after org
  :hook (org-mode . org-bullets-mode)
  :custom
  (org-bullets-bullet-list '("◉" "○" "●" "○" "●" "○" "●")))

Centrado de Buffers Org #

Uso visual-fill-column para centrar los búfers de org-mode para una experiencia de escritura más agradable, ya que centra el contenido del búfer horizontalmente para que parezca más, como si estuviera editando un documento. Esto es realmente una cuestión personal, por lo que puedes eliminar el bloque de continuación si no te gusta el comportamiento.

(use-package visual-fill-column
  :hook (org-mode . visual-fill-column-mode)
  :custom
  (visual-fill-column-center-text t)
  (visual-fill-column-width 100)
  (visual-fill-column-mode 1))

Org-agenda #

Contiene la configuración de las vistas de agenda, los contactos, plantillas de capturas, tareas, notificaciones, etc.

Org-Contacts #

La mejor solución para mantener tus contactos. Suelo usar org-contacts está disponible en org-contrib. Los contactos se guardan de forma automática en el fichero contactos.org

(use-package org-contacts
  :after org
  :custom
  (org-contacts-files '("~/.personal/agenda/contactos.org")))

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.

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

Para filtrar las vistas utilizo org-super-agenda, este paquete te permite “sobrealimentar” la agenda diaria/semanal. La idea es agrupar elementos en secciones, en lugar de tenerlos todos en una gran lista.

(global-set-key (kbd "<f7>") 'org-agenda)

(use-package org-super-agenda
  :config
  (org-super-agenda-mode))

(setq org-agenda-skip-scheduled-if-done t
      org-agenda-skip-deadline-if-done t
      org-agenda-compact-blocks t
      org-agenda-window-setup 'current-window
      org-agenda-start-on-weekday 1
      org-deadline-warning-days 7
      org-agenda-time-grid '((daily today require-timed))
      org-agenda-custom-commands
      '(
        ("x" "Vista trabajo"
         ((agenda "" ((org-agenda-span 3)
                      (org-super-agenda-groups
                       '((:name "Hoy"
                                :discard (:tag "personal")
                                :time-grid t
                                :scheduled past
                                :deadline past
                                :date today
                                :order 1)))))
          (alltodo "" ((org-agenda-overriding-header "")
                       (org-super-agenda-groups
                        '((:discard (:tag "personal" ))
                          (:name "Vencimiento hoy"
                                 :deadline today
                                 :order 5)
                          (:name "Próximamente"
                                 :deadline future
                                 :order 11)
                          (:name "Atrasado"
                                 :scheduled past
                                 :deadline past
                                 :order 12)
                          (:name "Por hacer"
                                  ;:discard (:scheduled future :deadline future)
                                 :todo "PORHACER"
                                 :order 12)
                          (:name "Esperando"
                                 :todo "BLOQUEADO"
                                 :order 14)))))
          (tags "trabajo/HECHO"
                ((org-agenda-overriding-header " Tareas Hechas")))))

        ("z" "Vista personal"
         ((agenda "" ((org-agenda-span 3)
                      (org-super-agenda-groups
                       '((:name "Hoy"
                                :discard (:tag "trabajo" :scheduled past :deadline past)
                                :time-grid t
                                :date today
                                :scheduled today
                                :order 1)
                         (:name ""
                                :tag "agenda"
                                :todo "Aniversarios")))))
          (alltodo "" ((org-agenda-overriding-header "")
                       (org-super-agenda-groups
                        '((:discard (:tag "trabajo" ))
                          (:name "Vencimiento hoy"
                                 :deadline today
                                 :order 5)
                          (:name "Atrasado"
                                 :scheduled past
                                 :deadline past
                                 :order 11)
                          (:name "Por hacer"
                                 :discard (:scheduled future :deadline future)
                                 :todo "PORHACER"
                                 :order 12)
                          (:name "Esperando"
                                 :todo "BLOQUEADO"
                                 :order 14)))))
          (tags "personal/HECHO"
                ((org-agenda-overriding-header " Tareas Hechas")))))
        ))

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.

(require 'appt)
(appt-activate 1)

(use-package notifications
  :demand t)
(add-hook 'org-finalize-agenda-hook 'org-agenda-to-appt) ;; update appt list on agenda view

(setq appt-display-format 'window
      appt-message-warning-time '5)
(setq appt-disp-window-function
      (lambda (nmins curtime msg)
        (notifications-notify :title "Recordatorio!!"
                              :body (format "Tienes una cita %s en %d minutos" msg (string-to-number nmins))
                              :app-name "Emacs: Org"
                              :sound-name "alarm-clock-elapsed")))
(display-time)   ;; activate time display
(run-at-time "24:01" 3600 'org-agenda-to-appt)   ;; update appt list hourly
(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.

(use-package org-capture
  :ensure nil
  :after org
  :bind ("C-c c" . org-capture)
  :preface
  (defvar my/org-basic-task-template "* PORHACER %?
   Añadido: %U" "Plantilla básica de tareas.")

  (defvar my/org-meeting-template "* Cita con %^{CON}
   :PROPERTIES:
   :SUMMARY: %^{DESCRIPCION ....}
   :NOMOBRE: %^{NOMBRE ....}
   :LUGAR: %^{DONDE ....}
   :DIRECCION: %^{CALLE ....}
   :TELEFONO: %^{123-456-789}
   :NOTA: %^{NOTAS}
   :AÑADIDA: %U
   :END:
   Fecha de la reunión: %?%T" "Plantilla para programar reuniones.")

  (defvar my/org-contacts-template "* %(org-contacts-template-name)
   :PROPERTIES:
   :EMAIL: %(org-contacts-template-email)
   :PHONE: %^{123-456-789}
   :HOUSE: %^{123-456-789}
   :ALIAS: %^{nick}
   :NICKNAME: %^{hefistion}
   :IGNORE:
   :NOTE: %^{NOTA}
   :ADDRESS: %^{Calle Ejemplo 1 2A, 28320, Pinto, Madrid, España}
   :BIRTHDAY: %^{yyyy-mm-dd}
   :END:" "Plantilla para org-contacts.")
  :custom
  (org-capture-templates
   `(("c" "Contactos" entry (file+headline "~/.personal/agenda/contactos.org" "Amigos"),
      my/org-contacts-template)

     ("f" "Fecha" entry (file+headline "~/.personal/agenda/reubicar.org" "Fechas"),
      my/org-basic-task-template)

     ("n" "Nota" entry (file+headline "~/.personal/agenda/reubicar.org" "Nota"),
      my/org-basic-task-template)

     ("i" "Cita" entry (file+datetree "~/.personal/agenda/diario.org"),
      my/org-meeting-template)

     ("b" "Blog" entry (file+headline "~/.personal/agenda/reubicar.org" "Blog"),
      my/org-basic-task-template)

     ("t" "Tarea" entry (file+headline "~/.personal/agenda/reubicar.org" "Tareas"),
      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

(use-package org-crypt
  :ensure nil
  :after org)
(org-crypt-use-before-save-magic)
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
(setq org-crypt-key "xxxxxxxx")
(setq org-crypt-disable-auto-save nil)

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.

(setq org-use-speed-commands 'my-org-use-speed-commands-for-headings-and-lists)
(with-eval-after-load 'org
  (let ((listvar (if (boundp 'org-speed-commands) 'org-speed-commands
                   'org-speed-commands-user)))
    (add-to-list listvar '("A" org-archive-subtree-default))
    (add-to-list listvar '("a" org-todo "ARCHIVAR"))
    (add-to-list listvar '("b" org-todo "BLOQUEADO"))
    (add-to-list listvar '("e" org-todo "ENPROCESO"))
    (add-to-list listvar '("x" org-todo "HECHO"))
    (add-to-list listvar '("x" org-todo-yesterday "HECHO"))
    (add-to-list listvar '("s" call-interactively 'org-schedule))
    (add-to-list listvar '("i" call-interactively 'org-clock-in))
    (add-to-list listvar '("o" call-interactively 'org-clock-out))
    (add-to-list listvar '("d" call-interactively 'org-clock-display))
    (add-to-list listvar '("$" call-interactively 'org-archive-subtree))))

;; Cambiamos el estado de la tarea cuando inicia o para el reloj
(setq org-clock-in-switch-to-state "ENPROCESO")
(setq org-clock-out-switch-to-state "BLOQUEADO")

Funciones propias #

Funciones muy simples que simplemente me van a ayudar a acceder fácilmente a mis ficheros de actividades, tareas y notas, escribiéndolo en el mini-buffer con M-x


(defun my-org-use-speed-commands-for-headings-and-lists ()
    "Activate speed commands on list items too."
  (or (and (looking-at org-outline-regexp) (looking-back "^\**" nil))
      (save-excursion (and (looking-at (org-item-re)) (looking-back "^[ \t]*" nil)))))

Personalizando el calendario #

calfw-org 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 realizo unos ajustes de aspecto, como poner que empiece el calendario en Lunes (por defecto lo hace en Domingo) y además pongo los meses y los días de la semana en español.

Personalizando los meses y semana #


(setq calendar-month-name-array
      ["Enero" "Febrero" "Marzo" "Abril" "Mayo" "Junio"
       "Julio"    "Agosto"   "Septiembre" "Octubre" "Noviembre" "Diciembre"])

(setq calendar-day-name-array
      ["Domingo" "Lunes" "Martes" "Miércoles" "Jueves" "Viernes" "Sábado"])

(setq org-icalendar-timezone "Europe/Madrid") ;; timezone
(setq calendar-week-start-day 1) ;; la semana empieza el lunes
(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.

(setq calendar-holidays '((holiday-fixed 1 1 "Año Nuevo")
                          (holiday-fixed 1 6 "Reyes Magos")
                          (holiday-fixed 3 19 "San José")
                          (holiday-fixed 5 1 "Dia del Trabajo")
                          (holiday-fixed 5 2 "Comunidad de Madrid")
                          (holiday-fixed 5 15 "San Isidro")
                          (holiday-fixed 8 15 "Asunción")
                          (holiday-fixed 10 12 "Día de la Hispanidad")
                          (holiday-fixed 11 01 "Todos los Santos")
                          (holiday-fixed 11 09 "Almudena")
                          (holiday-fixed 12 06 "Constitución")
                          (holiday-fixed 12 08 "Inmaculada")
                          (holiday-fixed 12 25 "Navidad")
                          ))

Poniendo una vista bonita al calendario #

(use-package calfw
    :config
  (setq cfw:org-overwrite-default-keybinding t)) ;; atajos de teclado de la agenda org-mode

(use-package calfw-org
    :ensure t
    :config
    (setq cfw:org-overwrite-default-keybinding t)
    :bind ([f8] . cfw:open-org-calendar))

Sincronización con Caldav #

Utilizo 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

(use-package org-caldav
  :bind ([f4] . org-caldav-sync)
  :preface
  :custom
  ;; Calendarios a utilizar
  (org-caldav-url "https://server.es/caldav/group==familia")
  (org-caldav-calendars
   '((:calendar-id "carlos--xxxxx"
                   :files ("~/.personal/agenda/diario.org")
                   :inbox "~/.personal/agenda/diario-ibx.org")))
  (org-caldav-backup-file "~/.personal/calendario/org-caldav-backup.org")
  (org-caldav-save-directory "~/.personal/calendario/")
  (org-icalendar-alarm-time 1)
  )

Configurar Lenguajes en Babel #

Para ejecutar o exportar código en bloques de código en org-mode, debes configurar org-babel-load-languages para cada lenguaje que desees utilizar. Esta página documenta todos los lenguajes que puedes usar con org-babel.

La función structure templates del Modo Org permite insertar rápidamente bloques de código en tus archivos Org escribiendo C-c C-, seguido del nombre de la plantilla como el o py y luego presione TAB. Por ejemplo, para insertar un bloque emacs-lisp vacío a continuación, puede escribir C-c C-, y presionar TAB para expandirlo en dicho bloque.

Puedes agregar más plantillas src de bloque, copiando una de las líneas y cambiando las dos cadenas al final, la primera para que sea el nombre de la plantilla y la segunda para que contenga el nombre del lenguaje como lo conoce Org Babel.

(org-babel-do-load-languages
 'org-babel-load-languages
 '((lisp . t)
   ;; (python . t)
   (shell . t)
   ))
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))

Auto-tangle Ficheros de Configuración #

Este snippet agrega un enlace a los búferes org-mode para que efs/org-babel-tangle-config se ejecute cada vez que se guarda dicho búfer. Esta función comprueba si el archivo que se está guardando es el archivo Emacs.org que estás viendo en este momento, y si es así, exporta automáticamente la configuración a los archivos de salida asociados.

;; Automatically tangle our Emacs.org config file when we save it
(defun efs/org-babel-tangle-config ()
  (when (string-equal (file-name-directory (buffer-file-name))
                      (expand-file-name user-emacs-directory))
    ;; Dynamic scoping to the rescue
    (let ((org-confirm-babel-evaluate nil))
      (org-babel-tangle))))

(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'efs/org-babel-tangle-config)))

Desarrollo #

Lenguajes #

Markdown #

A veces escribo notas en Markdown, por eso lo mantengo, utilizo pandoc

(use-package markdown-mode
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . gfm-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "pandoc")
  :config
  (setq visual-line-column 80)
  (setq markdown-fontify-code-blocks-natively t)
  (setq markdown-enable-math t))

Magit #

Magit es una interfaz para el sistema de control de versiones Git, implementado como un paquete Emacs.

git-gutter permite ver las líneas que se están modificando en el archivo mientras lo estoy editando.

Con git-timemachine visualizas fácilmente los cambios realizados en commits anteriores.

(use-package magit
  :bind
  ("C-x g" . magit-status))

(use-package git-gutter
  :defer 0.3
  :delight
  :init (global-git-gutter-mode))

(use-package git-timemachine
  :defer 1
  :delight)

Rainbow Delimiters #

rainbow-delimiters es útil en los modos de programación porque colorea los paréntesis y corchetes anidados de acuerdo con su profundidad de anidación. Esto hace que sea mucho más fácil hacer coincidir visualmente los paréntesis en el código

;; Mostrar al padre
(show-paren-mode 1)

;; auto close bracket insertion.
(electric-pair-mode 1)

(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))

Ox-hugo #

Exporta archivos org a formato markdown compatible con Hugo Server, mi blog está construido así

(use-package ox-hugo
  :after ox)

Terminal #

Vterm #

Porque es rápido, altamente compatible y e como se anuncia: “Usar vterm es como usar Gnome Terminal dentro de Emacs. A diferencia de eshell, vterm respeta mi archivo de configuración .zshrc.

(use-package vterm
  :bind
  (:map
   vterm-mode-map
   ("C-y" . vterm-yank)
   ("C-q" . vterm-send-next-key)))

Tramp #

Tramp es excelente para trabajar en archivos remotos. La configuración es simple

(use-package tramp
  :ensure nil
  :defer t
  :config
  (setq tramp-default-user "carlos"
        tramp-default-method "ssh")
  (use-package counsel-tramp
    :bind ("C-c t" . counsel-tramp))
  (put 'temporary-file-directory 'standard-value '("/tmp")))

Administrador de Archivos #

Dired #

Dired es un administrador de archivos integrado para Emacs que hace cosas asombrosas. Aquí hay algunas combinaciones de teclas que debes probar:

Atajos de teclado #

  • Navegación

    • n - próxima línea
    • p - lìnea previa
    • j - saltar al archivo en el búfer
    • RET - seleccionar archivo o directorio
    • ^ - ir al directorio superior
    • S-RET - Abrir fichero en “otra” ventana
    • M-RET - Mostrar archivo en otra ventana sin enfocar (vista previa de archivos)
    • g o (dired-view-file) -Abrir archivo pero en modo “vista previa”, cerrar con q
    • g / g r Actualice el búfer con revert-buffer después de cambiar la configuración (¡y después de que cambie el sistema de archivos!)
  • Marcar archivos

    • m - MArca un archivo
    • u - Desmarca un archivo
    • U - Desmarca todos los archivos del búfer
    • * t / t -Invierte archivos marcados en el búfer
    • % m - Marcar archivos en el búfer usando expresión regular
    • * - Muchas otras funciones de marcado automático
    • k / K - “Eliminar” elementos marcados (actualizar el búfer con g / g r para recuperarlos)
    • ¡Se pueden realizar muchas operaciones en un solo archivo si no hay marcas activas!
  • Copiar y renombrar archivos

    • C - Copiar archivos marcados (o si no hay archivos marcados, el archivo actual)
    • Copia de archivos únicos y múltiples
    • U - Desmarcar todos los archivos en el búfer
    • R - ¡Cambiar el nombre de los archivos marcados, cambiar el nombre de varios es un movimiento!
    • % R - Cambiar el nombre según la expresión regular: = ^ test =, = old - \ & =

    Comando: C-x C-q = (=dired-toggle-read-only) - ¡Hace que todos los nombres de archivo en el búfer sean editables directamente para cambiarles el nombre! Presione Z Z para confirmar el cambio de nombre o Z Q para cancelar.

  • Eliminando archivos

    • D - Eliminar archivo marcado
    • d - Marcar archivo para borrar
    • x - Ejecutar eliminación de marcas
    • delete-by-moving-to-trash - Mover a la papelera en lugar de eliminar permanentemente
  • Creación y extracción de archivos.

    • Z - Comprimir o descomprimir un archivo o carpeta en (.tar.gz)
    • c - Comprimir la selección a un archivo específico
    • dired-compress-files-alist - Vincular comandos de compresión a la extensión del archivo
    • + - Crear un directorio nuevo
  • Otras operaciones habituales

    • T - Toque (cambiar marca de tiempo)
    • M - Cambiar modo de archivo
    • O - Cambiar propietario del archivo
    • G - Cambiar grupo de archivos
    • S - Crea un enlace simbólico a este archivo
    • L - Carga un archivo Emacs Lisp en Emacs

Configuración #

(use-package dired
  :ensure nil
  :commands (dired dired-jump)
  :bind (("C-x C-j" . dired-jump))
  :custom ((dired-listing-switches "-agho --group-directories-first")))

(use-package all-the-icons-dired
  :hook (dired-mode . all-the-icons-dired-mode))

;; Por defecto los ficheros ocultos no se muestran hasta que pulsamos la tecla .
(use-package dired-hide-dotfiles
  :bind
  (:map dired-mode-map
        ("." . dired-hide-dotfiles-mode))
  :hook
  (dired-mode . dired-hide-dotfiles-mode))

Social #

Correo #

Manejo mis cuentas de correo desde Emacs, escribí un artillo sobre conmo preparar y configurar Emacs para Gamil. quizas estes interesado en echarle un vistazo 👀

Mbsync #

Se utiliza para descargar correos electrónicos desde diferentes servidores IMAP y sincronizar los cambios realizados con nuestro buzon local.

Necesitamos crear un fichero de configuración para mbsync, crea un fichero llamado .mbsyncrc en tu $HOME con el siguiente código:

IMAPAccount gmail
Host imap.gmail.com
User [email protected]
Pass password_gmail
AuthMechs LOGIN
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore gmail-remote
Account gmail

MaildirStore gmail-local
Subfolders Verbatim
Path ~/.mail/gmail/
Inbox ~/.mail/gmail/Inbox

Channel gmail
Far :gmail-remote:
Near :gmail-local:
Patterns * ![Gmail]* "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail"
Create Both
SyncState *

IMAPStore synology-remote
Account synology

IMAPAccount synology
Host dominio.es
User [email protected]
Pass xxxxxxx
AuthMechs LOGIN
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore synology-remote
Account synology

MaildirStore synology-local
Subfolders Verbatim
Path ~/.mail/synology/
Inbox ~/.mail/synology/Inbox

Channel synology
Far :synology-remote:
Near :synology-local:
Patterns *
Create Both
SyncState *

Mu4e #

Interfaz para Emacs de mu

El siguiente código está configurado para poder consultar mi correo de gmail y el de mi propio servidor de correo alojado en mi NAS.

(use-package mu4e
  :ensure nil
  :bind ("C-c m" . mu4e)
:config
(setq mail-user-agent 'mu4e-user-agent          ; mu4e e-mail default program
      message-kill-buffer-on-exit t
      message-send-mail-function 'smtpmail-send-it
      mu4e-attachment-dir "~/Descargas"
      mu4e-change-filenames-when-moving t
      mu4e-completing-read-function 'completing-read
      mu4e-compose-complete-addresses t
      mu4e-compose-context-policy nil
      mu4e-compose-dont-reply-to-self t
      mu4e-compose-keep-self-cc nil
      mu4e-context-policy 'pick-first
      mu4e-get-mail-command "mbsync -a"
      mu4e-headers-date-format "%d-%m-%Y %H:%M"
      mu4e-headers-fields '((:human-date . 20)
                            (:flags . 6)
                            (:mailing-list . 10)
                            (:from . 22)
                            (:subject))
      mu4e-headers-include-related t
      mu4e-sent-messages-behavior 'delete       ; don't save messages to Sent Messages
      mu4e-view-show-addresses t
      smtpmail-debug-info t
      smtpmail-stream-type 'starttls
      mm-sign-option 'guided
      mu4e-html2text-command "w3m -T text/html" ; how to hanfle html-formatted emails
      mu4e-update-interval 300                  ; seconds between each mail retrieval
      mu4e-headers-auto-update t                ; avoid to type `g' to update
      mu4e-view-show-images t                   ; show images in the view buffer
      mu4e-compose-signature-auto-include nil   ; I don't want a message signature
      mu4e-use-fancy-chars t)                   ; allow fancy icons for mail threads


(when (fboundp 'imagemagick-register-types)
  (imagemagick-register-types))

(defun sign-or-encrypt-message ()
  (let ((answer (read-from-minibuffer "Firmar o cifrar?\nEn blanco no hace nada.\n[f/c]: ")))
    (cond
     ((string-equal answer "f") (progn
                                  (message "Firmando mensaje.")
                                  (mml-secure-message-sign-pgpmime)))
     ((string-equal answer "c") (progn
                                  (message "Cifrando y formando mensaje.")
                                  (mml-secure-message-encrypt-pgpmime)))
     (t (progn
          (message "No firmar o cifrar mensaje.")
          nil)))))

(add-hook 'message-send-hook 'sign-or-encrypt-message)

(setq mu4e-contexts
      `( ,(make-mu4e-context
           :name "gmail"
           :enter-func (lambda ()
                         (mu4e-message "Entering gmail context")
                         (when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
                           (revert-buffer)))
           :leave-func (lambda ()
                         (mu4e-message "Leaving gmail context")
                         (when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
                           (revert-buffer)))
           :match-func (lambda (msg)
                         (when msg
                           (or (mu4e-message-contact-field-matches msg :to "[email protected]")
                               (mu4e-message-contact-field-matches msg :from "[email protected]")
                               (mu4e-message-contact-field-matches msg :cc "[email protected]")
                               (mu4e-message-contact-field-matches msg :bcc "[email protected]")
                               (string-match-p "^/gmail/Inbox" (mu4e-message-field msg :maildir)))))
           :vars '( ( user-mail-address            . "[email protected]" )
                    ( smtpmail-smtp-user           . "[email protected]" )
                    ( mu4e-compose-signature       . "Carlos M." )
                    ( smtpmail-smtp-server         . "smtp.gmail.com" )
                    ( smtpmail-smtp-service        . 587 )
                    ( mu4e-maildir-shortcuts       . ((:maildir "/gmail/Inbox" :key ?i)))
                    ( mu4e-bookmarks
                      .
                      (( :name  "Unread messages"
                         :query "maildir:/gmail/Inbox AND flag:unread AND NOT flag:trashed AND NOT outdoorexperten"
                         :key ?u)
                       ( :name "Today's messages"
                         :query "maildir:/gmail/Inbox AND date:today..now"
                         :key ?t)
                       ( :name "Last 7 days"
                         :query "maildir:/gmail/Inbox AND date:7d..now"
                         :hide-unread t
                         :key ?w)
                       ( :name "Deleted"
                         :query "flag:trashed"
                         :key ?d)))))

         ,(make-mu4e-context
           :name "synology"
           :enter-func (lambda ()
                         (mu4e-message "Entering synology context")
                         (when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
                           (revert-buffer)))
           :leave-func (lambda ()
                         (mu4e-message "Leaving synology context")
                         (when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
                           (revert-buffer)))
           :match-func (lambda (msg)
                         (when msg
                           (or (mu4e-message-contact-field-matches msg :to "[email protected]")
                               (mu4e-message-contact-field-matches msg :from "[email protected]")
                               (mu4e-message-contact-field-matches msg :cc "[email protected]")
                               (mu4e-message-contact-field-matches msg :bcc "[email protected]"))))

           :vars '( ( user-mail-address       . "[email protected]" )
                    ( smtpmail-smtp-user      . "[email protected]" )
                    ( smtpmail-smtp-server    . "smtp.dominio.es" )
                    ( smtpmail-smtp-service   . 587 )
                    ( mu4e-compose-signature  . "Carlos M." )
                    ( mu4e-maildir-shortcuts  . ((:maildir "/synology/Inbox" :key ?i)))
                    ( mu4e-bookmarks
                      .
                      (
                       ( :name  "Unread messages"
                         :query "maildir:/synology/Inbox AND flag:unread AND NOT flag:trashed"
                         :key ?u)
                       ( :name  "Draft mails"
                         :query "maildir:/synology/Draft"
                         :key ?b)
                       ( :name  "Sent mails"
                         :query "maildir:/synology/Sent"
                         :key ?s)
                       ( :name  "Junk"
                         :query "maildir:/synology/Junk"
                         :key ?j)
                       ( :name  "Trash"
                         :query "maildir:/synology/Trash"
                         :key ?t)
                       ( :name "Deleted"
                       :query "flag:trashed"
                       :key ?d))))))))

OrgMsg #

OrgMsg es un modo menor global de Emacs que combina el modo Org y el modo Mensaje para redactar y responder correos electrónicos en un estilo compatible con HTML.

(use-package org-msg
  :after mu4e
  :config
  (setq mail-user-agent 'mu4e-user-agent)
  (require 'org-msg)
  (setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
        org-msg-startup "hidestars indent inlineimages"
        org-msg-default-alternatives '((new		. (text html))
                                     (reply-to-html	. (text html))
                                     (reply-to-text	. (text)))
        org-msg-convert-citation t)
  (org-msg-mode))

Elfeed #

Lector de feeds RSS. Utilizo elfeed-org para guardar las direcciones de los feeds, elfeed-goddies para tener las vistas search y show en la misma ventana y elfeed-protocol para conectr con mi servidor FreshRss.

(use-package elfeed
  :bind
  ("C-x w" . elfeed))

(use-package elfeed-org
  :config
  (elfeed-org)
  (setq rmh-elfeed-org-files (list "~/.config/elfeed/elfeed.org"))
  (defun elfeed-search-format-date (date)
    (format-time-string "%Y-%m-%d %H:%M" (seconds-to-time date)))

  ;; Mark all YouTube entries
  (add-hook 'elfeed-new-entry-hook
            (elfeed-make-tagger :feed-url "youtube\\.com"
                                :add '(youtube)))
  ;; Mark all reddit entries
  (add-hook 'elfeed-new-entry-hook
            (elfeed-make-tagger :feed-url "reddit\\.com"
                                :add '(reddit))))



(use-package elfeed-goodies
  :after elfeed
  :config
  (elfeed-goodies/setup)
  (setq elfeed-goodies/entry-pane-position 'bottom
        elfeed-goodies/powerline-default-separator 'bar
        elfeed-goodies/entry-pane-size 0.65
        elfeed-goodies/feed-source-column-width 13
        elfeed-goodies/tag-column-width 24))

Mastodon #

Cliente para Mastodon

(use-package mastodon)
(setq mastodon-instance-url "https://mastodon.social"
      mastodon-active-user "@[email protected]")

#+end_src

Telegram #

telega.el es un cliente no oficial con todas las funciones para la plataforma Telegram en Emacs.

(use-package tracking)

(use-package telega
  :commands telega
  :defer t
  :custom
  (telega-use-tracking-for '(any pin unread))
  (telega-chat-use-markdown-formatting t)
  (telega-emoji-use-images t)
  (telega-completing-read-function #'selectrum-completing-read)
  (telega-msg-rainbow-title t)
  (telega-chat-fill-column 75)
  ;; (telega-appindicator-mode t)
  (telega-notifications-mode t)
  (telega-filters-custom nil))

(define-key global-map (kbd "C-c t") telega-prefix-map)

Emojify #

Emojify es una extensión Emacs para mostrar emojis. Puede mostrar emojis de estilo github como 😄 o simples ascii como :)

(use-package emojify
  :hook (after-init . global-emojify-mode))

Puedes encontrar mi fichero de configuracion en mi repositorio de Gitlab

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