Mi (nueva) configuración de GNU Emacs, usando org-mode y org-babel :)
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.git-crypt
marcadores
org-page-themes/shackra
plantillas
site-packages
themes corrigiendo error con la ubicación del tema jazz Nov 29, 2014
.gitattributes new: Habilita git-crypt en el repositorio Nov 1, 2017
.gitignore chg: Ajustes menores en estilo !minor Nov 4, 2018
.gitmodules chg: Elimina submodulo para Secretaria Oct 13, 2018
CHANGELOG.md
README.org
bookmarks
descargas.mustache
init.el
init_zsh.sh
sane.el
srcprecode.el Actualizando el código de EGO Nov 5, 2015

README.org

Configuración de GNU Emacs

                   🕇
Actiones nostras tibi comítimus, Dómine,
 ut ad maiorem gloriam tuam repleamur.
                 🕇   🕇

Introducción

Esta es mi configuración de GNU Emacs, casi siempre le estoy haciendo ajustes.

La configuración se hospeda en GitLab, la configuración que ves en Github es una copia espejo. El archivo init.el contiene código Elisp para hacer funcionar este formato de configuración.

;; sombrero de aluminio, le bajamos una rayita
(setq network-security-level 'medium)

;; https://jamiecollinson.com/blog/my-emacs-config/#make-it-easy-to-edit-this-file
(defun find-config ()
  "Abre el archivo de configuración de Emacs"
  (interactive)
  (find-file "~/.emacs.d/README.org"))

(global-set-key (kbd "C-c I") 'find-config)

(defun shackra-update-one-package (package)
  "Actualiza un paquete PACKAGE"
  (when (package-installed-p package)
    (let* ((newest-pkg (car-safe (cdr (assq package package-archive-contents))))
           (new-ver (and newest-pkg (package-desc-version newest-pkg)))
           (builtin-pkg (cdr (assq package package--builtins)))
           (installed-pkg (car-safe (cdr (assq package package-alist))))
           (old-dir (and installed-pkg (package-desc-dir installed-pkg)))
           (old-ver (or (and installed-pkg (package-desc-version installed-pkg))
                        (and builtin-pkg (package--bi-desc-version builtin-pkg)))))
      (when (and new-ver (version-list-< old-ver new-ver))
        ;; Instalamos la nueva versión de org-mode
        (condition-case nil
            ;; en caso de algún error tratando de bajar algún paquete, captura
            ;; el error para que no interfiera con la inicialización de Emacs
            (progn (package-install newest-pkg)
                   (message (format "Paquete «%s» actualizado de la versión %s a la versión %s"
                                    (package-desc-name newest-pkg) old-ver new-ver))))
        (when old-dir
          (delete-directory old-dir t))))))

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

;; Instala use-package si no esta disponible
(when (not (package-installed-p 'use-package))
  (package-install 'use-package))

(if (not (package-installed-p 'org-plus-contrib))
    (package-install 'org-plus-contrib)
  ;; El paquete esta instalado. Actualiza el paquete org-mode.
  (shackra-update-one-package 'org-plus-contrib))

(when (not (package-installed-p 'diminish))
  (package-install 'diminish))

(when (not (package-installed-p 'bind-key))
  (package-install 'bind-key))

(when (not (package-installed-p 'f))
  (package-install 'f))

(when (not (package-installed-p 'exec-path-from-shell))
  (package-install 'exec-path-from-shell))

;; Arreglo para LaTeX con Emacs en MacOS "El Capitan"
(when (eq system-type 'darwin)
  (setf exec-path (append exec-path '("/Library/TeX/texbin"))))

(unless (memq system-type '(ms-dos windos-nt cygwin))
  (require 'exec-path-from-shell)
  (exec-path-from-shell-initialize))

;; En caso de que /usr/local/bin no este agregado
(when (eq system-type 'darwin)
  (setenv "PATH" "Library/TeX/texbin/:$PATH" t))

(eval-when-compile
  (require 'use-package))
(require 'diminish)
(require 'bind-key)

(setf use-package-always-ensure t)

(defun shackra-org-confirm-babel-evaluate (lang body)
  (not (or (string= lang "emacs-lisp"))))
(setf org-confirm-babel-evaluate #'shackra-org-confirm-babel-evaluate)

(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)

Información personal

La ubicación geográfica usada es la de San José, Costa Rica siendo tan pequeño hace innecesario especificar nuestra ubicación geográfica exacta.

(setf user-full-name "Jorge Javier Araya Navarro"
      user-mail-address "jorge@esavara.cr"
      calendar-location-name "Siquirres, CR"
      calendar-latitude 9.935607
      calendar-longitude -84.1833856
      calendar-christian-all-holidays-flag t
      calendar-date-style 'european)

Repositorio de paquetes

Desde la versión 24 Emacs permite la instalación de paquetes de la misma manera como se realiza en distribuciones de GNU/Linux.

El sistema de paquetes de Emacs no es perfecto, para que algunos paquetes funcionen como deben aun debes poner algunas cosas en tu configuración de Emacs y tal. Revisa la descripción de cualquier paquetes que vayas a instalar para tener más información. Para ver qué paquetes hay disponibles, y cuales desea instalar, puede hacer uso del comando M-x package-list-packages

Códigos Elisp

funciones de Emacs lisp escritas por mi u otras personas (y que yo he recolectado para mi uso personal)

Inspector de entradas org-mode

Convierte un elemento org-mode bajo el puntero en su equivalente elisp para inspección

(defun org-inspect-element-at-point ()
  "Inspecciona el elemento org-mode en su forma elisp"
  (interactive)
  (let ((body (org-element-context)))
    (switch-to-buffer (get-buffer-create "*org-inspect-element-at-point*"))
    (erase-buffer)
    (insert (format "'%s" body))
    (pp-buffer)))

(defun org-inspect-element-buffer ()
  "Inspecciona todo el documento org-mode en su forma elisp"
  (interactive)
  (let ((body (org-element-parse-buffer)))
    (switch-to-buffer (get-buffer-create "*org-inspect-element-buffer*"))
    (erase-buffer)
    (insert (format "'%s" body))
    (pp-buffer)))

(defun org-inspect-buffer-clocktable ()
  "Inspecciona el documento org-mode en su forma elisp como una tabla org-clock"
  (interactive)
  (let ((body (org-clock-get-table-data (buffer-name) nil)))
    (switch-to-buffer (get-buffer-create "*org-inspect-buffer-clocktable*"))
    (erase-buffer)
    (insert (format "'%s" body))
    (pp-buffer)))

función para insertar etiquetas <kbd>

Gracias a Malabarba en su respuesta desde Emacs.stackexchange.

(defun endless/insert-key (key)
  "Ask for a key then insert its description.
Will work on both org-mode and any mode that accepts plain html."
  (interactive "kType key sequence: ")
  (let* ((is-org-mode (derived-mode-p 'org-mode))
         (tag (if is-org-mode
                  "@@html:<kbd>%s</kbd>@@"
                "<kbd>%s</kbd>")))
    (if (null (equal key "\r"))
        (insert
         (format tag (help-key-description key nil)))
      (insert (format tag ""))
      (forward-char (if is-org-mode -8 -6)))))

funciones con expresiones regulares que uso a menudo en edición de texto

estas son funciones que uso muy a menudo durante la edición de texto, tenerlos como comandos interactivos me ahorra tiempo escribiendo las expresiones regulares una y otra vez.

(defun shackra-no-saltos-linea (start end)
  "Elimina todos los saltos de linea en la selección"
  (interactive "r")
  (vr/replace "\n+" " " start end))

(defun shackra-no-multiple-espacios (start end)
  "Elimina todos los espacios en blanco seguidos en la selección"
  (interactive "r")
  (vr/replace " +" " " start end))

find-file y switch-buffer personalizados

Problema: Cuando estoy dentro de un proyecto con Projectile-mode, me gusta visitar archivos y buffers relacionados con el proyecto en el cual estoy trabajando.

Solución: Crear mis funciones personalizadas para find-file y switch-buffer.

Teclas

@@html:<kbd>C-x C-f</kbd>@@
Visitar archivo. Dentro de un proyecto: Visita archivo de proyecto, prefijo @@html:<kbd>C-u</kbd>@@ Visitar archivo, prefijo @@html:<kbd>C-u</kbd>@@ @@html:<kbd>C-u</kbd>@@ ag para buscar una cadena de texto entre miles de archivos.
@@html:<kbd>C-x b</kbd>@@
Cambiar buffer. Dentro de un proyecto: Cambiar buffer de archivo relacionado a proyecto, prefijo @@html:<kbd>C-u</kbd>@@ Cambiar buffer, prefijo @@html:<kbd>C-u</kbd>@@ @@html:<kbd>C-u</kbd>@@ Inicia menú Hydra para Windmove.
(with-eval-after-load "ivy"
  (with-eval-after-load "projectile"
    (with-eval-after-load "counsel"
      (defun shackra-find-file (arg)
        (interactive "p")
        (cond
         ((eq arg 4) (counsel-find-file))
         ((eq arg 16) (counsel-ag))
         ((eq arg 1) (if (projectile-project-p) (projectile-find-file-dwim) (counsel-find-file)))))

      (defun shackra-switch-to-buffer (arg)
        (interactive "p")
        (cond
         ((eq arg 4) (ivy-switch-buffer))
         ((eq arg 16) (hydra-win/body))
         ((eq arg 1) (if (projectile-project-p) (projectile-switch-to-buffer) (ivy-switch-buffer)))))
      ;; Remapea los atajos con mis propios comandos
      (global-set-key [remap find-file] #'shackra-find-file)
      (global-set-key [remap ivy-switch-buffer] #'shackra-switch-to-buffer))))

función para delete-frame-functions

(defun shackra-run-delete-frame-hooks (frame)
  "Esta función corre algunas funciones que no son llamadas cuando Emacs
corre como proceso de segundo plano"
  (when (server-running-p)
    (savehist-save)
    (recentf-save-list)))

(add-hook 'delete-frame-functions 'shackra-run-delete-frame-hooks)

salva algunos buffers al perder Emacs el foco

Sacado de Programming: Seven specialty Emacs settings with big payoffs

(defun guardar-todo ()
  (interactive)
  (save-some-buffers t))

;; uso:
;; (add-hook 'focus-out-hook #'guardar-todo)

No molestes, Shia LaBeouf!

(defun shackra-org-reschedule-tomorrow ()
  "Re-Programa para mañana una tarea que pude hacer hoy"
  (interactive)
  (org-schedule :time (format-time-string "%Y-%m-%d" (time-add (current-time) (seconds-to-time 86400)))))

defadvice temporal

(defmacro my/with-advice (adlist &rest body)
  "Execute BODY with temporary advice in ADLIST.

Each element of ADLIST should be a list of the form
  (SYMBOL WHERE FUNCTION [PROPS])
suitable for passing to `advice-add'.  The BODY is wrapped in an
`unwind-protect' form, so the advice will be removed even in the
event of an error or nonlocal exit."
  (declare (debug ((&rest (&rest form)) body))
           (indent 1))
  `(progn
     ,@(mapcar (lambda (adform)
                 (cons 'advice-add adform))
               adlist)
     (unwind-protect (progn ,@body)
       ,@(mapcar (lambda (adform)
                   `(advice-remove ,(car adform) ,(nth 2 adform)))
                 adlist))))

Omitir confirmación para y-or-n-p

(defun my/bypass-confirmation (function &rest args)
  "Call FUNCTION with ARGS, bypassing all `y-or-n-p' prompts."
  (my/with-advice
   ((#'y-or-n-p :override (lambda (prompt) t)))
   (apply function args)))

(defun my/bypass-confirmation-all (function &rest args)
  "Call FUNCTION with ARGS, bypassing all prompts.
This includes both `y-or-n-p' and `yes-or-no-p'."
  (my/with-advice
   ((#'y-or-n-p    :override (lambda (prompt) t))
    (#'yes-or-no-p :override (lambda (prompt) t)))
   (apply function args)))

usar Emacsclient como git mergetool

(defun shackra-emerge (local remote base output)
  "difftool que se abre en emacsclient"
  (emerge-files-with-ancestor nil local remote base output nil 'shackra-emerge--close-current-frame))

(defun shackra-emerge--close-current-frame ()
  "Cierra el frame actual"
  (delete-frame (selected-frame)))

Para hacer que Git use emacsclient como mergetool hay que modificar la configuración de Git

[merge]
        tool = emacsclient
[mergetool "emacsclient"]
        cmd = emacsclient -c -a \"\" --eval \"(shackra-emerge \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$BASE\\\" \\\"$OUTPUT\\\")\"
        trustExitCode = true

Generar enlaces de descargas para descargas directas y BitTorrent

(defun shackra-owp-descargas (title hashalist)
  "Enlaces Magnet a HTML."
  (let* ((nuevalista '())
         (nuevoelement (ht-create))
         (uri "")
         (nombre "")
         (tipo "")
         (!torrent)
         (mustache-partial-paths (list (expand-file-name "" user-emacs-directory))))
    ;; recreamos la lista en `hashalist' como una lista ht
    (dolist (e hashalist)
      (setf nombre (car e))
      (setf !torrent (car (cddr e)))
      (if !torrent
          (progn
            (setf uri (car (cdr e)))
            (setf tipo "directa"))
        (progn
          (setf tipo "con BitTorrent")
          (setf uri (format "magnet:?xt=urn:btih:%s&dn=%s&tr=%s"
                            (car (cdr e))
                            (url-hexify-string (car e))
                            (url-hexify-string (concat "udp://tracker.openbittorrent.com:80"
                                                       "&tr=udp://opentor.org:2710"
                                                       "&tr=udp://tracker.ccc.de:80"
                                                       "&tr=udp://tracker.blackunicorn.xyz:6969"
                                                       "&tr=udp://tracker.coppersurfer.tk:6969"
                                                       "&tr=udp://tracker.leechers-paradise.org:6969"))))))
      (ht-set! nuevoelement "nombre" nombre)
      (ht-set! nuevoelement "uri" uri)
      (ht-set! nuevoelement "es-torrent" (not !torrent))
      (ht-set! nuevoelement "tipo" tipo)
      (add-to-list 'nuevalista (ht-copy nuevoelement)))
    (mustache-render "{{> descargas}}" (ht ("hash-alist" nuevalista) ("titulo" title)))))

Probar si un puerto esta abierto

(defun shackra-port-open-p (server port)
  (let* ((conn nil))
    (condition-case err
        (progn
          (setf conn (open-network-stream "test-port-open" nil server port))
          (stop-process conn)
          t)
      (file-error nil))))

Comprobar si un modulo Python existe

(defun shackra-python-module-exist-p (module)
  "Retorna `t' si el modulo `MODULE' existe"
  (let ((exists (string-trim (shell-command-to-string (format "python -c 'import pkgutil; print(0 if pkgutil.find_loader(\"%s\") else 1)'" module)))))
    (when (string= exists "0")
      t)))

Convertir hh:mm a formato de punto flotante

(require 'thingatpt)
(require 'rx)

(defvar shackra-time-re (rx (group (one-or-more digit)) ":" (group (one-or-more digit)))
  "Expresión regular que coincide con notacion de tiempo HH:MM")

(defun shackra-time--to-seconds (timestr)
  "Convierte la notacion HH:MM a segundos"
  (unless timestr
    (setf timestr "0:00"))
  (let* ((matchindex (string-match shackra-time-re timestr))
         (hours (string-to-number (match-string 1 timestr)))
         (minutes (string-to-number (match-string 2 timestr))))
    (+ (* 60 (* hours 60)) (* minutes 60))))

(defun shackra-time-to-hours (timestr)
  "Expresa el tiempo en notacion de punto decimal"
  (format "%.3f" (/ (shackra-time--to-seconds timestr) 3600.0)))

(defun shackra-time-at-point-to-hours ()
  "Convierte el tiempo bajo el cursor a notacion decimal, lo copia al portapapeles"
  (interactive)
  (let ((decimal-time (shackra-time-to-hours (thing-at-point 'time))))
    (message decimal-time)
    (kill-new decimal-time)))

(defun time-bounds-of-time-at-point ()
  (save-excursion
    (while (looking-back "[^[:space:]]" 1)
      (backward-char))
    (save-match-data
      (if (looking-at shackra-time-re)
          (cons (point) (match-end 0))
        nil))))

(put 'time 'bounds-of-thing-at-point 'time-bounds-of-time-at-point)

Apaga el auto sangrado

(defun shackra-electric-indent-mode-off ()
  (electric-indent-local-mode -1)
  (define-key python-mode-map (kbd "RET") 'newline-and-indent)
  ;; Desactiva aggresive-indent si esta instalado y activo
  (when (fboundp 'aggressive-indent-mode)
    (aggressive-indent-mode -1)))

Palabras (=’word=) al principio de linea de (region-beginning) y (region-end)

(defun shackra-words-region-begin-end (begin end)
  "Retorna una lista con las palabras al principio de linea para `BEGIN' y `END'"
  (interactive "r")
  (save-excursion
    (let ((word1)
          (word2))
      ;; Mueve el cursor al principio de la región
      (goto-char begin)
      (beginning-of-line)
      (setf word1 (thing-at-point 'word t))
      ;; Mueve el cursor al final de la región
      (goto-char end)
      (beginning-of-line)
      (setf word2 (thing-at-point 'word t))
      ;; devuelve el resultado
      `(,word1 ,word2))))

Conveniencias para convertir de Asciidoc a LaTeX

Tengo documentos que tienen extensas formateo en Asciidoc. Deseo convertir todo al formato de LaTeX pues en la actualidad lo utilizo con más regularidad para publicar escritos.

(defvar shackra-footnote-asciidoc (rx "footnote:" "[" (group (one-or-more (not (any "[")))) "]")
  "Coincide con el formato de notas al pie de asciidoc que es `footnote:[ ... ]'")

(defvar shackra-emph-asciidoc (rx "_" (group (one-or-more (not (any "_")))) "_")
  "Coincide con el formato cursiva de asciidoc que es `_foo bar_'")

(defun shackra-footnote-asciidoc-to-latex ()
  (interactive)
  (save-excursion
    (replace-regexp shackra-footnote-asciidoc "\\\\footnote{\\1}")))

(defun shackra-emph-asciidoc-to-latex ()
  (interactive)
  (save-excursion
    (replace-regexp shackra-emph-asciidoc "\\\\emph{\\1}")))

Dinamicamente ajusta la posición de las etiquetas en org-mode

Sacado de Org ad hoc code, quick hacks and workarounds.

IMPORTANTE: Esto podría resultar lento en grandes archivos.

(with-eval-after-load "org"
  (setq ba/org-adjust-tags-column nil)

  (defun ba/org-adjust-tags-column-reset-tags ()
    "In org-mode buffers it will reset tag position according to
  `org-tags-column'."
    (when (and
           (not (string= (buffer-name) "*Remember*"))
           (eql major-mode 'org-mode))
      (let ((b-m-p (buffer-modified-p)))
        (condition-case nil
            (save-excursion
              (goto-char (point-min))
              (command-execute 'outline-next-visible-heading)
              ;; disable (message) that org-set-tags generates
              (cl-flet ((message (&rest ignored) nil))
                (org-set-tags 1 t))
              (set-buffer-modified-p b-m-p))
          (error nil)))))

  (defun ba/org-adjust-tags-column-now ()
    "Right-adjust `org-tags-column' value, then reset tag position."
    (set (make-local-variable 'org-tags-column)
         (- (- (window-width) (length (or org-ellipsis "....")))))
    (ba/org-adjust-tags-column-reset-tags))

  (defun ba/org-adjust-tags-column-maybe ()
    "If `ba/org-adjust-tags-column' is set to non-nil, adjust tags."
    (when ba/org-adjust-tags-column
      (ba/org-adjust-tags-column-now)))

  (defun ba/org-adjust-tags-column-before-save ()
    "Tags need to be left-adjusted when saving."
    (when ba/org-adjust-tags-column
      (setq org-tags-column 1)
      (ba/org-adjust-tags-column-reset-tags)))

  (defun ba/org-adjust-tags-column-after-save ()
    "Revert left-adjusted tag position done by before-save hook."
    (ba/org-adjust-tags-column-maybe)
    (set-buffer-modified-p nil))

  ;; automatically align tags on right-hand side
  (add-hook 'window-configuration-change-hook
            'ba/org-adjust-tags-column-maybe)
  (add-hook 'before-save-hook 'ba/org-adjust-tags-column-before-save)
  (add-hook 'after-save-hook 'ba/org-adjust-tags-column-after-save)
  (add-hook 'org-agenda-mode-hook (lambda ()
                                    (setq org-agenda-tags-column (- (window-width)))))

  ;; between invoking org-refile and displaying the prompt (which
  ;; triggers window-configuration-change-hook) tags might adjust,
  ;; which invalidates the org-refile cache
  (defadvice org-refile (around org-refile-disable-adjust-tags)
    "Disable dynamically adjusting tags"
    (let ((ba/org-adjust-tags-column nil))
      ad-do-it))
  (ad-activate 'org-refile))

Division de ventanas y movimiento inmediato del cursor a la nueva ventana

Combinaciones de teclas que no pertenecen a ningún paquete en particular.

(defun shackra-split-window-vertically ()
  "Divide la ventana por la mitad verticalmente y mueve el cursor a la ventana nueva"
  (interactive)
  (split-window-vertically)
  (other-window 1))

(defun shackra-split-window-horizontally ()
  "Divide la ventana por la mitad horizontalmente y mueve el cursor a la ventana nueva"
  (interactive)
  (split-window-horizontally)
  (other-window 1))

(global-set-key [remap split-window-below] #'shackra-split-window-vertically)
(global-set-key [remap split-window-right] #'shackra-split-window-horizontally)

Filtro de temas de mi cuaderno de apuntes técnicos

(defvar shackra-technotes-search-engine-url "https://duckduckgo.com/?q="
  "Motor de busqueda para encontrar coincidencias sobre determinada frase")

(defvar shackra-technotes-notebook "~/org/apuntes tecnicos.org"
  "Documento org-mode donde tengo apuntes de ingeniería")

(defun shackra--kill-this-buffer ()
  "Mata el buffer actual y borra la ventana"
  (interactive)
  (kill-this-buffer)
  (delete-window))

(defun shackra--technotes-action (entry)
  "Abre un enlace en `entry' apropiadamente"
  (progn
    (org-open-link-from-string (get-text-property 0 'property entry))
    (with-current-buffer (file-name-nondirectory shackra-technotes-notebook)
      (org-narrow-to-element)
      (org-cycle)
      ;; Cierra el buffer de `shackra-technotes-notebook'
      (use-local-map (copy-keymap org-mode-map))
      (local-set-key "q" 'shackra--kill-this-buffer)
      (read-only-mode))))

(defun shackra--technotes-source (string &optional predicate flag)
  (let ((collection))
    (with-current-buffer (find-file-noselect shackra-technotes-notebook)
      (goto-char (point-min))
      ;; Se dirige al primer encabezado
      (goto-char (re-search-forward "^*"))
      (set-mark (line-beginning-position))
      (goto-char (point-max))
      (setf collection
            (org-map-entries
             (lambda ()
               (let ((entry '())
                     (link (org-store-link 0))
                     (tags (map 'list (lambda (x) (concat "#" x)) (split-string (or (nth 5 (org-heading-components)) "") ":" t " "))))
                 (setf entry `(,(concat (nth 4 (org-heading-components)) " " (string-join tags " ")) . ,link))
                 (deactivate-mark)
                 entry)))))
    (setf collection (cl-remove-if-not (lambda (element) (string-match-p (counsel-unquote-regex-parens (ivy--regex-ignore-order string)) (car element))) collection))
    (add-to-list 'collection `(,(concat "Buscar en la web: " string) . ,(concat shackra-technotes-search-engine-url (url-encode-url string))) t)
    (cl-map 'list (lambda (elemt) (propertize (car elemt) 'property (cdr elemt))) collection)))

(defun shackra-technotes ()
  "Consulta una entrada de mis apuntes técnicos"
  (interactive)
  (ivy-read "Consultar> " #'shackra--technotes-source :action 'shackra--technotes-action :require-match t :dynamic-collection t :caller 'shackra-technotes))

(global-set-key (kbd "C-c T") #'shackra-technotes)

Nivel de sangrado para desarrollo web

Varios modos mayores que uso para desarrollo web tienen para personalizar el nivel de sangrado. Para todos quiero usar el mismo nivel de sangrado pero también quiero cambiarlo cuando así lo desee sin tener que rastrear las varias en la configuración.

(defvar shackra-webdev-indent 2 "Nivel de sangrado para desarrollo web")

Matar buffers de forma inmediata

(define-key global-map [remap kill-buffer] 'kill-this-buffer)

Desactivar lsp-mode cuando se activa múltiples cursores

He notado un grave descenso de la responsividad de Emacs cuando estoy usando iedit-mode o multiple-cursors mientras lsp-mode esta activo. Aparentemente el problema radica en lsp-on-change ejecutandose en cada cambio hecho al buffer a traves del gancho after-change-functions, esta función hace solicitudes a un servidor RPC lo cual por alguna razón congela Emacs.

La mejor solución seria quitar la función de los ganchos temporalmente.

(defvar-local shackra--lsp-on-change-exist nil
  "indica si la función `lsp-on-change' estaba insertada en `after-change-functions'")

(defun shackra-lsp-on-change-modify-hook ()
  "Remueve o agrega `lsp-on-change' de `after-change-functions'"
  (if (not shackra--lsp-on-change-exist)
      ;; quita la función, solamente si estaba insertada desde un principio
      (when (memq 'lsp-on-change after-change-functions)
        (setf shackra--lsp-on-change-exist t)
        (remove-hook 'after-change-functions 'lsp-on-change t))
    ;; agrega la función
    (add-hook 'after-change-functions #'lsp-on-change nil t)
    (setf shackra--lsp-on-change-exist nil)))

Macros

(fset 'untangle-use-packages
      [?\C-s ?\( delete ?u ?s ?e ?- ?p ?a ?c ?k ?a ?g ?e prior return ?\C-\M-b ?\C-  ?\C-\M-f ?\C-\M-f ?\M-x ?c ?o ?p ?y ?  ?t ?o return ?p ?\C-s ?\( delete ?u ?s ?e ?- ?p ?a ?c ?k ?a ?g ?e next up return ?\C-f ?\C-  ?\C-\M-f ?\M-x ?c ?o ?p ?y ?  return ?n ?\C-s ?\( delete ?u ?s ?e ?- ?p ?a ?c ?k ?a ?g ?e next return ?\C-\M-b ?\C-b ?\C-c ?0 ?\C-w ?\M-x ?b ?e ?g down down down down return return ?\M-x ?b ?e down down down down return ?\C-y ?\C-s ?\( delete ?u ?s ?e ?- ?p ?a ?c ?k ?a ?g ?e prior return ?\C-\M-f return ?: ?a ?f ?t ?e ?r ?  ?\( ?\M-x ?i ?n ?s ?e ?r ?t down down down return ?n ?\C-s ?\M-x ?i ?n ?s ?e ?r ?t ?  ?r ?e ?g return ?p return])

Custom.el

El archivo customize es completamente innecesario y todas las variables modificadas usando Customize fueron migradas. Cualquier cambio que se haga con Customize no será preservado pase lo que pase.

(setf custom-file null-device)

Aliases

Nombres más cortos para comandos usados frecuentemente

(defalias 'eb 'eval-buffer)
(defalias 'er 'eval-region)
(defalias 'ed 'eval-defun)

Paquetes de extensiones

Utilidades

noflet

Nos permite sobreescribir localmente funciones al estilo de flet, pero con acceso a la función original a través del símbolo this-fn.

(use-package noflet)

TRAMP

Transparent Remote Access, Multiple Protocols: paquete para editar archivos remotos. Manual de usuario.

(setf tramp-default-method "ssh")
(setf tramp-encoding-shell "/bin/zsh")

Bug hunter para configuración de Emacs

(use-package bug-hunter)

better-defaults

configuración sana de ciertas opciones en Emacs

(use-package better-defaults
  :init
  (defun my-minibuffer-setup-hook ()
    (setq gc-cons-threshold most-positive-fixnum))
  (defun my-minibuffer-exit-hook ()
    (setq gc-cons-threshold 800000))
  :config
  ;; Se cargan otras modificaciones para mejorar el comportamiento de Emacs
  (load-file (expand-file-name "sane.el" user-emacs-directory))
  (ido-mode nil)
  ;; Cursor
  (setq-default cursor-type 'box)
  (setf blink-cursor-blinks 0)
  (blink-cursor-mode)
  (setf blink-cursor-interval 0.1)
  ;; Evita que el recolector de basura entre en funcionamiento cuando se esta
  ;; dentro del minibuffer
  (add-hook 'minibuffer-setup-hook #'my-minibuffer-setup-hook)
  (add-hook 'minibuffer-exit-hook #'my-minibuffer-exit-hook))

Tipografía

Función que comprueba disponibilidad de tipografías en el sistema, además de establecer la tipografía.

(defun font-exists-p (font)
  "Comprueba si una tipografía existe. Sacado de https://redd.it/1xe7vr"
  (if (member font (font-family-list))
      t
    nil))

(add-to-list 'default-frame-alist '(font . "Fira Code-11"))
(add-to-list 'initial-frame-alist '(font . "Fira Code-11"))

;; Para NS/Cocoa
(when (eq system-type 'darwin)
  (set-fontset-font t 'unicode (font-spec :family "Apple Color Emoji") nil 'prepend))
;; Para todos los demas sistemas operativos
(when (not (eq system-type 'darwin))
  (set-fontset-font t 'unicode (font-spec :size 20 :name "Symbola") nil 'prepend))

View large files

Permite a Emacs manejar archivos enormes. Automáticamente se activa para archivos mayores a large-file-warning-threshold.

(use-package vlf-setup
  :ensure vlf
  :init
  (setf vlf-application 'dont-ask))

secreto

Saca cualquier rastro de tus archivos y datos privados de tu configuración de Emacs

(use-package secreto
  :ensure nil
  :load-path "site-packages/secreto.el/"
  :config
  (load-secretos))

secretaria

Mi intento de hacer algo mejor que =appt-mode=.

(use-package secretaria
  :init
  (setf secretaria-clocked-task-save-file "~/.secretaria-tarea")
  (add-hook 'after-init-hook #'secretaria-unknown-time-always-remind-me))

font-man

Escala la altura de la tipografía en todos los buffers de manera temporal

(use-package switch-buffer-functions
  :commands (switch-buffer-functions-run))
(use-package font-man
  :commands (font-man-mode)
  :after (switch-buffer-functions)
  :ensure nil
  :load-path "site-packages/font-man")

swiper & ivy

  • Refiled on [2015-11-12 jue 16:46]
Reemplazo para I-search, Swiper es el nombre en inglés de Zorro, un personaje de la serie Dora la exploradora.

Teclas

@@html:<kbd>C-s</kbd>@@
Buscar en buffer, reemplazando a isearch-forward
@@html:<kbd>C-r</kbd>@@
Buscar en buffer, reemplazando a isearch-backward
@@html:<kbd>C-c C-r</kbd>@@
Continua la ultima sesión de completado
@@html:<kbd>M-x</kbd>@@
Fragmentos de texto matados para pegar
@@html:<kbd>C-h f</kbd>@@
Describe funciones
@@html:<kbd>C-h v</kbd>@@
Describe variables
@@html:<kbd>C-h b</kbd>@@
Describe atajos de teclado disponibles
@@html:<kbd>C-x 8 RET</kbd>@@
Lista e inserta caracteres Unicode
@@html:<kbd>C-x f</kbd>@@
Lista archivos visitados recientemente
@@html:<kbd>C-x C-f</kbd>@@
Visita un archivo
@@html:<kbd>C-x b</kbd>@@
Cambia de buffer
(with-eval-after-load 'projectile
  (use-package counsel-projectile
    :commands (counsel-projectile counsel-projectile-switch-project counsel-projectile-switch-to-buffer)
    :after (counsel)))
(use-package counsel
  :after (ivy)
  :commands (counsel-org-tag dired)
  :bind (:map global-map
              ("M-x" . counsel-M-x)
              ("M-y" . counsel-yank-pop)
              :map help-map
              ("f" . counsel-describe-function)
              ("v" . counsel-describe-variable)
              ("b" . counsel-descbinds)
              :map ctl-x-map
              ("8 RET" . counsel-unicode-char)
              ("l" . counsel-locate)
              ("f" . counsel-recentf))
  :init
  (setf ivy-use-virtual-buffers nil)
  :config
  (with-eval-after-load 'org
    (global-set-key [remap org-set-tags-command] #'counsel-org-tag)))

(use-package ivy-hydra
  :after (counsel-projectile))

(use-package ivy
  :bind (:map global-map
              ("C-c C-r" . ivy-resume)
              :map ctl-x-map
              ("b" . ivy-switch-buffer))
  :init
  (setf ivy-count-format "(%d/%d) ")
  (setf ivy-height 15)
  :config
  (add-to-list 'ivy-ignore-buffers "\\*weechat-relay")
  (add-to-list 'ivy-ignore-buffers "\\*Messages\\*")
  (add-to-list 'ivy-ignore-buffers "\\*elfeed-log\\*")
  (add-to-list 'ivy-ignore-buffers "\\*Help\\*")
  (add-to-list 'ivy-ignore-buffers "\\*Compile-Log\\*")
  (add-to-list 'ivy-ignore-buffers "\\*anaconda-mode\\*")
  (add-to-list 'ivy-ignore-buffers "\\*prodigy-.*")
  (add-to-list 'ivy-ignore-buffers "\\*godoc .*")
  (add-to-list 'ivy-ignore-buffers "\\*magit-.*")
  (add-to-list 'ivy-ignore-buffers "\\magit-.*")
  (add-to-list 'ivy-ignore-buffers "\\*Slack Log.*")
  (add-to-list 'ivy-ignore-buffers "\\*tide")
  (add-to-list 'ivy-ignore-buffers "\\*Flycheck.*")
  (add-to-list 'ivy-ignore-buffers "\\*lsp-.*")
  (with-eval-after-load "projectile"
    (setf projectile-globally-ignored-buffers ivy-ignore-buffers)))
(ivy-mode 1)

(use-package swiper
  :bind (:map global-map
              ("C-s" . swiper)
              ("C-r" . swiper)))

hydra

  • Refiled on [2015-11-12 jue 16:45]
Cut off one head, Two more shall take its place. Hail HYDRA!―miembro HYDRA.

Permite tratar combinaciones de teclas como grupos… es algo difícil de explicar, puede ver este vídeo Switching Emacs windows with hydra and ace-window - YouTube para entender de qué trata este paquete.

(use-package ace-window
  :bind ("M-o" . shackra-other-window)
  :init
  (defun --count-frames ()
    "Retorna el numero de frames visibles"
    (let* ((frames (if (daemonp) (butlast (visible-frame-list) 1) (visible-frame-list))))
      (length frames)))
  :config
  (defface aw-leading-char-face '(:inherit ace-jump-face-foreground :height 2.0) "ace-jump leading character size")
  (setf aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
  (define-key global-map [remap other-window] 'ace-window))
(use-package windmove
  :ensure nil)
(use-package winner
  :ensure nil
  :config
  (winner-mode 1))
(use-package windresize)
(use-package ace-window)

(with-eval-after-load 'windmove
  (with-eval-after-load 'winner
    (with-eval-after-load 'windresize
      (with-eval-after-load 'ace-window
        (use-package hydra
          :after (ace-window)
          :preface
          (require 'hydra-examples)
          :init
          (defun shackra-python-indent-inclusive ()
            "Mueve el inicio de la región una linea por encima de `region-beginning'

Actualmente esta función no funciona como se espera"
            (interactive)
            (save-excursion
              (let ((begin (region-beginning))
                    (end (region-end)))
                (when (use-region-p)
                  (goto-char begin)
                  (forward-line -1)
                  (push-mark end)
                  (setq mark-active t)))))
          :config
          (defhydra hydra-py (:color red :pre (flycheck-mode -1) :post (progn (deactivate-mark) (flycheck-mode 1)))
            "Sangrado de bloques"
            ("," python-indent-shift-left "← Disminuir")
            ("." python-indent-shift-right "→ Aumentar"))
          (defhydra hydra-zoom (global-map "<f2>")
            "Acercamiento"
            ("f" text-scale-increase "in")
            ("j" text-scale-decrease "out"))
          (defhydra hydra-avy (:color blue :columns 2)
            "avy jump"
            ("z" avy-goto-line "Ir a la linea...")
            ("x" avy-goto-word-1 "Ir a la palabra...")
            ("c" avy-goto-char-in-line "Ir a la letra en la linea actual...")
            ("v" avy-goto-char "Ir a la palabra (2)..."))
          (bind-key "C-z" 'hydra-avy/body)
          ;; Hydra nos permite hacer magia con la administración de ventanas dentro de
          ;; un marco de Emacs. Varios paquetes estan especificados en el `:preface'
          ;; del macro para hydra
          (defhydra hydra-win (:columns 2 :color amaranth)
            "Manejo de ventanas"
            ("<up>" windmove-up "Cursor ↑")
            ("<left>" windmove-left "Cursor ←")
            ("<down>" windmove-down "Cursor ↓")
            ("<right>" windmove-right "Cursor →")
            ("C-<up>" hydra-move-splitter-up "Astilla ↑")
            ("C-<left>" hydra-move-splitter-left "Astilla ←")
            ("C-<down>" hydra-move-splitter-down "Astilla ↓")
            ("C-<right>" hydra-move-splitter-right "Astilla →")
            ("b" shackra-switch-buffer "Cambiar buffer")
            ("f" shackra-find-file "Visitar/Crear archivo")
            ("z" (lambda () (interactive) (ace-window 1) (add-hook 'ace-window-end-once-hook 'hydra-win/body)) "Mover cursor a otra ventana")
            ("2" (lambda () (interactive) (split-window-right) (windmove-right)) "Dividir |")
            ("3" (lambda () (interactive) (split-window-below) (windmove-down)) "Dividir -")
            ("c" (lambda () (interactive) (ace-window 4) (add-hook 'ace-window-end-once-hook 'hydra-win/body)) "Intercambiar buffer de ventana")
            ("s" save-buffer "Guardar buffer")
            ("x" delete-window "Borrar ventana")
            ("X" (lambda () (interactive) (ace-window 16) (add-hook 'ace-window-end-once-hook 'hydra-win/body)) "Borrar esta/otra ventana")
            ("1" ace-maximize-window "Maximizar esta ventana")
            ("," (progn (winner-undo) (setf this-command 'winner-undo)) "Deshacer ultimo cambio")
            ("." winner-redo "Rehacer ultimo cambio")
            ("SPC" nil "Salir"))
          (bind-key "M-1" #'hydra-win/body))))))

dired

  • Refiled on [2015-11-12 jue 16:45]
Manejador de archivos de serie para Emacs.

Algunas mejoras fueron sacadas de Dired as Default File Manager - Introduction.

(use-package ranger
  :init
  (setf ranger-cleanup-eagerly t))
(use-package dired+
  :ensure nil
  :load-path "site-packages/dired+/"
  :config
  (diredp-toggle-find-file-reuse-dir 1))
;; -*- lexical-binding: t -*-
(use-package dired
  :ensure nil
  :bind (:map dired-mode-map
              ("[" . multi-term)
              ("," . dired-omit-mode)
              ("e" . ora-ediff-files)
              ("c" . dired-do-compress-to) ;; Necesita Emacs 25.x
              )
  :init
  (setq-default dired-omit-mode t)
  (setq-default dired-omit-files "^\\.?#\\|^\\.$\\|^\\.")
  (setq-default dired-omit-verbose nil)
  (setf dired-dwim-target t)
  (defun shackra-dired-no-esconder-detalles ()
    "No esconder los detalles de los archivos en dired, se ven muy bien"
    (dired-hide-details-mode 0))
  (defun dired-sort-group-dirs ()
    "Sort dired listings with directories first."
    (save-excursion
      (let (buffer-read-only)
        (forward-line 2) ;; beyond dir. header
        (sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max)))
      (set-buffer-modified-p nil)))
  ;; extraído de https://oremacs.com/2017/03/18/dired-ediff/
  (defun ora-ediff-files ()
    (interactive)
    (let ((files (dired-get-marked-files))
          (wnd (current-window-configuration)))
      (if (<= (length files) 2)
          (let ((file1 (car files))
                (file2 (if (cdr files)
                           (cadr files)
                         (read-file-name
                          "Archivo: "
                          (dired-dwim-target-directory)))))
            (if (file-newer-than-file-p file1 file2)
                (ediff-files file2 file1)
              (ediff-files file1 file2))
            (add-hook 'ediff-after-quit-hook-internal
                      (lambda ()
                        (setq ediff-after-quit-hook-internal nil)
                        (set-window-configuration wnd))))
        (error "Más de 2 archivos no deberían ser marcados"))))
  (with-eval-after-load 'dired-aux
    ;; registra 7zip para compresión de archivos.
    (add-to-list 'dired-compress-files-alist '("\\tar\\.7z\\'" . "tar cf - %i | 7z a -si -m0=lzma2 -mx=3 %o.tar.7z")))
  :config
  (add-hook 'dired-mode-hook 'shackra-dired-no-esconder-detalles)
  (defadvice dired-readin
      (after dired-after-updating-hook first () activate)
    "Sort dired listings with directories first before adding marks."
    (dired-sort-group-dirs)))

keyfreq

  • Refiled on [2015-11-12 jue 16:45]
Registra la frecuencia con la que se usan ciertas teclas en Emacs. Esta información se puede utilizar para saber a qué comandos dar combinaciones de teclas más fáciles de presionar.
(use-package keyfreq
  :if (daemonp)
  :config
  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1))

¿Cómo procesar la información estadística obtenida por éste paquete?

Primero se ejecuta el comando command-frequency-display el cual popula un buffer con los datos, el contenido de ese buffer debe ser guardado en un archivo. Luego se usa un script de Python que procesara ese archivo, saneara los datos y creara un archivo HTML el cual contendrá el reporte.

undo-tree

  • Refiled on [2015-11-12 jue 16:45]
Comando asociado a @@html:<kbd>C-x u</kbd>@@.

Reemplaza el mecanismo de deshacer/hacer de Emacs con un sistema que trata los cambios realizados como un árbol con ramificaciones.

(use-package undo-tree
  ;; Reemplaza el mecanismo de deshacer/hacer de Emacs con un sistema que trata
  ;; los cambios realizados como un árbol con ramificaciones de cambios.
  ;; para revertir un cambio use `C-x u'. Más información en:
  ;;   http://melpa.milkbox.net/#/undo-tree
  :demand t
  :diminish undo-tree-mode
  :bind (:map
         undo-tree-visualizer-mode-map ("RET" . undo-tree-visualizer-quit)
         :map
         global-map ("C-x u" . undo-tree-visualizer))
  :init
  (defadvice undo-tree-make-history-save-file-name
      (after undo-tree activate)
    (setq ad-return-value (concat ad-return-value ".7z")))
  (defadvice undo-tree-visualize (around undo-tree-split-side-by-side activate)
    "Divide la ventana de lado a lado al visualizar undo-tree-visualize"
    (let ((split-height-threshold nil)
          (split-width-threshold 0))
      ad-do-it))
  (setf undo-tree-visualizer-timestamps t)
  (setf undo-tree-visualizer-diff t)
  (setf undo-tree-auto-save-history nil) ;; no salva el historial de cambios
  :config
  (defalias 'redo 'undo-tree-redo)
  (global-undo-tree-mode 1))

numero de lineas

Muestra el numero de lineas al margen del buffer.

(when (not (version< emacs-version "26"))
  (setf display-line-numbers-type 'relative)
  (defun shackra--display-line-numbers-better-width ()
    (setf display-line-numbers-width (number-to-string
                                      (ceiling (log (max 1 (/ (buffer-size) 80)) 10)))))
  (add-hook 'display-line-numbers-mode-hook #'shackra--display-line-numbers-better-width)
  (add-hook 'prog-mode-hook 'display-line-numbers-mode))

company

  • Refiled on [2015-11-12 jue 16:50]
Un mejor motor de autocompletado comparado con auto-complete/auto-complete.
(use-package company
  :diminish company-mode
  :init
  (setf company-backends '((company-files
                            company-keywords
                            company-capf
                            company-yasnippet)
                           (company-abbrev company-dabbrev)))
  (setf company-idle-delay 0.5)
  (setf company-tooltip-limit 10)
  (setf company-minimum-prefix-length 2)
  (setq company-dabbrev-downcase 0)
  (setf company-auto-complete nil)
  (add-hook 'after-init-hook #'global-company-mode))

company-posframe permite a company usar child-frame como menu de candidatos

(when (not (version< emacs-version "26.0"))
(use-package company-posframe
  :config
  (company-posframe-mode 1)))

company-statistics ofrece mejores predicciones en sus resultados de acuerdo a datos estadísticos.

(use-package company-statistics
  :after (company)
  :init
  (setf company-statistics-file "~/.company-statistics-cache.el")
  (add-hook 'after-init-hook 'company-statistics-mode))

company-auctex

backend para Company que provee auto completado para AUCTeX

(with-eval-after-load 'tex-site
  (use-package company-auctex
    :after (company)
    :config
    (company-auctex-init)))

projectile

  • Refiled on [2015-11-12 jue 16:50]
Manejo de archivos de un proyecto.
(use-package projectile
  :diminish projectile-mode
  :init
  (setf projectile-completion-system 'ivy
        projectile-switch-project-action 'counsel-projectile-find-file)
  (setf
   projectile-file-exists-remote-cache-expire (* 10 60)
   projectile-globally-ignored-files '("TAGS" "\#*\#" "*~" "*.la"
                                       "*.o" "*.pyc" "*.elc" "*.exe"
                                       "*.zip" "*.tar.*" "*.rar" "*.7z"))
  :config
  (add-to-list 'projectile-globally-ignored-directories "node_modules")
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
  (add-hook 'text-mode-hook #'projectile-mode)
  (add-hook 'prog-mode-hook #'projectile-mode))

(use-package ag)

recentf

  • Refiled on [2015-11-12 jue 16:51]
Archivos recientes abiertos en Emacs.
(use-package recentf
  :ensure nil
  :init
  (setf recentf-max-saved-items 100)
  :config
  (add-to-list 'recentf-exclude ".git/")
  (add-to-list 'recentf-exclude ".hg/")
  (add-to-list 'recentf-exclude "elpa/")
  (add-to-list 'recentf-exclude "\\.emacs.d/org-clock-save.el\\'")
  (add-to-list 'recentf-exclude "INBOX/"))

expand-region

  • Refiled on [2015-11-12 jue 16:51]
Incrementa la selección por unidades semánticas. Asociado a @@html:<kbd>C-c 0</kbd>@@
(use-package expand-region
  :bind ("C-c 0" . er/expand-region))

avy-jump

  • Refiled on [2015-11-12 jue 16:51]
El cursor salta en cualquier parte del buffer según un árbol de decisiones basado en caracteres. Asociado a @@html:<kbd>C-c z</kbd>@@
(use-package avy
  :defer 3
  :config
  (bind-keys :prefix-map shackra-avy-mode-map
             :prefix "C-c z"
             ("z" . avy-goto-line)
             ("x" . avy-goto-word-1)
             ("c" . avy-goto-char-in-line)
             ("v" . avy-goto-char)))

multi-term

  • Refiled on [2015-11-12 jue 16:51]
Ofrece un excelente emulador de terminal dentro de Emacs. Asociado a @@html:<kbd><f1></kbd>@@
(use-package counsel-term
  :after (counsel)
  :ensure nil
  :load-path "site-packages/counsel-term"
  :bind (:map term-mode-map
              ("C-." . counsel-term-cd)))

(use-package multi-term
  :bind ([f1] . multi-term)
  :init
  (defun shackra-maybe-disable-yasnippet ()
    "Desactiva yasnippet a pedido"
    (if (fboundp 'yas-minor-mode)
        (yas-minor-mode -1)))
  (defun shackra-term-line-or-char-mode ()
    "Cambia entre `term-line-mode' y `term-char-mode'"
    (interactive)
    (when (derived-mode-p 'term-mode)
      (if (term-in-char-mode)
          (term-line-mode)
        (term-char-mode))))
  :config
  (setf multi-term-buffer-name "term-"
        multi-term-program "/usr/bin/zsh"
        multi-term-program-switches "--login")
  (add-to-list 'term-bind-key-alist '("C-c C-c"   . term-interrupt-subjob))
  (add-to-list 'term-bind-key-alist '("C-p"       . previous-line))
  (add-to-list 'term-bind-key-alist '("C-n"       . next-line))
  (add-to-list 'term-bind-key-alist '("M-f"       . term-send-forward-word))
  (add-to-list 'term-bind-key-alist '("M-b"       . term-send-backward-word))
  (add-to-list 'term-bind-key-alist '("C-,"       . shackra-term-line-or-char-mode))
  (add-to-list 'term-bind-key-alist '("C-DEL"     . term-send-backward-kill-word))
  (add-to-list 'term-bind-key-alist '("M-d"       . term-send-forward-kill-word))
  (add-to-list 'term-bind-key-alist '("<C-left>"  . term-send-backward-word))
  (add-to-list 'term-bind-key-alist '("<C-right>" . term-send-forward-word))
  (add-to-list 'term-bind-key-alist '("C-r"       . term-send-reverse-search-history))
  (add-to-list 'term-bind-key-alist '("M-p"       . term-send-raw-meta))
  (add-to-list 'term-bind-key-alist '("M-y"       . term-send-raw-meta))
  (add-to-list 'term-bind-key-alist '("C-y"       . term-paste))

  (add-hook 'term-mode-hook #'shackra-maybe-disable-yasnippet)
  (add-hook 'term-mode-hook (lambda ()
                              (when (fboundp 'display-line-numbers-mode)
                                (display-line-numbers-mode -1))))
  (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on))

git

(use-package gitignore-mode)
(use-package gitconfig-mode)

magit

  • Refiled on [2015-11-12 jue 16:51]
Git en Emacs. A decir verdad, amo Mercurial y odio Git. Usar @@html:<kbd>C-c p v</kbd>@@ de projectile para invocarlo.
@@html:<kbd>C</kbd>@@
Genera fragmento de CHANGELOG en intervalo de commits seleccionados por una region.
(defun shackra-magit-commit-gitchangelog-region (begin end)
  "Crea un CHANGELOG a partir de un intervalo de commits seleccionados por region"
  (interactive "r")
  (when (use-region-p)
    (let* ((words (shackra-words-region-begin-end begin end))
           (body (shell-command-to-string (format "gitchangelog %s..%s" (cadr words) (car words))))
           (output-fmt "commonmark"))
      (kill-new (with-temp-buffer ;; copiado de pandoc.el
                  (insert body)
                  (apply 'call-process-region (point-min) (point-max) "pandoc" t t nil '("-f" "rst" "-t" output-fmt))
                  (buffer-substring-no-properties (point-min) (point-max))))
      (message "Salida de gitchangelog copiado al portapapeles"))))

(use-package magit-gh-pulls
  :after (magit)
  :config
  (add-hook 'magit-mode-hook 'turn-on-magit-gh-pulls))
(use-package magit
  :commands (magit-status)
  :bind (:map magit-mode-map
              ("C" . shackra-magit-commit-gitchangelog-region))
  :init
  (defcustom vc-state-update-commands '(other-window kill-buffer ace-window bury-buffer kill-or-bury-alive magit-mode-bury-buffer)
    "Cuando cada comando de esta lista es ejecutado, actualiza el estado VC del archivo actual"
    :type '(list (function :tag "Comandos de actualización")
                 (repeat :inline t (function :tag "Comandos de actualización"))))

  (defun vc-state-refresh-post-command-hook ()
    "Check if command in `this-command' was executed, then run `vc-refresh-state'"
    (when (memq this-command vc-state-update-commands)
      (vc-refresh-state)))
  (setf magit-last-seen-setup-instructions "1.4.0"
        magit-auto-revert-mode t
        magit-completing-read-function 'ivy-completing-read)
  (add-hook 'after-save-hook 'vc-refresh-state)
  (add-hook 'after-revert-hook 'vc-refresh-state)
  (add-hook 'post-command-hook #'vc-state-refresh-post-command-hook)
  (setf magit-commit-arguments nil)
  (setf magit-use-overlays nil))
(use-package magit-todos
  :config
  (add-hook 'magit-status-mode-hook 'magit-todos-mode))

git-gutter-fring

Muestra información de git diff en el fringe.

(use-package git-gutter-fringe
  :diminish git-gutter-mode
  :config
  (global-git-gutter-mode t))

monky

  • Refiled on [2015-11-12 jue 16:51]
Mercurial en Emacs. Amo Mercurial ;). Asociado a @@html:<kbd><C-f12></kbd>@@

Ver opciones más actualizadas para Mercurial en Best way to use Mercurial with Emacs? : emacs

(use-package monky
  :defer t
  :bind ([C-f12] . monky-status)
  :init
  (setf monky-process-type 'cmdserver))

(use-package hgignore-mode)

eldoc

Muestra en el área de eco la firma de la función actual.

(use-package eldoc
  :ensure nil
  :diminish eldoc-mode
  :init
  (setf eldoc-idle-delay 1.0)
  :config
  (with-eval-after-load 'paredit
    (eldoc-add-command
     'paredit-backward-delete
     'paredit-close-round)))

auto-revert-mode

Revierte el contenido de un buffer de manera automática cuando el contenido de un archivo a cambiado fuera de Emacs

(use-package autorevert
  :ensure nil
  :init
  (global-auto-revert-mode))

YASnippet

(use-package yasnippet
  :diminish yas-minor-mode
  :init
  (defun shackra-yas-reload ()
    "Recarga las definiciones de YaSnippet una vez"
    (yas-reload-all)
    (remove-hook 'after-init-hook 'shackra-yas-reload))
  :config
  (setq yas-snippet-dirs (append yas-snippet-dirs (list (expand-file-name "plantillas" user-emacs-directory))))
  (add-hook 'prog-mode-hook #'yas-minor-mode-on)
  (add-hook 'after-init-hook #'shackra-yas-reload))

(use-package auto-yasnippet
  :config
  (global-set-key (kbd "s-j") #'aya-create)
  (global-set-key (kbd "s-k") #'aya-expand))

imenu-anywhere

Crea menús a partir de secciones de documentos. Asociado a @@html:<kbd>C-c i</kbd>@@

(use-package imenu-anywhere
  :config
  (bind-key "C-c i" 'ivy-imenu-anywhere))
(use-package imenu+
  :disabled ;; ver razón en https://redd.it/3ahj2d
  :init
  (setf imenup-ignore-comments-flag t))

Bookmark+

Marcadores para varias cosas en Emacs, asociado a @@html:<kbd>M-p</kbd>@@

(use-package bookmark
  :ensure nil
  :init
  (setf bookmark-default-file "~/.emacs.d/bookmarks")
  (setf bookmark-save-flag 1))

(use-package bookmark+
  :ensure nil
  :load-path "site-packages/bookmark+/"
  :init
  (setf bmkp-auto-light-when-set 'all-in-buffer)
  (setf bmkp-last-as-first-bookmark-file bookmark-default-file)
  :config
  (defhydra hydra-bm (:color amaranth :hint nil)
    "
    Marcadores

    Cambiar                          Agregar           Editar
  ╭──────────────────────────────────────────────────────────────────────╯
   [_j_] Anterior (buffer actual)   [_f_] aquí...   [_e_] aquí...
   [_l_] Siguiente (buffer actual)  [_F_] archivo
   [_k_] Saltar a...
   [_K_] Saltar a... (por tipo)
   [_i_] Saltar a... (otra vent.)
  -----------------------------------------------------------------------
"
    ("j" bmkp-previous-bookmark-this-buffer)
    ("l" bmkp-next-bookmark-this-buffer)
    ("k" bmkp-jump-in-navlist :color blue)
    ("K" bmkp-jump-to-type :color blue)
    ("i" bmkp-jump-to-type-other-window :color blue)
    ("f" bmkp-bookmark-set-confirm-overwrite :color blue)
    ("F" bmkp-file-target-set :color blue)
    ("e" bmkp-edit-bookmark-name-and-location :color blue)
    ("L" bookmark-bmenu-list "Menú de marcadores" :color blue)
    ("l" bookmark-load "Cargar otro archivo de marcadores" :color blue)
    ("<ESC>" nil "Salir"))
  (bind-key (kbd "C-c b") 'hydra-bm/body global-map))

Firefox desde Emacs

(use-package moz-controller)

Chrome desde Emacs

(use-package kite-mini
  :disabled
  :after (simple-httpd)
  :init
  (defun shackra-webdev-refresh-page-on-save-chrome ()
    "Refresca la pagina en Chrome para ver los cambios realizados"
    (interactive)
    (let* ((currentfiledir (file-name-directory (buffer-file-name)))
           (inrootdir (string-suffix-p httpd-root currentfiledir)))
      (when (and (derived-mode-p 'sgml-mode 'css-mode 'web-mode) inrootdir)
        (kite-mini-reload))
      (when (and (derived-mode-p 'js-mode 'js2-mode) inrootdir)
        (kite-mini-update))))
  (add-hook 'js2-mode-hook (lambda () (kite-mini-mode t)))
  (add-hook 'css-mode-hook (lambda () (kite-mini-mode t)))
  (add-hook 'sgml-mode-hook (lambda () (kite-mini-mode t)))
  (add-hook 'after-save-hook #'shackra-webdev-refresh-page-on-save-chrome))

iedit

Edita varias ocurrencias de un texto en el buffer.

Teclas:

M-H
iedit-restrict-function
M-I
iedit-restrict-current-line
M-{
iedit-expand-up-a-line
M-}
iedit-expand-down-a-line
M-p
iedit-expand-up-to-occurrence
M-n
iedit-expand-down-to-occurrence
M-G
iedit-apply-global-modification
M-C
iedit-toggle-case-sensitive
(use-package iedit
  :bind (:map
         iedit-mode-keymap ("RET" . iedit-quit))
  :init
  (add-hook 'iedit-mode-hook #'shackra-lsp-on-change-modify-hook)
  (add-hook 'iedit-mode-end-hook #'shackra-lsp-on-change-modify-hook))

Language Server Protocol

Implementación para Emacs del Language Server Protocol.

(use-package lsp
  :ensure lsp-mode
  :config
  (require 'lsp-clients)
  (add-hook 'lsp-after-open-hook 'lsp-enable-imenu)
  :init
  (setf lsp-eldoc-render-all nil)
  (setq lsp-inhibit-message t)
  (setq lsp-message-project-root-warning t))

(use-package lsp-ui
  :after (lsp)
  :init
  (setf lsp-ui-sideline-enable nil)
  (setf lsp-ui-doc-enable nil)
  :config
  (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
  (define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references))

(use-package company-lsp
  :config
  (push 'company-lsp company-backends))

Comunicación

Correo electrónico

mu4e se usa para leer y enviar correo electrónico.

Este script descarga el correo y lo indexa, aquí asumimos que mbsync esta correctamente configurado.

#!/bin/sh

# sincroniza el correo
mbsync -a -V -c ~/.mbsyncrc.private
# Pide a mu hacer su trabajo de indexado
if pgrep -f 'mu server'; then
    emacsclient -e '(mu4e-update-index)'
else
    mu index --maildir=~/Mail
fi

Scripts ejecutables.

#!/bin/sh

chmod +x ~/.local/bin/getmail.sh

Para una configuración personalizada hay que cambiar user-mail-address y user-full-name ubicados en Información personal.

(use-package mu4e-alert
  :if (executable-find "mu")
  :init
  (add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
  (add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display)
  (setf mu4e-compose-forward-as-attachment t)
  (setf mu4e-compose-crypto-reply-encrypted-policy 'sign-and-encrypt)
  (setf mu4e-compose-crypto-reply-plain-policy 'sign)
  (setf mu4e-index-update-in-background nil) ;; goimapnotify hace esto por nosotros
  (setq mu4e-alert-email-notification-types '(subjects))
  :config
  (mu4e-alert-set-default-style 'libnotify))

(with-eval-after-load 'org
  (with-eval-after-load 'mu4e
    (use-package org-mu4e
      :ensure nil
      :init
      (setq org-mu4e-link-query-in-headers-mode nil))))

(use-package mu4e
  :commands (mu4e correo mu4e-compose-new mu4e-compose-edit mu4e-compose-resend mu4e-compose-reply)
  :ensure nil
  :preface
  ;;; message view action
  (defun mu4e-msgv-action-view-in-browser (msg)
    "Ver el cuerpo del mensaje HTML en el navegador web"
    (interactive)
    (let ((html (mu4e-msg-field (mu4e-message-at-point t) :body-html))
          (tmpfile (format "%s/%d.html" temporary-file-directory (random))))
      (unless html (error "No hay partes en HTML para este mensaje"))
      (with-temp-file tmpfile
        (insert
         "<html>"
         "<head><meta http-equiv=\"content-type\""
         "content=\"text/html;charset=UTF-8\">"
         html))
      (browse-url (concat "file://" tmpfile))))

  (defadvice mu4e (before mu4e-start activate)
    "Antes de ejecutar `mu4e' borramos todas las ventanas"
    (when (> 1 (count-windows))
      (window-configuration-to-register :mu4e-fullscreen)
      (delete-other-windows)))

  (defadvice mu4e-quit (after mu4e-close-and-push activate)
    "Despues de salir de mu4e ejecutamos un script para subir los cambios al buzon de correo y para también restaurar la disposición de ventanas"
    (start-process "pushmail" "*pushmail-mbsync*" "mbsync" "-a" "-V" "--push" "-c" "/home/jorge/.mbsyncrc.private")
    (when (get-register :mu4e-fullscreen)
      (jump-to-register :mu4e-fullscreen)))
  :init
  (setf mu4e-get-mail-command "getmail.sh")
  ;; html2text es un paquete que debe estar instalado en tu sistema
  (setf mu4e-html2text-command 'mu4e-shr2text)
  ;; hace mu4e el programa por defecto para escribir correo
  (setq mail-user-agent 'mu4e-user-agent)
  (setf mu4e-confirm-quit nil)
  (setf mu4e-context-policy 'pick-first)
  (setf mu4e-change-filenames-when-moving t)
  (setf mu4e-headers-date-format "%d/%m/%Y %H:%M")
  (setf message-citation-line-format "\nEl %A %d de %B del %Y a las %H%M horas, %N escribió:\n")
  (setf message-citation-line-function 'message-insert-formatted-citation-line)
  (setf message-cite-reply-position 'below)
  (setf mu4e-auto-retrieve-keys t)
  (setf mu4e-headers-leave-behavior 'apply)
  (setf mu4e-headers-visible-lines 8)
  (setf mu4e-hide-index-messages t)
  (setf message-kill-buffer-on-exit t)
  (setf mu4e-attachment-dir  "~/Descargas")
  (setf mu4e-maildir "~/Mail")
  (setf smtpmail-stream-type  'ssl)
  (setf smtpmail-smtp-service 465)
  (setf message-send-mail-function 'smtpmail-send-it)
  (setf mu4e-bookmarks
        '(("flag:unread" "No leido" ?u)
          ("flag:flagged" "Marcados como importantes" ?f)
          ("maildir:/personal/Drafts OR maildir:/personal/Borradores" "Borradores" ?b)))
  (setf smtpmail-smtp-server "mail.privateemail.com")
  (setf smtpmail-smtp-user user-mail-address)
  (setf mu4e-sent-folder "/personal/Sent")
  (setf mu4e-drafts-folder "/personal/Drafts")
  (setf mu4e-trash-folder "/personal/Trash")
  (setf mu4e-refile-folder "/personal/INBOX/Archive")
  (setf mu4e-compose-signature (concat
                                "👋 Pax et bonum.\n"
                                "Jorge Javier Araya Navarro\n"
                                "http://www.esavara.cr"))
  (setf mu4e-maildir-shortcuts '(("/personal/INBOX" . ?p)
                                 ("/personal/INBOX/Archive" . ?A)
                                 ("/personal/Trash" .?t)))
  :config
  (require 'mu4e-contrib)
  (defalias 'correo 'mu4e)
  (add-to-list 'mu4e-view-actions
               '("navegador web" . mu4e-msgv-action-view-in-browser) t)
  (bind-key "C-c c" 'org-mu4e-store-and-capture mu4e-headers-mode-map)
  (bind-key "C-c c" 'org-mu4e-store-and-capture mu4e-view-mode-map))

twittering-mode

  • Refiled on [2015-11-12 jue 16:53]
Twitter desde Emacs
(use-package twittering-mode
  :init
  (defalias 'tt 'twit)
  (setf twittering-use-master-password t)
  (setf twittering-display-remaining t)
  (setf twittering-icon-mode t)
  (setf twittering-timer-interval 300)
  (setf twittering-url-show-status nil)
  (setf twittering-connection-type-order '(wget native curl urllib-http urllib-https))
  :config
  (defun shackra-tt-fav-rett (&optional arg)
    "Marca como favorito y retweetea un tweet"
    (interactive "P")
    (my/bypass-confirmation-all #'twittering-retweet t)
    (my/bypass-confirmation-all #'twittering-favorite))
  (bind-key "C-c f" 'twittering-favorite twittering-mode-map)
  (bind-key "C-c F" 'shackra-tt-fav-rett twittering-mode-map)

  (add-hook 'twittering-edit-mode-hook #'ispell-minor-mode)
  (add-hook 'twittering-edit-mode-hook #'flyspell-mode))

sx

  • Refiled on [2015-11-12 jue 16:53]
Acceso a Stackoverflow y subsitios desde Emacs.
(use-package sx
  :defer 10)

org2web

  • Refiled on [2015-11-12 jue 16:57]
  • Refiled on [2015-11-12 jue 16:46]
Generador estático de sitios web que depende de Emacs, Git y Org-mode.
(with-eval-after-load 'el2org
  (with-eval-after-load 'ox-gfm
    (use-package org2web
      :config
      ;; Le pedimos a org-mode que no meta las patas cuando exporta archivos a
      ;; HTML. Nosotros manejaremos el marcado de sintaxis de código fuente.
      ;; Muchas gracias a Chen Bin[1] por los trozos de código[2] sacados de su
      ;; propio proyecto[3] :)
      ;;
      ;; [1]: http://emacs.stackexchange.com/users/202/chen-bin
      ;; [2]: http://emacs.stackexchange.com/a/9839/690
      ;; [3]: https://github.com/redguardtoo/org2nikola/blob/master/org2nikola.el
      (load-file (expand-file-name "srcprecode.el" user-emacs-directory))
      (org2web-add-project '("El blog de Shackra"
                             :repository-directory "~/Documentos/elblog.deshackra.com/"
                             :ignore-file-name-regexp "README"
                             :remote (rclone "rscf" "elblog.deshackra.com")
                             :site-domain "http://elblog.deshackra.com"
                             :site-main-title "El blog de Shackra"
                             :site-sub-title "No seas tan abierto de mente o tu cerebro se caerá"
                             :theme-root-directory (:eval (list (expand-file-name "org-page-themes" user-emacs-directory)))
                             :theme (shackra)
                             :source-browse-url ("Bitbucket" "https://bitbucket.org/shackra-blog")
                             :confound-email t
                             :default-category "blog"
                             :about ("Sobre mi" "/about")
                             :rss ("RSS" "/rss.xml")
                             :summary (("etiquetas" :tags))
                             :source-browse-url ("Bitbucket" "https://bitbucket.org/shackra-blog/")
                             :web-server-docroot "~/Documentos/deshackra.com/elblog.deshackra.com"
                             :web-server-port 5777))

      (with-eval-after-load 'ox
        '(progn
           (add-to-list 'org-export-filter-src-block-functions
                        'org2html-wrap-blocks-in-code))))))
(use-package el2org)
(use-package ox-gfm)

mediawiki

  • Refiled on [2015-11-12 jue 16:58]
  • Refiled on [2015-11-12 jue 16:53]
Interfaz para editar paginas en instancias de Mediawiki desde Emacs. Mediawiki.el - WikEmacs
(use-package mediawiki
  :disabled
  :init
  (setf mediawiki-site-alist '(("Wikipedia en español" "https://es.wikipedia.org/w/" "" "" "Portal:Iglesia_católica")
                               ("Wikipedia en Inglés" "https://en.wikipedia.org/w/" "" "" "Portal:Catholicism")
                               ("Parabola GNU/Linux-libre" "https://wiki.parabola.nu/" "" "" "User:Shackra")
                               ("Wikemacs" "http://wikemacs.org/" "" "" "User:Shackra")))
  (setf mediawiki-site-default "Wikemacs")
  :config
  (add-hook 'mediawiki-mode-hook '(lambda ()
                                    (turn-off-auto-fill)
                                    (visual-line-mode 1))))

Weechat

Conexión a Weechat desde Emacs

(when (executable-find "weechat")
  (use-package weechat
    :init
    (defun shackra-weechat-buffer-goodies ()
      "Activa y desactiva cosas"
      (when (fboundp 'linum-mode)
        (linum-mode -1))
      (when (fboundp 'display-line-numbers-mode)
        (display-line-numbers-mode -1))
      (visual-line-mode 1))
    (add-hook 'weechat-mode-hook #'shackra-weechat-buffer-goodies)
    (setf weechat-spelling-dictionaries '(("freenode\\." . "en")
                                          ("irc-hispano\\." . "es")
                                          ("afternet\\." . "en")))
    :config
    (load-library "weechat-spelling")
    (add-hook 'after-init-hook (lambda () (when (not (weechat-connected-p))
                                       (weechat-connect weechat-host-default weechat-port-default "xxx" 'plain))))))

Slack

(unless (boundp 'dbus-compiled-version)
  (setf dbus-compiled-version nil))
(use-package color)
(use-package slack
  :after color
  :init
  (setq slack-buffer-emojify t)
  (setq slack-prefer-current-team t)
  ;; Big QOL changes. took from
  ;; http://endlessparentheses.com/keep-your-slack-distractions-under-control-with-emacs.html
  (setq slack-completing-read-function
        #'ivy-completing-read)
  (setq slack-buffer-function #'switch-to-buffer)
  (setq slack-display-team-name nil)
  (setq slack-buffer-create-on-notify t)

  (with-eval-after-load 'tracking
    (define-key tracking-mode-map [f11]
      #'tracking-next-buffer))

  ;; Channels
  (setq slack-message-notification-title-format-function
        (lambda (_team room threadp)
          (concat (if threadp "Thread in #%s") room)))

  (defun endless/-cleanup-room-name (room-name)
    "Make group-chat names a bit more human-readable."
    (replace-regexp-in-string
     "--" " "
     (replace-regexp-in-string "#mpdm-" "" room-name)))

  ;; Private messages and group chats
  (setq
   slack-message-im-notification-title-format-function
   (lambda (_team room threadp)
     (concat (if threadp "Thread in %s")
             (endless/-cleanup-room-name room))))

  (defun endless/-author-at (pos)
    (replace-regexp-in-string
     (rx "\n" (* anything)) ""
     (or (get-text-property pos 'lui-raw-text) "")))

  (defun endless/-remove-slack-author ()
    "Remove author here if it's the same as above."
    (let ((author-here (endless/-author-at (point)))
          (author-above (endless/-author-at (1- (point)))))
      (when (and (looking-at-p (regexp-quote author-here))
                 (equal author-here author-above))
        (delete-region (1- (point))
                       (1+ (line-end-position))))))

  (defun endless/remove-slack-author-hook ()
    "For usage in `lui-pre-output-hook'."
    (when (derived-mode-p 'slack-mode)
      (save-excursion
        (goto-char (point-min))
        (save-restriction
          (widen)
          (endless/-remove-slack-author)))))

  (add-hook 'lui-pre-output-hook
            #'endless/remove-slack-author-hook)

  ;; Go to any channel with `C-x j'.
  (define-key ctl-x-map "j" #'slack-select-rooms)
  ;; Apaga la numeración de lineas en un buffer de slack
  (add-hook 'slack-mode-hook (lambda () (display-line-numbers-mode -1)))
  (add-hook 'slack-mode-hook 'flyspell-mode)
  (add-hook 'slack-mode-hook #'emojify-mode)
  :config
  ;; Quick 'n dirty way of opening the most recent link
  ;; in the current chat room.
  (define-key slack-mode-map (kbd "M-o")
    (kbd "<backtab> RET M->"))
  ;; I thumbs-up a lot. Don't judge me.
  (define-key slack-mode-map (kbd "C-;") ":+1:")
  (define-key slack-mode-map (kbd "C-:") ":thinking:")
  ;; Bring up the mentions menu with `@', and insert a
  ;; space afterwards.
  (define-key slack-mode-map "@"
    (defun endless/slack-message-embed-mention ()
      (interactive)
      (call-interactively #'slack-message-embed-mention)
      (insert " ")))

  ;; Pretty straightforward.
  (define-key slack-mode-map (kbd "C-c C-d")
    #'slack-message-delete)
  (define-key slack-mode-map (kbd "C-c C-e")
    #'slack-message-edit)
  (define-key slack-mode-map (kbd "C-c C-k")
    #'slack-channel-leave)
  (define-key slack-mode-map (kbd "C-c C-t")
    #'slack-thread-select))

Redmine

(with-eval-after-load 'auth-source
  (setf auth-source-save-behavior nil))
(when (boundp 'auth-sources)
  (use-package org-redmine
    :init
    (setq org-redmine-auth-netrc-use t)))

Desarrollo de software

Desarrollo de paquetes para Emacs

Set de paquetes que me ayudan a escribir paquetes para GNU Emacs

(use-package cask
  :ensure nil)

(use-package cask-mode)

(use-package flycheck-cask
  :after (flycheck-mode))

org-babel

(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (python . t)
   (shell . t)
   (go . t)))

prog-mode

Cualquier modo mayor que herede de prog-mode sera afectado por esta configuración.

(use-package highlight-numbers)
(use-package highlight-escape-sequences
  :config
  (put 'hes-escape-backslash-face 'face-alias 'font-lock-builtin-face)
  (put 'hes-escape-sequence-face 'face-alias 'font-lock-builtin-face))
(use-package rainbow-mode)
(use-package prog-mode
  :ensure nil
  :init
  (defun shackra-prog-mode ()
    (set (make-local-variable 'fill-column) 79)
    (set (make-local-variable 'comment-auto-fill-only-comments) t)
    ;; Nota: M-q rellena las columnas del párrafo actual
    ;;       M-o M-s centra una linea de texto
    (auto-fill-mode t)
    (highlight-numbers-mode)
    (hes-mode)
    (electric-pair-mode)
    (rainbow-turn-on)
    (when (or (executable-find "ispell") (executable-find "hunspell"))
      (flyspell-prog-mode))
    (prettify-symbols-mode))
  (bind-key* "C-M-," 'comment-dwim)
  (add-hook 'prog-mode-hook #'shackra-prog-mode))

org-mode

El modo Org (Org-mode) es un modo de edición del editor de texto Emacs mediante el cual se editan documentos jerárquicos en texto plano.

Su uso encaja con distintas necesidades, como la creación de notas de cosas por hacer, la planificación de proyectos y hasta la escritura de páginas web. Por ejemplo, los elementos to-do (cosas por hacer) pueden disponer de prioridades y fechas de vencimiento, pueden estar subdivididos en subtareas o en listas de verificación, y pueden etiquetarse o dársele propiedades. También puede generarse automáticamente una agenda de las entradas de cosas por hacer. ~org-mode - Wikipedia, la enciclopedia libre

Teclas

@@html:<kbd>C-c l</kbd>@@
Guardar enlace a cosa
@@html:<kbd>C-c a</kbd>@@
Abre la agenda
@@html:<kbd>C-c c</kbd>@@
Capturar algo
(use-package org-beautify-theme
  :disabled
  :after org)

(use-package org-bullets
  :after org
  :init (add-hook 'org-mode-hook 'org-bullets-mode))

(use-package org-download
  :init
  (setq-default org-download-image-dir "~/org/imagenes/"))

(use-package org
  :ensure org-plus-contrib ;; Funciona solo si el ELPA de Org-mode esta registrado
  :bind (:map global-map
              ("C-c a" . org-agenda)
              ("<F12>" . org-agenda)
              ("C-c l" . org-store-link)
              ("C-c c" . org-capture)
              :map org-mode-map
              ("C-<F12>" . shackra-time-at-point-to-hours))
  :init
  (setf org-directory (expand-file-name "org" (getenv "HOME")))
  (setf org-default-notes-file (expand-file-name  "diario.org" org-directory))
  (setf org-agenda-files `(,(expand-file-name "cosas por hacer.org" org-directory)))
  (add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:"))
  (add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" . "#\\+END_SRC"))
  (add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_EXAMPLE" . "#\\+END_EXAMPLE"))
  ;; Exclude DONE state tasks from refile targets
  (defun verify-refile-target ()
    "Exclude todo keywords with a done state from refile targets"
    (not (member (nth 2 (org-heading-components)) org-done-keywords)))
  (setf org-refile-target-verify-function #'verify-refile-target)
  (defun air-org-skip-subtree-if-priority (priority)
    "Skip an agenda subtree if it has a priority of PRIORITY.

PRIORITY may be one of the characters ?A, ?B, or ?C."
    (let ((subtree-end (save-excursion (org-end-of-subtree t)))
          (pri-value (* 1000 (- org-lowest-priority priority)))
          (pri-current (org-get-priority (thing-at-point 'line t))))
      (if (= pri-value pri-current)
          subtree-end
        nil)))
  (defun air-org-skip-subtree-if-habit ()
    "Skip an agenda entry if it has a STYLE property equal to \"habit\"."
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (if (string= (org-entry-get nil "STYLE") "habit")
          subtree-end
        nil)))
  (defun shackra-org-clocktable-formatter (ipos tables params)
    "Extrae el titulo de enlaces y elimina TODO keywords"
    (cl-loop for tbl in tables
             for entries = (nth 2 tbl)
             do (cl-loop for entry in entries
                         for headline = (nth 1 entry)
                         do (setq headline (replace-regexp-in-string (shackra--org-clocktable-regexp) "" headline))
                         do (when (string-match-p "\\[\\[.*\\]\\[\\(.*\\)\\]\\]" headline) (setf headline (replace-regexp-in-string "\\[\\[.*\\]\\[\\(.*\\)\\]\\]" "\\1" headline)))
                         do (setcar (nthcdr 1 entry) headline)))
    (org-clocktable-write-default ipos tables params))

  (defun shackra--org-clocktable-regexp ()
    "Genera una expresion regular a partir de la variable `org-todo-keywords'"
    (let ((regexp)
          (flat (shackra--flatten org-todo-keywords)))
      (dolist (e flat)
        (when (and (stringp e) (not (string-match-p "|" e)) (not (string-empty-p e)))
          (append regexp (replace-regexp-in-string "(.*)" " " e))))
      (string-join regexp "\\|")))

  (defun shackra--flatten (mylist)
    "Flat an array

Taken from https://rosettacode.org/wiki/Flatten_a_list#Emacs_Lisp"
    (cond
     ((null mylist) nil)
     ((atom mylist) (list mylist))
     (t
      (append (shackra--flatten (car mylist)) (shackra--flatten (cdr mylist))))))

  (setf org-clock-clocktable-formatter 'shackra-org-clocktable-formatter)
  ;; Targets include this file and any file contributing to the agenda - up to
  ;; 9 levels deep
  (setf org-refile-targets `((nil :maxlevel . 9)
                             (org-agenda-files :maxlevel . 9)
                             (org-default-notes-file :maxlevel . 9)
                             (,(expand-file-name "notas.org" org-directory) :maxlevel . 9)
                             (,(expand-file-name "quizas.org" org-directory) :maxlevel . 9)))
  (setf org-use-property-inheritance t)
  ;; Use full outline paths for refile targets
  (setq org-refile-use-outline-path 'file)

  (setq org-outline-path-complete-in-steps t)

  ;; Allow refile to create parent tasks with confirmation
  (setq org-refile-allow-creating-parent-nodes 'confirm)

  ;; evita dividir una linea con M-RET
  (setf org-M-RET-may-split-line '((default . nil)))
  (setf org-default-notes-file (expand-file-name "notas.org" org-directory)
        org-agenda-files (list (expand-file-name "cosas por hacer.org" org-directory)))
  (setf org-todo-keywords
        '((sequence "POR-HACER(p)" "SIGNT(s)" "|" "TERMINADO(t)")
          (sequence "ESPERA(e@/!)" "RETENER(r@/!)" "|" "CANCELADO(c@/!)")))
  (setf org-todo-keyword-faces
        '(("POR-HACER" :foreground "red" :weight bold)
          ("SIGNT" :foreground "blue" :weight bold)
          ("TERMINADO" :foreground "forest green" :weight bold)
          ("ESPERA" :foreground "orange" :weight bold)
          ("RETENER" :foreground "magenta" :weight bold)
          ("CANCELADO" :foreground "forest green" :weight bold)))
  (setf org-catch-invisible-edits 'show)
  (setf org-clock-persist 'history)
  (setf org-ctrl-k-protect-subtree t)
  (setf org-export-backends '(ascii html icalendar latex md texinfo))
  (setf org-fontify-quote-and-verse-blocks t)
  (setf org-footnote-auto-adjust t)
  (setf org-habit-graph-column 55)
  (setf org-imenu-depth 5)
  (setf org-log-done 'time)
  (setf org-modules '(org-bbdb org-bibtex org-crypt org-docview
                               org-gnus org-habit org-id org-info
                               org-irc org-mhe org-rmail org-w3m))
  (setf org-special-ctrl-k t)
  (setf org-startup-folded nil)
  (setf org-startup-indented t)
  (setf org-use-fast-todo-selection t)
  (setf org-treat-S-cursor-todo-selection-as-state-change nil)
  (setf org-todo-state-tags-triggers
        '(("CANCELADO" ("CANCELADO" . t))
          ("ESPERA" ("ESPERA" . t))
          ("RETENER" ("ESPERA") ("RETENER" . t))
          (done ("ESPERA") ("RETENER"))
          ("POR-HACER" ("ESPERA") ("CANCELADO") ("RETENER"))
          ("SIGNT" ("ESPERA") ("CANCELADO") ("RETENER"))
          ("TERMINADO" ("ESPERA") ("CANCELADO") ("RETENER"))))
  ;; según http://orgmode.org/manual/Link-abbreviations.html#Link-abbreviations
  (setf org-link-abbrev-alist
        '(("rarbg" . "https://rarbg.to/torrents.php?search=%s&category%5B%5D=17&category%5B%5D=18")
          ("nyaa" . "https://www.nyaa.se/?page=search&cats=1_0&filter=0&term=%s")
          ("bakabt" . "https://bakabt.me/browse.php?only=0&incomplete=1&bonus=1&c1=1&c2=1&reorder=1&q=%s")
          ("tokyotosho" . "https://www.tokyotosho.info/search.php?terms=%s&type=1&size_min=&size_max=&username=")))
  (setf org-capture-templates
        '(("t" "Anotacion técnica" entry (file "apuntes tecnicos.org")
           "* %^{titulo o situación} %^g\n\n%?\n- Enlaces de relacionados:\n" :kill-buffer t :clock-in t :clock-resume t)
          ("p" "Tarea por hacer" entry (file+headline "cosas por hacer.org" "Tareas")
           "* POR-HACER %^{breve descripción} %a %^g\n:PROPERTIES:\n:CREATED:%U\n:END:\n%?" :kill-buffer t :clock-in t :clock-resume t)
          ("n" "Notas" entry (file+headline org-default-notes-file "Reorganizar")
           "* %^{breve descripción}\n:PROPERTIES:\n:CREATED:%U\n:END:\n%?" :kill-buffer t :clock-in t :clock-resume t)
          ("f" "Fechas o eventos" entry (file+headline "cosas por hacer.org" "Fechas")
           "* POR-HACER %^{Nombre del evento} %^g\nSCHEDULED: %^T%?\n:PROPERTIES:%(if (yes-or-no-p \"¿Es esto un cumpleaños?\") (format \"\n:NACIMIENTO: %s\" (with-temp-buffer (org-time-stamp nil t) (buffer-string))) \"\")\n:CREATED: %U\n:END:" :kill-buffer t :clock-in t :clock-resume t)
          ("d" "Escribir una nota en el diario" entry (file+olp+datetree "diario.org")
           "* %^{Querido diario...}\n:PROPERTIES:\n:CREATED: %T\n:END:\n%?" :empty-lines 1 :kill-buffer t :clock-in t :clock-resume t)
          ("r" "Receta de cocina" entry (file "recetas.org")
           "* %^{Nombre de la receta}\n:PROPERTIES:\n:CREATED: %T\n:END:\n%?\n%(call-interactively 'org-download-image)\n- Sacado de: %^a\n** Ingredientes\n** Procedimiento"
           :kill-buffer t :clock-in t :clock-resume t)

          ("b" "Bitácora de pendientes")

          ("bp" "Tarea" entry (file+headline "quizas.org" "Cosas por hacer")
           "* %^{breve descripcion}\n:PROPERTIES:\n:CREATED: %U\n:END:\n%?" :kill-buffer t :clock-in t :clock-resume t)
          ("bt" "Aprender" entry (file+headline "quizas.org" "Cosas por hacer")
           "* Aprender sobre %^{cosa}\n:PROPERTIES:\n:CREATED: %T\n:END:\n%?" :kill-buffer t :clock-in t :clock-resume t)
          ("bl" "Libro" entry (file+headline "quizas.org" "Libros")
           "* Leer /%^{Titulo}/ por %^{Autor}\n:PROPERTIES:\n:CREATED: %T\n:AUTOR: %\\2\n:END:\n%?" :kill-buffer t :clock-in t :clock-resume t)
          ("bb" "Blog" entry (file+headline "quizas.org" "Blogs")
           "* Leer entrada de blog /%^{copy as org}/\n:PROPERTIES:\n:CREATED: %T\n:END:\n%\\1%?" :kill-buffer t :clock-in t :clock-resume t)
          ("bx" "Idea de proyecto" entry (file+headline "quizas.org" "Ideas para posibles proyectos")
           "* %^{Titulo o breve descripción} ^%g\n:PROPERTIES:\n:CREATED: %T\n:END:\n%?" :kill-buffer t :clock-in t :clock-resume t)
          ("bm" "Películas" entry (file+headline "quizas.org" "Películas")
           "* Ver [[rarbg:%^{Titulo}][%\\1]]\n:PROPERTIES:\n:CREATED: %T\n:END:" :kill-buffer t :clock-in t :clock-resume t)
          ("ba" "Anime" entry (file+headline "quizas.org" "Anime")
           "* Ver /%^{Anime}/\n:PROPERTIES:\n:CREATED: %T\n:CATEGORY: anime\n:EPISODIO: 1\n:EPISODIOS: %^{numero de episodios}\n:END:\n- [[nyaa:%\\1][Buscar %\\1 en Nyaa Torrents]]\n- [[bakabt:%\\1][Buscar %\\1 en BakaBT]]\n- [[tokyotosho:%\\1][Buscar %\\1 en Tokyo Toshokan]]" :kill-buffer t :clock-in t :clock-resume t)))

  ;; Do not dim blocked tasks
  (setf org-agenda-dim-blocked-tasks nil)

  ;; Compact the block agenda view
  (setf org-agenda-compact-blocks nil)

  ;; Custom agenda command definitions
  (setf org-agenda-custom-commands
        '(("a" "Agenda"
           ((tags "PRIORITY=\"A\""
                  ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                   (org-agenda-overriding-header "Tareas de alta prioridad por terminar:")))
            (agenda ""
                    ((org-agenda-span 'day)
                     (org-agenda-overriding-header "Hoy:")
                     (org-agenda-show-all-dates nil)))
            (agenda ""
                    ((org-agenda-span 'week)
                     (org-agenda-start-day "+1d") ;; A partir de mañana
                     (org-agenda-overriding-header "Semana:")
                     (org-agenda-show-all-dates nil)))
            (agenda ""
                    ((org-agenda-span 'month)
                     ;; A partir de la siguiente semana
                     (org-agenda-start-day "+1w")
                     (org-agenda-overriding-header "Mes:")
                     (org-agenda-show-all-dates nil)))
            (alltodo ""
                     ((org-agenda-skip-function
                       '(or (air-org-skip-subtree-if-habit)
                            (air-org-skip-subtree-if-priority ?A)
                            (org-agenda-skip-if nil '(scheduled deadline))))
                      (org-agenda-overriding-header "Todas las tareas de prioridad normal:")))))))
  (setf org-archive-location (expand-file-name "~/org-archivos/archivado.org::* Entradas viejas y archivadas"))
  (setf org-footnote-auto-adjust t)
  (setf org-outline-path-complete-in-steps nil)
  (setf org-refile-use-outline-path t)
  (setf org-html-htmlize-output-type 'css)
  (setf org-html-htmlize-font-prefix "org-")
  (setf org-habit-graph-column 55)
  (setf org-special-ctrl-k t)
  (setf org-ctrl-k-protect-subtree t) ;; al usar C-k, evitamos perder todo el subarbol
  (setf org-catch-invisible-edits 'show)
  (setf org-return-follow-link t)
  (setf org-startup-indented t)
  (setf org-startup-folded nil)
  (setf org-log-done nil)
  (setf org-log-reschedule 'note)
  (setf org-log-redeadline 'note)
  (setf org-log-note-clock-out nil)
  (setf org-log-refile nil)
  (setf org-log-into-drawer nil)
  (setf org-clock-persist 'history)
  :config
  (org-clock-persistence-insinuate))
(use-package org-indent
  :after (org)
  :ensure nil
  :diminish org-indent-mode)
(with-eval-after-load 'org
  (use-package org-projectile
    :after (projectile)
    :init
    (setq org-confirm-elisp-link-function nil)
    :config
    (setq org-agenda-files (append org-agenda-files (org-projectile-todo-files)))
    (add-to-list 'org-capture-templates (org-projectile-project-todo-entry
                                         :capture-character "P"))))

org-trello

Sincroniza archivos org-mode y tableros en Trello

(use-package org-trello
  :disabled
  :after (org)
  :init
  (custom-set-variables '(org-trello-files '("/home/jorge/go/src/bitbucket.org/capslockdev/betsy/proyecto.org"
                                             "/home/jorge/Kartelo/clientes/Design Soft/Selore POS/proyecto.org"
                                             "/home/jorge/go/src/bitbucket.org/shackra-4hoa/proyecto.org")))
  (defun shackra-org-trello-sync-after-save ()
    "Sincroniza el contenido del archivo org después de salvar"
    (interactive)
    (when (and (eq major-mode 'org-mode)
             (member buffer-file-name org-trello-files))
      (org-trello-sync-buffer)))
  (add-hook 'after-save-hook #'shackra-org-trello-sync-after-save))

pkgbuild-mode

Un modo mayor de Emacs para la edición de archivos PKGBUILD

(use-package pkgbuild-mode
  :mode "/PKGBUILD$")

Preparación previa

Si estas en Arch Linux o Parabola GNU/Linux-libre, tienes que instalar el paquete correspondiente desde el repositorio de software de la distribución

sudo pacman -S emacs-pkgbuild-mode

python

Modo mayor para programar en Python

(defun python-template ()
  (interactive)
  (insert "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n"))

(add-hook 'python-mode-hook
          '(lambda () (when (eq (buffer-size) 0) (python-template))))

(defun shackra-python-install-deps ()
  "Instala dependencias básicas dentro de un entorno virtual"
  (interactive)
  (shell-command "pip install 'python-language-server[rope,pydocstyle,pyflakes]' pyls-mypy black"))

(use-package pony-mode
  :after (python)
  :init
  (defun shackra-pony-remove-beautify-html ()
    "Quita el gancho para embellecer el HTML"
    (remove-hook 'before-save-hook 'web-beautify-html-buffer t))
  :config
  ;; quitamos el gancho que embellece el HTML cuando es guardado para que no
  ;; estropeé las plantillas de DJango
  (add-hook 'pony-tpl-minor-mode-hook #'shackra-pony-remove-beautify-html))

(use-package virtualenvwrapper
  :after (python)
  :commands (venv-workon venv-deactivate venv-initialize-interactive-shells venv-initialize-eshell)
  :init
  (venv-initialize-interactive-shells)
  (venv-initialize-eshell)
  :config
  (add-hook 'venv-postmkvirtualenv-hook #'shackra-python-install-deps))

(use-package pippel)

(use-package sphinx-doc
  :after (python)
  :init (add-hook 'python-mode-hook #'sphinx-doc-mode))

(use-package pydoc-info)

(use-package blacken
  :after (python-mode)
  :init
  (add-hook 'python-mode-hook #'blacken-mode))

(use-package python
  :if (executable-find "python")
  :bind (:map python-mode-map
              ("C-c ," . shackra-python-indent-shift-left)
              ("C-c ." . shackra-python-indent-shift-right))
  :interpreter ("python" . python-mode)
  :init
  (defun shackra-python-indent-shift-left ()
    (interactive)
    (if (fboundp 'hydra-py/python-indent-shift-left)
        (hydra-py/python-indent-shift-left)
      (python-indent-shift-left)))
  (defun shackra-python-indent-shift-right ()
    (interactive)
    (if (fboundp 'hydra-py/python-indent-shift-right)
        (hydra-py/python-indent-shift-right)
      (python-indent-shift-right)))
  (defun shackra-python-mode ()
    "Cosas que deseo activar/desactivar cuando voy a programar en Python"
    (shackra-electric-indent-mode-off)
    (aggressive-indent-mode -1))

  (setf python-shell-interpreter "python")
  (add-hook 'python-mode-hook #'shackra-python-mode)
  (with-eval-after-load 'lsp-clients
    (add-hook 'python-mode-hook #'lsp))
  :config
  ;; re-mapea todas los atajos que hagan referencia a `python-indent-shift-*' con `shackra-python-indent-shift-*'
  (global-set-key [remap python-indent-shift-left] 'shackra-python-indent-shift-left)
  (global-set-key [remap python-indent-shift-right] 'shackra-python-indent-shift-right))

LaTeX

Paquete extensivo para escribir y formatear documentos TeX

(use-package latex
  :ensure auctex
  :init
  (setf TeX-auto-save t
        TeX-parse-self t
        TeX-save-query nil
        TeX-newline-function 'newline-and-indent
        LaTeX-item-indent 0)
  (setq-default TeX-master nil)
  (setq-default TeX-engine 'xetex)
  (setq-default TeX-PDF-mode t)
  (add-hook 'LaTeX-mode-hook 'yas-minor-mode-on))
(use-package reftex
  :init
  (add-hook 'LaTeX-mode-hook 'turn-on-reftex)   ; with AUCTeX LaTeX mode
  (add-hook 'latex-mode-hook 'turn-on-reftex))   ; with Emacs latex mode

toml

El lenguaje minimalista y obvio de Tom

(use-package toml-mode
  :defer 10)

yaml

YAML: YAML Ain’t Markup Language

(use-package yaml-mode
  :defer 10
  :mode "\\.yml$")

rust

Modo mayor para editar código fuente en Rust. Rust es es un lenguaje de programación de sistemas que corre realmente rapido, previene fallos de segmentación (segfaults), y garantiza seguridad en programas multi-hilo.

(use-package rustfmt
  :disabled ;; no existe en Melpa (20/05/2017)
  :after (rust-mode)
  :config
  (add-hook 'rust-mode-hook #'rustfmt-enable-on-save))

(use-package cargo
  :after (rust-mode)
  :if (executable-find "cargo"))

(use-package rust-mode
  :if (executable-find "rustc")
  :init
  (setq rust-format-on-save t)
  :config
  (with-eval-after-load 'lsp-clients
    (add-hook 'rust-mode-hook #'lsp)))

emacs-traad

Una aproximación cliente servidor para usar la librería de refactorización rope.

(with-eval-after-load 'projectile
  (defun shackra-traad-open ()
    "Inicia un servidor traad usando la ubicación del proyecto actual"
    (interactive)
    (if (projectile-project-p)
        (traad-open (projectile-project-root))
      (message "No estas en ningún proyecto!"))))

(use-package python-environment
  :after (python)
  :init
  (setq python-environment-directory "~/.virtualenvs"))

(use-package traad
  :after (python-environment)
  :init
  (with-eval-after-load 'hydra
    (defhydra hydra-traad-history (:columns 2)
      "Historial de cambios de rope"
      ("u" traad-undo "deshacer" :color red)
      ("r" traad-redo "re-hacer" :color red)
      ("h" traad-display-history "mostrar historial de cambios" :color blue)
      ("b" hydra-traad/body "volver" :color blue)
      ("q" nil "salir"))
    (defhydra hydra-traad-rename (:columns 2)
      "Renombrar con rope"
      ("f" traad-rename-current-file "archivo/modulo actual" :color blue)
      ("r" traad-rename "objeto en locación actual" :color red)
      ("b" hydra-traad/body "volver" :color blue)
      ("q" nil "salir"))
    (defhydra hydra-traad-signature (:columns 2)
      "Cambiar firma con rope"
      ("n" traad-normalize-arguments "normalizar argumentos" :color blue)
      ("r" traad-remove-argument "remover argumentos" :color blue)
      ("b" hydra-traad/body "volver" :color blue)
      ("q" nil "salir"))
    (defhydra hydra-traad-extraction (:columns 2)
      "Extracción con rope"
      ("m" traad-extract-method "método" :color blue)
      ("v" traad-extract-variable "variable" :color blue)
      ("b" hydra-traad/body "volver" :color blue)
      ("q" nil "salir"))
    (defhydra hydra-traad-imports (:columns 3)
      "Importaciones con rope"
      ("o" traad-organize-imports "organizar" :color red)
      ("s" traad-expand-star-imports "expandir *" :color red)
      ("f" traad-froms-to-imports "convertir 'from' a normales" :color red)
      ("r" traad-relatives-to-absolutes "convertir relativos a absolutos" :color red)
      ("l" traad-handle-long-imports "manejar importaciones largas" :color red)
      ("S" traad-imports-super-smackdown "Smackdown!" :color blue)
      ("b" hydra-traad/body "volver")
      ("q" nil "salir"))
    (defhydra hydra-traad (:columns 2)
      "Refactorización en Python con rope"
      ("h" hydra-traad-history/body "Historial" :exit t)
      ("r" hydra-traad-rename/body "Renombrar" :exit t)
      ("s" hydra-traad-signature/body "Firma" :exit t)
      ("e" hydra-traad-extraction/body "Extracción" :exit t)
      ("i" hydra-traad-imports/body "Importaciones" :exit t)))
  :config
  (with-eval-after-load 'hydra
    (bind-key "C-c t" 'hydra-traad/body python-mode-map))
  ;; Si aun no se ha creado el entorno virtual para traad, lo mandamos a crear
  ;; de manera automática
  (if (not (file-exists-p (expand-file-name (concat python-environment-directory "/traad"))))
      (traad-install-server)))

web-mode

Un modo mayor para editar paginas web

(use-package web-beautify
  :after (web-mode)
  :config
  (add-hook 'json-mode-hook
            (lambda ()
              (add-hook 'before-save-hook 'web-beautify-js-buffer t t)))
  (add-hook 'html-mode-hook
            (lambda ()
              (add-hook 'before-save-hook 'web-beautify-html-buffer t t)))
  (add-hook 'css-mode-hook
            (lambda ()
              (add-hook 'before-save-hook 'web-beautify-css-buffer t t))))
(use-package emmet-mode
  :config
  (add-hook 'sgml-mode-hook 'emmet-mode)
  (add-hook 'web-mode-hook 'emmet-mode))

(use-package web-mode
  :preface
  (defun shackra-webdev-refresh-page-on-save ()
    "Actualiza una pagina web en el navegador al guardar un buffer"
    (interactive)
    (let* ((currentfiledir (file-name-directory (buffer-file-name)))
           (isrootfile (string-suffix-p httpd-root currentfiledir)))
      (when (and (derived-mode-p 'sgml-mode 'css-mode 'web-mode 'js2-mode) isrootfile (shackra-port-open-p moz-repl-host moz-repl-port))
        (moz-controller-page-refresh))))
  :init
  (setf web-mode-code-indent-offset shackra-webdev-indent)
  (setf web-mode-css-indent-offset shackra-webdev-indent)
  (setf web-mode-sql-indent-offset shackra-webdev-indent)
  (setf web-mode-markup-indent-offset shackra-webdev-indent)
  :config
  (with-eval-after-load 'lsp-clients
    (add-hook 'web-mode-hook #'lsp))
  (add-hook 'after-save-hook #'shackra-webdev-refresh-page-on-save)
  (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)))

CSS con LSP-mode

dependencias externas

Si esto no se instala no tendremos disponible autocompletado para CSS con LSP

npm i -g vscode-css-languageserver-bin
css-mode
(use-package css-mode
  :ensure nil
  :init
  (setf css-indent-offset shackra-webdev-indent)
  (with-eval-after-load 'lsp-clients
    (add-hook 'css-mode-hook #'lsp)))

PHP

modo mayor para editar código PHP

dependencias externas

Composer debe estar configurado con al menos la siguientes lineas, este cambio afecta globalmente todos los paquetes de PHP por lo cual hay que ser cauteloso.

{
  "minimum-stability": "dev",
  "prefer-stable": true
}

Se instala el paquete externo mediante composer

composer global require felixfbecker/language-server
composer global run-script --working-dir=~/.config/composer/vendor/felixfbecker/language-server parse-stubs

Y esta es la configuración.

(use-package php-refactor-mode
  :after (php-mode)
  :config
  (add-hook 'php-mode-hook 'php-refactor-mode))

(use-package php-mode
  :config
  (with-eval-after-load 'lsp-clients
    (add-hook 'php-mode-hook #'lsp)))

golang

Modo mayor para editar archivos Golang.

Teclas

@@html:<kbd>M-.</kbd>@@
Salta a definición / Go Guru: salto a definición
@@html:<kbd>C-c C-a</kbd>@@
Agrega importación
@@html:<kbd>C-c C-r</kbd>@@
Quita importaciones sin usar
@@html:<kbd>C-c C-i</kbd>@@
Ir a sección donde están las importaciones
@@html:<kbd>C-c C-c</kbd>@@
Compilar proyecto
@@html:<kbd>C-M-m</kbd>@@
Inicia Go Doctor
@@html:<kbd>C-M-g</kbd>@@
Inicia Go Guru

Es necesario instalar =gometalinter= para localizar varios tipos de errores en el código fuente

go get -u gopkg.in/alecthomas/gometalinter.v1

También estas otras bibliotecas

go get -u github.com/sourcegraph/go-langserver # reemplaza a gocode ya que estamos usando lsp-mode
go get github.com/godoctor/godoctor
go install github.com/godoctor/godoctor
go get golang.org/x/tools/cmd/guru # Como usar Go Guru http://golang.org/s/using-guru
go build golang.org/x/tools/cmd/guru
(use-package f) ;; requerido para `shackra-go-update-compile-definition'
(use-package go-mode
  :after (f)
  :if (executable-find "go")
  :bind (:map go-mode-map
              ("M-." . godef-jump)
              ("C-c C-a" . go-import-add)
              ("C-c C-r" . go-remove-unused-imports)
              ("C-c C-i" . go-goto-imports)
              ("C-c C-c" . compile))
  :init
  (defun shackra-go-update-compile-definition ()
    "Actualiza la definición del comando COMPILE para go-mode"
    (interactive)
    (when (eq major-mode 'go-mode)
      (if (string-suffix-p "_test.go" (buffer-name))
          (set (make-local-variable 'compile-command) "go test -bench=. -v")
        (set (make-local-variable 'compile-command) (format "go build && ./%s" (f-base (f-dirname (f-full (buffer-name)))))))))
  :config
  (add-hook 'go-mode-hook (lambda () (add-to-list (make-local-variable 'grep-find-ignored-directories) "vendor")))
  (add-hook 'go-mode-hook 'shackra-go-update-compile-definition)
  (add-hook 'go-mode-hook (lambda ()
                            (add-to-list 'flycheck-disabled-checkers 'lsp-ui)
                            (setf flycheck-checker 'go-golint)))
  (with-eval-after-load 'lsp-clients
    (setf lsp-clients-go-server "go-langserver")
    (add-hook 'go-mode-hook #'lsp))
  (add-hook 'after-save-hook 'shackra-go-update-compile-definition))

(use-package go-eldoc
  :after (go-mode)
  :config
  (add-hook 'go-mode-hook 'go-eldoc-setup))

(use-package go-snippets
  :after (go-mode))

(with-eval-after-load 'hydra
  (use-package godoctor
    :after (go-mode)
    :if (executable-find "godoctor")
    :bind (:map go-mode-map ("C-M-m" . hydra-godoctor/body))
    :config
    (defhydra hydra-godoctor (:color blue :columns 2)
      "Motor de refactorización para Go"
      ("a" godoctor-rename "Renombra identificador, punto actual")
      ("s" godoctor-extract "Refactorizacion en una función, marca actual")
      ("d" godoctor-toggle "Cambia declaración de variable")
      ("f" godoctor-godoc "Crea esqueleto de documentación"))))
(with-eval-after-load 'hydra
  (use-package go-guru
    :after (go-mode)
    :if (executable-find "guru")
    :demand t
    :init
    (defun shackra-go-mode-set-scope ()
      (when (eq major-mode 'go-mode)
        (set (make-local-variable 'go-guru-scope)
             (concat (projectile-project-root) "..."))))
    :bind (:map go-mode-map
                ("M-." . go-guru-definition)
                ("C-M-g" . hydra-go-guru/body))
    :config
    (defhydra hydra-go-guru (:color blue :columns 2)
      "Contesta preguntas sobre código fuente escrito en Go"
      ("a" go-guru-callees "Receptores de llamada, función bajo punto actual")
      ("s" go-guru-callers "Llamadores, función bajo punto actual")
      ("d" go-guru-callstack "Muestra grafo de llamadas desde una raíz, función bajo punto actual")
      ("f" go-guru-describe "Describe la sintaxis seleccionada, su tipo y métodos")
      ("g" go-guru-freevars "Enumera las variables libres, marca actual")
      ("h" go-guru-referrers "Enumera referencias al objeto, identificador marcado")
      ("j" go-guru-peers "Enumera un set de remitentes/destinatarios para las operaciones enviar/recibir de este canal")
      ("k" go-guru-pointsto "Muestra lo que apunta, expresión marcada")
      ("l" go-guru-implements "Describe la relación de implementación para tipos en un paquete conteniendo el cursor")
      ("ñ" go-guru-whicherrs "Muestra globales, constantes y tipos, expresión marcada (de tipo 'error')"))
    (add-hook 'go-mode-hook #'go-guru-hl-identifier-mode)
    (add-hook 'projectile-mode-hook #'shackra-go-mode-set-scope)))
(with-eval-after-load 'go-mode
  (use-package flycheck-gometalinter
    :if (or (executable-find "gometalinter.v1") (executable-find "gometalinter"))
    :after (flycheck-mode)
    :init
    (if (executable-find "gometalinter.v1")
        (setf flycheck-gometalinter-executable "gometalinter.v1")
      (setf flycheck-gometalinter-executable "gometalinter"))
    (setf flycheck-gometalinter-vendor t)
    (setf flycheck-gometalinter-test t)
    (setf flycheck-gometalinter-fast t)
    (setf flycheck-gometalinter-enable-linters '("unused"))
    (setf flycheck-gometalinter-disable-linters '("gotype"))
    (setq flycheck-gometalinter-deadline "5s")
    :config
    (progn
      (flycheck-gometalinter-setup))))

(use-package ob-go)

javascript

JSON

  • @@html:<kbd>C-c C-f</kbd>@@: format the region/buffer with =json-reformat=
  • @@html:<kbd>C-c C-p</kbd>@@: display a path to the object at point with =json-snatcher=
  • @@html:<kbd>C-c P</kbd>@@: copy a path to the object at point to the kill ring with json-snatcher
  • @@html:<kbd>C-c C-t</kbd>@@: Toggle between true and false at point
  • @@html:<kbd>C-c C-k</kbd>@@: Replace the sexp at point with null
  • @@html:<kbd>C-c C-i</kbd>@@: Increment the number at point
  • @@html:<kbd>C-c C-d</kbd>@@: Decrement the number at point
(use-package json-mode
  :init
  (defun jsconfig-default-conf ()
    (interactive)
    (yas-insert-snippet))

  (add-hook 'json-mode-hook
            '(lambda () (when (and (eq (buffer-size) 0)
                              (string-match-p "jsconfig.json" (buffer-file-name)))
                     (jsconfig-default-conf)))))

Dependencias externas

Instalar estos componentes en el sistema operativo

npm install -g babel-cli babel-preset-react eslint babel-eslint eslint-plugin-react typescript-language-server --save-dev
(defun shackra-js-install-deps ()
  "Instala localmente dependencias de JavaScript"
  (interactive)
  (shell-command "yarn add eslint@3.x babel-eslint@7 eslint-plugin-react --dev"))
configuracion eslint
{
  "parser": "babel-eslint",
  "plugins": [ "react" ],
  "env": {
    "browser": true,
    "es6": true,
    "node": true
  },
  "ecmaFeatures": {
    "arrowFunctions": true,
    "blockBindings": true,
    "classes": true,
    "defaultParams": true,
    "destructuring": true,
    "forOf": true,
    "generators": true,
    "modules": true,
    "spread": true,
    "templateStrings": true,
    "jsx": true
  },
  "rules": {
    "consistent-return": [0],
    "key-spacing": [0],
    "quotes": [0],
    "new-cap": [0],
    "no-multi-spaces": [0],
    "no-shadow": [0],
    "no-unused-vars": [1],
    "no-use-before-define": [2, "nofunc"],
    "react/jsx-no-undef": 1,
    "react/jsx-uses-react": 1,
    "react/jsx-uses-vars": 1
  }
}

Paquetes para editar JavaScript

(setq-default js-indent-level shackra-webdev-indent)

(use-package typescript-mode
  :init
  (setf typescript-indent-level shackra-webdev-indent)
  (add-to-list 'auto-mode-alist '("\\.tsx?\\'" . (lambda () (typescript-mode) (rjsx-minor-mode))))
  :config
  (with-eval-after-load 'lsp-clients
    (add-hook 'typescript-mode-hook #'lsp)))

(use-package js2-refactor
  :after (js2-mode)
  :config
  (add-hook 'js2-mode-hook #'js2-refactor-mode)
  (js2r-add-keybindings-with-prefix "C-c C-m"))

(use-package xref-js2
  :after (js2-mode)
  :init
  (add-hook 'js2-mode-hook (lambda () (add-hook 'xref-backend-functions #'xref-js2-xref-backend nil t))))

(use-package js2-mode
  :mode "\\.js\\'"
  :init
  (add-hook 'js2-mode-hook #'js2-imenu-extras-mode)
  (setf js2-mode-indent-inhibit-undo t)
  :config
  (with-eval-after-load 'lsp-clients
    (add-hook 'js2-mode-hook #'lsp)))

;; Indium se conecta con una pestaña del navegador web o un proceso de NodeJS
;; y provee varias características para el desarrollo en JavaScript
(use-package indium ;; https://indium.readthedocs.io/en/latest/setup.html
  :config
  (add-hook 'js-mode-hook #'indium-interaction-mode))

;; Modo mayor para trabajar con Reactive.JS
(use-package rjsx-mode
  :init
  (add-to-list 'auto-mode-alist '("components?\\/.*\\.js\\'" . rjsx-mode))
  (add-to-list 'auto-mode-alist '("containers?\\/.*\\.js\\'" . rjsx-mode))
  (add-hook 'rjsx-mode-hook (lambda () (flyspell-mode-off) (aggressive-indent-mode -1)))
  :config
  ;; tomado de https://emacs.stackexchange.com/a/33544/690 mejora el sangrado
  ;; de lineas
  (defadvice js-jsx-indent-line (after js-jsx-indent-line-after-hack activate)
    "Workaround sgml-mode and follow airbnb component style."
    (save-excursion
      (beginning-of-line)
      (if (looking-at-p "^ +\/?> *$")
          (delete-char sgml-basic-offset))))
  (with-eval-after-load 'lsp-clients
    (add-to-list 'lsp-language-id-configuration '(rjsx-mode . "javascript"))
    (add-hook 'rjsx-mode-hook #'lsp)))

(with-eval-after-load 'flycheck
  ;; tomado de https://jamiecollinson.com/blog/my-emacs-config/ hace que
  ;; flycheck utilice eslint instalado en el proyecto en lugar del habilitado
  ;; globalmente en el sistema
  (defun jc/use-eslint-from-node-modules ()
    "Set local eslint if available."
    (let* ((root (locate-dominating-file
                  (or (buffer-file-name) default-directory)
                  "node_modules"))
           (eslint (and root
                        (expand-file-name "node_modules/eslint/bin/eslint.js"
                                          root))))
      (when (and eslint (file-executable-p eslint))
        (setq-local flycheck-javascript-eslint-executable eslint))))

  (add-hook 'flycheck-mode-hook #'jc/use-eslint-from-node-modules))

html-mode

(use-package sgml-mode
  :ensure nil
  :init
  (setf sgml-basic-offset shackra-webdev-indent)
  (with-eval-after-load 'lsp-clients
    (add-hook 'html-mode-hook #'lsp)))

HTML con LSP-mode

dependencias externas
npm i -g vscode-html-languageserver-bin

Android

Desarrollo de aplicaciones para Android desde GNU Emacs

(use-package android-mode
  :init
  (setf android-mode-sdk-dir "~/opt/android"))

SLIME

SLIME is the Superior Lisp Interaction Mode for Emacs.

(use-package slime
  :init
  ;; Sacado de https://www.emacswiki.org/emacs/ParEdit#toc3 evita que SLIME
  ;; coja DEL porque interfiere con el funcionamiento normal de paredit
  (defun override-slime-repl-bindings-with-paredit ()
    (define-key slime-repl-mode-map
      (read-kbd-macro paredit-backward-delete-key) nil))
  ;; Estoy leyendo Land of Lisp, así que necesito usar CLISP
  (setf inferior-lisp-program "/usr/bin/clisp")
  (setf slime-contribs '(slime-fancy))
  (add-hook 'slime-repl-mode-hook #'enable-paredit-mode)
  (add-hook 'slime-repl-mode-hook 'override-slime-repl-bindings-with-paredit))

Stylus

(use-package stylus-mode
  :after (rainbow-mode)
  :init
  (add-hook 'stylus-mode-hook 'rainbow-mode))

SCSS

(use-package scss-mode
  :init (setf scss-compile-at-save nil)
  :config
  (when (fboundp 'lsp-scss-enable)
    (add-hook 'scss-mode-hook 'lsp-scss-enable)))

Gherkin

(use-package feature-mode
  :mode ("\\.feature$" . feature-mode))

kotlin

(use-package kotlin-mode
  :if (executable-find "kotlin"))

(use-package flycheck-kotlin
  :after (kotlin-mode))

(use-package gradle-mode
  :after (kotlin-mode))

Gimp

Now you can run the GIMP with `M-x run-gimp’. Alternatively, connect to GIMP server with `M-x gimp-cl-connect’.

Type `M-x gimp-help’ for help.

(use-package gimp-mode
  :disabled
  :ensure nil
  :load-path "site-packages/gimp-mode"
  :config
  (load (expand-file-name "site-packages/gimp-mode/gimp-init.el" user-emacs-directory)))

Java

(use-package meghanada
  :config
  (add-hook 'java-mode-hook
            (lambda ()
              ;; meghanada-mode on
              (meghanada-mode t)
              (setq c-basic-offset 2)
              ;; use code format
              (add-hook 'before-save-hook 'meghanada-code-beautify-before-save))))

VueJS

(use-package vue-mode
  :init
  (setq mmm-submode-decoration-level 2)
  (with-eval-after-load 'lsp-clients
    (add-hook 'vue-mode-hook #'lsp)))

C#

(use-package omnisharp
  :bind ((("C-c r r" . omnisharp-run-code-action-refactoring)
          ("C-c C-c" . recompile)))
  :init
  (defun shackra-csharp-config ()
    (setq indent-tabs-mode nil)
    (setq c-syntactic-indentation t)
    (c-set-style "ellemtel")
    (setq c-basic-offset 4)
    (setq tab-width 4))
  :config
  (add-hook 'csharp-mode-hook 'omnisharp-mode)
  (add-hook 'csharp-mode-hook #'shackra-csharp-config)
  (add-hook 'omnisharp-mode-hook (lambda () (add-to-list (make-local-variable 'company-backends) 'company-omnisharp))))

Edición de texto y generalidades relacionadas

flyspell-mode

  • Refiled on [2015-11-12 jue 16:56]
  • Refiled on [2015-11-12 jue 16:51]
Revisión ortográfica al vuelo. Asociado a @@html:<kbd>C-.</kbd>@@. @@html:<kbd><f8></kbd>@@ cambia el idioma de Español a Inglés y viceversa.
(with-eval-after-load 'flyspell
  (use-package flyspell-correct-ivy
    :after (ivy-mode)
    :bind (:map flyspell-mode-map ("C-." . flyspell-correct-previous-word-generic))
    :init
    (setf flyspell-correct-auto-delay 2.0)))
(use-package flyspell
  :if (or (executable-find "ispell") (executable-find "hunspell"))
  :diminish flyspell-mode
  :ensure nil
  :init
  ;; sacado de http://blog.binchen.org/posts/what-s-the-best-spell-check-set-up-in-emacs.html
  ;; if (aspell installed) { use aspell}
  ;; else if (hunspell installed) { use hunspell }
  ;; whatever spell checker I use, I always use English dictionary
  ;; I prefer use aspell because:
  ;; 1. aspell is older
  ;; 2. looks Kevin Atkinson still get some road map for aspell:
  ;; @see http://lists.gnu.org/archive/html/aspell-announce/2011-09/msg00000.html
  (defun flyspell-detect-ispell-args (&optional run-together)
    "if RUN-TOGETHER is true, spell check the CamelCase words."
    (let (args)
      (cond
       ((string-match  "aspell$" ispell-program-name)
        ;; Force the Spanish dictionary for aspell
        ;; Support Camel Case spelling check (tested with aspell 0.6)
        (setq args (list "--sug-mode=ultra" "--lang=es_ES"))
        (if run-together
            (setq args (append args '("--run-together" "--run-together-limit=5" "--run-together-min=2")))))
       ((string-match "hunspell$" ispell-program-name)
        ;; Force the Spanish dictionary for hunspell
        (setq args "-d es_ES")))
      args))

  (cond
   ((executable-find "aspell")
    ;; you may also need `ispell-extra-args'
    (setq ispell-program-name "aspell"))
   ((executable-find "hunspell")
    (setq ispell-program-name "hunspell")

    ;; Please note that `ispell-local-dictionary` itself will be passed to hunspell cli with "-d"
    ;; it's also used as the key to lookup ispell-local-dictionary-alist
    ;; if we use different dictionary
    (setq ispell-local-dictionary "es_ES")
    (setq ispell-local-dictionary-alist
          '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)
            ("es_ES" "[[:alpha:]]" "[^[:alpha:]]" "[ñ]" nil ("-d" "es_ES") nil utf-8))))
   (t (setq ispell-program-name nil)))

  ;; ispell-cmd-args is useless, it's the list of *extra* arguments we will append to the ispell process when "ispell-word" is called.
  ;; ispell-extra-args is the command arguments which will *always* be used when start ispell process
  ;; Please note when you use hunspell, ispell-extra-args will NOT be used.
  ;; Hack ispell-local-dictionary-alist instead.
  (setq-default ispell-extra-args (flyspell-detect-ispell-args t))
  ;; (setq ispell-cmd-args (flyspell-detect-ispell-args))
  (defadvice ispell-word (around my-ispell-word activate)
    (let ((old-ispell-extra-args ispell-extra-args))
      (ispell-kill-ispell t)
      (setq ispell-extra-args (flyspell-detect-ispell-args))
      ad-do-it
      (setq ispell-extra-args old-ispell-extra-args)
      (ispell-kill-ispell t)))

  (defadvice flyspell-auto-correct-word (around my-flyspell-auto-correct-word activate)
    (let ((old-ispell-extra-args ispell-extra-args))
      (ispell-kill-ispell t)
      ;; use emacs original arguments
      (setq ispell-extra-args (flyspell-detect-ispell-args))
      ad-do-it
      ;; restore our own ispell arguments
      (setq ispell-extra-args old-ispell-extra-args)
      (ispell-kill-ispell t)))

  (defadvice flyspell-correct-word-generic (around my-flyspell-correct-word-generic activate)
    (let ((old-ispell-extra-args ispell-extra-args))
      (ispell-kill-ispell t)
      ;; use emacs original arguments
      (setq ispell-extra-args (flyspell-detect-ispell-args))
      ad-do-it
      ;; restore our own ispell arguments
      (setq ispell-extra-args old-ispell-extra-args)
      (ispell-kill-ispell t)))

  (defun text-mode-hook-setup ()
    ;; Turn off RUN-TOGETHER option when spell check text-mode
    (setq-local ispell-extra-args (flyspell-detect-ispell-args)))
  :config
  (add-hook 'text-mode #'text-mode-hook-setup))

(use-package shackra-ispell-dict-switch
  :bind (("<f8>" . shackra-ispell-cycle-dict))
  :no-require t
  :ensure nil
  :preface (provide 'shackra-ispell-dict-switch)
  :config
  (setf shackra-ispell-dict-list (list "es" "en"))
  :init
  (defvar shackra-ispell-dict-list (list) "Lista de diccionarios para cambiar")

  (defun shackra--ispell-current-dict ()
    "Obtiene el diccionario actual o retorna el establecido por defecto"
    (if ispell-current-dictionary
        (cl-position ispell-current-dictionary shackra-ispell-dict-list :test 'string=)
      (if (stringp (getenv "LANG"))
          (cl-position (nth 0 (split-string (getenv "LANG") "_")) shackra-ispell-dict-list :test 'string=)
        0))) ;; retorna español mientras tanto

  (defun shackra-ispell-cycle-dict ()
    "Cambia de un diccionario a otro"
    (interactive)
    (let ((dict-list-size (- (length shackra-ispell-dict-list) 1))
          (dict-current-index (shackra--ispell-current-dict)))
      (if (> (+ dict-current-index 1) dict-list-size)
          (setf dict-current-index 0)
        (setf dict-current-index (+ dict-current-index 1)))
      ;; luego de realizar la matemática, cambiamos el diccionario
      (ispell-change-dictionary (nth dict-current-index shackra-ispell-dict-list)))
    ;; Nuevo diccionario, nada de palabras subrayadas
    (flyspell-delete-all-overlays)
    ;; Mandamos a revisar la ortografía del párrafo en que estamos
    (flyspell-region (line-beginning-position) (line-end-position))))

flycheck-mode

  • Refiled on [2015-11-12 jue 16:56]
  • Refiled on [2015-11-12 jue 16:51]
Revisión de errores en el código fuente, al vuelo.
(use-package flycheck-package :after (flycheck))
(use-package flycheck
  :diminish flycheck-mode
  :init
  (setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc javascript-jshint))
  (setf flycheck-indication-mode 'left-fringe)
  (setf flycheck-display-errors-delay 5.0)
  :config
  (add-hook 'prog-mode-hook #'flycheck-mode))

Corrección gramatical

Corrección gramatical en varios idiomas con languagetool.

Configuración adecuada para Arch Linux gracias a la siguiente corrección desde Reddit.

(use-package langtool
  :init
  (if (not (member system-type '(ms-dos windows-nt cygwin)))
      (setq langtool-java-classpath "/usr/share/languagetool:/usr/share/java/languagetool/*")
    (setf langtool-language-tool-jar "d:/languagetool/4.1/languagetool-commandline.jar"))
  (defalias 'lt-check 'langtool-check)
  (defalias 'lt-correct 'langtool-correct-buffer))

multiple-cursors

  • Refiled on [2015-11-12 jue 16:56]
  • Refiled on [2015-11-12 jue 16:51]
Multiples cursores en Emacs. Asociado a @@html:<kbd>C-c n</kbd>@@
(with-eval-after-load 'hydra
  (with-eval-after-load 'multiple-cursors
    (defhydra hydra-mc-next (:columns 4 :color amaranth)
      "Multiple-cursors: Siguiente"
      ("n"    mc/mark-next-like-this "Como este")
      ("N"    mc/unmark-next-like-this "Desmarcar")
      ("M-n"  mc/skip-to-next-like-this "Saltar")
      ("C-n"  mc/mark-next-lines "Linea")
      ("SPC" nil "Salir" :color blue))
    (defhydra hydra-mc-previous (:columns 4 :color amaranth)
      "Multiple-cursors: Anterior"
      ("p"   mc/mark-previous-like-this "Como este")
      ("P"   mc/unmark-previous-like-this "Desmarcar")
      ("M-p" mc/skip-to-previous-like-this "Saltar")
      ("C-p" mc/mark-previous-lines "Linea")
      ("SPC" nil "Salir" :color blue))
    (bind-keys :prefix-map shackra-mc-map
               :prefix "C-c n"
               ("n"   . hydra-mc-next/mc/mark-next-like-this)
               ("N"   . hydra-mc-next/mc/unmark-next-like-this)
               ("M-n" . hydra-mc-next/mc/skip-to-next-like-this)
               ("C-n" . hydra-mc-next/mc/mark-next-lines)
               ("p"   . hydra-mc-previous/mc/mark-previous-like-this)
               ("P"   . hydra-mc-previous/mc/unmark-previous-like-this)
               ("M-p" . hydra-mc-previous/mc/skip-to-previous-like-this)
               ("C-p" . hydra-mc-previous/mc/mark-previous-lines))))

(use-package multiple-cursors
  :init
  (add-hook 'multiple-cursors-mode-hook #'shackra-lsp-on-change-modify-hook)
  :config
  (bind-keys :prefix-map shackra-mc-map
             :prefix "C-c n"
             ("n"   . mc/mark-next-like-this)
             ("N"   . mc/unmark-next-like-this)
             ("M-n" . mc/skip-to-next-like-this)
             ("C-n" . mc/mark-next-lines)
             ("p"   . mc/mark-previous-like-this)
             ("P"   . mc/unmark-previous-like-this)
             ("M-p" . mc/skip-to-previous-like-this)
             ("C-p" . mc/mark-previous-lines)
             ("a"   . mc/mark-all-dwim)
             ("A"   . mc/mark-all-like-this-dwim)
             ("M-a" . mc/mark-all-like-this-in-defun)
             ("M-A" . mc/mark-all-words-like-this-in-defun)
             ("0"   . mc/insert-numbers)
             ("h"   . mc/mark-sgml-tag-pair)
             ("s"   . mc/sort-regions)
             ("m"   . set-rectangular-region-anchor)
             ("r"   . mc/reverse-regions)
             ("M-l" . mc/edit-lines)
             ("l"   . mc/edit-beginnings-of-lines)
             ("C-l" . mc/edit-ends-of-lines)))

pcre2el

Convierte entre sintaxis de expresiones regulares PCRE, Emacs y RX.

(use-package pcre2el
  :diminish pcre-mode
  :config (pcre-mode t))

visual-fill-column

  • Refiled on [2015-11-12 jue 16:57]
  • Refiled on [2015-11-12 jue 16:49]
fill-column for visual-line-mode
(use-package visual-fill-column
  :defer t)

subword-mode

  • Refiled on [2015-11-12 jue 16:57]
  • Refiled on [2015-11-12 jue 16:50]
Navegación y edición de SubPalabras. Siendo “HolaMundoAdios” una nomenclatura, subword-mode permite mover el cursor entre cada subpalabra, deteniéndolo en “Adios”, “Mundo” y “Hola” si se mueve el cursor de derecha a izquierda presionando la tecla CTRL. Este modo menor es muy útil, especialmente para aquellos desarrolladores en Java que usan variables con JorobasDeCamello.
(use-package subword
  :ensure nil
  :diminish subword-mode)

hungry-delete

  • Refiled on [2015-11-12 jue 16:58]
  • Refiled on [2015-11-12 jue 16:53]
Borra espacios en blanco consecutivos con sólo presionar backspace una vez :)
(use-package hungry-delete
  :diminish hungry-delete-mode
  :config
  (global-hungry-delete-mode))

aggressive-indent-mode

  • Refiled on [2015-11-12 jue 16:58]
  • Refiled on [2015-11-12 jue 16:53]
Porque electric-indent-mode no es lo suficientemente bueno.
(use-package aggressive-indent
  :diminish aggressive-indent-mode
  :config
  (add-to-list
   'aggressive-indent-dont-indent-if
   '(and (derived-mode-p 'c++-mode)
         (null (string-match "\\([;{}]\\|\\b\\(if\\|for\\|while\\)\\b\\)"
                             (thing-at-point 'line)))))
  (global-aggressive-indent-mode 1)
  (add-to-list 'aggressive-indent-excluded-modes 'html-mode))

text-mode

  • Refiled on [2015-11-12 jue 17:00]
Cualquier modo mayor que herede de text-mode sera afectado por esta configuración.
(defun shackra-text-mode ()
  (when (or (executable-find "ispell") (executable-find "hunspell"))(flyspell-mode))
  (set (make-local-variable 'fill-column) 100)
  (turn-off-auto-fill)
  (turn-on-visual-line-mode))
(remove-hook 'text-mode-hook #'turn-on-auto-fill)
(add-hook 'text-mode-hook #'shackra-text-mode)

Mover el cursos de manera inteligente al inicio de la linea

He tenido el problema, desde que no uso auto-indent-mode, que al presionar M-a el cursor va a la columna 0 en lugar de posicionarse en el primer carácter no-blanco de la linea, que es un comportamiento deseado cuando se esta programando. En Stackoverflow hay una respuesta para el problema :)

(use-package sbol
  :no-require t
  :ensure nil
  :preface (provide 'sbol)
  :bind (([home] . smart-beginning-of-line)
	   ("C-a" . smart-beginning-of-line))
  :init
  (defun smart-beginning-of-line ()
    "Move point to first non-whitespace character or beginning-of-line.

Move point to the first non-whitespace character on this line.
If point was already at that position, move point to beginning of line."
  (interactive)
  (let ((oldpos (point)))
    (back-to-indentation)
    (and (= oldpos (point))
	   (beginning-of-line)))))

paredit

Un modo menor para la edición de paréntesis. Para aprender qué hace este modo menor y sus posibilidades, ver The Animated Guide to Paredit.

(use-package paredit
  :diminish paredit-mode
  :config
  (add-hook 'emacs-lisp-mode-hook 'enable-paredit-mode)
  (add-hook 'lisp-mode-hook 'enable-paredit-mode)
  (add-hook 'lisp-interaction-mode-hook 'enable-paredit-mode)
  (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
  (add-hook 'ielm-mode-hook             #'enable-paredit-mode)
  (add-hook 'scheme-mode-hook           #'enable-paredit-mode))

Move-text

Mover texto a voluntad

(use-package move-text
  :config (move-text-default-bindings))

Otros

golden-ratio-scroll-screen

Subraya la linea anterior y la siguiente luego de hacer saltar de linea el cursor del mouse

(use-package golden-ratio-scroll-screen
  :config
  (global-set-key [remap scroll-down-command] 'golden-ratio-scroll-screen-down)
  (global-set-key [remap scroll-up-command] 'golden-ratio-scroll-screen-up))

mustache

(use-package mustache-mode)

fixmee

  • Refiled on [2015-11-12 jue 16:49]
Subraya cualquier termino “TODO” en cualquier modo mayor de programación.
(use-package fixmee
  :diminish fixmee-mode
  :defer 5
  :config
  (add-hook 'prog-mode #'fixmee-mode))

all-the-icons

Paquete de utilidades para formatear varios fuentes de iconos dentro de Emacs

(use-package all-the-icons)

(use-package all-the-icons-dired
  :init
  (add-hook 'dired-mode-hook 'all-the-icons-dired-mode))

mode-line

Los caracteres en el mode-line de Emacs pueden ser modificados ¿No es genial? (según The Cliffs of Inanity, también lunarsite. referencias sobre mode-line-format en la referencia de Elisp)

Utilidades

(defvar shackra-vc-mode nil)
(make-variable-buffer-local 'shackra-vc-mode)

(require 'vc)
(defun shackra-vc-command-hook (&rest args)
  (let ((file-name (buffer-file-name)))
    (setq shackra-vc-mode (and file-name
                               (not (vc-registered file-name))
                               (ignore-errors
                                 (vc-responsible-backend file-name))))))

(add-hook 'vc-post-command-functions #'shackra-vc-command-hook)
(add-hook 'find-file-hook #'shackra-vc-command-hook)

(defun shackra-faicon-icon (icon &optional color help-echo)
  "Retorna una cadena de texto formateada con `propertize' de un icono de all-the-icons"
  (propertize (all-the-icons-faicon icon) 'face `(:foreground ,(or color "white") :height 1.3 :family ,(all-the-icons-faicon-family))
              'display '(raise -0.1) 'help-echo help-echo))

(defun shackra-flycheck-errors ()
  "Retorna una cadena con errores y warnings de Flycheck"
  (if flycheck-current-errors
      (let* ((count (flycheck-count-errors flycheck-current-errors))
             (warns (let-alist count
                      (or .warning 0)))
             (errors (let-alist count
                       (or .error 0)))
             (info (let-alist count
                     (or .info 0)))
             (messages nil))
        (when (> warns 0)
          (push (propertize (format "Adv: %s" warns) 'face 'flycheck-error-list-warning) messages))
        (when (> errors 0)
          (push (propertize (format "Err: %s" errors) 'face 'flycheck-error-list-error) messages))
        (when (> info 0)
          (push (propertize (format "Inf: %s" info) 'face 'flycheck-error-list-info) messages))
        (when (> (+ warns errors info) 0)
          (string-join messages ", ")))
    (propertize "Nada que reportar" 'face 'success)))

(defun shackra-vc-state ()
  "Revisa el estado VC del buffer"
  (if vc-mode
      (vc-state (buffer-file-name (current-buffer)))
    nil))

(defun shackra-buffer-vc-modified ()
  "Retorna iconos de acuerdo al estado VCS del buffer actual"
  (let ((vc-modified ""))
    (if (buffer-modified-p)
        (setf vc-modified (concat vc-modified (shackra-faicon-icon "exclamation-circle" "tomato" "Buffer modificado.")))
      (setf vc-modified (concat vc-modified (shackra-faicon-icon "check-circle" "medium sea green" "Guardado."))))
    (when (eq (shackra-vc-state) 'edited)
      (setf vc-modified (concat vc-modified " " (shackra-faicon-icon "exclamation-triangle" "tomato" "Cambios sin registrar en VCS remoto."))))
    (when (eq (shackra-vc-state) 'missing)
      (setf vc-modified (concat vc-modified " " (shackra-faicon-icon "trash" nil "Archivo sólo existe en VCS, no en el disco duro."))))
    (when (eq (shackra-vc-state) 'ignored)
      (setf vc-modified (concat vc-modified " " (shackra-faicon-icon "ban" nil  "Archivo ignorado"))))
    (when (eq (shackra-vc-state) 'added)
      (setf vc-modified (concat vc-modified " " (shackra-faicon-icon "plus" nil "Archivo será registrado en VCS en el siguiente commit."))))
    (when (eq (shackra-vc-state) 'unregistered)
      (setf vc-modified (concat vc-modified " " (shackra-faicon-icon "question" nil  "Archivo sin registrar al VCS."))))
    vc-modified))

(defun shackra-vc-info-slice (branch)
  "Recorta el nombre de la rama si es muy larga"
  (let ((size (length "issue-000"))
        (branch (format "%s" branch)))
    (if (> (length branch) size)
        (concat (substring branch 0 size) "")
      branch)))

(defun shackra-vc-info ()
  "Icono del sistema VCS y rama actual"
  (when vc-mode
    (cond ((string-match "Git[:-]" vc-mode)
           (let ((branch (mapconcat 'concat (cdr (split-string vc-mode "[:-]")) "-")))
             (concat
              (propertize (format " %s " (all-the-icons-faicon "git-square" :v-adjust -0.1)) 'face `(:foreground "orange" :height 1.3 :family ,(all-the-icons-octicon-family)))
              (propertize (shackra-vc-info-slice branch) 'face `(:foreground "orange")))))
          (t (format "%s" vc-mode)))))

(defun shackra-flycheck-status ()
  "Estado de Flycheck"
  (let* ((text (pcase flycheck-last-status-change
                 (`finished (shackra-flycheck-errors))
                 (`running     (propertize "En ejecución" 'face `(:foreground "deep sky blue")))
                 (`no-checker  (propertize "No existe revisor" 'face `(:foreground "dim grey")))
                 (`not-checked (propertize "Sin revisar" 'face `(:foreground "dim grey")))
                 (`errored     (propertize "Error con Flycheck" 'face `(:foreground "tomato")))
                 (`interrupted (propertize "Interrumpido" 'face `(:foreground "tomato")))
                 (`suspicious  (shackra-faicon-icon "question" "tomato")))))
    (propertize (concat (propertize "!Flyc" 'face 'flycheck-error-list-error) (propertize "{" 'face 'flycheck-error-list-error) text (propertize "}" 'face 'flycheck-error-list-error))
                'help-echo "Reporte de Flycheck para errores de alta y baja prioridad"
                'local-map (make-mode-line-mouse-map
                            'mouse-1 (lambda () (interactive) (flycheck-list-errors))))))

(defun shackra-virtualenv-name ()
  (when (boundp 'venv-current-name)
    (if venv-current-name
        (format "venv: %s" venv-current-name)
      "venv: -")))

mode-line-format

(setq-default mode-line-format
              '("%e"
                mode-line-front-space
                mode-line-buffer-identification
                "   "
                (:eval (concat
                        (shackra-buffer-vc-modified)
                        "  "
                        (shackra-vc-info)
                        "	"
                        (shackra-flycheck-status)
                        ))
                "	"
                mode-line-modes
                mode-line-misc-info))

telephone-line

  • Refiled on [2015-11-12 jue 16:50]
Soy como =powerline=, pero mejor
(use-package telephone-line
  :init
  ;; define una nueva cara
  (defface shackra-orange '((t (:foreground "black" :background "orange"))) "")
  ;; Cambia el estilo de los separadores
  (setq telephone-line-primary-left-separator 'telephone-line-cubed-left
        telephone-line-secondary-left-separator 'telephone-line-cubed-hollow-left
        telephone-line-primary-right-separator 'telephone-line-cubed-right
        telephone-line-secondary-right-separator 'telephone-line-cubed-hollow-right)
  (setf telephone-line-height 40)
  :config
  ;; Informa a telephone-line sobre la existencia de la nueva cara, llamada `orange'
  (add-to-list 'telephone-line-faces '(accent-orange . (shackra-orange . telephone-line-accent-inactive)))

  (telephone-line-defsegment shackra-line-buffer-segment ()
    (telephone-line-raw mode-line-buffer-identification))

  (telephone-line-defsegment shackra-vc-segment ()
    (if (shackra-vc-info)
        (telephone-line-raw (concat (shackra-buffer-vc-modified) "  " (shackra-vc-info)))
      (telephone-line-raw (shackra-buffer-vc-modified))))

  (telephone-line-defsegment shackra-flycheck-status-segment ()
    (telephone-line-raw (shackra-flycheck-status)))

  (telephone-line-defsegment shackra-venv-segment ()
    (shackra-virtualenv-name))

  (setf telephone-line-lhs
        '((accent . (shackra-line-buffer-segment))
          (nil .  (shackra-vc-segment shackra-flycheck-status-segment))))

  (setf telephone-line-rhs '((nil . (telephone-line-misc-info-segment telephone-line-major-mode-segment))
                             (accent-orange . (shackra-venv-segment))))
  (telephone-line-mode 1))

visual-line-mode

  • Refiled on [2015-11-12 jue 16:50]
Envuelve las filas de texto si son muy anchas visualmente en nuevas filas.
(setf visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))

notify

  • Refiled on [2015-11-12 jue 16:52]
Permite a emacs enviar notificaciones por DBus o diferentes medios. En este caso usare libnotify (el método definido no es multiplataforma).
(setf notify-method 'notify-via-libnotify)

vimish-fold

  • Refiled on [2015-11-12 jue 16:53]
Pleguar o desplegar bloques de texto. Asociado a @@html:<kbd>C-c v</kbd>@@.
(use-package vimish-fold
  :defer 10
  :config
  (bind-keys :prefix-map shackra-vimish-fold-map
             :prefix "C-c v"
             ("v" . vimish-fold-toggle)
             ("V" . vimish-fold-toggle-all)
             ("f" . vimish-fold)
             ("u" . vimish-fold-unfold)
             ("u" . vimish-fold-unfold-all)
             ("d" . vimish-fold-delete)
             ("D" . vimish-fold-delete-all)
             ("n" . vimish-fold-next-fold)
             ("p" . vimish-fold-previous-fold))
  (add-hook 'prog-mode #'vimish-fold-mode))

alert

(use-package alert
  :init
  (if (eq system-type 'windows-nt)
      (setf alert-default-style 'message)
    (setf alert-default-style 'libnotify)))

appt

  • Refiled on [2015-11-12 jue 16:53]
Appointments me alerta de mis citas o pendientes que tengo por hacer.
;; configuración adaptada de http://emacs.stackexchange.com/a/5821/690 Gracias
;; a http://redd.it/35kbf6
(use-package appt
  :after (alert)
  :if (not (eq system-type 'darwin))
  :ensure nil
  :init
  (setf appt-message-warning-time 10
        appt-display-interval (1+ appt-message-warning-time)
        appt-display-mode-line nil)
  ;; Muestra las citas como notificaciones en el manejador de ventanas
  (setf appt-disp-window-function 'shackra-appt-muestra-notificacion)
  ;;(setf appt-delete-window-function nil)
  (defun shackra-appt-muestra-notificacion (min-to-app new-time msg)
    "Envia notificaciones usando libnotify. Esto no funcionara si DBus no esta instalado y corriendo"
    ;; `min-to-app' puede ser una lista, o no.
    (if (atom min-to-app)
        (alert
         (if (<= (string-to-number min-to-app) 1)
             (format "<b>Cita en %s minuto</b>" min-to-app)
           (format "<b>Cita en %s minutos</b>" min-to-app))
         :title msg
         :mode 'Emacs-Org
         :severity 'high
         :persistent t)
      ;; no entiendo este trozo de código, pero asumo que itera una lista de
      ;; cosas por hacer.
      (dolist (i (number-sequence 0 (1- (length min-to-app))))
        (alert
         (if (<= (string-to-number (nth i min-to-app)) 1)
             (format "<b>Cita en %s minuto</b>" (nth i min-to-app))
           (format "<b>Cita en %s minutos</b>" (nth i min-to-app)))
         :title (nth i msg)
         :mode 'Emacs-Org
         :severity 'high
         :persistent t))))
  (defun shackra-appt-update-when-file-updated ()
    "Actualiza appt cuando ciertos archivos son actualizados"
    ;; si `org-directory' es prefijo en el nombre del archivo del buffer
    ;; actual, ejecuta la funcion `shackra-org-agenda-to-appt'
    (if (string-prefix-p org-directory (buffer-file-name))
        (shackra-org-agenda-to-appt)))
  (defun shackra-org-agenda-to-appt ()
    (interactive)
    (setf appt-time-msg-list nil)
    (org-agenda-to-appt))
  :config
  (shackra-org-agenda-to-appt)
  (run-at-time "12:05am" (* 24 3600) 'shackra-org-agenda-to-appt)
  (appt-activate t)
  ;; automáticamente actualiza las citas cuando el archivo cosasporhacer.org es
  ;; salvado (ahí es donde yo guardo mi lista de cosas por hacer, y mi agenda)
  (add-hook 'after-save-hook #'shackra-appt-update-when-file-updated))

uniquify

  • Refiled on [2015-11-12 jue 16:54]
(use-package uniquify
  :ensure nil
  :init
  (setf uniquify-buffer-name-style 'forward))

systemd

Modo mayor para editar archivos de servicio systemd.

(use-package systemd
  :config
  (add-hook 'systemd-mode-hook #'yas-minor-mode-on))

interfaz para AUR

(use-package aurel
  :init
  (setf aurel-download-directory "~/proyectos/aur/aurel")
  (setf aurel-aur-user-package-info-check t))

golden-ratio

Redimensiona las ventanas para hacer más cómoda la edición en cualquiera de ellas

(use-package golden-ratio
  :disabled
  :diminish golden-ratio-mode
  :init
  (setf golden-ratio-auto-scale nil)
  :config
  (golden-ratio-mode 1))

RSS feed

Lector de RSS feed dentro de Emacs

(use-package elfeed
  :bind (:map elfeed-show-mode-map (("." . elfeed-open-url)))
  :init
  (setf url-queue-timeout 30)
  (defun elfeed-open-url ()
    "Open an URL with eww"
    (interactive)
    (let* ((url-to-visit))
      (save-excursion
        (goto-char (point-min))
        (search-forward "Link: " nil t)
        (setf url-to-visit (thing-at-point 'url t)))
      (eww url-to-visit)))
  (defun elfeed-search-format-date (date)
    (format-time-string "%d-%m-%Y %H:%M" (seconds-to-time date)))
  ;; fuentes RSS feed
  (setf elfeed-feeds '(("https://www.aciprensa.com/rss/noticias.xml" Iglesia noticias)
                       ("http://feeds.feedburner.com/santodeldia" Iglesia santoral)
                       ("http://www.asianews.it/es.xml" Iglesia asía)
                       ("http://localhost:9077/feed/crhoy/atom" noticias nacionales)
                       ("http://localhost:9077/feed/rt-espanol/atom" noticias internacionales)
                       ("https://godotengine.org/rss.xml" godot gamedev)))
  :config
  (add-hook 'elfeed-new-entry-hook
            (elfeed-make-tagger :before "2 weeks ago"
                                :remove 'unread))
  (add-hook 'elfeed-new-entry-hook
            (elfeed-make-tagger :feed-url "\\.crhoy\\.com"
                                :entry-title "Video"
                                :remove 'unread)))

ws-butler

Eliminación de espacios de manera no obstrusiva

(use-package ws-butler
  :diminish ws-butler-mode
  :config
  (add-hook 'after-init-hook #'ws-butler-global-mode))

Mingus

Cliente para MPD

(use-package mingus
  :if (executable-find "mpd"))

Shackle

Como display-buffer-alist pero más sencillo

(use-package shackle
  :init
  (setq shackle-rules '(("\\`\\*helm.*?\\*\\'" :regexp t :align t :size 0.3)
                        ((circe-server-mode circe-channel-mode circe-query-mode) :ignore t)
                        (compilation-mode :select t :align 'right :size 0.3)))
  :config
  (add-hook 'after-init-hook 'shackle-mode))

pdf-tools

Mejor visor de PDFs para Emacs

(use-package pdf-tools
  :mode ("\\.pdf\\'" . pdf-view-mode))

Emojify 😏

Muestra imágenes de emojis en lugar de los caracteres utf-8

(use-package emojify
  ;; Este paquete sólo funciona si la versión de Emacs es mayor o igual a 24.3
  ;; y Emacs fue compilado con soporte para PNG
  :if (and (version<= "24.3" emacs-version) (image-type-available-p 'png))
  :bind (:map global-map ("C-!" . emojify-insert-emoji))
  :init
  (add-hook 'after-init-hook #'global-emojify-mode))
(use-package company-emoji
  :after (emojify)
  :config (add-hook 'text-mode-hook
                    (lambda ()
                      (add-to-list
                       (make-local-variable 'company-backends) '(company-emoji :with company-yasnippet)))))

free-keys

Muestra cuales combinaciones de teclas están libres para asignar. Asociado @@html:<kbd>C-h C-k</kbd>@@.

(use-package free-keys
  :bind (:map help-map
              ("C-k" . free-keys)))

Pocket

(use-package el-pocket
  :preface (require 'thingatpt)
  :bind (:map notmuch-show-mode-map ("l" . el-pocket-add-url-at-point))
  :init (defun el-pocket-add-url-at-point ()
          "Add URL at point to Pocket"
          (interactive)
          (let* ((url-shr (get-text-property (point) 'shr-url))
                 (url-at-point (thing-at-point 'url))
                 (url (or url-shr url-at-point)))
            (el-pocket-add-url url)))
  :config (el-pocket-load-auth))

highlight-indent-guides

Modo menor que subraya los niveles de identación en el buffer usando font-lock. Los anchos de identación son descubiertos de manera dinámica.

(use-package highlight-indent-guides
  :after (python-mode)
  :init
  (setf highlight-indent-guides-method 'fill)
  (add-hook 'python-mode 'highlight-indent-guides-mode))

Limitaciones

Este modo menor no funciona bien con otros modos menores que hacen uso de la propiedad display de los textos en el buffer o que modifican como se muestran los espacios en blanco como hace whitespace-mode. Más info: Limitations.

Manejador de procesos para el sistema

(use-package proced
  :ensure nil
  :if (or (string-equal system-type "gnu/linux") (string-equal system-type "gnu/kfreebsd")))

schrute-mode

Recuerda al usuario que hay una manera más eficiente de hacer algo

(use-package schrute
  :disabled
  :ensure nil
  :load-path "site-packages/dwight"
  :init
  (defun shackra-super-next-line ()
    (interactive)
    (ignore-errors (forward-line 3)))
  (defun shackra-super-previous-line ()
    (interactive)
    (ignore-errors (forward-line -3)))
  (defun shackra-super-left-char ()
    (interactive)
    (ignore-errors (left-char 3)))
  (defun shackra-super-right-char ()
    (interactive)
    (ignore-errors (right-char 3)))
  (defun shackra-super-forward-word ()
    (interactive)
    (ignore-errors (forward-word 3)))
  (defun shackra-super-backward-word ()
    (interactive)
    (ignore-errors (backward-word 3)))
  (setf schrute-command-repetitions 1)
  (setf schrute-lighter " 🐻 ")
  (setf schrute-shortcuts-commands '((shackra-super-next-line     . (next-line))
                                     (shackra-super-previous-line . (previous-line))
                                     (shackra-super-left-char     . (left-char))
                                     (shackra-super-right-char    . (right-char))
                                     (shackra-super-forward-word  . (forward-word))
                                     (shackra-super-backward-word . (backward-word))))
  (add-hook 'after-init-hook #'schrute-mode))

Yasnippet en todos los backends de Company

Company-mode siempre escogerá un backend a la vez, la única forma de hacer que muestre candidatos de auto-completado y candidatos yasnippet es agrupando los backends

;; http://emacs.stackexchange.com/questions/10431/get-company-to-show-suggestions-for-yasnippet-names
;; Add yasnippet support for all company backends
;; https://github.com/syl20bnr/spacemacs/pull/179

(defun company-mode/backend-with-yas (backend)
  (if (or (and (listp backend) (member 'company-yasnippet backend)))
      backend
    (append (if (consp backend) backend (list backend))
            '(:with company-yasnippet))))

(add-hook 'after-init-hook (lambda () (setf company-backends (mapcar #'company-mode/backend-with-yas company-backends))) t)

webpaste

Pega regiones o buffers completos en servicios como pastebin

(use-package webpaste
  :bind (("C-c C-p C-b" . webpaste-paste-buffer)
         ("C-c C-p C-r" . webpaste-paste-region)))

Chronos

Multiples temporizadores simultaneos

(use-package chronos
  :init
  (setf chronos-expiry-functions '(chronos-desktop-notifications-notify)))

docker 🐋

Utilidades para integrar Emacs y docker

(use-package docker)

(use-package docker-compose-mode)

(use-package dockerfile-mode
  :mode "Dockerfile\\'")

Depuración

(use-package realgud
  :init
  (setf realgud:ipdb-command-name "python -c \"from IPython import start_ipython; from sys import argv; start_ipython(['--simple-prompt', '-i', '-c', '%run -d {}'.format(' '.join(argv[1:]))])\""))

Temas

Establece cuales temás son seguros.

(setf custom-safe-themes '("f1a6cbc40528dbee63390fc81da426f1b00b4fc09a60fe35752f5838b12fbe0a" "51867fa64534ff7ca87fdc1537fbfffc168fa4673e3980850436dc87e31ef426" "3119b66b441eaa36acad473952dfdf901a5924b1fbc995b58477f031e12547c4" "f0b0710b7e1260ead8f7808b3ee13c3bb38d45564e369cbe15fc6d312f0cd7a0" "a27c00821ccfd5a78b01e4f35dc056706dd9ede09a8b90c6955ae6a390eb1c1e" "8aebf25556399b58091e533e455dd50a6a9cba958cc4ebb0aab175863c25b9a4" "d677ef584c6dfc0697901a44b885cc18e206f05114c8a3b7fde674fce6180879" "a8245b7cc985a0610d71f9852e9f2767ad1b852c2bdea6f4aadc12cce9c4d6d0" "3c83b3676d796422704082049fc38b6966bcad960f896669dfc21a7a37a748fa" "c74e83f8aa4c78a121b52146eadb792c9facc5b1f02c917e3dbb454fca931223" "134f38000f413a88743764983c751ac34edbec75a602065e2ae3b87fcf26c451" "930a202ae41cb4417a89bc3a6f969ebb7fcea5ffa9df6e7313df4f7a2a631434" "c5a044ba03d43a725bd79700087dea813abcb6beb6be08c7eb3303ed90782482" "9dae95cdbed1505d45322ef8b5aa90ccb6cb59e0ff26fef0b8f411dfc416c552" "3a727bdc09a7a141e58925258b6e873c65ccf393b2240c51553098ca93957723" "6a37be365d1d95fad2f4d185e51928c789ef7a4ccf17e7ca13ad63a8bf5b922f" default))

CANCELADO zenburn

  • State “CANCELADO” from [2018-03-28 mié 02:06]
    desactiva el tema
(use-package zenburn-theme
  :disabled
  :config
  (load-theme 'zenburn t))

Monokai

  • State “CANCELADO” from “CANCELADO” [2018-03-28 mié 17:25]
  • State “CANCELADO” from [2018-03-28 mié 16:55]
    desactiva el tema
(use-package monokai-theme
  :init
  ;; FIX: Arregla tipografia erronea en org-mode en Windows
  (when (and (eq system-type 'windows-nt) (> emacs-major-version 24))
    (add-hook 'window-setup-hook '(lambda () (load-theme 'monokai t))))
  :config
  (load-theme 'monokai t))