(cl-defun my-edit-async (finish &key mode buffer-name setup cancel) "Open a buffer, let the user edit its content. Return the editing buffer. Call FINISH in the editing buffer if the user validates his edit (C-c C-c). When CANCEL is non-nil, call CANCEL in the editing buffer if the user cancels his edit (C-c C-k). When done, delete the buffer and its content. When MODE is non-nil, use it as the major-mode. When BUFFER-NAME is non-nil, use it to generate a new unique name of the editing buffer. When SETUP is non-nil, call it in the edit buffer to setup the buffer before starting the edit." (unless buffer-name (setq buffer-name "@Async edit")) (let ((buf (generate-new-buffer buffer-name))) (with-current-buffer buf (when mode (funcall mode)) (when setup (funcall setup)) (with-editor-mode 1) (setq with-editor-previous-winconf (current-window-configuration)) (add-hook 'with-editor-pre-finish-hook (lambda () (funcall finish) (set-buffer-modified-p nil)) nil :local) (add-hook 'with-editor-pre-cancel-hook (lambda () (when cancel (funcall cancel)) (set-buffer-modified-p nil)) nil :local) (switch-to-buffer buf)) buf)) (my-edit-async (lambda () (message "My edit:\n%S" (buffer-string))) :cancel (lambda () (message "Canceled (discarded: %s)" (buffer-string))) :setup (lambda () (insert "initial content") (goto-char (point-min))))