Mar 05 2014

Ejecucion de Swank (servidor Lisp) y Emacs (como cliente)

Tag: advancedoverdrive @ 10:42 pm

SLIME esta implementado de tal forma que puede ejecutarse el cliente Emacs desde un lado (slime.el) mientras el servidor Lisp en otra maquina distinta. Asi que en un host ejecutaremos emacs y le diremos a SLIME que conecte a una maquina remota.

Conectando a un Lisp remoto

Si queremos cargar swank sin ejecutar emacs de manera habitual, debemos ejecutar lo siguiente:
(load "/path/to/swank-loader.lisp")
(swank-loader:init)
Dentro de la imagen lisp que se esta ejecutando, tan solo debemos iniciar el servidor swank.
(swank:create-server)

Como vamos a tener tunneling en nuestra conexion mediante ssh, podemos indicar a sawnk que no use una conexion extra para la salida, de la siguiente forma:

(setf swank:*use-dedicated-output-stream* nil)

Si debemos realizar ciertas tareas tales como reconectar a swank, debemos mirar en otros argumentos de swank:create-server. Estos argumentos son:

:PORT : Puerto del servidor de escucha (por defecto es 4005).

:STYLE : Estilo de comunicacion

:DONT-CLOSE : Valor booleano que indica si el servidor continua aceptando conexiones despues de recibir la primera (por defecto es NIL). Util si tenemos procesos lisp ejecutandose por largo periodo de tiempo, donde conectariamos en diferentes momentos, en dicho caso deberiamos especificar :dont-close t.

:CODING-SYSTEM : Sistema de codificacion usado para la comunicacion entre Emacs y Lisp.

Un ejemplo completo con estos argumentos:

(swank:create-server :port 4005  :dont-close t :coding-system "utf-8-unix")

Mientras que en el lado de emacs deberiamos usar esto para dicha configuracion:

