Equivalente a --no-wait for emacs


8

Il emacsclientprogramma consente un flag --no-wait(abbreviato come -n) che farà sì che il server emacs visiti il ​​file specificato e ritorni immediatamente.

emacsclient -n ~/.bashrc

Se fornisco un editor alternativo, funzionerà comunque nei casi in cui non è in esecuzione il server Emacs

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

Tuttavia, questo mi dà un comportamento incoerente perché nei casi in cui il server è in esecuzione, questa chiamata tornerà immediatamente. Nei casi in cui non è in esecuzione alcun server e viene utilizzato l'editor alternativo, la chiamata diventa una chiamata bloccante e non tornerà finché non esco da Emacs.

C'è un modo per dire emacs(al contrario di emacsclient) di creare un nuovo frame e poi tornare?


1
Sembra che tu sia a tuo agio nel fornire Emacs come editor alternativo. C'è un motivo per cui stai scegliendo di non utilizzare l' -a ''opzione "avvia il demone Emacs e riprova emacsclient"?
purple_arrows,

@purple_arrows Nella mia esperienza, l'utilizzo -a ''avvierà un demone anziché un server. Quindi tenta di aprire un terminale Emacs, ma poiché ho fornito l' -nopzione, non rimane aperto. Rimbalza appena fuori dalla shell.
nispio,

Risposte:


6

Descrizione

Il comportamento predefinito quando si richiama emacsclient è un po 'conservativo. Guarda questo commento da 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.  */

Dalla descrizione e dai commenti, sembra che tu stia cercando di avviare il server Emacs su richiesta mentre usi anche la -nbandiera. Il commento "ad esempio" qui è perché emacsclient -n -a '' FILEnon soddisfa ciò che stai cercando quando nessun server è in esecuzione.

  1. La -a ''logica avvia un demone.
  2. Quindi gli emacsclientdice di creare un nuovo frame terminale, perché è quello predefinito a meno che non stiate valutando elisp.
  3. La -nlogica uccide immediatamente quel nuovo frame terminale.

Se potessi modificare il passaggio 2 per creare un nuovo frame grafico per impostazione predefinita, emacsclient -n -a '' FILEfarebbe quello che vuoi.

Soluzione Elisp

È possibile fare in modo che Emacs crei un nuovo frame grafico per impostazione predefinita se si consiglia la funzione in questo server-process-filtermodo:

(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"))))

Inseriscilo nel file init, quindi, come detto, emacsclient -n -a '' FILEe Bob è tuo zio.

Confronta con la soluzione Shell

Da un lato, posso indicare alcuni vantaggi nell'uso di questo approccio defadvice rispetto all'uso dello script suggerito da Archenoth

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

come editor alternativo. Con il defadvice:

  1. save-buffers-kill-terminal( C-x C-cper impostazione predefinita) si comporta in modo coerente in tutti i frame. Non uccide mai il processo Emacs, perché ogni frame è sempre un frame client.
  2. La cornice terminale del demone si blocca. Comandi come find-grepquelli shell out verso processi esterni si comportano meglio quando c'è il terminale stupido. Almeno, avverto meno mal di testa correlati alla fuga di shell.

D'altra parte ... sì.

  1. Lo script della shell è meravigliosamente semplice.
  2. Consigliare il protocollo di comunicazione di Emacs non lo è.

Conclusione

Forse c'è un compromesso? Questo è il massimo che ho potuto inventare. Lo imposta come $ 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

Quindi, come posso consigliare una funzione quando emacs non è in esecuzione?
nispio,

Dovresti essere in grado di rilasciarlo nel file init. Il daemon legge quel file all'avvio e termina la lettura prima che emacsclient inizi a inviare comandi. È così che lo sto facendo, almeno.
purple_arrows,

4

Non sono sicuro di come farlo rigorosamente all'interno di Emacs, ma per fortuna ci sono altri modi per ottenere ciò che descrivi.

Se non hai qualcosa in tuo .emacsper avviare un server, puoi sempre creare un piccolo script che avvii Emacs con il file che vuoi modificare e avviare il server biforcato.

Qualcosa di simile a:

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

E poi passalo a -a.


Tuttavia ...
Se hai il server avviato nel tuo .emacs, non hai davvero bisogno di creare uno script; hai un'opzione leggermente più concisa:

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

La e commerciale farà da sfondo al processo e ti restituirà immediatamente la tua shell, anche quando Emacs si avvia per la prima volta.

Potrebbe essere necessario disownil processo se bash uccide i lavori all'uscita. In tal caso, aggiungi semplicemente disowna alla fine:

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

Su Windows, l'equivalente più vicino sarebbe il " start" comando ...

Quindi, come il suggerimento dello script sopra, probabilmente dovresti creare un file batch che contenesse qualcosa come:

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

E poi punta l' -aargomento.
Ciò dovrebbe eseguire il file batch e restituire immediatamente dopo l'avvio di Emacs con il file appropriato.


Sono su Linux (RHEL 6.5) ed è &stata la prima cosa che ho pensato di provare. Sfortunatamente, il seguente testo viene inviato a stderr: e quindi alle morsettiere in attesa che il processo finisca: emacsclient: can't find socket; have you started the server? To start the server in Emacs, type "M-x server-start". sto indovinando che le emacsclientforcelle sullo sfondo, ma poi invoca ciò emacsche viene aperto in primo piano.
nispio,

In tal caso, forse un piccolo script potrebbe essere la strada migliore ..? Qualcosa del genere emacs --eval '(server-start)' $* &forse? In questo modo il server si avvia, ottieni il tuo terminale e emacsclientha un server a cui può connettersi.
Archenoth,

L'ho provato e l'ho aggiunto alla mia risposta ... Mi dispiace! Avevo pensato che avessi un meccanismo per avviare il server quando funzionavi emacsnormalmente. Mi viene in mente che la maggior parte delle persone probabilmente non avrebbe quella configurazione, quindi questa è ora la prima parte della risposta. Spero che sia d'aiuto..!
Archenoth,

@nispio imposta il parametro dell'editor alternativo per avere un & alla fine.
Malabarba,

2
@Malabarba Non è possibile passare argomenti della riga di comando o direttive della shell all'editor alternativo, motivo per cui ho suggerito un piccolo script.
Archenoth,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.