Equivalente a --no-wait for emacs

8

El emacsclientprograma permite una marca --no-wait(abreviada como -n) que hará que el servidor emacs visite el archivo especificado y regrese de inmediato.

emacsclient -n ~/.bashrc

Si proporciono un editor alternativo, esto seguirá funcionando en los casos en que no se esté ejecutando el servidor Emacs

emacsclient -n -a "/usr/local/bin/emacs" ~/.bashrc

Sin embargo, esto me da un comportamiento inconsistente porque en los casos en que el servidor se está ejecutando, esta llamada volverá de inmediato. En los casos en que no hay ningún servidor en ejecución y se utiliza el editor alternativo, la llamada se convierte en una llamada de bloqueo y no volverá hasta que salga de Emacs.

¿Hay alguna manera de decir emacs(en lugar de emacsclient) crear un nuevo marco y luego regresar?

nispio
fuente
1
Parece que te sientes cómodo proporcionando Emacs como tu editor alternativo. ¿Hay alguna razón por la que elige no utilizar la -a ''opción "iniciar el demonio Emacs y volver a intentar emacsclient"?
purple_arrows
@purple_arrows En mi experiencia, el uso -a ''iniciará un demonio en lugar de un servidor. Luego intenta abrir un terminal Emacs, pero debido a que he proporcionado la -nopción, no permanece abierto. Simplemente rebota de vuelta al caparazón.
nispio

Respuestas:

6

Descripción

El comportamiento predeterminado al invocar emacsclient es un poco conservador. Mira este comentario de emacsclient.c :

  /* Unless we are certain we don't want to occupy the tty, send our
     tty information to Emacs.  For example, in daemon mode Emacs may
     need to occupy this tty if no other frame is available.  */

Según su descripción y comentarios, parece que está intentando iniciar el servidor Emacs a pedido mientras también usa la -nbandera. El comentario "por ejemplo" aquí es por qué emacsclient -n -a '' FILEno satisface lo que está buscando cuando no se está ejecutando ningún servidor.

  1. La -a ''lógica inicia un demonio.
  2. Luego emacsclientle dice que cree un nuevo marco de terminal, porque ese es el valor predeterminado a menos que esté evaluando elisp.
  3. La -nlógica mata inmediatamente ese nuevo marco de terminal.

Si pudieras cambiar el Paso 2 para crear un nuevo marco gráfico por defecto, entonces emacsclient -n -a '' FILEharías lo que quieras.

Solución Elisp

Puede hacer que Emacs cree un nuevo marco gráfico de forma predeterminada si aconseja la función de esta server-process-filtermanera:

