Mi configuración de emacs para el framework de doom.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
drymer 34c025db51
Add previously delete org-agenda-custom-commands
пре 8 месеци
Makefile Initial commit пре 8 месеци
README.md Initial commit пре 8 месеци
README.org Add previously delete org-agenda-custom-commands пре 8 месеци

README.md

Índice

  1. Acerca de este documento
  2. Configurar el init.el
    1. Configurar el bind léxico
    2. Hacer más usable ivy
    3. Hacer más usable evil
    4. Configuración principal de doom
  3. Configuración Genérica
    1. Arrancar emacs
    2. Inicia empaquetado de configuración generica
    3. Seguridad de las conexiones
    4. Formato de las columnas de numeracion
    5. Aumentar y disminuir tamaño de la fuente
    6. Moverse por el buffer
    7. Establecer nombre y correo
    8. Lenguaje por defecto en emacs y org-mode
    9. No seguir enlaces simbólicos
    10. Mantener lista de buffers recientes
    11. Borrar espacios sobrantes
    12. Usar ssh con tramp
    13. Abrir enlaces en el navegador por defecto
    14. Terminal
    15. kill-this-buffer en vez de kill-buffer
    16. Ispell
    17. Mostrar orden en minibuffer
    18. Tipo de fuente
    19. Tema
    20. Scroll
    21. Deshabilitar numeros en los laterales
    22. Asignar un atajo de teclado a recompile
    23. Kill-ring-max
    24. Terminar empaquetado de configuración genérica
  4. org-mode
    1. Agenda
      1. Definir archivos de la agenda
      2. Comandos de Agenda
      3. Capturas de notas
      4. Estados de los objetos de las listas
      5. Refile
      6. Configuración del calendario
      7. Tareas repetitivas
      8. Quitar tags de la agenda
      9. Alargar el historial del reloj
      10. Mostrar los clockin en la agenda
      11. Añadir timestamp al terminar tarea
      12. Archivado
      13. org-super-agenda
      14. punch-in y punch-out
      15. Desactivar festivos
      16. org-clock-convenience
    2. Edición, diseño y varios
      1. Definir lenguajes que entiende babel
      2. Asteriscos bonitos
      3. Seguir links
      4. Exportar a Markdown
      5. Exportar a rst
      6. Exportar a asciidoc
      7. Exportar a reveal.js
      8. Bloque de codigo de peticiones http
      9. elasticsearch-mode
      10. Configuracion de bloques de código
      11. Elementos de marcado
      12. Quitar confirmación al evaluar código
      13. Añadir imágenes in-line
      14. Notas a pie de página
      15. toc-org
      16. Más profundidad en imenu
      17. Empareja simbolos de marcado y paréntesis
      18. org-protocol
      19. Ejecución de bloques babel asincrona
      20. Hábitos
      21. org-yank-rich
      22. org-download
      23. evil-org
      24. org-cliplink
      25. appt
      26. Mostrar horas en vez dias
      27. Mostrar popups de org-mode más grandes
      28. org-brain
      29. org-tempo
      30. org-noter
      31. org-mru-clock
    3. Asignar keybinds
      1. Mapear org-cycle
  5. Misc
    1. emacs-lisp
      1. package-lint
      2. paredit
    2. rainbow-mode
    3. hl-todo-mode
    4. lua-mode
    5. terraform-mode
    6. groovy-mode
    7. python-mode
    8. kivy-mode
    9. compile-mode
    10. ivy-mode / counsel-mode / swipper-mode
    11. command-log-mode
    12. counsel-rg
    13. notmuch
    14. camcorder
    15. i3wm-config-mode
    16. csv-mode
    17. markdown-mode
    18. ledger-mode
    19. po-mode
    20. mail-mode
    21. undo-tree
    22. google-translate
    23. evil-nerd-commenter
    24. evil-mode
    25. shell-mode
    26. magit
    27. adoc-mode
    28. evil-ediff
    29. company
    30. webpaste
    31. calfw
    32. hugo
    33. url accionables
    34. docker
    35. Apañar doom
  6. Funciones personalizadas
    1. Insertar bloque src para org-mode
    2. Insertar bloque src para markdown
    3. Insertar fecha
    4. multi-term
    5. Agrandar y enpequeñecer
  7. En progreso / Pendiente
    1. Yaml
      1. flycheck-yamllint
      2. ansible
      3. molecule
      4. k8s-mode
    2. lsp
      1. Docs
      2. TODO
      3. Configuración
      4. Python
    3. evil-hardcore-mode
    4. skeletor
    5. Añadir el nombre a la propiedad
    6. Ecloud
    7. keyfreq
    8. Sprint actual

Acerca de este documento

Este documento está hecho en org-mode y es tanto mi configuración de emacs como la explicación de esta. Más información sobre la programación literaria aquí.

Mi idea es que termine siendo más o menos un tutorial de emacs, extendido con los articulos del blog.

Uso doom, que es una configuración muy “opinionada”. Es similar a spacemacs, pero mucho más pequeño, modulado, orientado a vim y facilita el que tu le añadas tus propios módulos. Se puede ver más en este articulo que aún no existe.

Si hay alguna variable o función que no explique que hace, siempre se puede usar describe-variable o describe-function.

Configurar el init.el

Configurar el bind léxico

La verdad es que no termino que es ni por que es bueno usarlo. En la wiki de emacs lo explican muy bien, pero doy para lo que doy.

;;; init.el -*- lexical-binding: t; -*-

Hacer más usable ivy

FLX ordena los resultados de M-x de acorde al último usado.

(def-package-hook! flx
  :pre-init
  (setq ivy-re-builders-alist
        '((counsel-ag . ivy--regex-plus)
          (counsel-rg . ivy--regex-plus)
          (counsel-pt . ivy--regex-plus)
          (counsel-grep-or-swiper . ivy--regex-plus)
          (read-file-name-internal . ivy--regex-fuzzy)
          (t . ivy--regex-plus))
        ivy-initial-inputs-alist nil))

Hacer más usable evil

(def-package-hook! evil
  :pre-init
  (setq evil-cross-lines t)
  (setq evil-move-cursor-back nil)
  (setq evil-want-fine-undo t)
  (setq evil-want-keybinding t))

Configuración principal de doom

Aquí es donde se define toda la configuración que no se modificará en este documento. Se puede ver información de estos módulos en la documentación de doom.

Referente a lo que sale aquí, solo vale la pena explicar el módulo :daemons. Esa es mi configuración particular, y tengo una sección pública y otra privada.

(doom! :feature
       workspaces
       eval
       (evil +everywhere)
       (lookup +devdocs +docsets)
       snippets
       syntax-checker
       file-templates
       spellcheck
       debugger

       :completion
       (company +childframe +auto)
       (ivy +fuzzy)

       :tools
       magit
       password-store
       pdf
       make
       ansible
       docker
       terraform

       :emacs
       dired
       ediff
       electric
       eshell
       imenu
       vc

       :lang
       data
       emacs-lisp
       java
       javascript
       latex
       lua
       markdown
       perl
       php
       rest
       ruby
       sh

       :config
       (default +bindings +snippets +evil-commands)

       :app
       (email +gmail)
       calendar

       :editor
       multiple-cursors

       :ui
       doom
       doom-dashboard
       doom-modeline
       doom-quit
       neotree
       fci
       treemacs
       evil-goggles
       (popup +all +defaults +hacks)
       hl-todo
       nav-flash
       unicode
       window-select
       pretty-code
       vc-gutter

       :daemons
       default
       private)

Configuración Genérica

Arrancar emacs

En esta secció se tocará la configuración que tenga que ver con el manejo general de emacs. Yo suelo arrancar emacs usando un script que llamo demacs. En el llamo a emacs en modo demonio para que quede corriendo en segundo plano y luego abro emacsclient.

Que ventajas tiene esto? Emacs no es como vim, no abres tantos emacs como ediciones quieres hacer. Dado que es mucho más pesado que vim, lo más eficiente es abrir uno solo y cuando quieres editar algún fichero usas emacsclient, un binario que permite conectarse a una sesión existente.

demacs contiene lo siguiente:

#!/bin/bash

USERID=`id -u`
if [[ ! -e /tmp/emacs$USERID/server ]]
then
    emacs --daemon
else
    emacsclient -c -n
fi

Inicia empaquetado de configuración generica

Doom hace sus cosas magicas cuando tiene las cosas empaquetadas para que arranque más rápido, declarar autoloads y demás. Por ello, creo un “paquete” genérico, para ecapsular toda la información que no hace referencia a algo clasificable.

