Configuración de Emacs paso a paso (03)

Nota
Este artículo se actualizó por última vez el 2022-04-22, es posible que el contenido no esté actualizado.

Continuamos configurando nuestro Emacs, paquetes generales para programar. Projectile, Magit, Yasnippet, Flycheck y Company.

Tengo que comentar que uso Emacs como cliente la mayor parte del tiempo. Eso hace que Emacs se arranque una sola vez (por sesión) como servidor y las sucesivas llamadas a Emacs abren buffers en la misma instancia.

Para trabajar de esta forma he creado alias para invocar el editor. En zsh es fácil sin más que instalar el bundle emacs de oh-my_zsh, que añade alguna funcionalidad a mayores. Pero si no usas zsh ni oh-my-zsh te valdría con estos alias:

1
2
3
alias ef='emacsclient -create-frame --alternate-editor=""'
alias e='emacsclient --alternate-editor=""'
alias gemacs='/usr/bin/emacs'

Se trata de tener alias que llamen siempre a emacsclient, en caso de necesidad tenemos un alias que llama al Emacs original.

Trabajar de esa forma es mucho más rápido y carga menos al sistema pero tiendes a acumular un montón de ficheros abiertos (buffers en _Emacs).

Mi atajo C-del, o sea control-suprimir para cerrar los buffers y el uso del paquete projectile (C-c p k cierra todos los buffers del proyecto activo) me ayudan a mantener acotado el número de ficheros abiertos.

projectile

projectile identifica un arbol de directorio como proyecto si es un repo de git (considera también otros sistemas de control de versiones, pero yo sólo uso git) o si creamos un fichero .projectile (puede estar vacío)

Con el uso normal que hagamos de nuestro editor projectile va recopilando “proyectos” y los apunta en un fichero en el directorio ~/.emacs.d

Con la configuración propuesta tenemos muchísimos atajos de teclado para invocar a projectile, en la página de _counsel-projectile podemos ver un amplio listado.

Si invocamos C-c p gracias a which-key veremos los comandos de projectile a nuestra disposición. Los que más uso son:

C-c p p: Cambiar de proyecto C-c p f: Abrir fichero en el proyecto actual C-c p b: Ir a un buffer (un fichero ya abierto en Emacs) del proyecto actual C-c p k: Cerrar todos los buffers del proyecto actual.

