Etiqueta: emacs

Recargar el navegador desde Emacs

Aunque Emacs no suele aparecer entre los editores preferidos para desarrollo web sigue teniendo opciones que lo hacen interesante.

En este artículo vamos a comentar algunos «plugins» que nos ayudan a recargar el navegador automáticamente cuando hacemos cambios en el código. No todos funcionan en las últimas versiones de Emacs, pero los dejo en el artículo para saber lo que hay disponible, o al menos lo que no merece la pena probar.

Conclusiones

Para quien quiera ir directo al grano el que me parece más recomendable en este momento es Mini Kite Mode, que se comenta al final de listado y que descubrí a través de esta pregunta de stackoverlow. En las respuestas se mencionan algunos complementos para emacs para trabajar con desarrollo web que no he probado y que también podrían ser interesantes pero están todos desactualizados.

Listado de plugins

Impatient Mode

Uno de los limitantes de Impatient Mode es que hay que habilitar el impatient-mode por cada uno de los buffers que se quieran observar. Aunque supongo que se puede configurar de algún modo algún hook para que automáticamente habilite la observación en los buffers abiertos con determinadas extensiones.

Tras habilitar el modo M-x impatient-mode y lanzar el servidor M-x httpd-start tendremos en localhost un navegador que escuche los cambios http://localhost:8080/imp/

Otro de sus problemas es que lo que parece hacer, es cargar dentro de un iframe la web que estamos editando en emacs, y desde el código html/js en el que está empotrado el frame se hace un pooling cada cierto tiempo para ver si el contenido cambia y recargar. Empotrar tu código dentro de un iframe al final excepto para casos sencillos puede ser problemático y el sistema de pooling tampoco es muy efectivo en la práctica, porque cada pocas pulsaciones de teclas se hace un refresco de la página.

Skewer Mode

Para hacer funcionar Skewer Mode seguramente haya que hacer un par de pruebas, pero hay un vídeo y una pregunta de stackexchange que pueden ayudar.

La parte interesante de este modo es que permite abrir un buffer en modo REPL para javascript. De modo que podemos evaluar el código js directamente en emacs como si estuvieramos usando la consola del navegador. O podemos editar nuestra fuente javascript y relanzar una función o porciones de código al navegador.

Uno de los mayores limitante es que la recarga no es automática, y en el modo html funciona tag a tag. Es decir, no podemos reenviar el buffer entero al navegador, si no sólo los tags que nos interesen. Lo que hace es modificar el dom, para actulizar el contenido de los tags. No lo he encontrado especialmente cómodo, pero tiene algunas extensiones que podrían simplificar el trabajo como skewer-less o skewer-reload-stylesheets.

Emacs browser refresh

Browser refresh es una idea sencilla e interesante. Basicamente usa xdotool, una herramienta que permite scriptear movimiento de ratón y pulsaciones de teclas, para poner la ventana del navegador en foco y pulsar «F5», cuando le damos a salvar. El script original no funciona del todo bien, y aunque es fácil de arreglar es una solución «error prone». Si tenemos varias ventanas del navegador abiertas, o hemos cambiado de pestaña puede funcionar incorrectamente.

GC Refresh Mode

De nuevo una buena idea pero el código de GC Refresh Mode está desactualizado y no funciona. Al activar el modo M-x gc-refresh-mode pregunta la url a recargar, que puede ser un http://localhost o un file:///, abre esa uri en chrome en modo remote-debugging y sobreescribe C-x C-s para que al recargar se ejecute un script en python. El script en python es una implementación muy sencilla del Chrome Debugging Protocol que conecta a un socket con el que comunicarse con la instancia del navegador que abrió antes, busca la pestaña donde está la uri de interés y la recarga.

El problema es que Chrome ya no usa exactamente este sistema y el script no funciona. Este plugin está inspirado en la página de Save And Reload Browser del Emacs Wiki.

chrome-reload-page

Basándose en la idea de GC Refresh Mode hace algún tiempo escribí un ejemplo de código (funcional) que acabó de subir a github.

Este script usa el Chrome debugging protocol para recargar la pestaña. El script lleva empotrado el código de python del fork de max-weller de chrome_remote_shell para ahorrar trabajo.

Mini Kite Mode

Mini Kite Mode es la más funcional de las opciones de este artículo.

Se puede instalar directamente desde MELPA. Para usarlo añadiremos a nuestro .emacs, las siguientes líneas.