(setq slime-net-coding-system 'utf-8-unix)
(slime-connect "127.0.0.1" 4005)

Configurando el cliente Emacs

Desde aqui necesitamos crear un tunel ssh en el puerto 4005 desde nuestra maquina local hasta el puerto 4005 en la maquina remota.

$ ssh -L4005:127.0.0.1:4005 username@remote.example.com

Despues de esto podemos ejecutar SLIME mediante M-x slime-connect.

Configurando las translaciones pathname

Cuando ejecutamos swank remotamente, Emacs asume que los ficheros que se vayan a encontrar son ficheros normales. Sin embargo, si queremos slime-compile-and-load-file (C-c C-k) y slime-edit-definition (M-.) para trabajar correctamente, necesitamos encontrar algun modo de decirle a nuestro Emacs local que debe referirse a ficheros remotos.

Existen principalmente dos formas de hacer esto. La primera es usar mount, NFS o similar, el disco duro de la maquina remota sera visible en nuestro sistema de ficheros local como cualquier otro fichero. Sin embargo NFS es realmente lento, con bugs etc. Es por eso que la mejor forma es tener una conexion ssh y emacs con tramp-mode para hacer el resto. Lo que hacemos es decirle a Emacs como debe coger el fichero en una maquina remota y traducirlo en algo que tramp puede entender y acceder. cl:machine-instance devuelve el «hostname» para una maquina remota como hostname.domain.com.  Por lo que podemos tener algo asi:

(add-to-list 'slime-filename-translations
             (slime-create-filename-translator
              :machine-instance "hostname"
              :remote-host "hostname.domain.com"
              :username "user"))

Redireccion global de todo IO al REPL

Por defecto SLIME no cambia *standard-output*  y variantes fuera del REPL. Por lo que si tenemos cualquier otro thread el cual llama format, write-string, etc. La salida solo sera vista en *inferior-lisp* buffer o en la terminal. Por lo que podemos hacer es:

(run-in-new-thread
  (lambda ()
    (write-line "In some random thread.~%" *standard-output*)))

Para enviar la salida al buffer REPL de SLIME, de manera contraria a *inferior-lisp*, configuramos swank:*globally-redirect-io* a T.

El valor de esta variable solo es checkeado una vez cuando swank acepta la conexion. Por lo que debemos configurarlo mediante ~/.swank.lisp, ya que sino necesitaremos llamar a swank::globally-redirect-io-to-connection manualmente.

Conectando a SLIME de manera automatica

Para hacer que SLIME conecte a nuestro Lisp cualquiera que sea nuestro fichero lisp abierto, debemos anadir esto en nuestro .emacs:

(add-hook 'slime-mode-hook
          (lambda ()
            (unless (slime-connected-p)
              (save-excursion (slime)))))

Para entender un poco mejor la arquitectura de SLIME, Swank y Emacs podemos visualizar el siguiente grafico:

slime_swank


Mar 03 2014

Configuracion de Swank (servidor Lisp) y Emacs (como cliente)

Tag: advancedoverdrive @ 1:31 am

Swank (servidor Lisp) y Emacs (como cliente) puede ser altamente configurado, de manera que podemos desde elegir los estilos de comunicacion, comportamiento y hooks entre otras cosas.

2

Configuracion del grupo SLIME mediante customize

Cliente Emacs

La parte de Emacs de SLIME puede ser configurada con el sistema customize de Emacs, mas concretamente mediante M-x customize-group-slime. Dicho sistema de customizacion se describe a si mismo, por lo que el tutorial de SLIME y tambien aqui, nos centraremos en aquellas partes mas importantes u oscuras que necesitasen clarificaciones, aqui algunas variables que se pueden modificar.

slime-truncate-lines : por defecto es ‘t’, lo cual garantiza que las lineas no sean cortadas en los backtraces, listados de apropos, etc.

slime-complete-symbol-function : Se emplea para completar simbolos lisp, existen 3 posibles estilos: slime-simple-complete-symbol, slime-complete-symbol* y slime-fuzzy-complete-symbol. El valor por defecto es slime-simple-complete-symbol, el cual completa en el estilo usual de emacs.

slime-filename-translations : Controla la traduccion de ficheros entre Emacs  y el sistema Lisp. Esto es util si se ejecuta Emacs y Lisp en maquinas separadas las cuales no comparten un sistema de ficheros en comun o bien si se comparte el sistema de ficheros pero que tienen layouts differentes (como por ejemplo en SMB).

slime-net-coding-system : Para transmitir caracteres unicode entre Emacs y el sistema Lisp, es necesario configurar esta variable, por ejemplo como    (setq slime-net-coding-system ‘utf-8-unix). Ademas, paa mostrar los caracteres unicode dbeemos disponer de fuentes apropiadas.

Hooks:

slime-mode-hook : Este hook se ejecuta cada vez que el buffer entra en slime-mode. Ideal para configurar el buffer local, por ejemplo para activar slime-autodoc-mode.

slime-connected-hook : Este hook se ejecuta cuando SLIME establece conexion con el servidor Lisp.

sldb-hook : Se ejecuta despues de que SLDB sea invocado. Por  ejemplo anadiendo sldb-print-condition a este hook hara que todas las condiciones debuggeadas con SLDB sean registradas en el buffer REPL.

Swank

Por otra parte, existe el lado de Lisp como servidor, conocido como «Swank», que ofrece multiples variables que pueden ser configuradas. El fichero de inicializacion es ~/.swank.lisp el cual es automaticamente evaluado en el arranque y puede ser usado para modificar el valor de estas variables.

Estilo de comunicacion:

La configuracion mas importante se encuentra en SWANK:*COMMUNICATION-STYLE*, el cual especifica el mecanismo por el cual Lisp lee y procesa los mensajes de protocol desde Emacs. La eleccion del estilo de comunicacion tiene una influencia global en las operaciones SLIME. Los diferentes estilos de comunicacion son los siguientes:

NIL : Simplemente hace loop del input de lectura del socket de comunicacion y da servicio a los eventos del protocolo SLIME.

:FD-HANDLER : Utiliza el clasico estilo UNIX select() loop. Swank registra el socket de comunicacion con un framework de evento dispatch (e.g. SERVE-EVENT en CMUCL y SBCL) y recibe un callback cuando los datos estan disponibles.

:SIGIO : Este estilo usa senales I/O con un manejador de senales SIGIO. Lisp recibe peticiones de Emacs con una senal, causando la interrupcion sin importar que se este haciendo para asi dar servicio a la peticion. Esto permite a Emacs lanzar peticiones de manera concurrente.

:SPAWN : Utiliza soporte multiproceso en el sistema Lisp para ejecutar cada peticion en un thread separado, pero en este caso no se emplean senales, ademas las peticiones son procesadas por Emacs y pueden ser ejecutadas de manera paralela.

El estilo para el manejo de peticiones es elegido dependiendo del soporte de nuestro sistema Lisp. El orden general por preferencia es; :SPAWN, :SIGIO, :FD-HANDLER, NIL.

Otras configuraciones:

Las siguientes variables Lisp pueden ser configuradas mediante el fichero ~/.swank.lisp:

SWANK:*CONFIGURE-EMACS-INDENTATION* : Controla el estilo de identacion para los argumentos &body en las macros que son descubiertas y enviadas a Emacs. Esta opcion esta activada por defecto.

SWANK:*GLOBALLY-REDIRECT-IO* : Cuando esta activada, causa que los streams standars (*standard-output*, etc) sean globalmente redireccionados al REPL en Emacs. Si el valor es NIL (que es por defecto) estos streams son solo redireccionados de manera temporal a Emacs usando bindings dinamicos mientras se manejan las peticiones. *standard-input* nunca es redireccionado a Emacs, debido a que puede interactuar de manera erronea con el REPL nativo de Lisp.

SWANK:*GLOBAL-DEBUGGER* : Cuando es true (opcion por defecto) causa que *DEBUGGER-HOOK*  sea globalmente configurado a SWANK:SWANK-DEBUGGER-HOOK y por lo tanto SLIME manejara todo el debugging en una imagen Lisp. Se utiliza para debugging en multithread y aplicaciones callback-driven.

SWANK:*SLDB-QUIT-RESTART* : Nombra el reinicio que es invocado cuando se pulsa q (para sldb-quit) en SLDB. Para la evaluacion de peticiones SLIME esto es usado de manera incondicional para reiniciar y volver a un punto seguro. Ejemplo:  (setf swank:*sldb-quit-restart* ‘sb-thread:terminate-thread)

SWANK:*BACKTRACE-PRINTER-BINDINGS*, SWANK:*MACROEXPAND-PRINTER-BINDINGS*, SWANK:*SLDB-PRINTER-BINDINGS*, SWANK:*SWANK-PPRINT-BINDINGS* : Estas variables se emplean para configurar el printer en distintas situaciones. Por ejemplo para activar el pretty printer para el formato de los backtraces en SLDB podemos emplear:  (push ‘(*print-pretty* . t) swank:*sldb-printer-bindings*).

SWANK:*USE-DEDICATED-OUTPUT-STREAM* : Esta variable controla el uso para hackear una eficiencia insegura cuando enviamos a la salida para impresion desde Lisp a Emacs. El valor por defecto es nil. Se recomienda no cambiar el valor de esta variable, ya que cuando es t, un socket separado se establece desde Lisp para enviar a la salida de impresion para Emacs, el cual es mas rapido que enviar la salida en los mensajes de protocolo a Emacs. Sin embargo, no esta garantizado el tiempo entre la salida de stream dedicada y la salida de mensajes de protocolo, por lo que la salida de un comando Lisp puede llegare antes o despues de los correspondientes resultados de REPL, o bien llegar en orden incorrecto, e incluso interferidos en el buffer REPL.

SWANK:*DEDICATED-OUTPUT-STREAM-PORT* : Cuando *USE-DEDICATED-OUTPUT-STREAM* es t, el stream sera abierto en este puerto. El valor por defecto es 0, lo que significa que el stream sera abierto en un puerto aleatorio.

SWANK:*LOG-EVENTS* : Configurando esta variable t causara que todos los mensajes de protocolos intercambiados con Emacs seran mostrados en *TERMINAL-IO*. Esto es util para debugging a bajo nivel y para observar como SLIME trabaja ‘on the wire’. La salida de *TERMINAL-IO* puede ser mostrada en nuestro propio listener de nuestro sistema Lisp, usualmente en el buffer *inferior-lisp*.

1

Ejemplo de configuracion del puerto para el servidor de Swank.


May 22 2013

SLIME avanzado

Tag: advancedoverdrive @ 11:37 pm

Algunas funcionalidades y usos de SLIME no es tan basico como las opciones que comentabamos en posts anteriores. Ademas de SLDB que comentabamos en el post anterior, existen muchas otras opciones que hacen de SLIME un gran modo para trabajar en nuestro entorno GNU/emacs.

SLIME Selector

El comando slime-selector es empleado para cambiar de forma rapida entre buffers importantes: REPL, SLDB, el codigo fuente Lisp donde hackeamos, etc. Una vez invocado el prompt, nos permite usar una letra especifica para indicar que buffer queremos mostrar:

? : Muestra ayuda sobre los buffers disponibles de slime-selectors.

r : El buffer REPL para la conexion SLIME actual.

d : El buffer SLDB empleado mas recientemente activado para la conexion actual.

l : El buffer de codigo empleando lisp-mode usado mas recientemente.

s : Buffer *slime-scratch*.

c : Buffer de conexion Lisp.

n : Ciclo hacia la siguiente conexion Lisp.

t : SLIME threads buffer.

SLIME Macroexpansion

Con los buffers de SLIME existen comandos extra empleados especificamente para la expansion de macros.

C-c C-m : ‘slime-macroexpand-1-inplace‘ ; Como slime-macroexpand-1 pero en la forma original es reemplazado con la expansion.

g : ‘slime-macroexpand-1-inplace‘ : La ultima expansion de macros es realizada de nuevo, los contenidos actuales del buffer de la expansion de macros son reemplazados con la nueva expansion.

q : ‘slime-temp-buffer-quit‘ ; Cierra el buffer de expansion.

C-_ : ‘slime-macroexpand-undo‘ ; Deshace la ultima operacion de expansion de macros.

Multiples conexiones con SLIME
SLIME es capaz de conectar a multiples procesos Lisp al mismo tiempo. Cuando el comando M-x slime es invocado con argumentos de prefijo, se ofrecera un proceso Lisp adicional si actualmente uno esta siendo ejecutado. Esto resulta conveniente, pero requiere el conocimiento suficiente y estar seguro de que los comandos SLIME son ejecutados en el sistema Lisp que deseamos. Por lo tanto, algunos buffers estaran asociados a procesos Lisp especificos. Cada conexion Lisp tendra eso si, su propio buffer REPL, y todas las expresiones introducidas o comandos SLIME seran invocados en este buffer y enviados a la conexion asociada. Otros buffers creados por SLIME estaran asociados a las conexiones que originaron dicho buffer, incluyendo por ejemplo buffers SLDB, resultado de listados de apropos, etc. Estos buffers son el resultado de alguna interaccion con los procesos Lisp, por loque los comandos en ellos seran siempre enviados al mismo proceso. Ademas, cabe resaltar que comandos ejecutados en otras partes, como los buffers de codigo que empleen slime-mode, estaran siempre asociados a la conexion por defecto; usualmente esta sera la conexion establecida mas recientemente, aunque esto puede ser reasignado mediante el buffer «connection list»:
C-c C-x c : ‘slime-list-connections‘ ; Muestra el listado de buffers de las conexiones establecidas (es equivalente a pulsar c desde el SLIME selector).
C-c C-x n : ‘slime-cycle-connections‘ ; Cambia las conexiones Lisp actuales moviendose por todas las conexiones (es equivalente a pulsar n desde SLIME selector)
C-c C-x t : ‘slime-list-threads‘ ; Muestra el listado de threads actuales (es equivalente a pulsar t desde SLIME selector).
El buffer mostrado mediante slime-list-connections nos dara un sumario de una linea por conexion. Dicho sumario muestra la lista de conexiones mediante un numero de serie, el nombre de la implementacion Lisp, asi como otros detalles del proceso Lisp. La conexion actual por defecto es indicada mediante un asterisco.
RET : ‘slime-goto-connection‘ ; Hace pop del buffer REPL de la conexion en el punto actual.
d : ‘slime-connection-list-make-default‘ ; Crea una conexion en el punto actual para la conexion por defecto. Esto sera usado para comandos en los buffers de codigo con slime-mode.
g : ‘slime-update-connection-list‘ ; Actualiza la lista de conexiones en el buffer.
q : ‘slime-temp-buffer-quit‘ ; Sale de la lista de conexiones (elimina el buffer y reestablece la configuracion de ventanas).
R : ‘slime-restart-connection-at-point‘ ; Reinicia el proceso Lisp para la conexion en el punto actual.
(sin keybinding asociada) : ‘slime-connect‘ ; Conecta a un servidor ejecutando Swank.
(sin keybinding asociada) : ‘slime-disconnect‘ ; Desconecta todas las conexiones.
(sin keybinding asociada) : ‘slime-abort-connection‘ ; Aborta el intento de conexion actual.
Selection_003
SLIME empleando multiples conexiones a sistemas Lisp, listando las conexiones, threads y eventos.

« Página anteriorPágina siguiente »