Durante mi sesión de trabajo suelo cambiar a un proyecto C-c p p y abrir los ficheros necesarios en el proyecto que esté trabajando C-c p f y terminar cerrando todos los ficheros del proyecto al final C-c p k

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
* projectile
#+begin_src emacs-lisp
  (use-package projectile
    :ensure t
    :config
    (projectile-global-mode)
    (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
    (setq projectile-completion-system 'ivy)
    )

  (use-package counsel-projectile
    :ensure t
    :config
    (setq counsel-projectile-mode t)
    )
#+end_src

git: Magit y git-gutter

Dos paquetes para interactuar con git: Magit y git-gutter

Magit es un super paquete, con una versatilidad y utilidad a la altura del org-mode, por si solo ya justifica usar Emacs. En el artículo A walkthrought the Magit interface tenemos una excelente introducción al uso de este paquete que nos permite hacer todas las operaciones de git sin salir de nuestro editor. Pero no solo eso, magit también hará que si usamos Emacs como editor configurado en git se use toda la potencia de Magit al editar los mensajes de commits. C-c g Nos llevará a la ventana de estado de Magit

Por su parte git-gutter marcará las lineas que estamos editando en cualquier fichero que esté monitorizado por git, como si tuviéramos activado un diff en tiempo real, además con el arbol hydra configurado podemos navegar por los cambios hechos en el fichero y hacer commits de cambios atómicos(pasar al stage solo los cambios en el fichero que nos interesen) M-g M-g abre la hydra de git-gutter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
* git
#+begin_src emacs-lisp
  (use-package magit
    :ensure t
    :init
    (progn
      (bind-key "C-x g" 'magit-status)
      )
    )

  (setq magit-status-margin
        '(t "%Y-%m-%d %H:%M " magit-log-margin-width t 18))

  (use-package git-gutter
    :ensure t
    :init
    (global-git-gutter-mode +1)
    )

  (global-set-key (kbd "M-g M-g") 'hydra-git-gutter/body)

  (use-package git-timemachine
    :ensure t
    )

  (defhydra hydra-git-gutter (:body-pre (git-gutter-mode 1)
                              :hint nil)
    "
    Git gutter:
      _j_: next hunk        _s_tage hunk     _q_uit
      _k_: previous hunk    _r_evert hunk    _Q_uit and deactivate git-gutter
      ^ ^                   _p_opup hunk
      _h_: first hunk
      _l_: last hunk        set start _R_evision
    "
    ("j" git-gutter:next-hunk)
    ("k" git-gutter:previous-hunk)
    ("h" (progn (goto-char (point-min))
                (git-gutter:next-hunk 1)))
    ("l" (progn (goto-char (point-min))
                (git-gutter:previous-hunk 1)))
    ("s" git-gutter:stage-hunk)
    ("r" git-gutter:revert-hunk)
    ("p" git-gutter:popup-hunk)
    ("R" git-gutter:set-start-revision)
    ("q" nil :color blue)
    ("Q" (progn (git-gutter-mode -1)
                ;; git-gutter-fringe doesn't seem to
                ;; clear the markup right away
                (sit-for 0.1)
                (git-gutter:clear))
     :color blue))
#+end_src

yasnippet

yasnippet nos permite usar plantillas para bloques muy usados. Por ejemplo si estamos programando, digamos en python, podemos tener plantillas para los bloques for o para un bloque if-else o para la cabecera de ficheros, etc. Junto con yasnippet he instalado yasnippets-snippets que es una buena colección de snippets predefinidos.

Puedes crear fácilmente tus propios snippets (echa un ojo a la documentación)

Como complemento instalo también el paquete auto-yasnippet que permite crear un snippet “al vuelo” mientras estás editando.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
* yasnippet
Place your own snippets on ~/.emacs.d/snippets
  #+begin_src emacs-lisp
    (use-package yasnippet
      :ensure t
      :config
      :init
      (yas-global-mode 1)
      )
    (use-package auto-yasnippet
      :ensure t
      )
    (use-package yasnippet-snippets
      :ensure t)
  #+end_src

A mayores añadimos un par de atajos de teclado para definir un auto-snippet y para expandirlo. He asignado la combinación C-ñ como prefijo para mi own-map pero podeis asignar cualquier combinación libre, como por ejemplo C-z

flycheck

flycheck nos dará detección de errores sintácticos cuando estamos programando.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
* flycheck
  #+begin_src emacs-lisp
    (use-package flycheck
      :ensure t
      :config
      (global-set-key  (kbd "C-c C-p") 'flycheck-previous-error)
      (global-set-key  (kbd "C-c C-n") 'flycheck-next-error)
      :init
      (global-flycheck-mode t)
      )
  #+end_src

auto-complete o company

Hay dos escuelas principales de auto completado en Emacs: podemos usar el paquete auto-complete o el paquete company. Yo de momento estoy usando auto-complete, pero estoy probando company que parece que da menos problemas de compatibilidad con los paquetes que uso para programar en python.

Los ficheros de configuración basados en auto-complete quedan en el repositorio de gitlab (ver sección ficheros para descargar) en la rama auto-complete. Los he usado durante varios meses sin demasiados problemas. Para el resto de esta serie vamos a utilizar una configuración basada en company.

company

company es un paquete muy modular que se complementa con _plugins para distintas tareas, a medida que vayamos añadiendo nuevas secciones para distintos entornos de programación iremos añadiendo los plugins necesarios.

De momento vamos a añadir la configuración básica de company:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
* company
  Autocompletion with company
  #+begin_src emacs-lisp
    (use-package company
      :ensure t
      :config
      (setq company-idle-delay 0)
      (setq company-minimum-prefix-length 3)
      (global-company-mode t)
      )
  #+end_src

  ** company-quickhelp
   In case you want popup help instead of status line help
  #+begin_src emacs-lisp
    (use-package company-quickhelp
      :ensure t
      :config
      (company-quickhelp-mode)
    )
  #+end_src

Ficheros para descargar

Los ficheros descritos: init.el y myinit.org puedes descargarlos desde este enlace

Los ficheros están almacenados en https://gitlab.com/comacero/emacs_conf_step e irán ampliándose a medida que publiquemos esta serie. En realidad el único fichero que tienes que actualizar es el myinit.org. El init.el debería cambiar automaticamente sin intervención de nadie.

Referencias