Comment définir le statut de sortie pour emacsclient

4

Je me suis retrouvé à utiliser ma session principale Emacs (CocoaEmacs sous OSX) pour modifier ma ligne de commande bash. Pour ce faire, mon éditeur est réglé sur emacsclient. Ensuite, je modifie la ligne dans Emacs, puis enregistre et quitte ce tampon - normalement à l’aide de celui "C-x #"qui s’exécute (server-edit).

Le problème est que, parfois, je suis en train de modifier une ligne et je me rends compte que je ne veux pas réellement exécuter la ligne (le regret s'installe). Le problème est que bash détermine si la ligne doit être exécutée ou non en fonction du statut de retour.

Ce que j'aimerais, c'est qu'il y ait deux options pour moi.

  1. Si je clique sur "C-x #"sauvegarder le tampon et que je retourne le code de sortie 0(c’est-à-dire que j’ai terminé mon montage et que je suis prêt pour que Bash s’enfonce).

  2. Si je tue le tampon, n'enregistrez pas le tampon, tuez-le et renvoyez un code de sortie non nul. Je n'aurais même pas l'esprit si je devais frapper une autre liaison.

Une solution partielle consiste simplement à commenter la ligne. Je ne vois pas cela comme une option pour moi, car normalement, si je modifie une ligne de commande dans Emacs, c'est que je travaille sur plusieurs lignes.

laitier
la source
Est-ce que vider le tampon, sauvegarder et sortir fonctionnerait pour vous? Devrait être facile de lier cela à quelque chose.
user314253
probablement pas parce que je ne veux pas que l’histoire soit effacée et je pense que cela pose un problème. Bien que je doive maîtriser un peu mieux l'histoire de la bash.
milkypostman

Réponses:

4

Dans les versions relativement actuelles d’Emacs (par exemple, dans ma copie d’Emacs 24.2, mais pas dans la distribution d’Emacs 22.1 sous OS X), vous pouvez écrire du code Elisp qui enverra une commande à emacsclient lui indiquant de quitter avec un statut d’exit d’erreur.

C'est plus facile que ça en a l'air.

Il existe une variable locale du tampon server-buffer-clients, avec les clients attachés au tampon. Et la fonction server-send-stringpeut être utilisée pour communiquer des commandes suivant le server-process-filterprotocole.

Par exemple:

(server-send-string (car server-buffer-clients) "-error die")

provoque (un des) emacsclient (s) associé (s) au tampon à émettre immédiatement le texte

*ERROR*: die

puis quittez avec le code de sortie 1.


Donc, il est assez facile de définir une fonction interactive que vous pourriez appeler depuis emacs pour tuer les clients emacs:

(defun tell-emacsclients-for-buffer-to-die ()
  "Sends error exit command to every client for the current buffer."
  (interactive)
  (dolist (proc server-buffer-clients)
    (server-send-string proc "-error die")))

Avec ce qui précède dans votre .emacsfichier (et une version suffisamment récente d’Emacs), vous pouvez M-x tell-emacsclients-for-buffer-to-diefaire appel pour que les clients emacs soient fermés avec le statut d’erreur. (Et bien sûr, vous pouvez lier cette fonction à une autre séquence de touches appropriée.)


note de bas de page

Idéalement, on couplerait ensuite la fonction ci-dessus avec un crochet server-kill-bufferpour atteindre le nombre d'objectifs (2.) de la question d'origine. (Autrement dit, tuer le tampon sans l'enregistrer via C-x #devrait déclencher les mêmes erreurs que emacsclient.)

Cependant, mes tentatives pour l'ajouter à kill-buffer-hookont échoué, car la server-kill-bufferfonction est placée au premier plan de la kill-buffer-hookliste une fois les server-visit-hookpoints d'ancrage exécutés. La server-kill-bufferfonction par défaut est donc exécutée en premier. (On pourrait réparer la kill-buffer-hooksuite, mais je ne sais pas encore où mettre le code pour le faire dans le flux de contrôle Elisp.)

Mise à jour: d'accord, voici un moyen vraiment déconcertant d'accomplir ce qui précède:

(defun kill-buffer-with-special-emacsclient-handling ()
  (interactive)
  (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t)
  (kill-buffer))

(global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling)

Mise à jour 2: variante légèrement plus robuste:

(defun kill-buffer-with-special-emacsclient-handling ()
  "Wrapper around kill-buffer that ensures tell-emacsclients-for-buffer-to-die is on the hooks"
  (interactive)
  (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t)
  (kill-buffer))

;; (global-set-key (kbd "C-x k") 'kill-buffer)

(defun install-emacsclient-wrapped-kill-buffer ()
  "Installs wrapped kill-buffer with special emacsclient handling.
Best not to install it unconditionally because the server is not
necessarily running."
  (interactive)
  (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))

(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer)
pnkfelix
la source
OK, laissez-moi essayer ceci et voir comment cela fonctionne. C'est ce que je cherchais.
milkypostman
milkypostman: cela a-t-il fonctionné pour vous?
pnkfelix
tbh je ne me souviens plus maintenant. mais j'ai des problèmes similaires alors je vais essayer à nouveau.
milkypostman
1

Appuyez simplement sur Ctrl+Cle terminal sur lequel vous exécutez bash. Ceci annule l'édition et pousse la ligne d'origine dans l'historique. Si vous ne pouvez pas le faire directement car Emacs est exécuté sur le même terminal, interrompez le emacsclientprocessus par le moyen de votre choix.

Gilles
la source
c'est bon. Existe-t-il un moyen simple de tuer le processus client depuis emacs? ce serait encore mieux, vous ne pensez pas? semble difficile à traversserver.el
milkypostman