(require 'kite-mini)
(require 'kite-mini-console)
# Automatically Turn on the mode for your buffer of choice.
(add-hook 'js-mode-hook (lambda () (kite-mini-mode t)))
(add-hook 'css-mode-hook (lambda () (kite-mini-mode t)))
(add-hook 'html-mode-hook (lambda () (kite-mini-mode t)))

El segundo require sólo es necesario si queremos abrir un buffer de Emacs como una consola js en modo REPL (similar a la consola de DevTools). Y los hooks permiten activar el modo para los buffers de interés en tener que activarlo a mano M-x kite-mini-mode

Una vez en un buffer (y través a ver lanzado chrome / chromium en modo remote debug) simplemente conectamos con

M-x kite-mini-connect

Si la pestaña que tenemos abierta es con la que queremos interactual podemos simplemente pulsar intro. A partir de ese momento podemos lanzar la consola de js, enviar una región al navegador para que sea evaluada, o recargar la pestaña.

El mayor problema, de esta herramienta, y en realidad de todas las que usen el Remote Debug, es que sóla una herramienta puede estar conectada mediante el protocolo a la vez, y las DevTools hace uso de este sistema también. De modo que si kite está conectado y se abren las DevTools kite se desconectará. Y si son las DevTools las que estan activadas cuando hacemos kite-mini-connect, kite no llegará a conectar.

Para simplificar un poco el flujo he editado el fichero de ~/.emacs.d/elpa/kite-mini-20160508.406/kite-mini-el para que antes de hacer el reload salve el buffer, quedando así

(defun kite-mini-reload ()
(interactive)
(save-buffer)
(kite-mini-call-rpc
"Page.reload"
(list :ignoreCache t)))

De este modo al pulsar C-c C-r, primero salva y luego recarga. El siguiente paso, sería que mientras esté conectado, pulsar C-x C-s salve el buffer y recargue, pero por ahora con esto me llega.

Emacs y análisis estático de código en python

Gracias a Cartolab he podido seguir dándole una vuelta al análisis de código estático en python. La idea era reducir los incómodos errores que se producen porque te equivocas al escribir el nombre de una variable o cosas parecidas de las que no te das cuenta has que ejecutas el código. Tratar de detectar estos errores de la forma en que lo veíamos en el artículo anterior sigue sin ser demasiado productivo y aquí es donde entra en juego la extensión para emacs Flymake.

Lo que hace Flymake es «pedirle» a emacs que esté continuamente realizando ciertos análisis sobre el código o tratando de compilarlo y/o ejecutarlo. En realidad flymake es un plugin bastante genérico que funciona del siguiente modo:

  1. Si al abrir un nuevo buffer está marcado como «a chequear», flymake programa un temporizador para el buffer. La forma de marcar buffers suele ser en función de la extensión del archivo que abramos
  2. Crea una copia temporal de los buffers abiertos cada cierto tiempo
  3. Ejecuta un programa externo sobre la copia del buffer. Este programa puede ser gcc, make u otra cosa como una herramienta de análisis estático de código.
  4. Parsea la salida que produce el programa externo y da una salida visual en el buffer actual para representar los posibles errores.

Activar flymake

Activar flymake junto a alguna de las herramientas que veíamos en el post anterior es bastante fácil. Flymake viene instalado por defecto, así que sólo tenemos que tener en el path los ejecutables a las herramientas de análisis, y añadir a nuestro .emacs las instrucciones para que se activen con los ficheros python.

flymake con pyflakes:

(when (load "flymake" t)
(defun flymake-pyflakes-init ()
(let* ((temp-file (flymake-init-create-temp-buffer-copy
'flymake-create-temp-inplace))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "pyflakes" (list local-file))))
(add-to-list 'flymake-allowed-file-name-masks'("\\.py\\'" flymake-pyflakes-init)))

flymake con pylint (el comando epylint es un modo especial de pylint para trabajar con emacs)

(when (load "flymake" t)
(defun flymake-pylint-init ()
(let* ((temp-file (flymake-init-create-temp-buffer-copy
'flymake-create-temp-inplace))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "epylint" (list local-file))))
(add-to-list 'flymake-allowed-file-name-masks'("\\.py\\'" flymake-pylint-init)))

flymake con pep8
(when (load "flymake" t)
(defun flymake-pylint-init ()
(let* ((temp-file (flymake-init-create-temp-buffer-copy
'flymake-create-temp-inplace))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "pep8.py" (list "--repeat" local-file))))
(add-to-list 'flymake-allowed-file-name-masks'("\\.py\\'" flymake-pylint-init)))

Por otro lado también podriamos configurar flymake para hacer que se pasarán las tres herramientas de forma automática pero yo lo veo innecesario dado que la información que proporcionan es en muchos casos redudante y estamos disminuyendo el rendimiento del ordenador.

Además de indicarle a flymake con que herramienta queremos trabajar, tenemos que activarlo para los buffers que nos interesen. Esto podemos hacerlo de varios modos:

  • Manual. Activando el modo menor de flymake. M-x flymake-mode
  • Que active el modo menor flymake cuando estemos en el modo python. Añadiendo al .emacs
    (add-hook 'python-mode-hook 'flymake-mode)
  • O que active el modo flymake en base a las extensiones de fichero que le hemos pasado anteriorme (flymake-allowed-file-name-masks)
    (add-hook 'find-file-hook 'flymake-find-file-hook)

Configurar flymake

Por defecto flymake ilumina (highlight) la línea de código donde se produce el error, empleando un color u otro en función de si es un error o un warning. Al dejar el ratón encima de la línea con el error (hover) nos muestra la descripción del error.

Para cambiar los colores que se emplean por defecto podemos emplear algo parecido a esto:

'(flymake-errline ((((class color)) (:background "LightPink" :foreground "black"))))
'(flymake-warnline ((((class color)) (:background "LightBlue2" :foreground "black"))))

Para que subraye en lugar de hacer highlight de la línea con el error:

'(flymake-errline ((((class color)) (:underline "red"))))
'(flymake-warnline ((((class color)) (:underline "yellow")))))

Para hacer que el fringe derecho se muestre un indicador de en que líneas hay errores podemos usar rfringe. Aunque yo no he sido capaz de hacerlo funcionar.

Mostrar la descripción del error en el minibuffer. Esto es imprescindible cuando se trabaja en modo -nw.

(defun my-flymake-show-help ()
(when (get-char-property (point) 'flymake-overlay)
(let ((help (get-char-property (point) 'help-echo)))
(if help (message "%s" help)))))
(add-hook 'post-command-hook 'my-flymake-show-help)

Aunque el código anterior a mi me funciona, para mostrar el error en el minibuffer se suele emplear el plugin flymake-cursor.

Moverse a través de los errores. Podemos emplear los comandos M-x flymake-goto-prev-error para ir al error anterior, o M-x flymake-goto-next-error para ir al siguiente. También podemos vincularlos a determinadas teclas:

(global-set-key [TECLA] 'flymake-goto-prev-error)
(global-set-key [TECLA] 'flymake-goto-next-error)

Links relacionados