Équivalent à --no-wait for emacs

8

Le emacsclientprogramme autorise un indicateur --no-wait(abrégé en -n) qui amènera le serveur emacs à visiter le fichier spécifié et à revenir immédiatement.

emacsclient -n ~/.bashrc

Si je fournis un autre éditeur, cela fonctionnera toujours dans les cas où il n'y a pas de serveur Emacs en cours d'exécution

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

Cependant, cela me donne un comportement incohérent car dans les cas où le serveur est en cours d'exécution, cet appel reviendra immédiatement. Dans les cas où aucun serveur n'est en cours d'exécution et où l'éditeur alternatif est utilisé, l'appel devient un appel bloquant et ne reviendra pas tant que je ne quitterai pas Emacs.

Existe-t-il un moyen de dire emacs(par opposition à emacsclient) de créer un nouveau cadre, puis de revenir?

nispio
la source
1
Il semble que vous soyez à l'aise de fournir Emacs comme éditeur alternatif. Y a-t-il une raison pour laquelle vous choisissez de ne pas utiliser l' -a ''option «Démarrer le démon Emacs et réessayer emacsclient»?
purple_arrows
@purple_arrows D'après mon expérience, l'utilisation -a ''démarrera un démon au lieu d'un serveur. Ensuite, il essaie d'ouvrir un terminal Emacs, mais parce que j'ai fourni l' -noption, il ne reste pas ouvert. Il rebondit juste sur la coque.
nispio

Réponses:

6

La description

Le comportement par défaut lors de l'appel à emacsclient est un peu conservateur. Découvrez ce commentaire d' 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.  */

D'après votre description et vos commentaires, il semble que vous essayez de démarrer le serveur Emacs à la demande tout en utilisant le -ndrapeau. Le commentaire "par exemple" est ici pourquoi emacsclient -n -a '' FILEne satisfait pas ce que vous recherchez quand aucun serveur n'est en cours d'exécution.

  1. La -a ''logique démarre un démon.
  2. Lui emacsclientdit ensuite de créer un nouveau cadre de terminal, car c'est la valeur par défaut, sauf si vous évaluez elisp.
  3. La -nlogique tue immédiatement cette nouvelle trame terminale.

Si vous pouviez changer l'étape 2 pour créer un nouveau cadre graphique par défaut, alors vous emacsclient -n -a '' FILEferiez ce que vous voulez.

Elisp Solution

Vous pouvez amener Emacs à créer un nouveau cadre graphique par défaut si vous conseillez la fonction server-process-filtercomme ceci:

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

Mettez-le dans votre fichier init, puis, comme dit, emacsclient -n -a '' FILEet Bob est votre oncle.

Comparez avec Shell Solution

D'une part, je peux souligner quelques avantages à utiliser cette approche par défaut par rapport à l'utilisation du script suggéré par Archenoth

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

comme éditeur alternatif. Avec le defadvice:

  1. save-buffers-kill-terminal( C-x C-cpar défaut) se comporte de manière cohérente dans toutes les images. Cela ne tue jamais le processus Emacs, car chaque trame est toujours une trame client.
  2. Le cadre terminal du démon traîne. Les commandes comme find-grepce shell vers les processus externes se comportent mieux lorsque le terminal muet est là. Au moins, je ressens moins de maux de tête liés à l'échappement.

D'un autre côté ... ouais.

  1. Ce script shell est magnifiquement simple.
  2. Le protocole de communication d'Emacs ne l'est pas.

Conclusion

Peut-être y a-t-il un compromis? C'est le mieux que j'ai pu trouver. Vous le définissez comme votre $ 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
purple_arrows
la source
Alors, comment puis-je conseiller une fonction lorsque emacs n'est pas en cours d'exécution?
nispio
Vous devriez pouvoir le déposer dans le fichier init. Le démon lit ce fichier au démarrage et termine la lecture avant qu'emacsclient commence à envoyer des commandes. C'est comme ça que je le fais, au moins.
purple_arrows
4

Je ne sais pas comment faire cela strictement dans Emacs, mais heureusement, il existe d'autres façons d'obtenir ce que vous décrivez.

Si vous n'avez pas quelque chose en vous .emacspour démarrer un serveur, vous pouvez toujours créer un petit script qui démarre Emacs avec le fichier que vous souhaitez modifier et démarrer le serveur forké.

Quelque chose comme:

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

Et puis passez ça à -a.


Cependant ...
Si vous avez le démarrage du serveur dans votre .emacs, vous n'avez pas vraiment besoin de créer un script; vous avez une option un peu plus laconique:

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

L'esperluette mettra en arrière-plan le processus et vous rendra instantanément votre coque, même lorsque Emacs démarre pour la première fois.

Vous devrez peut-être disownle processus si bash tue les travaux à la sortie. Si tel est le cas, vous ajoutez simplement un disownà la fin:

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

Sous Windows, l'équivalent le plus proche serait la startcommande " " ...

Ainsi, comme la suggestion de script ci-dessus, vous devrez probablement créer un fichier de commandes contenant quelque chose comme:

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

Et puis pointez l' -aargument.
Cela devrait exécuter le fichier de commandes et revenir immédiatement après le démarrage d'Emacs avec le fichier approprié.

Archenoth
la source
Je suis sous Linux (RHEL 6.5) et &j'ai été la première chose à essayer. Malheureusement, le texte suivant est envoyé à stderr: et ensuite les borniers attendent la fin du processus: emacsclient: can't find socket; have you started the server? To start the server in Emacs, type "M-x server-start". je suppose que la emacsclientfourche est en arrière-plan, mais ensuite elle invoque celle emacsqui s'ouvre au premier plan.
nispio
Dans ce cas, peut-être qu'un petit script peut être le meilleur itinéraire ..? Quelque chose comme emacs --eval '(server-start)' $* &peut-être? De cette façon, le serveur démarre, vous obtenez votre terminal et emacsclientdispose d'un serveur auquel il peut se connecter.
Archenoth
Je l'ai testé et ajouté à ma réponse ... Désolé pour ça! J'avais pensé que vous aviez un mécanisme pour démarrer le serveur lorsque vous couriez de emacsmanière normale. Il me semble que la plupart des gens n'auraient probablement pas cette configuration, c'est donc maintenant la première partie de la réponse. J'espère que cela aide..!
Archenoth
@nispio définissez votre paramètre d'éditeur alternatif pour avoir un & à la fin.
Malabarba
2
@Malabarba Vous ne pouvez pas passer d'arguments de ligne de commande ou de directives shell à l'éditeur alternatif, c'est pourquoi j'ai suggéré un petit script.
Archenoth