(defadvice server-process-filter (before prefer-graphical activate)
  ;; STRING is a sequence of commands sent from emacsclient to the server.
  (when (and
         ;; Check that we're editing a file, as opposed to evaluating elisp.
         (string-match "-file" string)
         ;; Check that there are no frames beyond the Emacs daemon's terminal.
         (daemonp)
         (null (cdr (frame-list)))
         (eq (selected-frame) terminal-frame)
         ;; Check that we have a graphical display.
         ;; `display-graphic-p' doesn't work here.
         (getenv "DISPLAY"))
    (setq string (concat
                  ;; STRING must be all one line, but comes to us
                  ;; newline-terminated.  Strip off the trailing newline.
                  (replace-regexp-in-string "\n$" "" string)
                  ;; Add the commands to create a graphical frame.
                  "-window-system "
                  "-display " (getenv "DISPLAY")
                  ;; Add back the newline.
                  "\n"))))

Pon eso en tu archivo de inicio, entonces, como se dijo, emacsclient -n -a '' FILEy Bob es tu tío.

Comparar con la solución Shell

Por un lado, puedo señalar algunas ventajas de usar este enfoque de desajuste en comparación con el uso del script sugerido por Archenoth

#!/bin/bash
emacs --eval '(server-start)' $* &

como el editor alternativo. Con el defadvice:

  1. save-buffers-kill-terminal( C-x C-cpor defecto) se comporta de manera consistente en todos los cuadros. Nunca mata el proceso de Emacs, porque cada marco es siempre un marco de cliente.
  2. El marco de la terminal del demonio se cuelga. Los comandos como find-grepese se envían a procesos externos se comportan mejor cuando la terminal tonta está allí. Al menos, experimento menos dolores de cabeza relacionados con escapar de la concha.

Por otro lado ... sí.

  1. Ese script de shell es maravillosamente simple.
  2. No es aconsejable el protocolo de comunicación de Emacs.

Conclusión

Tal vez hay un compromiso? Esto es lo mejor que se me ocurrió. Lo configuras como tu $ EDITOR.

#!/bin/sh

emacsclient -e "(frames-on-display-list \"${DISPLAY}\")" 1>/dev/null 2>/dev/null
if [ "$?" = "1" ]; then
    emacsclient -c -n -a "" "$@"
else
    emacsclient -n "$@"
fi
flechas_púrpura
fuente
Entonces, ¿cómo aconsejo una función cuando emacs no se está ejecutando?
nispio
Debería poder soltarlo en el archivo de inicio. El demonio lee ese archivo cuando se inicia y termina de leer antes de que emacsclient comience a enviar comandos. Así es como lo estoy haciendo, al menos.
purple_arrows
4

No estoy seguro de cómo hacerlo estrictamente dentro de Emacs, pero afortunadamente hay otras formas de obtener lo que usted describe.

Si no tiene algo .emacspara iniciar un servidor, siempre puede hacer un pequeño script que inicie Emacs con el archivo que desea editar e inicie el servidor bifurcado.

Algo como:

#!/bin/bash
emacs --eval '(server-start)' $* &

Y luego pasa eso a -a.


Sin embargo ...
Si tiene el servidor iniciado en su .emacs, realmente no necesita crear un script; tienes una opción un poco más concisa:

emacsclient -n -a "/usr/local/bin/emacs" ~/.bashrc &

El ampersand pondrá en segundo plano el proceso y le devolverá instantáneamente su caparazón, incluso cuando Emacs se inicie por primera vez.

Es posible que deba realizar disownel proceso si bash mata los trabajos al salir. Si ese es el caso, simplemente agregue un disownal final:

emacsclient -n -a "/usr/local/bin/emacs" ~/.bashrc & disown

En Windows, el equivalente más cercano sería el " start" comando ...

Entonces, al igual que la sugerencia de script anterior, es probable que tenga que crear un archivo por lotes que contenga algo como:

start /b C:\path\to\emacs %*

Y luego apunta el -aargumento.
Eso debería ejecutar el archivo por lotes y regresar inmediatamente después de iniciar Emacs con el archivo apropiado.

Archenoth
fuente
Estoy en Linux (RHEL 6.5), y &fue lo primero que pensé en probar. Desafortunadamente, el siguiente texto se envía a stderr: y luego los bloques de terminales esperan a que finalice el proceso: emacsclient: can't find socket; have you started the server? To start the server in Emacs, type "M-x server-start". supongo que las emacsclientbifurcaciones pasan a un segundo plano, pero luego invoca lo emacsque se abre en primer plano.
nispio
En ese caso, ¿quizás un pequeño guión sea la mejor ruta? Algo como emacs --eval '(server-start)' $* &tal vez? De esa forma, el servidor se inicia, obtienes tu terminal y emacsclienttiene un servidor al que puede conectarse.
Archenoth
Lo probé y lo agregué a mi respuesta ... ¡Lo siento! Supuse que tenías un mecanismo para iniciar el servidor cuando corrías emacsnormalmente. Me doy cuenta de que la mayoría de las personas probablemente no tendrían esa configuración, así que esa es ahora la primera parte de la respuesta. Espero eso ayude..!
Archenoth
@nispio establece su parámetro de editor alternativo para tener un & al final.
Malabarba
2
@Malabarba No puede pasar argumentos de línea de comandos o directivas de shell al editor alternativo, por eso sugerí un pequeño script.
Archenoth