(def-package! generic
  :demand t
  :config

Seguridad de las conexiones

(setq network-security-level 'high)

Formato de las columnas de numeracion

Por defecto no se activan, hay que hacerlo a mano con M-x linum-mode.

(setq linum-format "%4d \u2502 ")

Aumentar y disminuir tamaño de la fuente

Con M-+ aumenta la fuente y con M-- la disminuye.

(map! :ne "M-=" (λ! (text-scale-set 0))
      :ne "M-+" #'text-scale-increase
      :ne "M--" #'text-scale-decrease)

Moverse por el buffer

Subir y bajar párrafos:

(map! :ne "M-p" 'backward-paragraph
      :ne "M-n" 'forward-paragraph)

Establecer nombre y correo

Al exportar en org-mode, por ejemplo, coge estos valores.

(setq user-full-name "drymer"
      user-mail-address "drymer [ EN ] autistici.org")

Lenguaje por defecto en emacs y org-mode

(setq current-language-environment "Spanish")
(setq org-export-default-language "es")

No seguir enlaces simbólicos

(setq vc-follow-symlinks nil)

Mantener lista de buffers recientes

Al usar ivy o helm y ejecutar switch-buffer (C-x b) se pueden ver los buffers que se han abierto recientemente si se tiene recentf activo.

(setq recentf-max-saved-items 200)
(setq recentf-max-menu-items 200)

Borrar espacios sobrantes

Al guardar, borrar los que sobren de cada linea despues de el último carácter.

(add-hook 'before-save-hook 'delete-trailing-whitespace)

Usar ssh con tramp

Por defecto usa scp, que es muy lento. Así se usará ssh.

(setq tramp-default-method "ssh")

Abrir enlaces en el navegador por defecto

Para las cosas de mi trabajo suelo usar firefox, pero para las cosas personales uso qutebrowser. Por ello, hice un script para que detecte si firefox está en marcha. Si lo está, se abre el enlace en firefox, sino ĺo hace en qutebrowser. El script es este y tiene que estar en el PATH:

#!/bin/bash

firefox="$(pgrep firefox)"

if [[ -n $firefox ]]
then
    firefox "$@"
else
    qutebrowser --target tab "$@"
fi

Yo lo he llamado my-sensible-browser, por lo que puedo llamarlo así en emacs:

(setq browse-url-browser-function 'browse-url-generic)
(setq browse-url-generic-program "my-sensible-browser")

Terminal

Establecer zsh como shell por defecto, aunque no lo uso demasiado.

(setq explicit-shell-file-name "/bin/zsh")
(setq shell-file-name explicit-shell-file-name)
(setenv "SHELL" shell-file-name)
(add-hook 'comint-output-filter-functions 'comint-strip-ctrl-m)

kill-this-buffer en vez de kill-buffer

No quiero que me pregunte si de verdad quiero matar un buffer, quiero que lo mate y punto.

(map! :ne "C-x k" 'kill-this-buffer)

Fuente: http://pragmaticemacs.com/emacs/dont-kill-buffer-kill-this-buffer-instead/

Ispell

Instalamos el diccionario de esta dirección y configuramos emacs para que lo use:

(setq ispell-dictionary "español")

Mostrar orden en minibuffer

(setq echo-keystrokes 0.1)

Tipo de fuente

(setq doom-font (font-spec :family "DejaVu Sans Mono" :height 107))

Tema

(setq doom-theme 'doom-molokai)

Scroll

Similar a la manera de vim. No tengo claro en que se diferencia, pero me gusta cómo funciona.

(setq scroll-step            1
      scroll-conservatively  10000)

(setq scroll-margin 80
      scroll-conservatively 3000
      scroll-up-aggressively 0.02
      scroll-down-aggressively 0.02)

Deshabilitar numeros en los laterales

(setq doom-line-numbers-style nil)
(setq display-line-numbers-type nil)

Asignar un atajo de teclado a recompile

(map! "C-," 'recompile)

Kill-ring-max

(setq kill-ring-max 500)

Fuente: http://puntoblogspot.blogspot.com/2018/10/kill-ring-max-is-thing.html?m=1

Terminar empaquetado de configuración genérica

)

org-mode

org-mode merece tener la configuración a parte. Ahí va.

Agenda

Definir archivos de la agenda

(setq org-agenda-files '("~/Documentos/org/inbox.org" "~/Documentos/org/trabajo.org" "~/Documentos/org/index.org"))

Comandos de Agenda

(setq org-agenda-custom-commands
    '(
      ("a" "Agenda" agenda ""
       ((org-super-agenda-groups
         '((:log t)  ; Automatically named "Log"
           (:name "Schedule"
                  :time-grid t)
           (:name "Today"
                  :scheduled today)
           (:habit t)
           (:name "Due today"
                  :deadline today)
           (:name "Overdue"
                  :deadline past)
           (:name "Due soon"
                  :deadline future)
           (:name "Blocked..."
                  :todo "BLOCKD"
                  :order 98)
           (:name "Unimportant"
                  :todo ("TOFOLLOW" "MAYBE" "CHECK" "TO-READ" "TO-WATCH")
                  :order 100)
           (:name "Scheduled earlier"
                  :scheduled past)))))
      ("g" . "General")
      ("gh" "Hecho hoy" agenda ""
       ((org-agenda-overriding-header "Done today")
        (org-agenda-span 1)
        (org-agenda-start-with-log-mode t)
        (org-agenda-log-mode-items '(clock closed))
        (org-agenda-archives-mode t)
        (org-agenda-show-log 'clockcheck)))
      ;; Casa
      ("c" . "Casa")
      ("ca" "Tareas del sprint actual o inmediatas"
       tags
       (concat "+personal+sprint"
               daemons/active-sprint
               "-scrum")
       ((org-agenda-remove-tags nil)
        (org-agenda-hide-tags-regexp "personal")
        (org-agenda-files '("~/Documentos/org/index.org"))))
      ;; Tareas por empezar sin asignar a un sprint
      ("ce" "Tareas por empezar" tags "+personal-{sprint}/+TODO"
       ((org-agenda-remove-tags nil)
        (org-agenda-hide-tags-regexp "personal")
        (org-agenda-files '("~/Documentos/org/index.org"))))
      ("cs" "Tareas sin fecha" tags (concat "+personal+sprint"
                                            daemons/active-sprint
                                            "-scrum")
       ((org-agenda-remove-tags nil)
        (org-agenda-hide-tags-regexp "personal")
        (org-agenda-skip-function (quote (org-agenda-skip-entry-if (quote scheduled))))
        (org-agenda-files '("~/Documentos/org/index.org"))))
      ("cn" "Tareas de la semana siguiente" agenda ""
       ((org-agenda-remove-tags nil)
        (org-agenda-hide-tags-regexp "personal")
        (org-agenda-span 7)
          (org-agenda-start-day "+7d")
        (org-agenda-files '("~/Documentos/org/index.org"))))
      ("cr" "Mostras radar" tags "+radar"
       ((org-agenda-files '("~/Documentos/brain/index.org"))
        (org-agenda-remove-tags nil)
        (org-agenda-hide-tags-regexp "radar")))
      ;; Reportes del trabajo
      ("w" . "Trabajo")
      ("wp" "Ver proyectos" tags "+trabajo/INPROGRESS|TOFOLLOW|BLOCKED|TODO|NEXT|EVENT|DONE|CANCELLED"
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-projects)))
      ("wt" "Hecho en los últimos tres días" agenda ""
       ((org-agenda-overriding-header "Last three days")
        (org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-log)
        (org-agenda-span 4)
        (org-agenda-start-day "-3d")
        (org-agenda-start-with-log-mode t)
        (org-agenda-log-mode-items '(clock closed))
        (org-agenda-clockreport-mode t)
        (org-agenda-archives-mode t)
        (org-agenda-show-log 'clockcheck)))
      ("wi" "Hecho en la última semana" agenda ""
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-log)
        (org-agenda-span 7)
        (org-agenda-start-day "-7d")
        (org-agenda-start-with-log-mode t)
        (org-agenda-log-mode-items '(clock closed))
        (org-agenda-archives-mode t)
        (org-agenda-show-log 'clockcheck)))
      ("l" . "Archivo")
      ("la" "Buscar archivado" search ""
       ((org-agenda-files (file-expand-wildcards "~/Documentos/org/*.org_archive"))))
      ;; Mostrar tareas a reubicar
      ("r" "Reubicar" tags "+refile" ((org-agenda-remove-tags nil) (org-agenda-hide-tags-regexp "refile")))))

(setq org-agenda-custom-commands
    '(;; Casa
      ("g" . "General")
      ("ch" "Hecho hoy" agenda ""
       ((org-agenda-overriding-header "Done today")
        (org-agenda-span 1)
        (org-agenda-start-with-log-mode t)
        (org-agenda-log-mode-items '(clock closed))
        (org-agenda-archives-mode t)
        (org-agenda-show-log 'clockcheck)))
      ("c" . "Casa")
      ;; Reportes del trabajo
      ("w" . "Trabajo")
      ("wt" "Hecho en los últimos tres días" agenda ""
       ((org-agenda-overriding-header "Last three days")
        (org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-log)
        (org-agenda-span 4)
        (org-agenda-start-day "-3d")
        (org-agenda-start-with-log-mode t)
        (org-agenda-log-mode-items '(clock closed))
        (org-agenda-clockreport-mode t)
        (org-agenda-archives-mode t)
        (org-agenda-show-log 'clockcheck)))
      ("wi" "Hecho en la última semana" agenda ""
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-log)
        (org-agenda-span 7)
        (org-agenda-start-day "-7d")
        (org-agenda-start-with-log-mode t)
        (org-agenda-log-mode-items '(clock closed))
        (org-agenda-archives-mode t)
        (org-agenda-show-log 'clockcheck)))
      ("wn" "Siguientes tareas" tags-todo "+trabajo/NEXT"
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-next)))
      ("wa" "Tareas activas o posiblemente activas" tags-todo
       "+trabajo/TODO|INPROGRESS|TESTING|HOTFIX"
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-active)))
      ("wb" "Tareas paradas" tags-todo "+trabajo/BLOCKED|TOFOLLOW"
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-blocked)))
      ("wt" "Tareas por hacer" tags "+trabajo/TODO"
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-todo)))
      ("wd" "Tareas terminadas sin archivar" tags "+trabajo/DONE|CANCELLED"
       ((org-super-agenda-mode)
        (org-super-agenda-groups org-agenda-supergroup-tags-done)))
      ;; Mostrar tareas a reubicar
      ("r" "Reubicar" tags "+refile" ((org-agenda-remove-tags nil) (org-agenda-hide-tags-regexp "refile")))))

Referencias:

Capturas de notas

(setq org-capture-templates
    '(
    ("r" "Reuniones" entry (file "~/Documentos/org/inbox.org")
     (file "~/.doom.d/org-capture-templates/reuniones.org")
     :clock-in t :clock-resume t)
    ;; Para reuniones de seguimiento, tener el arbol partido en días
    ("rs" "Reuniones semanales" entry (file "~/Documentos/org/inbox.org")
     (file "~/.doom.d/org-capture-templates/reuniones-periodicas.org")
     :clock-in t :clock-resume t)
    ;; Para cuando voy a comer en el trabajo
    ("c" "Comida" entry
     (file+olp "~/Documentos/org/trabajo.org" "Meta" "Comidas")
     "* Comida %(emacswiki/insert-current-date) "
     :clock-in t :clock-resume t)
    ;; Meter fecha debajo de un header principal para no tener chorrocientos "Dailies"
    ("d" "Daily" entry (file+olp "~/Documentos/org/trabajo.org" "Meta" "Dailies")
        "* Daily %(emacswiki/insert-current-date)" :clock-in t :clock-resume t)
    ("a" "Atraco" entry (file "~/Documentos/org/inbox.org")
        "* %?\n" :clock-in t :clock-resume t)
    ("tr" "Tarea con reloj" entry (file "~/Documentos/org/inbox.org")
        "* %? %^G\n%U\n" :clock-in t :clock-resume t)
    ("tn" "Tarea simple" entry (file "~/Documentos/org/inbox.org")
        "* %? %^G\n%U\n")
    ;; Revisiones
    ("rsp" "Revisión Semanal Personal" entry (file+olp+datetree "~/Documentos/org/log.org" "Revisión Semanal")
        (file "~/.doom.d/org-capture-templates/personal-weekly-review.org"))
    ("rst" "Revisión Semanal Trabajo" entry (file+headline "~/Documentos/org/trabajo.org" "Revisión Semanal")
        (file "~/.doom.d/org-capture-templates/work-weekly-review.org"))
    ("s" "Sprint Nuevo Trabajo" entry (file "~/Documentos/org/trabajo.org")
        (file "~/.doom.d/org-capture-templates/new-sprint.org"))
    ("p" "Sprint Nuevo Personal" entry (file "~/Documentos/org/index.org")
        (file "~/.doom.d/org-capture-templates/new-personal-sprint.org"))
    ("e" "Estado de la vida" entry (file "~/Documentos/org/index.org")
        (file "~/.doom.d/org-capture-templates/estado-de-la-vida.org"))
    ("m" "Captura desde correo" entry (file "~/Documentos/org/inbox.org") "* %? %^G\n%U\n%a\n" :clock-in t :clock-resume t)
    ("log" "Log" entry (file+olp+datetree "~/Documentos/org/log.org" "Log")
        (file "~/.doom.d/org-capture-templates/log.org"))
    ("b" "Articulo" entry (file "~/Proyectos/BadDaemons/content-org/articulos.org")
        "* TODO %(read-string \"Insert title: \")\n:PROPERTIES:\n:EXPORT_FILE_NAME: %(org-hugo-slug (nth 4 (org-heading-components)))\n:END:")))

Referencias:

Estados de los objetos de las listas

Todas las secuencias anteriores al símbolo | son tareas que no se consideran terminadas, al contrario de las que estan después de este.

Los estados que tienen el símbolo @ son los que, al escogerlos, abren un buffer preguntando si se quiere añadir alguna nota respecto al cambio de estado. Las que tienen el símbolo !, en cambio, crean una estampa de tiempo, para dejar constancia de cuando se ha cambiado a ese estado.

(setq org-todo-keywords
    '((sequence "TODO(t)" "NEXT(n)" "INPROGRESS(p@/!)" "WAITING(w@/!)" "|" "DONE(d!)" "CANCELED(c@)")))

Refile

Mover un arbol debajo de otro del mismo fichero o de los archivos de las agendas.

(setq org-refile-targets '((nil :maxlevel . 10) (org-agenda-files . (:maxlevel . 10))))

Crear nodo si no existe:

;; Source: https://blog.aaronbieber.com/2017/03/19/organizing-notes-with-refile.html
(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-allow-creating-parent-nodes t)

Configuración del calendario

(setq org-icalendar-timezone "Europe/Madrid")

Tareas repetitivas

Las tareas marcadas para repetirse, al marcarlas cómo DONE vuelven al estado TODO y añade un timestamp del dia y la hora.

(setq org-log-repeat "time")

Quitar tags de la agenda

(setq org-agenda-remove-tags t)

Alargar el historial del reloj

(setq org-clock-history-length 60)

Mostrar los clockin en la agenda

(setq org-agenda-clock-consistency-checks t)

Añadir timestamp al terminar tarea

(setq org-log-done 'time)

Archivado

(setq org-archive-mark-done t)

org-super-agenda

(package! org-super-agenda :recipe (:fetcher github :repo "alphapapa/org-super-agenda"))

(def-package! org-super-agenda :config (org-super-agenda-mode))

punch-in y punch-out

Estas funciones tan útiles las he cogido de eof. Las funciones principales son eos/punch-in y eos/punch-out. La primera va a una tarea genérica que tengo en el fichero principal del trabajo y empieza el reloj. Después de hacer eso, cuando quiera, podré arrancar el reloj en la tarea que considere. Cuando acabe esta y pare el reloj, gracias a la función de punch-in, en vez de quedarme sin contabilizar el tiempo, el reloj se encenderá en la tarea genérica. Cuando termino, le doy a punch-out y se para el reloj definitivamente.

Esto es muy cómodo por que me permite contabilizar todo el tiempo que estoy delante del ordenador trabajando.

(setq bh/keep-clock-running nil)
(setq bh/organization-task-id nil)
(defun bh/find-project-task ()
"Move point to the parent (project) task if any"
(save-restriction
(widen)
(let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
    (while (org-up-heading-safe)
    (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
        (setq parent-task (point))))
    (goto-char parent-task)
    parent-task)))

(defun bh/punch-in (arg)
"Start continuous clocking and set the default task to the
selected task.  If no task is selected set the Organization task
as the default task."
(interactive "p")
(setq bh/keep-clock-running t)
(if (equal major-mode 'org-agenda-mode)
    ;;
    ;; We're in the agenda
    ;;
    (let* ((marker (org-get-at-bol 'org-hd-marker))
            (tags (org-with-point-at marker (org-get-tags-at))))
    (if (and (eq arg 4) tags)
        (org-agenda-clock-in '(16))
        (bh/clock-in-organization-task-as-default)))
;;
;; We are not in the agenda
;;
(save-restriction
    (widen)
    ; Find the tags on the current task
    (if (and (equal major-mode 'org-mode) (not (org-before-first-heading-p)) (eq arg 4))
        (org-clock-in '(16))
    (bh/clock-in-organization-task-as-default)))))

(defun bh/punch-out ()
(interactive)
(setq bh/keep-clock-running nil)
(when (org-clock-is-active)
(org-clock-out))
(org-agenda-remove-restriction-lock))

(defun bh/clock-in-default-task ()
(save-excursion
(org-with-point-at org-clock-default-task
    (org-clock-in))))

(defun bh/clock-in-parent-task ()
"Move point to the parent (project) task if any and clock in"
(let ((parent-task))
(save-excursion
    (save-restriction
    (widen)
    (while (and (not parent-task) (org-up-heading-safe))
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
        (setq parent-task (point))))
    (if parent-task
        (org-with-point-at parent-task
            (org-clock-in))
        (when bh/keep-clock-running
        (bh/clock-in-default-task)))))))

(defun bh/clock-in-organization-task-as-default ()
(interactive)
(org-with-point-at (org-id-find bh/organization-task-id 'marker)
(org-clock-in '(16))))

(defun bh/clock-out-maybe ()
(when (and bh/keep-clock-running
            (not org-clock-clocking-in)
            (marker-buffer org-clock-default-task)
            (not org-clock-resolving-clocks-due-to-idleness))
(bh/clock-in-parent-task)))

(add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append)
(setq org-clock-out-remove-zero-time-clocks t)
(setq org-clock-out-when-done t)
(setq org-clock-perist t)
(setq org-clock-report-include-clocking-task t)
(setq org-clone-delete-id t)

; Exclude DONE state tasks from refile targets
(defun bh/verify-refile-target ()
"Exclude todo keywords with a done state from refile targets"
(not (member (nth 2 (org-heading-components)) org-done-keywords)))
(setq org-refile-target-verify-function 'bh/verify-refile-target)

;; Change tasks to INPROGRESS when clocking in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-progress)

(defun bh/clock-in-to-progress (kw)
"Based in bh/clock-in-to-next: Switch a task from
TODO to INPROGRESS when clocking in. Skips capture tasks,
projects, and subprojects. Switch projects and
subprojects from INPROGRESS back to TODO"
(when (not (and (boundp 'org-capture-mode) org-capture-mode))
(cond
    ((and (member (org-get-todo-state) (list "TODO"))
        (bh/is-task-p))
    "INPROGRESS")
    ((and (member (org-get-todo-state) (list "INPROGRESS"))
        (bh/is-project-p))
    "TODO"))))

;; Usado por bh/clock-in-to-progress
(defun bh/is-task-p ()
"Any task with a todo keyword and no subtask"
(save-restriction
(widen)
(let ((has-subtask)
        (subtree-end (save-excursion (org-end-of-subtree t)))
        (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
    (save-excursion
    (forward-line 1)
    (while (and (not has-subtask)
                (< (point) subtree-end)
                (re-search-forward "^\*+ " subtree-end t))
        (when (member (org-get-todo-state) org-todo-keywords-1)
        (setq has-subtask t))))
    (and is-a-task (not has-subtask)))))

;; Usado por bh/clock-in-to-progress
(defun bh/is-subproject-p ()
"Any task which is a subtask of another project"
(let ((is-subproject)
    (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
(save-excursion
    (while (and (not is-subproject) (org-up-heading-safe))
    (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
        (setq is-subproject t))))))

;; Usado por bh/clock-in-to-progress
(defun bh/is-project-p ()
"Any task with a todo keyword subtask"
(save-restriction
(widen)
(let ((has-subtask)
        (subtree-end (save-excursion (org-end-of-subtree t)))
        (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
    (save-excursion
    (forward-line 1)
    (while (and (not has-subtask)
                (< (point) subtree-end)
                (re-search-forward "^\*+ " subtree-end t))
        (when (member (org-get-todo-state) org-todo-keywords-1)
        (setq has-subtask t))))
    (and is-a-task has-subtask))))

Desactivar festivos

(setq calendar-holidays nil)

org-clock-convenience

(package! org-clock-convenience)

(def-package! org-clock-convenience
  :config
  (defun dfeich/org-agenda-mode-fn ()
    (define-key org-agenda-mode-map
      (kbd "<S-up>") #'org-clock-convenience-timestamp-up)
    (define-key org-agenda-mode-map
      (kbd "<S-down>") #'org-clock-convenience-timestamp-down)
    (define-key org-agenda-mode-map
      (kbd "ö") #'org-clock-convenience-fill-gap)
    (define-key org-agenda-mode-map
      (kbd "é") #'org-clock-convenience-fill-gap-both))
  (add-hook 'org-agenda-mode-hook #'dfeich/org-agenda-mode-fn))

Edición, diseño y varios

Definir lenguajes que entiende babel

(org-babel-do-load-languages
'org-babel-load-languages
'((dot . t)
(emacs-lisp . t)
(gnuplot . t)
(latex . t)
(ledger . t)
(python . t)
(shell . t)
(sql . t)
(sqlite . t)))

Asteriscos bonitos

Requerir el paquete y activarlo sólo cuando se abra un buffer de org-mode.

(package! org-bullets :recipe (:fetcher github :repo "Kaligule/org-bullets"))

(def-package! org-bullets
  :init
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

Seguir links

Presionando tanto RET cómo TAB.

(setq org-return-follows-link t)
(setq org-tab-follows-link t)

Exportar a Markdown

(def-package! ox-md)

Exportar a rst

(package! ox-rst :recipe (:fetcher github :repo "masayuko/ox-rst"))

(def-package! ox-rst)

Exportar a asciidoc

(package! ox-asciidoc)

(def-package! ox-asciidoc)

Exportar a reveal.js

(package! ox-reveal)

(def-package! ox-reveal)

Bloque de codigo de peticiones http

(package! ob-http)

(def-package! ob-http
      :config
      (add-to-list 'org-babel-load-languages '(http . t)))

elasticsearch-mode

(package! es-mode)

(def-package! es-mode
  :config
  (add-to-list 'org-babel-load-languages '(elasticsearch . t)))

Configuracion de bloques de código

(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-src-preserve-indentation t)
(setq org-edit-src-content-indentation 0)

Elementos de marcado

La primera línea esconde los símbolos y aplica el marcado, y la segunda cambia el color a los elementos de marcado que empiezan por =.

(setq org-hide-emphasis-markers t)
(add-to-list 'org-emphasis-alist '("=" (:foreground "cyan")))

Quitar confirmación al evaluar código

Cada vez que se evalua código de un bloque, pide que se confirme. Con el siguiente código, no lo hará.

(setq org-confirm-babel-evaluate nil)

Añadir imágenes in-line

(org-display-inline-images t t)
;; Con un tamaño a concretar inline: #+attr_org: :width 750px
(setq org-image-actual-width nil)

Notas a pie de página

Prefiero que aparezcan las notas debajo del arbol en el que se ha tomado.

(setq org-footnote-section nil)

toc-org

(package! toc-org)

(def-package! toc-org
  :defer t
  :init (add-hook 'org-mode-hook 'toc-org-enable))

Más profundidad en imenu

(setq org-imenu-depth 50)

Empareja simbolos de marcado y paréntesis

(modify-syntax-entry ?/ "(/" org-mode-syntax-table)
(modify-syntax-entry ?* "(*" org-mode-syntax-table)
(modify-syntax-entry ?_ "(_" org-mode-syntax-table)
(modify-syntax-entry ?= "(=" org-mode-syntax-table)

org-protocol

(def-package! org-protocol)

Ejecución de bloques babel asincrona

(package! ob-async :recipe (:fetcher github :repo "astahlman/ob-async"))

(def-package! ob-async)

Hábitos

(def-package! org-habit
  :init
  (add-to-list 'org-modules 'org-habit)
  :config
  (setq org-habit-preceding-days 7
    org-habit-following-days 0
    org-habit-graph-column 50
    org-habit-show-habits-only-for-today t
    org-habit-show-all-today t))

org-yank-rich

(package! org-rich-yank)

(after! org
  (def-package! org-rich-yank
    :config
    (map! :map org-mode-map
          (:leader
            (:prefix "c"
              :desc "Rich yank" :nv "Y" #'org-rich-yank)))))

org-download

Para descargar imágenes comodamente.

(package! org-download)

(def-package! org-download
  :init
  (setq org-download-image-dir "./img/")
  (setq org-download-heading-lvl nil)
  (setq org-download-image-html-width 750))

evil-org

Bindings y configuraciones de evil para org-mode:

(package! evil-org)

(def-package! evil-org
  :config
  (add-hook! 'org-mode-hook 'evil-org-mode)
  (evil-org-set-key-theme '(navigation insert textobjects additional calendar)))

(def-package! evil-org-agenda
  :config (evil-org-agenda-set-keys))

org-cliplink

(package! org-cliplink)

(def-package! org-cliplink)

appt

Notifications:

(def-package! appt
  :config
  (appt-activate t)

  (setq appt-message-warning-time 20) ; Show notification 10 minutes before event
  (setq appt-display-interval 3) ; Disable multiple reminders
  (setq appt-display-mode-line nil)

  ;; Update alarms when...
  ;; (1) ... Everyday at 09:05am (useful in case you keep Emacs always on)
;  (run-at-time "9:05am" (* 24 3600) 'my-org-agenda-to-appt)

  ;; (2) ... When trabajo.org is saved
  (add-hook 'after-save-hook
        '(lambda ()
           (if (string= (buffer-file-name) (concat (getenv "HOME") "/Documentos/org/trabajo.org"))
           (my-org-agenda-to-appt))))

  ;; Display appointments as a window manager notification
  (setq appt-disp-window-function 'my-appt-display)
  (setq appt-delete-window-function (lambda () t))

  (setq my-appt-notification-app "appt-notification"))

;; Use appointment data from org-mode
(defun my-org-agenda-to-appt ()
  (interactive)
  (setq appt-time-msg-list nil)
  (org-agenda-to-appt))

(defun my-appt-display (min-to-app new-time msg)
  (if (atom min-to-app)
      (start-process "my-appt-notification-app" nil my-appt-notification-app min-to-app msg)
    (dolist (i (number-sequence 0 (1- (length min-to-app))))
      (start-process "my-appt-notification-app" nil my-appt-notification-app (nth i min-to-app) (nth i msg)))))

Mostrar horas en vez dias

(setq org-duration-format 'h:mm)

Mostrar popups de org-mode más grandes

(set-popup-rule! "agenda" :size 0.50 :select t)

org-brain

(package! org-brain)
(package! ascii-art-to-unicode)

(def-package! org-brain
  :defer t
  :init
  (setq org-brain-path (expand-file-name "~/Documentos/brain/"))
  ;; For Evil users
  (with-eval-after-load 'evil
    (evil-set-initial-state 'org-brain-visualize-mode 'emacs))
  :config
  (setq org-id-track-globally t)
  (setq org-id-locations-file "~/.emacs.d/.org-id-locations")
  (setq org-brain-title-max-length 79)
  (setq org-brain-visualize-default-choices 'all))

(def-package! ascii-art-to-unicode
  :init
  (defun aa2u-buffer ()
    (aa2u (point-min) (point-max)))
  (add-hook 'org-brain-after-visualize-hook #'aa2u-buffer))

(set-popup-rule! "org-brain" :size 0.70)
(after! org-brain
  (defun org-brain-cliplink-resource ()
    "Add a URL from the clipboard as an org-brain resource.
  Suggest the URL title as a description for resource."
    (interactive)
    (let ((url (org-cliplink-clipboard-content)))
      (org-brain-add-resource
       url
       (org-cliplink-retrieve-title-synchronously url)
       t)))

  (defun daemons-brain-insert-description()
    "Insert src code blocks."
    (interactive)

    (cond
     ((region-active-p)
      (let ((start (region-beginning))
      (end (region-end)))
        (progn
    (goto-char end)
    (insert "\n#+END_DESCRIPTION\n")
    (goto-char start)
    (insert (format "#+BEGIN_DESCRIPTION%s\n" )))))
     (t (insert (format "#+BEGIN_DESCRIPTION\n" ))
        (save-excursion (insert "\n#+END_DESCRIPTION")))))
  (setq org-brain-wander-interval 15))

org-tempo

(setq org-structure-template-alist '(("n" . "notes")
 ("a" . "export ascii")
 ("c" . "center")
 ("C" . "comment")
 ("e" . "example")
 ("E" . "export")
 ("h" . "export html")
 ("l" . "export latex")
 ("q" . "quote")
 ("s" . "src")
 ("v" . "verse")))
(require 'org-tempo)

org-noter

(package! org-noter)

(after! org-noter-mode
  (map! :map org-noter-mode-map
    (:localleader
      (:desc "Annotations" :prefix "i"
      :n "c" #'org-noter-sync-pdf-page-current
      :n "p" #'org-noter-sync-pdf-page-previous
      :n "n" #'org-noter-sync-pdf-page-next)))
  (map! :map org-noter-pdf-mode-map
    :n "i" #'org-noter-add-note))

org-mru-clock

(package! org-mru-clock)

(require 'org-timer)
(require 'org-clock)
(def-package! org-mru-clock
  :config
  (setq org-clock-persist 'history)
  (setq org-mru-clock-how-many 200)
  (setq org-mru-clock-completing-read #'ivy-completing-read)
  (setq org-clock-persist t)
  (setq  org-mru-clock-include-entry-at-point nil)
  (org-clock-persistence-insinuate)
  (map!
   (:localleader
     :mode org-mode
     (:desc "clock stuff"
       :prefix "c"
       :desc "Clock in previous" :nv "c" #'org-mru-clock-in
       :desc "Clock select recent" :nv "j" #'org-mru-clock-select-recent-task))))

Asignar keybinds

(after! org
  (map! [remap outline-toggle-children] #'org-cycle)
  (map! :n "TAB" #'org-cycle
        (:leader
          (:desc "brain stuff"
            :prefix "k"
            :desc "Brain visualize" :n "v" #'org-brain-visualize
            :desc "Brain cliplink resource" :n "l" #'org-brain-cliplink-resource
            :desc "Brain goto" :n "g" #'org-brain-goto
            :desc "Brain add friendship" :n "f" #'org-brain-add-friendship
            :desc "Brain add parent" :n "p" #'org-brain-add-parent))
        (:leader
          (:desc "agenda stuff"
            :prefix "a"
            :desc "Agenda" :n "a" #'org-agenda
            :desc "Capture" :n "c" #'counsel-org-capture))
        (:leader
          (:desc "link stuff"
            :prefix "l"
            :desc "Insert link" :nv "i" #'org-insert-link
            :desc "Store link" :nv "l" #'org-store-link
            :desc "Go to link" :nv "o" #'counsel-ace-link
            :desc "Cliplink" :nv "L" #'org-cliplink))
        (:localleader
          :mode org-mode
          (:desc "clock stuff"
            :prefix "c"
            :desc "Clock in" :nv "i" #'org-clock-in
            :desc "Clock out" :nv "o" #'org-clock-out
            :desc "Clock goto" :nv "g" #'org-clock-goto
            :desc "Clock resolve" :nv "r" #'org-resolve-clocks)
          (:prefix "e"
            :desc "Edit SRC"
            :desc "Edit" :n "e" #'org-edit-special
            :desc "Close" :n "x" #'org-edit-src-exit)
          :desc "Cycle TODOs" :nv "t" #'org-todo
          :desc "Set schedule" :nv "s" #'org-schedule
          :desc "Set deadline" :nv "d" #'org-deadline
          :desc "Refile" :nv "r" #'org-refile
          :desc "Copy" :nv "R" #'org-copy
          :desc "Narrow element" :nv "n" #'org-narrow-to-element
          :desc "Widen element" :nv "w" #'widen
          :desc "Todo to list" :nv "-" #'org-ctrl-c-minus
          :desc "List to TODO" :nv "*" #'org-ctrl-c-star
          :desc "Ctrl-Ctrl" :nv "C" #'org-ctrl-c-ctrl-c)))

Mapear org-cycle

Por algún motivo, en algunos ficheros de org-mode la tecla TAB está mapeada con outline-toggle-children en vez d org-cycle. No me gusta

(setq +org/toggle-fold nil)

Misc

emacs-lisp

package-lint

Linter de problemas habituales de paquetes de melpa:

(package! package-lint)

(after! emacs-lisp
 (def-package! package-lint :defer t))

paredit

Movimiento por sexp:

(package! paredit)

(after! emacs-lisp
  (def-package! paredit))

rainbow-mode

Muestra los colores de paletas HTML (hexadecimal) con el color que representa.

(package! rainbow-mode)

(def-package! rainbow-mode)

hl-todo-mode

(global-hl-todo-mode)

lua-mode

Modo para lua:

(package! lua-mode)

(def-package! lua-mode :defer t)

terraform-mode

Modo y completado para terraform:

(after! terraform-mode
  (setq daemons/terraform-prefix nil)

  (defun daemons/terraform-set-aws-prefix ()
    (interactive)
    (let ((aws-profile (shell-command-to-string "grep 'profile' $HOME/.aws/config | sed -e 's/.*profile //' | sed -e 's/\]$//'"))
          (terraform-profile))
      (if (equal current-prefix-arg '(4))
          (setq daemons/terraform-prefix nil))
      (if (not daemons/terraform-prefix)
          (progn
            (setq terraform-profile (completing-read "AWS profiles: " (split-string aws-profile)))
            (setq daemons/terraform-prefix (concat "asp " terraform-profile ";"))))))
  (add-hook 'terraform-mode-hook 'terraform-format-on-save-mode))

(map! :after terraform-mode
      :map terraform-mode-map
      :localleader
      :desc "terraform apply" "a" (λ! (compile (concat daemons/terraform-prefix "terraform apply")))
      :desc "terraform init"  "i" (λ! (compile (concat daemons/terraform-prefix "terraform init")))
      :desc "terraform plan"  "p" (λ! (compile (concat daemons/terraform-prefix "terraform plan"))))

groovy-mode

Modo para groovy:

(package! groovy-mode)

(def-package! groovy-mode :defer t)

python-mode

(package! elpy)
(package! pyvenv)

Configuración propia de elpy:

(def-package! elpy
  :defer t
  :init
  (setq elpy-modules '(elpy-module-sane-defaults elpy-module-company elpy-module-eldoc elpy-module-pyvenv))
  (setq elpy-rpc-backend "jedi")
  :config
  (setq elpy-rpc-python-command "python3")
  (setq elpy-company-add-completion-from-shell t)
  ;; véase https://github.com/abo-abo/swiper/issues/892
  (add-to-list 'ivy-completing-read-handlers-alist '(elpy-doc . completing-read-default))
  (add-to-list 'elpy-project-ignored-directories "__pycache__")
  (add-to-list 'elpy-project-ignored-directories ".cache")
  (set-company-backend! 'elpy-mode 'elpy-company-backend)
  (set-company-backend! 'inferior-python-mode 'elpy-company-backend)
  (elpy-enable))
(add-hook 'python-mode-hook 'elpy-mode)
(setq python-shell-prompt-pdb-regexp "[(<]*[Ii]?[Pp]db[>)]?\\+\\+[)] ")

Función de test de elpy para usar una imagen de docker para ejecutar tests:

;; Crear un fichero en el path llamado docker-tox con este contenido:
;; docker run -ti -v `pwd`:/tox/files/ registry.daemons.it/tox:latest tox
(defun elpy-test-docker-tox-runner (top file module test)
  "Test the project using the docker-tox test runner."
  (interactive (elpy-test-at-point))
  (let ((test-directory (elpy-project-find-projectile-root)))
    (apply #'elpy-test-run test-directory elpy-test-docker-tox-runner-command)))
(setq elpy-test-runner 'elpy-test-docker-tox-runner)
(setq elpy-test-docker-tox-runner-command '("docker-tox"))

Hackity hack para hacer que en buffer de compilacion se active pdb:

(defun python-test-track-pdb-prompt ()
  "Change compilation to `python-inferior-mode' when a pdb prompt is detected.
This function is a hack that enables `inferior-python-mode' when
a pdb prompt is detected in `compilation-mode' buffers, and to
work is meant to be added to `compilation-filter-hook'.  To go
back to `compilation-mode' you need to call
\\[python-test-back-to-compilation]."
  (let ((output (ignore-errors (buffer-substring-no-properties compilation-filter-start (point)))))
    (when (and output (string-match-p (concat "^" python-shell-prompt-pdb-regexp) output))
      (message "Entering pdb...")
      (setq buffer-read-only nil)
      (let ((python-shell--interpreter nil)
            (python-shell--interpreter-args nil))
        (set-process-filter (get-buffer-process (current-buffer)) 'comint-output-filter)
        (setq python-shell--interpreter nil)
        (setq python-shell--interpreter-args nil)
        (inferior-python-mode)
        (run-hook-with-args 'comint-output-filter-functions output)))))

(defun python-test-ansi-color-filter ()
  "Handle match highlighting escape sequences.
This function is called from `compilation-filter-hook'."
  (ansi-color-apply-on-region compilation-filter-start (point)))

(add-hook 'compilation-filter-hook 'python-test-track-pdb-prompt)
;; (add-hook 'compilation-filter-hook 'python-test-ansi-color-filter)

Volver a modo compilacion cuando se entra en pdb:

(defun python-test-back-to-compilation ()
  "Go back to compilation mode.
See `python-test-track-pdb-prompt' documentation for more
information."
  (interactive)
  (let ((process (get-buffer-process (current-buffer))))
    (when process
      (message "Enabling compilation mode... ")
      (set-process-filter process 'compilation-filter)
(compilation-mode))))

Configuración de doom para hacer que las ventanas repl tengan un tamaño más apropiado:

(set-popup-rule! "*Python*" :size 0.30 :quit nil)

Bindings para elpy:

;; No se usa elpy-goto-definition en favor de +lookup/definition
(after! elpy-mode
  (map! :map elpy-mode-map
    ;; No estan evilificados, no se pueden gestionar con operaciones
    :n "gk" #'elpy-nav-backward-block
    :n "gj" #'elpy-nav-forward-block
    :n "gh" #'elpy-nav-backward-indent
    :n "gl" #'elpy-nav-forward-indent
    :n "mk" #'elpy-nav-move-line-or-region-up
    :n "mj" #'elpy-nav-move-line-or-region-down
    :n "mh" #'elpy-nav-indent-shift-left
    :n "ml" #'elpy-nav-indent-shift-right))

kivy-mode

Modo para kivy:

(package! kivy-mode)

(def-package! kivy-mode
  :defer t)

compile-mode

Varias herramientas usan el modo compile, como molecule.el:

;; Fuente: https://stackoverflow.com/questions/13397737/ansi-coloring-in-compilation-mode
(def-package! compile
  :defer t
  :config
  (set-popup-rule! "*compilation*" :size 0.40 :quit nil)
  ;; (add-hook 'compilation-filter-hook 'colorize-compilation-buffer)
  (setq compilation-scroll-output 'first-error))

ivy-mode / counsel-mode / swipper-mode

Ivy es más liviano que helm, aunque más simple. Más información aquí.

(def-package! ivy
  :config
  ;; Muestra las coincidencias con lo que se escribe y la posicion en estas
  (setq ivy-count-format "(%d/%d) ")
  ;; counsel-ffap
  (setq counsel-find-file-at-point t))

(after! ivy
    (map! (:map ivy-minibuffer-map
            "M-y" 'ivy-next-line-and-call)))

ace-isearch y smex:

(package! ace-isearch)
(package! smex)

(def-package! ace-isearch
  :config
  (setq avy-background t)
  (setq ace-isearch-function 'avy-goto-char)
  (setq ace-isearch-input-length 5)
  (setq ace-isearch-jump-delay 0.30)
  (setq ace-isearch-use-jump 'printing-char)
  (setq ace-isearch-function-from-isearch 'ace-isearch-swiper-from-isearch)
  (global-ace-isearch-mode))

(map! (:leader
       (:desc "search"
        :prefix "s"
        :desc "Search in buffer" :nv "r" #'isearch-backward
        :desc "Search in buffer" :nv "s" #'isearch-forward)))

command-log-mode

Mostrar teclas presionadas en un buffer:

(package! command-log-mode :recipe (:fetcher github :repo "lewang/command-log-mode"))

(def-package! command-log-mode :defer t)

counsel-rg

Seguir enlaces simbólicos:

(setq counsel-rg-base-command "rg -L -S --no-heading --line-number --color never %s .")

notmuch

Cliente de correo:

(package! notmuch)
(package! counsel-notmuch)
(package! org-plus-contrib)

(after! evil
  (def-package! notmuch
    :defer t
    :init
    (setq notmuch-show-logo nil)
    (setq notmuch-mua-cite-function 'message-cite-original-without-signature)
    (setq message-kill-buffer-on-exit t)
    ;; Preguntar a quien envias el mail
    (setq notmuch-always-prompt-for-sender t)
    ;; Indentacion en cadenas
    (setq notmuch-show-indent-messages-width 4)
    ;; Mostrar los más nuevos primero
    (setq notmuch-search-oldest-first t)
    ;; Esconder mierdas
    (setq notmuch-show-all-multipart/alternative-parts nil)
    ;; Iniciar notmuch en modo emacs
    (evil-set-initial-state 'notmuch-hello-mode 'emacs)
    ;; Cabeceras al mínimo
    (setq notmuch-hello-sections '(notmuch-hello-insert-saved-searches))
    ;; Enviar mail sin mas
    (setq send-mail-function 'smtpmail-send-it)
    (setq message-sendmail-envelope-from 'header)
    (setq notmuch-show-all-multipart/alternative-parts nil)
    (add-hook 'notmuch-hello-mode-hook 'evil-insert-state))

  (def-package! org-notmuch)

  (def-package! counsel-notmuch
    :defer t))

;;;###autoload
(defun daemons-notmuch-toggle-read ()
  "Toggle unread tag for thread."
  (interactive)
  (if (member "unread" (notmuch-search-get-tags))
      (notmuch-search-tag '("-unread"))
    (notmuch-search-tag '("+unread"))))

(after! notmuch
    (map!
     (:map notmuch-show-mode-map
           :nve "r" 'notmuch-show-reply
           :nve "R" 'notmuch-show-reply-sender
           :nve "M-j" 'notmuch-show-next-message
           :nve "M-k" 'notmuch-show-previous-message
           :nve "s" 'counsel-notmuch
           :nve "u" 'daemons-notmuch-toggle-read)
     (:map notmuch-search-mode-map
           :nve "r" 'notmuch-search-reply-to-thread
           :nve "R" 'notmuch-search-reply-to-thread-sender
           :nve "u" 'daemons-notmuch-toggle-read
           :nve "s" 'counsel-notmuch)
     (:map notmuch-hello-mode-map
           :nve "s" 'counsel-notmuch
           :nve "u" 'daemons-notmuch-toggle-read)))

camcorder

Para hacer gifs:

(package! camcorder)

(def-package! camcorder
  :defer t
  :config
  (setq camcorder-recording-command '("recordmydesktop" " --fps 100 --no-sound --windowid " window-id " -o " file)))

i3wm-config-mode

Modo para mejorar la paleta de conf-space-mode cuando se edita el fichero de configuración de org-mode:

(package! i3wm-config-mode :recipe (:fetcher github :repo "Alexander-Miller/i3wm-Config-Mode"))

(def-package! i3wm-config-mode :defer t)

csv-mode

(package! csv-mode)

(def-package! csv-mode :defer t)

markdown-mode

(package! markdown-mode)
(package! markdown-toc)

(def-package! markdown-mode
  :config
  (setq markdown-xhtml-header-content "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />")
  :defer t)

Crear un TOC:

(def-package! markdown-toc
  :defer t
  :config
  (setq markdown-toc-header-toc-title "# Índice"))

ledger-mode

(package! ledger-mode)
(package! flycheck-ledger)

(def-package! ledger-mode
  :defer t)

po-mode

(package! po-mode)

(def-package! po-mode
  :defer t)

;; Fuente: https://www.emacswiki.org/emacs/PoMode
(defun po-wrap ()
    "Filter current po-mode buffer through `msgcat' tool to wrap all lines."
    (interactive)
    (if (eq major-mode 'po-mode)
    (let ((tmp-file (make-temp-file "po-wrap."))
          (tmp-buf (generate-new-buffer "*temp*")))
      (unwind-protect
          (progn
        (write-region (point-min) (point-max) tmp-file nil 1)
        (if (zerop
             (call-process
              "msgcat" nil tmp-buf t (shell-quote-argument tmp-file)))
            (let ((saved (point))
              (inhibit-read-only t))
              (delete-region (point-min) (point-max))
              (insert-buffer-substring tmp-buf)
              (goto-char (min saved (point-max))))
          (with-current-buffer tmp-buf
            (error (buffer-string)))))
        (kill-buffer tmp-buf)
        (delete-file tmp-file)))))

mail-mode

Abrir mails de mutt en modo email:

(add-to-list 'auto-mode-alist '(".*mutt-" . mail-mode))

undo-tree

(def-package! undo-tree
  :config
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-auto-save-history t)
  (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo-tree"))))

google-translate

(package! google-translate)

(def-package! google-translate
  :defer t
  :config
  (setq google-translate-translation-directions-alist
      '(("es" . "en") ("en" . "es"))))

evil-nerd-commenter

Doom por defecto usa evil-commentary, que no me gusta por que hace raros. Me gusta más este:

(package! evil-nerd-commenter)

(def-package! evil-nerd-commenter
  :config
  (evilnc-default-hotkeys))

(map! :map global-map
      (:nmvo "gc" nil
      :nmvo "gc" #'evilnc-comment-operator))

evil-mode

(def-package! evil
  :config
  (setq evil-motion-state-modes (append evil-emacs-state-modes evil-motion-state-modes))
  (add-to-list 'evil-insert-state-modes 'global-git-commit)
  (defun evilmi-customize-keybinding ()
    (evil-define-key 'normal evil-matchit-mode-map
      "ñ" 'evilmi-jump-items)))

(map! (:leader
        (:desc "inc number" :nmvo "+" #'evil-numbers/inc-at-pt)
        (:desc "dec number" :nmvo "-" #'evil-numbers/dec-at-pt)))

shell-mode

Hace source de las funciones para poder usarlas desde shell-command:

(setq shell-command-switch "-ic")

magit

(evil-set-initial-state 'magit-popup-mode 'emacs)
(setq with-editor-emacsclient-executable "/usr/local/bin/emacsclient")

adoc-mode

(package! adoc-mode)

(def-package! adoc-mode :defer t)

evil-ediff

(package! evil-ediff)

(def-package! evil-ediff :defer t)

company

Uso la configuración que trae doom por defecto.

webpaste

(package! webpaste)

(def-package! webpaste
  :defer t
  :config
  (setq webpaste-paste-confirmation t)
  (setq webpaste-provider-priority '("ptpb.pw" "dpaste.de" "ix.io")))

calfw

Calendario molón. Uso la configuración de doom, con algunas cosillas más:

(setq ical-calfw-sources (list (cfw:org-create-source "Blue")))
(setq cfw:org-overwrite-default-keybinding t)
(setq calendar-week-start-day 1)

(defun daemons/ical-monthly-calendar ()
  (interactive)
  (cond
   ((equal current-prefix-arg '(4))
    (cfw:ical-data-cache-clear-all)))
  (cfw:open-calendar-buffer
   :contents-sources ical-calfw-sources))

(defun daemons/ical-weekly-calendar ()
  (interactive)
  (cond
   ((equal current-prefix-arg '(4))
    (cfw:ical-data-cache-clear-all)))
  (cfw:open-calendar-buffer
   :view 'week
   :contents-sources ical-calfw-sources))

(defun daemons/org-weekly-calendar ()
  (interactive)
  (let ((cfw:org-icalendars '("~/Documentos/org/index.org")))
    (cfw:open-calendar-buffer
     :view 'week
     :contents-sources (list (cfw:org-create-source)))))

(defun daemons/org-monthly-calendar ()
  (interactive)
  (let ((cfw:org-icalendars '("~/Documentos/org/index.org")))
    (cfw:open-calendar-buffer
     :contents-sources (list (cfw:org-create-source)))))

hugo

(package! ox-hugo)

(def-package! ox-hugo)

url accionables

Ver este articulo.

(use-package goto-addr
  :hook ((compilation-mode . goto-address-mode)
         (prog-mode . goto-address-prog-mode)
         (eshell-mode . goto-address-mode)
         (shell-mode . goto-address-mode))
  :bind (:map goto-address-highlight-keymap
              ("<RET>" . goto-address-at-point)
              ("M-<RET>" . newline))
  :commands (goto-address-prog-mode
             goto-address-mode))

docker

Uso la configuración por defecto de doom, pero me gusta que no muera el buffer de compilación:

(set-popup-rule! "docker-build-output" :size 0.30 :select t)

Apañar doom

Cambiar los atajos por unos que me gustan más.

(map! (:leader
        :desc "Execute comands" :nmvo "SPC" #'counsel-M-x
        :nmvo "s" nil
        (:prefix "s"
          :desc "Search in project" :nmvo "p" #'counsel-projectile-rg
          :desc "Interactive menu" :nmvo "i" #'counsel-imenu)
        (:prefix "f"
          :nmvo "." nil
          :nmvo "/" nil
          :nmvo "R" nil
          :nmvo "P" nil
          :nmvo "a" nil
          :nmvo "c" nil
          :nmvo "e" nil
          :nmvo "?" nil
          :nmvo ">" nil
          :desc "Find directory" :nmvo "D" #'dired
          :desc "Find directory in project" :nmvo "d" #'projectile-dired
          :desc "Sudo find file" :nmvo "s" #'doom/sudo-find-file
          :desc "Find file in project" :nmvo "f" #'projectile-find-file
          :desc "Find file" :nmvo "F" #'counsel-find-file
          :desc "Fuzzy find file" :nmvo "z" #'counsel-fzf)
        (:prefix "p"
          :nmvo "t" #'+neotree/open)
        (:prefix "b"
          :desc "Switch buffer across projects" :nmvo "B" #'ivy-switch-buffer
          :desc "Switch buffer other window" :nmvo "o" #'ivy-switch-buffer-other-window)
        :desc "Narrow / widen dwim" :nmvo "n" #'endless/narrow-or-widen-dwim
        :desc "Switch window" :nmvo "o" #'ace-window
        :nmvo "gG" nil
        :nmvo "gL" nil
        :nmvo "<" nil
        :nmvo "/" nil
        :nmvo "]" nil
        :nmvo "[" nil
        :nmvo "." nil
        :nmvo "t" nil
        :nmvo "X" nil)
      :nmvoi "M-y" #'counsel-yank-pop
      :nmvoi "C-a" #'evil-beginning-of-line
      :nmvoi "C-e" #'evil-end-of-line
      :nmvoi "C-ñ" #'recenter-top-bottom
      :nmvoi "C-d" #'evil-scroll-page-down
      :nmvoi "C-u" #'evil-scroll-page-up)

Funciones personalizadas

Insertar bloque src para org-mode

Además, funciona tanto sin ninguna región activa cómo con esta. De haber región activa, la envuelve.

(defun org-src-insert (choice)
  "Insert src code blocks."
  (interactive
     (if (org-at-table-p)
         (call-interactively 'org-table-rotate-recalc-marks)
       (let ((choices '("emacs-lisp" "python" "shell" "css" "ledger" "latex" "lisp" "sqlite")))
         (list (ido-completing-read "Source code type: " choices)))))

  (cond
   ((region-active-p)
    (let ((start (region-beginning))
      (end (region-end)))
      (progn
    (goto-char end)
    (insert "\n#+END_SRC\n")
    (goto-char start)
    (insert (format "#+BEGIN_SRC %s\n" choice)))
      )
    )

   (t
    (insert (format "#+BEGIN_SRC %s\n" choice))
    (save-excursion (insert "\n#+END_SRC")))))

Insertar bloque src para markdown

(defun markdown-src-insert (choice)
  "Insert src code blocks."
  (interactive
     (if (org-at-table-p)
         (call-interactively 'org-table-rotate-recalc-marks)
       (let ((choices '("bash" "python" "css" "ledger" "latex" "lisp" "sqlite")))
         (list (ido-completing-read "Source code type: " choices)))))

  (cond
   ((region-active-p)
    (let ((start (region-beginning))
      (end (region-end)))
      (progn
    (goto-char end)
    (insert "```\n")
    (goto-char start)
    (insert (format "```%s\n" choice)))
      )
    )

   (t
    (insert (format "```%s\n" choice))
    (save-excursion (insert "```\n")))))

Insertar fecha

Esta la he cogido de emacswiki:

(defun emacswiki/insert-current-date ()
  (interactive)
  (shell-command-to-string "echo -n $(date +%Y-%m-%d)"))

Siguiendo la misma tonica:

(defun daemons/insert-current-month-number ()
  (interactive)
  (shell-command-to-string "echo -n $(date +%m)"))

Siguiendo la misma tonica:

(defun daemons/insert-current-year-number ()
  (interactive)
  (shell-command-to-string "echo -n $(date +%Y)"))

Siguiendo la misma tonica:

(defun daemons/insert-current-week-number ()
  (interactive)
  (shell-command-to-string "echo -n $(date +%V)"))

Fecha de la semana que viene:

(defun daemons/insert-next-week()
  (interactive)
  (shell-command-to-string "echo -n $(date -d 'next week' '+%m %d %Y')"))

multi-term

(package! multi-term)

Copiado de las funciones derivadas de +eshell:run de Doom para emularlo en multi-term.

(def-package! multi-term
  :config
  (defvar +multi-term-buffer-name "*doom multi-term*")
  (defvar +multi-term-buffers (make-ring 25)
    "List of open multi-term buffers.")

  (evil-define-command +multi-term:run (command bang)
    ;; TODO Add COMMAND support
    (interactive "<fsh><!>")
    (if bang
        (+multi-term/open command)
      (+multi-term/open-popup command)))

  (defun +multi-term--set-window (window &optional flag)
    (when window
      (set-window-parameter window 'no-other-window flag)
      (set-window-parameter window 'visible flag)))

  (defun +multi-term--buffer (&optional new-p)
    (or (unless new-p
          (cl-loop for buf in (ring-elements +multi-term-buffers)
                   if (and (buffer-live-p buf)
                           (not (get-buffer-window buf)))
                   return buf))
        (generate-new-buffer +multi-term-buffer-name)))

  (defun +multi-term--unused-buffer (&optional new-p)
    (or (unless new-p
          (cl-loop for buf in (ring-elements +multi-term-buffers)
                   if (and (buffer-live-p buf)
                           (not (get-buffer-window buf t)))
                   return buf))
        (generate-new-buffer multi-term-buffer-name)))

  (defun +multi-term/open (arg &optional command)
    "Open multi-term in the current buffer."
    (interactive "P")
    (when (eq major-mode 'multi-term-mode)
      (user-error "Already in an multi-term buffer"))
    (let* ((default-directory (if arg default-directory (doom-project-root)))
           (buf (+multi-term--unused-buffer)))
      (with-current-buffer (switch-to-buffer buf)
        (if command (+multi-term-run-command command buf)))
      buf))

  (defun +multi-term/open-popup (&optional command)
    "Open multi-term in a popup window."
    (interactive)
    (let ((buf (+multi-term--buffer)))
      (pop-to-buffer buf)
      (multi-term)
      (+multi-term--set-window (get-buffer-window buf) t)
      (when command
        (+multi-term-run-command command)))))

(map! :leader :nmvo "," 'nil
      :leader :nmvo "," '+multi-term:run)

Agrandar y enpequeñecer

(defun endless/narrow-or-widen-dwim (p)
  "Widen if buffer is narrowed, narrow-dwim otherwise.
Dwim means: region, org-src-block, org-subtree, or
defun, whichever applies first. Narrowing to
org-src-block actually calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer
is already narrowed."
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((region-active-p)
         (narrow-to-region (region-beginning)
                           (region-end)))
        ((derived-mode-p 'org-mode)
         ;; `org-edit-src-code' is not a real narrowing
         ;; command. Remove this first conditional if
         ;; you don't want it.
         (cond ((ignore-errors (org-edit-src-code) t)
                (delete-other-windows))
               ((ignore-errors (org-narrow-to-block) t))
               (t (org-narrow-to-subtree))))
        ((derived-mode-p 'latex-mode)
         (LaTeX-narrow-to-environment))
        (t (narrow-to-defun))))

En progreso / Pendiente

En esta sección van las cosas que no tengo muy provadas o tengo a medio configurar.

Yaml

flycheck-yamllint

(package! flycheck-yamllint)

(add-hook 'flycheck-mode-hook 'flycheck-yamllint-setup)

ansible

No se activa automaticamente

;; (add-hook 'yaml-mode-hook '+ansible-yaml-mode)

molecule

No se activa automaticamente.

(package! molecule)

(def-package! molecule)
  ;; :config (add-hook 'yaml-mode-hook 'molecule-mode))

k8s-mode

(package! k8s-mode)

(def-package! k8s-mode
  :config
  (setq k8s-site-docs-version "v1.10"))
  ;; (add-hook 'yaml-mode-hook 'k8s-mode))

lsp

Docs

  • describe thing at point (no va en python)
  • rename (algo lento)
  • find definition (mola)
  • find references (mola, aunque necesitaria ivy)
  • symbol highlight (agobia un poco, seria bueno quitarlo)
  • lsp-eldoc-render-all (no tengo claro si me gusta)

TODO

Configuración

(package! lsp-mode)
(package! lsp-ui)
(package! company-lsp)

(def-package! lsp-mode
  :config
  ;; (require 'lsp-imenu)
  (add-hook 'lsp-after-open-hook 'lsp-enable-imenu)
  (setq lsp-prefer-flymake nil)
  ;; eldoc
  (setq lsp-eldoc-render-all nil)
  (setq lsp-eldoc-enable-hover nil)
  (setq lsp-eldoc-enable-signature-help nil)
  (setq lsp-ui-sideline-ignore-duplicate t)
  )

Python

pipenv install "python-language-server[all]"

(package! lsp-python)

(add-hook 'python-mode-hook #'lsp)
(set-company-backend! 'python-mode 'company-lsp)
;; (set-company-backend! 'inferior-python-mode 'company-lsp)

evil-hardcore-mode

Hardcodear atajos de teclado:

(package! evil-hardcore-mode :recipe (:fetcher git :url "https://git.daemons.it/drymer/evil-hardcore-mode.git/"))

(def-package! evil-hardcore-mode
  :init
  (setq evil-hardcore-my-bad-keybinds nil)
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-x C-i")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-x C-o")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-x C-z")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-x C-j")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-t")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-s")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-c C-d")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-x 1")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-x 2")
  (add-to-list 'evil-hardcore-my-bad-keybinds "C-x 3")
  :config
  (global-evil-hardcore-mode))

skeletor

(package! skeletor)

(def-package! skeletor
  :config
  (setq skeletor-project-directory "~/Proyectos/")
  (setq skeletor-user-directory "~/.doom.d/skeletor-templates/")

(defun skeletor-molecule--read-driver ()
  "Read a molecule driver from the user."
   (completing-read "Molecule driver: " '("azure" "delegated" "docker" "ec2" "gce" "lxc" "lxd" "openstack" "vagrant")))

  (skeletor-define-template "daemons-ansible"
    :after-creation
      (lambda (dir)
       ((let (molecule-driver (skeletor-molecule--read-driver))
       ;; coger el nombre del rol de dir usando basenam o algo
        (skeletor-async-shell-command (concat "molecule init scenario --driver-name " molecule-driver " --role-name " dir)))
))
    :default-license (rx bol "gpl3")

    :requires-executables '(("git" . "https://git-scm.com/")))

  (skeletor-define-template "daemons-python"
    :after-creation
      (lambda (dir)
        (skeletor-async-shell-command "make tooling"))
    :default-license (rx bol "gpl3")

    :requires-executables '(("git" . "https://git-scm.com/")
                            ("make" . "http://www.gnu.org/software/make/")
                            ("virtualenv" . "http://www.virtualenv.org")))

)

Añadir el nombre a la propiedad

A diferencia de la función de writequit, esta establece el título como customid.

;; Fuente: https://writequit.org/articles/emacs-org-mode-generate-ids.html
;; requerir libreria de ayuda
;;;###autoload
(def-package! org-id :defer t)

;; función que creará los id
;;;###autoload
(defun eos/org-custom-id-get (&optional pom create prefix)
"Get the CUSTOM_ID property of the entry at point-or-marker POM.
If POM is nil, refer to the entry at point. If the entry does
not have an CUSTOM_ID, the function returns nil. However, when
CREATE is non nil, create a CUSTOM_ID if none is present
already. PREFIX will be passed through to `org-id-new'. In any
case, the CUSTOM_ID of the entry is returned."
(interactive)
(org-with-point-at pom
(let ((id (org-entry-get nil "CUSTOM_ID")))
    (cond
    ((and id (stringp id) (string-match "\\S-" id))
    id)
    (create
    (setq id (org-get-heading))
    (org-entry-put pom "CUSTOM_ID" id)
    (org-id-add-location id (buffer-file-name (buffer-base-buffer)))
    id))))))

;;;###autoload
(defun eos/org-add-ids-to-headlines-in-file ()
"Add CUSTOM_ID properties to all headlines in the
current file which do not already have one."
(interactive)
(org-map-entries (lambda () (eos/org-custom-id-get (point) 'create))))

Ecloud

(package! ecloud :recipe (:fetcher git :url "https://github.com/techniumlabs/ecloud/"))

(def-package! ecloud :defer t)

keyfreq

(package! keyfreq)

(def-package! keyfreq
  :config
  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1)
  (setq daemons/command-frequency-script "~/Scripts/bin/emacs-command-frequency.py")
  (if (not (file-exists-p daemons/command-frequency-script))
      (progn
        (url-copy-file "http://ergoemacs.org/emacs/command-frequency.py" daemons/command-frequency-script)
        (shell-command-to-string (concat "chmod +x " daemons/command-frequency-script)))))

Sprint actual

Estoy haciendo el experimento de hacer sprints de un mes para mis cosas personales. El número de sprint lo uso en algunas ordenes, así que he pensado que la mejor forma es definirlo en una variable e irlo subiendo al final de sprint.

(setq daemons/active-sprint "1")