pax_global_header00006660000000000000000000000064126524716050014522gustar00rootroot0000000000000052 comment=580f225a6c4476feb36b707c6c705b027339717b with-editor-2.5.0/000077500000000000000000000000001265247160500137655ustar00rootroot00000000000000with-editor-2.5.0/Makefile000066400000000000000000000017101265247160500154240ustar00rootroot00000000000000ELS = with-editor.el DEPS = dash INFOPAGES = with-editor.info TEXIPAGES = with-editor.texi ELCS = $(ELS:.el=.elc) DFLAGS = $(addprefix -L ../,$(DEPS)) EFLAGS ?= $(DFLAGS) EMACS ?= emacs BATCH = $(EMACS) -batch -Q -L . $(EFLAGS) MAKEINFO ?= makeinfo INSTALL_INFO ?= $(shell command -v ginstall-info || printf install-info) .PHONY: help clean help: $(info make all - compile elisp and manual) $(info make lisp - compile elisp) $(info make info - generate info manual) $(info make clean - remove generated files) @printf "\n" all: lisp info lisp: $(ELCS) %.elc: %.el @printf "Compiling %s\n" $< @$(BATCH)\ --eval '(setq with-editor-emacsclient-executable nil)'\ -f batch-byte-compile $< info: $(INFOPAGES) dir %.info: %.texi @printf "Generating $@\n" @$(MAKEINFO) --no-split $< -o $@ dir: $(TEXIPAGES) @printf "Generating dir\n" @echo $^ | xargs -n 1 $(INSTALL_INFO) --dir=$@ clean: @printf "Cleaning...\n" @rm -f $(ELCS) with-editor-2.5.0/README.md000066400000000000000000000043001265247160500152410ustar00rootroot00000000000000With-Editor =========== This library makes it possible to reliably use the Emacsclient as the `$EDITOR` of child processes. It makes sure that they know how to call home. For remote processes a substitute is provided, which communicates with Emacs on standard output/input instead of using a socket as the Emacsclient does. It provides the commands `with-editor-async-shell-command` and `with-editor-shell-command`, which are intended as replacements for `async-shell-command` and `shell-command`. They automatically export `$EDITOR` making sure the executed command uses the current Emacs instance as "the editor". With a prefix argument these commands prompt for an alternative environment variable such as `$GIT_EDITOR`. To always use these variants add this to your init file: (define-key (current-global-map) [remap async-shell-command] 'with-editor-async-shell-command) (define-key (current-global-map) [remap shell-command] 'with-editor-shell-command) Alternatively use the global `shell-command-with-editor-mode`, which always sets `$EDITOR` for all Emacs commands which ultimately use `shell-command` to asynchronously run some shell command. The command `with-editor-export-editor` exports `$EDITOR` or another such environment variable in `shell-mode`, `term-mode` and `eshell-mode` buffers. Use this Emacs command before executing a shell command which needs the editor set, or always arrange for the current Emacs instance to be used as editor by adding it to the appropriate mode hooks: (add-hook 'shell-mode-hook 'with-editor-export-editor) (add-hook 'term-mode-hook 'with-editor-export-editor) (add-hook 'eshell-mode-hook 'with-editor-export-editor) Some variants of this function exist, these two forms are equivalent: (add-hook 'shell-mode-hook (apply-partially 'with-editor-export-editor "GIT_EDITOR")) (add-hook 'shell-mode-hook 'with-editor-export-git-editor) This library can also be used by other packages which need to use the current Emacs instance as editor. In fact this library was written for Magit and its `git-commit-mode` and `git-rebase-mode`. Consult `git-rebase.el` and the related code in `magit-sequence.el` for a simple example. with-editor-2.5.0/with-editor.el000066400000000000000000000737761265247160500165720ustar00rootroot00000000000000;;; with-editor.el --- Use the Emacsclient as $EDITOR -*- lexical-binding: t -*- ;; Copyright (C) 2014-2016 The Magit Project Contributors ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli ;; Package-Requires: ((emacs "24.4") (async "1.5") (dash "2.12.1")) ;; Keywords: tools ;; Homepage: https://github.com/magit/with-editor ;; This file is not part of GNU Emacs. ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this file. If not, see . ;;; Commentary: ;; This library makes it possible to reliably use the Emacsclient as ;; the `$EDITOR' of child processes. It makes sure that they know how ;; to call home. For remote processes a substitute is provided, which ;; communicates with Emacs on standard output/input instead of using a ;; socket as the Emacsclient does. ;; It provides the commands `with-editor-async-shell-command' and ;; `with-editor-shell-command', which are intended as replacements ;; for `async-shell-command' and `shell-command'. They automatically ;; export `$EDITOR' making sure the executed command uses the current ;; Emacs instance as "the editor". With a prefix argument these ;; commands prompt for an alternative environment variable such as ;; `$GIT_EDITOR'. To always use these variants add this to your init ;; file: ;; ;; (define-key (current-global-map) ;; [remap async-shell-command] 'with-editor-async-shell-command) ;; (define-key (current-global-map) ;; [remap shell-command] 'with-editor-shell-command) ;; Alternatively use the global `shell-command-with-editor-mode', ;; which always sets `$EDITOR' for all Emacs commands which ultimately ;; use `shell-command' to asynchronously run some shell command. ;; The command `with-editor-export-editor' exports `$EDITOR' or ;; another such environment variable in `shell-mode', `term-mode' and ;; `eshell-mode' buffers. Use this Emacs command before executing a ;; shell command which needs the editor set, or always arrange for the ;; current Emacs instance to be used as editor by adding it to the ;; appropriate mode hooks: ;; ;; (add-hook 'shell-mode-hook 'with-editor-export-editor) ;; (add-hook 'term-mode-hook 'with-editor-export-editor) ;; (add-hook 'eshell-mode-hook 'with-editor-export-editor) ;; Some variants of this function exist, these two forms are ;; equivalent: ;; ;; (add-hook 'shell-mode-hook ;; (apply-partially 'with-editor-export-editor "GIT_EDITOR")) ;; (add-hook 'shell-mode-hook 'with-editor-export-git-editor) ;; This library can also be used by other packages which need to use ;; the current Emacs instance as editor. In fact this library was ;; written for Magit and its `git-commit-mode' and `git-rebase-mode'. ;; Consult `git-rebase.el' and the related code in `magit-sequence.el' ;; for a simple example. ;;; Code: (require 'cl-lib) (require 'dash) (require 'server) (require 'tramp) (require 'tramp-sh nil t) (and (require 'async-bytecomp nil t) (memq 'magit (bound-and-true-p async-bytecomp-allowed-packages)) (fboundp 'async-bytecomp-package-mode) (async-bytecomp-package-mode 1)) (eval-when-compile (progn (require 'dired nil t) (require 'eshell nil t) (require 'term nil t) (require 'warnings nil t))) (declare-function dired-get-filename 'dired) (declare-function term-emulate-terminal 'term) (defvar eshell-preoutput-filter-functions) ;;; Options (defgroup with-editor nil "Use the Emacsclient as $EDITOR." :group 'external :group 'server) (defun with-editor-locate-emacsclient () "Search for a suitable Emacsclient executable." (--if-let (with-editor-locate-emacsclient-1 (with-editor-emacsclient-path) 3) it (display-warning 'with-editor (format "\ Cannot determine a suitable Emacsclient Determining an Emacsclient executable suitable for the current Emacs instance failed. For more information please see https://github.com/magit/magit/wiki/Emacsclient.")) nil)) (defun with-editor-locate-emacsclient-1 (path depth) (let* ((version-lst (-take depth (split-string emacs-version "\\."))) (version-reg (concat "^" (mapconcat #'identity version-lst "\\.")))) (or (locate-file-internal "emacsclient" path (cl-mapcan (lambda (v) (cl-mapcar (lambda (e) (concat v e)) exec-suffixes)) (nconc (cl-mapcon (lambda (v) (setq v (mapconcat #'identity (reverse v) ".")) (list v (concat "-" v) (concat ".emacs" v))) (reverse version-lst)) (list "" "-snapshot"))) (lambda (exec) (ignore-errors (string-match-p version-reg (with-editor-emacsclient-version exec))))) (and (> depth 1) (with-editor-locate-emacsclient-1 path (1- depth)))))) (defun with-editor-emacsclient-version (exec) (-when-let (1st-line (car (process-lines exec "--version"))) (cadr (split-string 1st-line)))) (defun with-editor-emacsclient-path () (let ((path exec-path)) (when invocation-directory (push (directory-file-name invocation-directory) path) (let* ((linkname (expand-file-name invocation-name invocation-directory)) (truename (file-chase-links linkname))) (unless (equal truename linkname) (push (directory-file-name (file-name-directory truename)) path))) (when (eq system-type 'darwin) (let ((dir (expand-file-name "bin" invocation-directory))) (when (file-directory-p dir) (push dir path))) (when (string-match-p "Cellar" invocation-directory) (let ((dir (expand-file-name "../../../bin" invocation-directory))) (when (file-directory-p dir) (push dir path)))))) (cl-remove-duplicates path :test 'equal))) (defcustom with-editor-emacsclient-executable (with-editor-locate-emacsclient) "The Emacsclient executable used by the `with-editor' macro." :group 'with-editor :type '(choice (string :tag "Executable") (const :tag "Don't use Emacsclient" nil))) (defcustom with-editor-sleeping-editor "\ sh -c '\ echo \"WITH-EDITOR: $$ OPEN $0\"; \ sleep 604800 & sleep=$!; \ trap \"kill $sleep; exit 0\" USR1; \ trap \"kill $sleep; exit 1\" USR2; \ wait $sleep'" "The sleeping editor, used when the Emacsclient cannot be used. This fallback is used for asynchronous process started inside the macro `with-editor', when the process runs on a remote machine or for local processes when `with-editor-emacsclient-executable' is nil (i.e. when no suitable Emacsclient was found, or the user decided not to use it). Where the latter uses a socket to communicate with Emacs' server, this substitute prints edit requests to its standard output on which a process filter listens for such requests. As such it is not a complete substitute for a proper Emacsclient, it can only be used as $EDITOR of child process of the current Emacs instance." :group 'with-editor :type 'string) (defcustom with-editor-finish-query-functions nil "List of functions called to query before finishing session. The buffer in question is current while the functions are called. If any of them returns nil, then the session is not finished and the buffer is not killed. The user should then fix the issue and try again. The functions are called with one argument. If it is non-nil then that indicates that the user used a prefix argument to force finishing the session despite issues. Functions should usually honor that and return non-nil." :group 'with-editor :type 'hook) (put 'with-editor-finish-query-functions 'permanent-local t) (defcustom with-editor-cancel-query-functions nil "List of functions called to query before canceling session. The buffer in question is current while the functions are called. If any of them returns nil, then the session is not canceled and the buffer is not killed. The user should then fix the issue and try again. The functions are called with one argument. If it is non-nil then that indicates that the user used a prefix argument to force canceling the session despite issues. Functions should usually honor that and return non-nil." :group 'with-editor :type 'hook) (put 'with-editor-cancel-query-functions 'permanent-local t) (defcustom with-editor-mode-lighter " WE" "The mode-line lighter of the With-Editor mode." :group 'with-editor :type '(choice (const :tag "No lighter" "") string)) (defvar with-editor-server-window-alist nil "Alist of filename patterns vs corresponding `server-window'. Each element looks like (REGEXP . FUNCTION). Files matching REGEXP are selected using FUNCTION instead of the default in `server-window'. Note that when a package adds an entry here then it probably has a reason to disrespect `server-window' and it likely is not a good idea to change such entries.") ;;; Mode Commands (defvar with-editor-pre-finish-hook nil) (defvar with-editor-pre-cancel-hook nil) (defvar with-editor-post-finish-hook nil) (defvar with-editor-post-finish-hook-1 nil) (defvar with-editor-post-cancel-hook nil) (defvar with-editor-post-cancel-hook-1 nil) (defvar with-editor-cancel-alist nil) (put 'with-editor-pre-finish-hook 'permanent-local t) (put 'with-editor-pre-cancel-hook 'permanent-local t) (put 'with-editor-post-finish-hook 'permanent-local t) (put 'with-editor-post-cancel-hook 'permanent-local t) (defvar with-editor-show-usage t) (defvar with-editor-cancel-message nil) (defvar with-editor-previous-winconf nil) (make-variable-buffer-local 'with-editor-show-usage) (make-variable-buffer-local 'with-editor-cancel-message) (make-variable-buffer-local 'with-editor-previous-winconf) (put 'with-editor-cancel-message 'permanent-local t) (put 'with-editor-previous-winconf 'permanent-local t) (defvar-local with-editor--pid nil "For internal use.") (put 'with-editor--pid 'permanent-local t) (defun with-editor-finish (force) "Finish the current edit session." (interactive "P") (when (run-hook-with-args-until-failure 'with-editor-finish-query-functions force) (let ((with-editor-post-finish-hook-1 (ignore-errors (delq t with-editor-post-finish-hook)))) (run-hooks 'with-editor-pre-finish-hook) (with-editor-return nil) (accept-process-output nil 0.1) (run-hooks 'with-editor-post-finish-hook-1)))) (defun with-editor-cancel (force) "Cancel the current edit session." (interactive "P") (when (run-hook-with-args-until-failure 'with-editor-cancel-query-functions force) (let ((message with-editor-cancel-message)) (when (functionp message) (setq message (funcall message))) (let ((with-editor-post-cancel-hook-1 (ignore-errors (delq t with-editor-post-cancel-hook))) (with-editor-cancel-alist nil)) (run-hooks 'with-editor-pre-cancel-hook) (with-editor-return t) (accept-process-output nil 0.1) (run-hooks 'with-editor-post-cancel-hook-1)) (message (or message "Canceled by user"))))) (defun with-editor-return (cancel) (let ((winconf with-editor-previous-winconf) (clients server-buffer-clients) (dir default-directory) (pid with-editor--pid)) (remove-hook 'kill-buffer-query-functions 'with-editor-kill-buffer-noop t) (cond (cancel (save-buffer) (if clients (dolist (client clients) (ignore-errors (server-send-string client "-error Canceled by user")) (delete-process client)) ;; Fallback for when emacs was used as $EDITOR instead ;; of emacsclient or the sleeping editor. See #2258. (ignore-errors (delete-file buffer-file-name)) (kill-buffer))) (t (save-buffer) (if clients ;; Don't use `server-edit' because we do not want to show ;; another buffer belonging to another client. See #2197. (server-done) (kill-buffer)))) (when pid (let ((default-directory dir)) (process-file "kill" nil nil nil "-s" (if cancel "USR2" "USR1") pid))) (when (and winconf (eq (window-configuration-frame winconf) (selected-frame))) (set-window-configuration winconf)))) ;;; Mode (defvar with-editor-mode-map (let ((map (make-sparse-keymap))) (define-key map "\C-c\C-c" 'with-editor-finish) (define-key map [remap server-edit] 'with-editor-finish) (define-key map "\C-c\C-k" 'with-editor-cancel) (define-key map [remap kill-buffer] 'with-editor-cancel) (define-key map [remap ido-kill-buffer] 'with-editor-cancel) (define-key map [remap iswitchb-kill-buffer] 'with-editor-cancel) map)) (define-minor-mode with-editor-mode "Edit a file as the $EDITOR of an external process." :lighter with-editor-mode-lighter ;; Protect the user from killing the buffer without using ;; either `with-editor-finish' or `with-editor-cancel', ;; and from removing the key bindings for these commands. (unless with-editor-mode (error "With-Editor mode cannot be turned off")) (add-hook 'kill-buffer-query-functions 'with-editor-kill-buffer-noop nil t) ;; `server-execute' displays a message which is not ;; correct when using this mode. (when with-editor-show-usage (with-editor-usage-message))) (put 'with-editor-mode 'permanent-local t) (defun with-editor-kill-buffer-noop () (message (substitute-command-keys "\ Don't kill this buffer. Instead cancel using \\[with-editor-cancel]"))) (defun with-editor-usage-message () ;; Run after `server-execute', which is run using ;; a timer which starts immediately. (run-with-timer 0.01 nil `(lambda () (with-current-buffer ,(current-buffer) (message (substitute-command-keys "\ Type \\[with-editor-finish] to finish, \ or \\[with-editor-cancel] to cancel")))))) ;;; Wrappers (defvar with-editor--envvar nil "For internal use.") (defmacro with-editor (&rest body) "Use the Emacsclient as $EDITOR while evaluating BODY. Modify the `process-environment' for processes started in BODY, instructing them to use the Emacsclient as $EDITOR. If optional ENVVAR is provided then bind that environment variable instead. \n(fn [ENVVAR] BODY...)" (declare (indent defun) (debug (body))) `(let ((with-editor--envvar ,(if (stringp (car body)) (pop body) '(or with-editor--envvar "EDITOR"))) (process-environment process-environment)) (if (or (not with-editor-emacsclient-executable) (file-remote-p default-directory)) (setenv with-editor--envvar with-editor-sleeping-editor) ;; Make sure server-use-tcp's value is valid. (unless (featurep 'make-network-process '(:family local)) (setq server-use-tcp t)) ;; Make sure the server is running. (unless server-process (when (server-running-p server-name) (setq server-name (format "server%s" (emacs-pid))) (when (server-running-p server-name) (server-force-delete server-name))) (server-start)) ;; Tell $EDITOR to use the Emacsclient. (setenv with-editor--envvar (concat (shell-quote-argument with-editor-emacsclient-executable) ;; Tell the process where the server file is. (and (not server-use-tcp) (concat " --socket-name=" (shell-quote-argument (expand-file-name server-name server-socket-dir)))))) (when server-use-tcp (setenv "EMACS_SERVER_FILE" (expand-file-name server-name server-auth-dir))) ;; As last resort fallback to the sleeping editor. (setenv "ALTERNATE_EDITOR" with-editor-sleeping-editor)) ,@body)) (defun with-editor-server-window () (or (and buffer-file-name (cdr (--first (string-match-p (car it) buffer-file-name) with-editor-server-window-alist))) server-window)) (defun server-switch-buffer--with-editor-server-window-alist (fn &optional next-buffer killed-one filepos) "Honor `with-editor-server-window-alist' (which see)." (let ((server-window (with-current-buffer (or next-buffer (current-buffer)) (when with-editor-mode (setq with-editor-previous-winconf (current-window-configuration))) (with-editor-server-window)))) (funcall fn next-buffer killed-one filepos))) (advice-add 'server-switch-buffer :around 'server-switch-buffer--with-editor-server-window-alist) (defun start-file-process--with-editor-process-filter (fn name buffer program &rest program-args) "When called inside a `with-editor' form and the Emacsclient cannot be used, then give the process the filter function `with-editor-process-filter'. To avoid overriding the filter being added here you should use `with-editor-set-process-filter' instead of `set-process-filter' inside `with-editor' forms. When the `default-directory' is located on a remote machine, then also manipulate PROGRAM and PROGRAM-ARGS in order to set the appropriate editor environment variable." (if (not with-editor--envvar) (apply fn name buffer program program-args) (when (file-remote-p default-directory) (unless (equal program "env") (push program program-args) (setq program "env")) (push (concat with-editor--envvar "=" with-editor-sleeping-editor) program-args)) (let ((process (apply fn name buffer program program-args))) (set-process-filter process 'with-editor-process-filter) (process-put process 'default-dir default-directory) process))) (advice-add 'start-file-process :around 'start-file-process--with-editor-process-filter) (defun with-editor-set-process-filter (process filter) "Like `set-process-filter' but keep `with-editor-process-filter'. Give PROCESS the new FILTER but keep `with-editor-process-filter' if that was added earlier by the adviced `start-file-process'. Do so by wrapping the two filter functions using a lambda, which becomes the actual filter. It calls `with-editor-process-filter' first, passing t as NO-STANDARD-FILTER. Then it calls FILTER, which may or may not insert the text into the PROCESS' buffer." (set-process-filter process (if (eq (process-filter process) 'with-editor-process-filter) `(lambda (proc str) (,filter proc str) (with-editor-process-filter proc str t)) filter))) (defvar with-editor-filter-visit-hook nil) (defun with-editor-output-filter (string) (save-match-data (if (string-match "^WITH-EDITOR: \\([0-9]+\\) OPEN \\(.+?\\)\r?$" string) (let ((pid (match-string 1 string)) (file (match-string 2 string))) (with-current-buffer (find-file-noselect (if (file-name-absolute-p file) (if (tramp-tramp-file-p default-directory) (with-parsed-tramp-file-name default-directory nil (tramp-make-tramp-file-name method user host file hop)) file) (expand-file-name file))) (with-editor-mode 1) (setq with-editor--pid pid) (run-hooks 'with-editor-filter-visit-hook) (funcall (or (with-editor-server-window) 'switch-to-buffer) (current-buffer)) (kill-local-variable 'server-window)) nil) string))) (defun with-editor-process-filter (process string &optional no-default-filter) "Listen for edit requests by child processes." (let ((default-directory (process-get process 'default-dir))) (with-editor-output-filter string)) (unless no-default-filter (internal-default-process-filter process string))) ;;; Augmentations (cl-defun with-editor-export-editor (&optional (envvar "EDITOR")) "Teach subsequent commands to use current Emacs instance as editor. Set and export the environment variable ENVVAR, by default \"EDITOR\". The value is automatically generated to teach commands use the current Emacs instance as \"the editor\". This works in `shell-mode', `term-mode' and `eshell-mode'." (interactive (list (with-editor-read-envvar))) (cond ((derived-mode-p 'comint-mode 'term-mode) (let* ((process (get-buffer-process (current-buffer))) (filter (process-filter process))) (set-process-filter process 'ignore) (goto-char (process-mark process)) (process-send-string process (format "export %s=%s\n" envvar (shell-quote-argument with-editor-sleeping-editor))) (while (accept-process-output process 0.1)) (set-process-filter process filter) (if (derived-mode-p 'term-mode) (with-editor-set-process-filter process 'with-editor-emulate-terminal) (add-hook 'comint-output-filter-functions 'with-editor-output-filter nil t)))) ((derived-mode-p 'eshell-mode) (add-to-list 'eshell-preoutput-filter-functions 'with-editor-output-filter) (setenv envvar with-editor-sleeping-editor)) (t (error "Cannot export environment variables in this buffer"))) (message "Successfully exported %s" envvar)) (defun with-editor-export-git-editor () "Like `with-editor-export-editor' but always set `$GIT_EDITOR'." (interactive) (with-editor-export-editor "GIT_EDITOR")) (defun with-editor-export-hg-editor () "Like `with-editor-export-editor' but always set `$HG_EDITOR'." (interactive) (with-editor-export-editor "HG_EDITOR")) (defun with-editor-emulate-terminal (process string) "Like `term-emulate-terminal' but also handle edit requests." (when (with-editor-output-filter string) (term-emulate-terminal process string))) (defvar with-editor-envvars '("EDITOR" "GIT_EDITOR" "HG_EDITOR")) (cl-defun with-editor-read-envvar (&optional (prompt "Set environment variable") (default "EDITOR")) (let ((reply (completing-read (if default (format "%s (%s): " prompt default) (concat prompt ": ")) with-editor-envvars nil nil nil nil default))) (if (string= reply "") (user-error "Nothing selected") reply))) (define-minor-mode shell-command-with-editor-mode "Teach `shell-command' to use current Emacs instance as editor. Teach `shell-command', and all commands that ultimately call that command, to use the current Emacs instance as editor by executing \"EDITOR=CLIENT COMMAND&\" instead of just \"COMMAND&\". CLIENT is automatically generated; EDITOR=CLIENT instructs COMMAND to use to the current Emacs instance as \"the editor\", assuming no other variable overrides the effect of \"$EDITOR\". CLIENT may be the path to an appropriate emacsclient executable with arguments, or a script which also works over Tramp. Alternatively you can use the `with-editor-async-shell-command', which also allows the use of another variable instead of \"EDITOR\"." :global t) (defun with-editor-async-shell-command (command &optional output-buffer error-buffer envvar) "Like `async-shell-command' but with `$EDITOR' set. Execute string \"ENVVAR=CLIENT COMMAND\" in an inferior shell; display output, if any. With a prefix argument prompt for an environment variable, otherwise the default \"EDITOR\" variable is used. With a negative prefix argument additionally insert the COMMAND's output at point. CLIENT is automatically generated; ENVVAR=CLIENT instructs COMMAND to use to the current Emacs instance as \"the editor\", assuming it respects ENVVAR as an \"EDITOR\"-like variable. CLIENT maybe the path to an appropriate emacsclient executable with arguments, or a script which also works over Tramp. Also see `async-shell-command' and `shell-command'." (interactive (with-editor-shell-command-read-args "Async shell command: " t)) (let ((with-editor--envvar envvar)) (with-editor (async-shell-command command output-buffer error-buffer)))) (defun with-editor-shell-command (command &optional output-buffer error-buffer envvar) "Like `shell-command' or `with-editor-async-shell-command'. If COMMAND ends with \"&\" behave like the latter, else like the former." (interactive (with-editor-shell-command-read-args "Shell command: ")) (if (string-match "&[ \t]*\\'" command) (with-editor-async-shell-command command output-buffer error-buffer envvar) (shell-command command output-buffer error-buffer))) (defun with-editor-shell-command-read-args (prompt &optional async) (let ((command (read-shell-command prompt nil nil (--when-let (or buffer-file-name (and (eq major-mode 'dired-mode) (dired-get-filename nil t))) (file-relative-name it))))) (list command (if (or async (setq async (string-match-p "&[ \t]*\\'" command))) (< (prefix-numeric-value current-prefix-arg) 0) current-prefix-arg) shell-command-default-error-buffer (and async current-prefix-arg (with-editor-read-envvar))))) (defun shell-command--shell-command-with-editor-mode (fn command &optional output-buffer error-buffer) (cond ((or (not (or with-editor--envvar shell-command-with-editor-mode)) (not (string-match-p "&\\'" command))) (funcall fn command output-buffer error-buffer)) ((and with-editor-emacsclient-executable (not (file-remote-p default-directory))) (with-editor (funcall fn command output-buffer error-buffer))) (t (apply fn (format "%s=%s %s" (or with-editor--envvar "EDITOR") (shell-quote-argument with-editor-sleeping-editor) command) output-buffer error-buffer) (ignore-errors (let ((process (get-buffer-process (or output-buffer (get-buffer "*Async Shell Command*"))))) (set-process-filter process (lambda (proc str) (comint-output-filter proc str) (with-editor-process-filter proc str t))) process))))) (advice-add 'shell-command :around 'shell-command--shell-command-with-editor-mode) ;;; with-editor.el ends soon (defun with-editor-debug () "Debug configuration issues. See `with-editor.info' for instructions." (interactive) (with-current-buffer (get-buffer-create "*with-editor-debug*") (pop-to-buffer (current-buffer)) (erase-buffer) (ignore-errors (with-editor)) (insert (format "with-editor: %s\n" (locate-library "with-editor.el")) (format "emacs: %s (%s)\n" (expand-file-name invocation-name invocation-directory) emacs-version) "system:\n" (format " system-type: %s\n" system-type) (format " system-configuration: %s\n" system-configuration) (format " system-configuration-options: %s\n" system-configuration-options) "server:\n" (format " server-running-p: %s\n" (server-running-p)) (format " server-process: %S\n" server-process) (format " server-use-tcp: %s\n" server-use-tcp) (format " server-name: %s\n" server-name) (format " server-socket-dir: %s\n" server-socket-dir)) (if (and server-socket-dir (file-accessible-directory-p server-socket-dir)) (--each (directory-files server-socket-dir nil "^[^.]") (insert (format " %s\n" it))) (insert (format " %s: not an accessible directory\n" (if server-use-tcp "WARNING" "ERROR")))) (insert (format " server-auth-dir: %s\n" server-auth-dir)) (if (file-accessible-directory-p server-auth-dir) (--each (directory-files server-auth-dir nil "^[^.]") (insert (format " %s\n" it))) (insert (format " %s: not an accessible directory\n" (if server-use-tcp "ERROR" "WARNING")))) (let ((val with-editor-emacsclient-executable) (def (default-value 'with-editor-emacsclient-executable)) (fun (let ((warning-minimum-level :error) (warning-minimum-log-level :error)) (with-editor-locate-emacsclient)))) (insert "magit-emacsclient-executable:\n" (format " value: %s (%s)\n" val (and val (with-editor-emacsclient-version val))) (format " default: %s (%s)\n" def (and def (with-editor-emacsclient-version def))) (format " funcall: %s (%s)\n" fun (and fun (with-editor-emacsclient-version fun))))) (insert "path:\n" (format " $PATH: %S\n" (getenv "PATH")) (format " exec-path: %s\n" exec-path)) (insert (format " with-editor-emacsclient-path:\n")) (--each (with-editor-emacsclient-path) (insert (format " %s (%s)\n" it (car (file-attributes it)))) (when (file-directory-p it) (dolist (exec (directory-files it t "emacsclient")) (insert (format " %s (%s)\n" exec (with-editor-emacsclient-version exec)))))))) (defconst with-editor-font-lock-keywords '(("(\\(with-\\(?:git-\\)?editor\\)\\_>" (1 'font-lock-keyword-face)))) (font-lock-add-keywords 'emacs-lisp-mode with-editor-font-lock-keywords) (provide 'with-editor) ;; Local Variables: ;; indent-tabs-mode: nil ;; End: ;;; with-editor.el ends here with-editor-2.5.0/with-editor.info000066400000000000000000000321251265247160500171040ustar00rootroot00000000000000This is with-editor.info, produced by makeinfo version 5.2 from with-editor.texi. The library ‘with-editor’ makes it easy to use the Emacsclient as the ‘$EDITOR’ of child processes, making sure they know how to call home. For remote processes a substitute is provided, which communicates with Emacs on standard output instead of using a socket as the Emacsclient does. This library was written because Magit has to be able to do the above to allow the user to edit commit messages gracefully and to edit rebase sequences, which wouldn’t be possible at all otherwise. Because other packages can benefit from such functionality, this library is made available as a separate package. It also defines some additional functionality which makes it useful even for end-users, who don’t use Magit or another package which uses it internally. Copyright (C) 2015-2016 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This document is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. INFO-DIR-SECTION Emacs START-INFO-DIR-ENTRY * With-Editor: (with-editor). Using the Emacsclient as $EDITOR. END-INFO-DIR-ENTRY  File: with-editor.info, Node: Top, Next: Using the With-Editor package, Up: (dir) With-Editor User Manual *********************** The library ‘with-editor’ makes it easy to use the Emacsclient as the ‘$EDITOR’ of child processes, making sure they know how to call home. For remote processes a substitute is provided, which communicates with Emacs on standard output instead of using a socket as the Emacsclient does. This library was written because Magit has to be able to do the above to allow the user to edit commit messages gracefully and to edit rebase sequences, which wouldn’t be possible at all otherwise. Because other packages can benefit from such functionality, this library is made available as a separate package. It also defines some additional functionality which makes it useful even for end-users, who don’t use Magit or another package which uses it internally. Copyright (C) 2015-2016 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This document is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * Menu: * Using the With-Editor package:: * Using With-Editor as a library:: * Debugging:: — The Detailed Node Listing — Using the With-Editor package * Configuring With-Editor:: * Using With-Editor commands::  File: with-editor.info, Node: Using the With-Editor package, Next: Using With-Editor as a library, Prev: Top, Up: Top 1 Using the With-Editor package ******************************* The ‘With-Editor’ package is used internally by Magit when editing commit messages and rebase sequences. It also provides some commands and features which are useful by themselves, even if you don’t use Magit. For information about using this library in you own package, see *note Using With-Editor as a library: Using With-Editor as a library. * Menu: * Configuring With-Editor:: * Using With-Editor commands::  File: with-editor.info, Node: Configuring With-Editor, Next: Using With-Editor commands, Up: Using the With-Editor package 1.1 Configuring With-Editor =========================== With-Editor tries very hard to locate a suitable emacsclient executable, so ideally you should never have to customize the option ‘with-editor-emacsclient-executable’. When it fails to do so, then the most likely reason is that someone found yet another way to package Emacs (most likely on OS X) without putting the executable on ‘$PATH’, and we have to add another kludge to find it anyway. -- User Option: with-editor-emacsclient-executable The emacsclient executable used as the editor by child process of this Emacs instance. By using this executable, child processes can call home to their parent process. This option is automatically set at startup by looking in ‘exec-path’, and other places where the executable could be installed, to find the emacsclient executable most suitable for the current emacs instance. You should *not* customize this option permanently. If you have to do it, then you should consider that a temporary kludge and inform the Magit maintainer as described in *note Debugging: Debugging. If With-Editor fails to find a suitable emacsclient on you system, then this should be fixed for all users at once, by teaching ‘with-editor-locate-emacsclient’ how to so on your system and system like yours. Doing it this way has the advantage, that you won’t have do it again every time you update Emacs, and that other users who have installed Emacs the same way as you have, won’t have to go through the same trouble. Note that there also is a nuclear option; setting this variable to ‘nil’ causes the "sleeping editor" described below to be used even for local child processes. Obviously we don’t recommend that you use this except in "emergencies", i.e. before we had a change to add a kludge appropriate for you setup. -- Function: with-editor-locate-emacsclient The function used to set the initial value of the option ‘with-editor-emacsclient-executable’. There’s a lot of voodoo here. The emacsclient cannot be used when using Tramp to run a process on a remote machine. (Theoretically it could, but that would be hard to setup, very fragile, and rather insecure). With-Editor provides an alternative "editor" which can be used by remote processes in much the same way as local processes use an emacsclient executable. This alternative is known as the "sleeping editor" because it is implemented as a shell script which sleeps until it receives a signal. -- User Option: with-editor-sleeping-editor The sleeping editor is a shell script used as the editor of child processes when the emacsclient executable cannot be used. This fallback is used for asynchronous process started inside the macro ‘with-editor’, when the process runs on a remote machine or for local processes when ‘with-editor-emacsclient-executable’ is ‘nil’. Where the latter uses a socket to communicate with Emacs’ server, this substitute prints edit requests to its standard output on which a process filter listens for such requests. As such it is not a complete substitute for a proper Emacsclient, it can only be used as ‘$EDITOR’ of child process of the current Emacs instance. It is unlikely that you should ever have to customize this option.  File: with-editor.info, Node: Using With-Editor commands, Prev: Configuring With-Editor, Up: Using the With-Editor package 1.2 Using With-Editor commands ============================== This section describes how to use the ‘with-editor’ library _outside_ of Magit. You don’t need to know any of this just to create commits using Magit. The commands ‘with-editor-async-shell-command’ and ‘with-editor-shell-command’ are intended as drop in replacements for ‘async-shell-command’ and ‘shell-command’. They automatically export ‘$EDITOR’ making sure the executed command uses the current Emacs instance as "the editor". With a prefix argument these commands prompt for an alternative environment variable such as ‘$GIT_EDITOR’. -- Command: with-editor-async-shell-command Like ‘async-shell-command’, but the command is run with the current Emacs instance exported as ‘$EDITOR’. -- Command: with-editor-shell-command Like ‘async-shell-command’, but the command is run with the current Emacs instance exported as ‘$EDITOR’. This only has an effect if the command is run asynchronously, i.e. when the command ends with ‘&’. To always use these variants add this to you init file: (define-key (current-global-map) [remap async-shell-command] 'with-editor-async-shell-command) (define-key (current-global-map) [remap shell-command] 'with-editor-shell-command) Alternatively use the global ‘shell-command-with-editor-mode’. -- Variable: shell-command-with-editor-mode When this mode is active, then ‘$EDITOR’ is exported whenever ultimately ‘shell-command’ is called to asynchronously run some shell command. This affects most variants of that command, whether they are defined in Emacs or in some third-party package. The command ‘with-editor-export-editor’ exports ‘$EDITOR’ or another such environment variable in ‘shell-mode’, ‘term-mode’ and ‘eshell-mode’ buffers. Use this Emacs command before executing a shell command which needs the editor set, or always arrange for the current Emacs instance to be used as editor by adding it to the appropriate mode hooks: (add-hook 'shell-mode-hook 'with-editor-export-editor) (add-hook 'term-mode-hook 'with-editor-export-editor) (add-hook 'eshell-mode-hook 'with-editor-export-editor) Some variants of this function exist; these two forms are equivalent: (add-hook 'shell-mode-hook (apply-partially 'with-editor-export-editor "GIT_EDITOR")) (add-hook 'shell-mode-hook 'with-editor-export-git-editor) -- Command: with-editor-export-editor When invoked in a ‘shell-mode’, ‘term-mode’, or ‘eshell-mode’ buffer, this command teaches shell commands to use the current Emacs instance as the editor, by exporting ‘$EDITOR’. -- Command: with-editor-export-git-editor Like ‘with-editor-export-editor’ but exports ‘$GIT_EDITOR’. -- Command: with-editor-export-hg-editor Like ‘with-editor-export-editor’ but exports ‘$HG_EDITOR’.  File: with-editor.info, Node: Using With-Editor as a library, Next: Debugging, Prev: Using the With-Editor package, Up: Top 2 Using With-Editor as a library ******************************** This section describes how to use the with-editor library _outside_ of Magit to teach another package how to have its child processes call home, just like Magit does. You don’t need to know any of this just to create commits using Magit. You can also ignore this if you use ‘with-editor’ outside of Magit, but only as an end-user. For information about interactive use and options which affect both interactive and non-interactive use, see *note Using the With-Editor package: Using the With-Editor package. -- Macro: with-editor &rest body This macro arranges for the emacsclient or the sleeping editor to be used as the editor of child processes, effectively teaching them to call home to the current emacs instance when they require that the user edits a file. This is essentially done by establishing a local binding for ‘process-environment’ and changing the value of the ‘$EDITOR’ environment variable. This affects all processes started by forms inside BODY. -- Function: with-editor-set-process-filter process filter This function is like ‘set-process-filter’ but ensures that adding the new FILTER does not remove the ‘with-editor-process-filter’. This is done by wrapping the two filter functions using a lambda, which becomes the actual filter. It calls ‘with-editor-process-filter’ first, passing ‘t’ as NO-STANDARD-FILTER. Then it calls FILTER.  File: with-editor.info, Node: Debugging, Prev: Using With-Editor as a library, Up: Top 3 Debugging *********** With-Editor tries very hard to locate a suitable emacsclient executable, and then sets option ‘with-editor-emacsclient-executable’ accordingly. In very rare cases this fails. When it does fail, then the most likely reason is that someone found yet another way to package Emacs (most likely on OS X) without putting the executable on ‘$PATH’, and we have to add another kludge to find it anyway. If you are having problems using ‘with-editor’, e.g. you cannot commit in Magit, then please open a new issue at and provide information about your Emacs installation. Most importantly how did you install Emacs and what is the output of ‘M-x with-editor-debug’?  Tag Table: Node: Top1545 Node: Using the With-Editor package3237 Node: Configuring With-Editor3853 Node: Using With-Editor commands7460 Node: Using With-Editor as a library10623 Node: Debugging12295  End Tag Table  Local Variables: coding: utf-8 End: with-editor-2.5.0/with-editor.org000066400000000000000000000243161265247160500167430ustar00rootroot00000000000000#+TITLE: With-Editor User Manual #+AUTHOR: Jonas Bernoulli #+EMAIL: jonas@bernoul.li #+DATE: 2015-2016 #+LANGUAGE: en #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: With-Editor: (with-editor). #+TEXINFO_DIR_DESC: Using the Emacsclient as $EDITOR #+SUBTITLE: for version 2.5 #+OPTIONS: H:4 num:3 toc:2 * Copying :PROPERTIES: :COPYING: t :END: #+BEGIN_TEXINFO @ifnottex The library @code{with-editor} makes it easy to use the Emacsclient as the @code{$EDITOR} of child processes, making sure they know how to call home. For remote processes a substitute is provided, which communicates with Emacs on standard output instead of using a socket as the Emacsclient does. This library was written because Magit has to be able to do the above to allow the user to edit commit messages gracefully and to edit rebase sequences, which wouldn't be possible at all otherwise. Because other packages can benefit from such functionality, this library is made available as a separate package. It also defines some additional functionality which makes it useful even for end-users, who don't use Magit or another package which uses it internally. @end ifnottex @quotation Copyright (C) 2015-2016 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This document is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @end quotation #+END_TEXINFO * Using the With-Editor package The ~With-Editor~ package is used internally by Magit when editing commit messages and rebase sequences. It also provides some commands and features which are useful by themselves, even if you don't use Magit. For information about using this library in you own package, see [[*Using With-Editor as a library]]. ** Configuring With-Editor With-Editor tries very hard to locate a suitable emacsclient executable, so ideally you should never have to customize the option ~with-editor-emacsclient-executable~. When it fails to do so, then the most likely reason is that someone found yet another way to package Emacs (most likely on OS X) without putting the executable on ~$PATH~, and we have to add another kludge to find it anyway. - User Option: with-editor-emacsclient-executable The emacsclient executable used as the editor by child process of this Emacs instance. By using this executable, child processes can call home to their parent process. This option is automatically set at startup by looking in ~exec-path~, and other places where the executable could be installed, to find the emacsclient executable most suitable for the current emacs instance. You should *not* customize this option permanently. If you have to do it, then you should consider that a temporary kludge and inform the Magit maintainer as described in [[*Debugging][Debugging]]. If With-Editor fails to find a suitable emacsclient on you system, then this should be fixed for all users at once, by teaching ~with-editor-locate-emacsclient~ how to so on your system and system like yours. Doing it this way has the advantage, that you won't have do it again every time you update Emacs, and that other users who have installed Emacs the same way as you have, won't have to go through the same trouble. Note that there also is a nuclear option; setting this variable to ~nil~ causes the "sleeping editor" described below to be used even for local child processes. Obviously we don't recommend that you use this except in "emergencies", i.e. before we had a change to add a kludge appropriate for you setup. - Function: with-editor-locate-emacsclient The function used to set the initial value of the option ~with-editor-emacsclient-executable~. There's a lot of voodoo here. The emacsclient cannot be used when using Tramp to run a process on a remote machine. (Theoretically it could, but that would be hard to setup, very fragile, and rather insecure). With-Editor provides an alternative "editor" which can be used by remote processes in much the same way as local processes use an emacsclient executable. This alternative is known as the "sleeping editor" because it is implemented as a shell script which sleeps until it receives a signal. - User Option: with-editor-sleeping-editor The sleeping editor is a shell script used as the editor of child processes when the emacsclient executable cannot be used. This fallback is used for asynchronous process started inside the macro ~with-editor~, when the process runs on a remote machine or for local processes when ~with-editor-emacsclient-executable~ is ~nil~. Where the latter uses a socket to communicate with Emacs' server, this substitute prints edit requests to its standard output on which a process filter listens for such requests. As such it is not a complete substitute for a proper Emacsclient, it can only be used as ~$EDITOR~ of child process of the current Emacs instance. It is unlikely that you should ever have to customize this option. ** Using With-Editor commands This section describes how to use the ~with-editor~ library /outside/ of Magit. You don't need to know any of this just to create commits using Magit. The commands ~with-editor-async-shell-command~ and ~with-editor-shell-command~ are intended as drop in replacements for ~async-shell-command~ and ~shell-command~. They automatically export ~$EDITOR~ making sure the executed command uses the current Emacs instance as "the editor". With a prefix argument these commands prompt for an alternative environment variable such as ~$GIT_EDITOR~. - Command: with-editor-async-shell-command Like ~async-shell-command~, but the command is run with the current Emacs instance exported as ~$EDITOR~. - Command: with-editor-shell-command Like ~async-shell-command~, but the command is run with the current Emacs instance exported as ~$EDITOR~. This only has an effect if the command is run asynchronously, i.e. when the command ends with ~&~. To always use these variants add this to you init file: #+BEGIN_SRC emacs-lisp (define-key (current-global-map) [remap async-shell-command] 'with-editor-async-shell-command) (define-key (current-global-map) [remap shell-command] 'with-editor-shell-command) #+END_SRC Alternatively use the global ~shell-command-with-editor-mode~. - Variable: shell-command-with-editor-mode When this mode is active, then ~$EDITOR~ is exported whenever ultimately ~shell-command~ is called to asynchronously run some shell command. This affects most variants of that command, whether they are defined in Emacs or in some third-party package. The command ~with-editor-export-editor~ exports ~$EDITOR~ or another such environment variable in ~shell-mode~, ~term-mode~ and ~eshell-mode~ buffers. Use this Emacs command before executing a shell command which needs the editor set, or always arrange for the current Emacs instance to be used as editor by adding it to the appropriate mode hooks: #+BEGIN_SRC emacs-lisp (add-hook 'shell-mode-hook 'with-editor-export-editor) (add-hook 'term-mode-hook 'with-editor-export-editor) (add-hook 'eshell-mode-hook 'with-editor-export-editor) #+END_SRC Some variants of this function exist; these two forms are equivalent: #+BEGIN_SRC emacs-lisp (add-hook 'shell-mode-hook (apply-partially 'with-editor-export-editor "GIT_EDITOR")) (add-hook 'shell-mode-hook 'with-editor-export-git-editor) #+END_SRC - Command: with-editor-export-editor When invoked in a ~shell-mode~, ~term-mode~, or ~eshell-mode~ buffer, this command teaches shell commands to use the current Emacs instance as the editor, by exporting ~$EDITOR~. - Command: with-editor-export-git-editor Like ~with-editor-export-editor~ but exports ~$GIT_EDITOR~. - Command: with-editor-export-hg-editor Like ~with-editor-export-editor~ but exports ~$HG_EDITOR~. * Using With-Editor as a library This section describes how to use the =with-editor= library /outside/ of Magit to teach another package how to have its child processes call home, just like Magit does. You don't need to know any of this just to create commits using Magit. You can also ignore this if you use ~with-editor~ outside of Magit, but only as an end-user. For information about interactive use and options which affect both interactive and non-interactive use, see [[*Using the With-Editor package]]. - Macro: with-editor &rest body This macro arranges for the emacsclient or the sleeping editor to be used as the editor of child processes, effectively teaching them to call home to the current emacs instance when they require that the user edits a file. This is essentially done by establishing a local binding for ~process-environment~ and changing the value of the ~$EDITOR~ environment variable. This affects all processes started by forms inside BODY. - Function: with-editor-set-process-filter process filter This function is like ~set-process-filter~ but ensures that adding the new FILTER does not remove the ~with-editor-process-filter~. This is done by wrapping the two filter functions using a lambda, which becomes the actual filter. It calls ~with-editor-process-filter~ first, passing ~t~ as NO-STANDARD-FILTER. Then it calls FILTER. * Debugging With-Editor tries very hard to locate a suitable emacsclient executable, and then sets option ~with-editor-emacsclient-executable~ accordingly. In very rare cases this fails. When it does fail, then the most likely reason is that someone found yet another way to package Emacs (most likely on OS X) without putting the executable on ~$PATH~, and we have to add another kludge to find it anyway. If you are having problems using ~with-editor~, e.g. you cannot commit in Magit, then please open a new issue at https://github.com/magit/magit/issues and provide information about your Emacs installation. Most importantly how did you install Emacs and what is the output of ~M-x with-editor-debug~? # LocalWords: Emacsclient LocalWords Magit async emacs emacsclient # LocalWords: hg init rebase startup with-editor-2.5.0/with-editor.texi000066400000000000000000000263431265247160500171270ustar00rootroot00000000000000\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename ./with-editor.info @settitle With-Editor User Manual @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying @ifnottex The library @code{with-editor} makes it easy to use the Emacsclient as the @code{$EDITOR} of child processes, making sure they know how to call home. For remote processes a substitute is provided, which communicates with Emacs on standard output instead of using a socket as the Emacsclient does. This library was written because Magit has to be able to do the above to allow the user to edit commit messages gracefully and to edit rebase sequences, which wouldn't be possible at all otherwise. Because other packages can benefit from such functionality, this library is made available as a separate package. It also defines some additional functionality which makes it useful even for end-users, who don't use Magit or another package which uses it internally. @end ifnottex @quotation Copyright (C) 2015-2016 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This document is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @end quotation @end copying @dircategory Emacs @direntry * With-Editor: (with-editor). Using the Emacsclient as $EDITOR. @end direntry @finalout @titlepage @title With-Editor User Manual @subtitle for version 2.5 @author Jonas Bernoulli @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top With-Editor User Manual @insertcopying @end ifnottex @menu * Using the With-Editor package:: * Using With-Editor as a library:: * Debugging:: @detailmenu --- The Detailed Node Listing --- Using the With-Editor package * Configuring With-Editor:: * Using With-Editor commands:: @end detailmenu @end menu @node Using the With-Editor package @chapter Using the With-Editor package The @code{With-Editor} package is used internally by Magit when editing commit messages and rebase sequences. It also provides some commands and features which are useful by themselves, even if you don't use Magit. For information about using this library in you own package, see @ref{Using With-Editor as a library,Using With-Editor as a library}. @menu * Configuring With-Editor:: * Using With-Editor commands:: @end menu @node Configuring With-Editor @section Configuring With-Editor With-Editor tries very hard to locate a suitable emacsclient executable, so ideally you should never have to customize the option @code{with-editor-emacsclient-executable}. When it fails to do so, then the most likely reason is that someone found yet another way to package Emacs (most likely on OS X) without putting the executable on @code{$PATH}, and we have to add another kludge to find it anyway. @defopt with-editor-emacsclient-executable The emacsclient executable used as the editor by child process of this Emacs instance. By using this executable, child processes can call home to their parent process. This option is automatically set at startup by looking in @code{exec-path}, and other places where the executable could be installed, to find the emacsclient executable most suitable for the current emacs instance. You should @strong{not} customize this option permanently. If you have to do it, then you should consider that a temporary kludge and inform the Magit maintainer as described in @ref{Debugging,Debugging}. If With-Editor fails to find a suitable emacsclient on you system, then this should be fixed for all users at once, by teaching @code{with-editor-locate-emacsclient} how to so on your system and system like yours. Doing it this way has the advantage, that you won't have do it again every time you update Emacs, and that other users who have installed Emacs the same way as you have, won't have to go through the same trouble. Note that there also is a nuclear option; setting this variable to @code{nil} causes the "sleeping editor" described below to be used even for local child processes. Obviously we don't recommend that you use this except in "emergencies", i.e. before we had a change to add a kludge appropriate for you setup. @end defopt @defun with-editor-locate-emacsclient The function used to set the initial value of the option @code{with-editor-emacsclient-executable}. There's a lot of voodoo here. @end defun The emacsclient cannot be used when using Tramp to run a process on a remote machine. (Theoretically it could, but that would be hard to setup, very fragile, and rather insecure). With-Editor provides an alternative "editor" which can be used by remote processes in much the same way as local processes use an emacsclient executable. This alternative is known as the "sleeping editor" because it is implemented as a shell script which sleeps until it receives a signal. @defopt with-editor-sleeping-editor The sleeping editor is a shell script used as the editor of child processes when the emacsclient executable cannot be used. This fallback is used for asynchronous process started inside the macro @code{with-editor}, when the process runs on a remote machine or for local processes when @code{with-editor-emacsclient-executable} is @code{nil}. Where the latter uses a socket to communicate with Emacs' server, this substitute prints edit requests to its standard output on which a process filter listens for such requests. As such it is not a complete substitute for a proper Emacsclient, it can only be used as @code{$EDITOR} of child process of the current Emacs instance. It is unlikely that you should ever have to customize this option. @end defopt @node Using With-Editor commands @section Using With-Editor commands This section describes how to use the @code{with-editor} library @emph{outside} of Magit. You don't need to know any of this just to create commits using Magit. The commands @code{with-editor-async-shell-command} and @code{with-editor-shell-command} are intended as drop in replacements for @code{async-shell-command} and @code{shell-command}. They automatically export @code{$EDITOR} making sure the executed command uses the current Emacs instance as "the editor". With a prefix argument these commands prompt for an alternative environment variable such as @code{$GIT_EDITOR}. @cindex with-editor-async-shell-command @deffn Command with-editor-async-shell-command Like @code{async-shell-command}, but the command is run with the current Emacs instance exported as @code{$EDITOR}. @end deffn @cindex with-editor-shell-command @deffn Command with-editor-shell-command Like @code{async-shell-command}, but the command is run with the current Emacs instance exported as @code{$EDITOR}. This only has an effect if the command is run asynchronously, i.e. when the command ends with @code{&}. @end deffn To always use these variants add this to you init file: @lisp (define-key (current-global-map) [remap async-shell-command] 'with-editor-async-shell-command) (define-key (current-global-map) [remap shell-command] 'with-editor-shell-command) @end lisp Alternatively use the global @code{shell-command-with-editor-mode}. @defvar shell-command-with-editor-mode When this mode is active, then @code{$EDITOR} is exported whenever ultimately @code{shell-command} is called to asynchronously run some shell command. This affects most variants of that command, whether they are defined in Emacs or in some third-party package. @end defvar The command @code{with-editor-export-editor} exports @code{$EDITOR} or another such environment variable in @code{shell-mode}, @code{term-mode} and @code{eshell-mode} buffers. Use this Emacs command before executing a shell command which needs the editor set, or always arrange for the current Emacs instance to be used as editor by adding it to the appropriate mode hooks: @lisp (add-hook 'shell-mode-hook 'with-editor-export-editor) (add-hook 'term-mode-hook 'with-editor-export-editor) (add-hook 'eshell-mode-hook 'with-editor-export-editor) @end lisp Some variants of this function exist; these two forms are equivalent: @lisp (add-hook 'shell-mode-hook (apply-partially 'with-editor-export-editor "GIT_EDITOR")) (add-hook 'shell-mode-hook 'with-editor-export-git-editor) @end lisp @cindex with-editor-export-editor @deffn Command with-editor-export-editor When invoked in a @code{shell-mode}, @code{term-mode}, or @code{eshell-mode} buffer, this command teaches shell commands to use the current Emacs instance as the editor, by exporting @code{$EDITOR}. @end deffn @cindex with-editor-export-git-editor @deffn Command with-editor-export-git-editor Like @code{with-editor-export-editor} but exports @code{$GIT_EDITOR}. @end deffn @cindex with-editor-export-hg-editor @deffn Command with-editor-export-hg-editor Like @code{with-editor-export-editor} but exports @code{$HG_EDITOR}. @end deffn @node Using With-Editor as a library @chapter Using With-Editor as a library This section describes how to use the @verb{~with-editor~} library @emph{outside} of Magit to teach another package how to have its child processes call home, just like Magit does. You don't need to know any of this just to create commits using Magit. You can also ignore this if you use @code{with-editor} outside of Magit, but only as an end-user. For information about interactive use and options which affect both interactive and non-interactive use, see @ref{Using the With-Editor package,Using the With-Editor package}. @defmac with-editor &rest body This macro arranges for the emacsclient or the sleeping editor to be used as the editor of child processes, effectively teaching them to call home to the current emacs instance when they require that the user edits a file. This is essentially done by establishing a local binding for @code{process-environment} and changing the value of the @code{$EDITOR} environment variable. This affects all processes started by forms inside BODY. @end defmac @defun with-editor-set-process-filter process filter This function is like @code{set-process-filter} but ensures that adding the new FILTER does not remove the @code{with-editor-process-filter}. This is done by wrapping the two filter functions using a lambda, which becomes the actual filter. It calls @code{with-editor-process-filter} first, passing @code{t} as NO-STANDARD-FILTER. Then it calls FILTER. @end defun @node Debugging @chapter Debugging With-Editor tries very hard to locate a suitable emacsclient executable, and then sets option @code{with-editor-emacsclient-executable} accordingly. In very rare cases this fails. When it does fail, then the most likely reason is that someone found yet another way to package Emacs (most likely on OS X) without putting the executable on @code{$PATH}, and we have to add another kludge to find it anyway. If you are having problems using @code{with-editor}, e.g. you cannot commit in Magit, then please open a new issue at @uref{https://github.com/magit/magit/issues} and provide information about your Emacs installation. Most importantly how did you install Emacs and what is the output of @code{M-x with-editor-debug}? @bye