emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 8ee21db4af: Add new function `read-string-from-buffer'.


From: Lars Ingebrigtsen
Subject: master 8ee21db4af: Add new function `read-string-from-buffer'.
Date: Sun, 24 Apr 2022 09:16:05 -0400 (EDT)

branch: master
commit 8ee21db4af0f1d3a11b943fa113201dd45e01784
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Add new function `read-string-from-buffer'.
    
    * doc/lispref/minibuf.texi (Text from Minibuffer): Document it.
    * lisp/textmodes/string-edit.el: New file.
---
 doc/lispref/minibuf.texi      |   7 +++
 etc/NEWS                      |  11 ++++
 lisp/textmodes/string-edit.el | 122 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+)

diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index f05f087ba7..986da6365f 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -244,6 +244,13 @@ This function works by calling the
     value))
 @end group
 @end smallexample
+
+@findex read-string-from-buffer
+If you have a long string (for instance, one that is several lines
+long) that you wish to edit, using @code{read-string} may not be
+ideal.  In that case, popping to a new, normal buffer where the user
+can edit the string may be more convenient, and you can use the
+@code{read-string-from-buffer} function to do that.
 @end defun
 
 @defun read-regexp prompt &optional defaults history
diff --git a/etc/NEWS b/etc/NEWS
index 04231ff16f..81e3003e05 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1469,6 +1469,17 @@ functions.
 
 * Lisp Changes in Emacs 29.1
 
+---
+** New function 'string-edit'.
+This is meant to be used when the user has to edit a (potentially)
+long string.  It pops you to a new buffer where you can edit the
+string, and a callback is called when the user types 'C-c C-c'.
+
++++
+** New function 'read-string-from-buffer'.
+This is a modal version of 'string-edit', and can be used as an
+alternative to 'read-string'.
+
 +++
 ** The return value of 'clear-message-function' is not ignored anymore.
 If the function returns 'dont-clear-message', then the message is not
diff --git a/lisp/textmodes/string-edit.el b/lisp/textmodes/string-edit.el
new file mode 100644
index 0000000000..9f28fe773f
--- /dev/null
+++ b/lisp/textmodes/string-edit.el
@@ -0,0 +1,122 @@
+;;; string-edit.el --- editing long strings  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl-lib)
+
+(defface string-edit-help-text
+  '((t (:inherit font-lock-comment-face)))
+  "Face used on `string-edit' help text."
+  :group 'text
+  :version "29.1")
+
+(defvar string-edit--success-callback)
+(defvar string-edit--abort-callback)
+
+(cl-defun string-edit (string success-callback
+                              &key abort-callback help-text)
+  "Switch to a new buffer to edit STRING.
+When the user finishes editing (with `C-c C-c'), SUCCESS-CALLBACK
+is called with the resulting string.
+
+If the user aborts (with `C-c C-d'), ABORT-CALLBACK (if any) is
+called with no parameters.
+
+If present, HELP-TEXT will be inserted at the start of the
+buffer, but won't be included in the resulting string."
+  (pop-to-buffer-same-window (generate-new-buffer "*edit string*"))
+  (when help-text
+    (let ((inhibit-read-only t))
+      (insert help-text)
+      (ensure-empty-lines 0)
+      (add-text-properties (point-min) (point)
+                           (list 'intangible t
+                                 'face 'string-edit-help-text
+                                 'read-only t))
+      (insert (propertize (make-separator-line) 'rear-nonsticky t))
+      (add-text-properties (point-min) (point)
+                           (list 'string-edit--help-text t))))
+  (let ((start (point)))
+    (insert string)
+    (goto-char start))
+  (set-buffer-modified-p nil)
+  (setq buffer-undo-list nil)
+  (string-edit-mode)
+  (setq-local string-edit--success-callback success-callback)
+  (when abort-callback
+    (setq-local string-edit--abort-callback abort-callback))
+  (message "%S" (substitute-command-keys
+                 "Type `C-c C-c' when you've finished editing")))
+
+(defun read-string-from-buffer (string &optional help-text)
+  "Switch to a new buffer to edit STRING in a recursive edit.
+The user finishes editing with `C-c C-c', or aborts with `C-c C-d').
+
+If present, HELP-TEXT will be inserted at the start of the
+buffer, but won't be included in the resulting string."
+  (string-edit
+   string
+   (lambda (edited)
+     (setq string edited)
+     (exit-recursive-edit))
+   :help-text help-text
+   :abort-callback (lambda ()
+                     (exit-recursive-edit)
+                     (error "Aborted edit")))
+  (recursive-edit)
+  string)
+
+(defvar-keymap string-edit-mode-map
+  "C-c C-c" #'string-edit-done
+  "C-c C-d" #'string-edit-abort)
+
+(define-derived-mode string-edit-mode text-mode "String"
+  "Mode for editing strings."
+  :interactive nil)
+
+(defun string-edit-done ()
+  "Finish editing the string and call the callback function.
+This will kill the current buffer."
+  (interactive)
+  (goto-char (point-min))
+  ;; Skip past the help text.
+  (when-let ((match (text-property-search-forward
+                     'string-edit--help-text nil t)))
+    (goto-char (prop-match-beginning match)))
+  (let ((string (buffer-substring (point) (point-max)))
+        (callback string-edit--success-callback))
+    (kill-buffer (current-buffer))
+    (funcall callback string)))
+
+(defun string-edit-abort ()
+  "Abort editing the current string."
+  (interactive)
+  (let ((callback string-edit--abort-callback))
+    (kill-buffer (current-buffer))
+    (when callback
+      (funcall callback))))
+
+(provide 'string-edit)
+
+;;; string-edit.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]