1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-03 11:33:37 +00:00

Allow moving members of editable-list widget, via delete+insert

* etc/NEWS (Widget): Announce the feature (bug#6419).
* lisp/wid-edit.el (widget-editable-list-delete-at): Save into a new
widget property, :last-deleted, the WIDGET to be deleted.  Add
docstring.
(widget-editable-list-insert-before): If there is a recently deleted
child for the editable list, insert that one, instead of a new default
widget.  Add docstring.
(insert-button widget): Make :help-echo a function to avoid the
help-echo string become too long.
(delete-button widget): Tweak the :help-echo string, to document this
behavior.

* test/lisp/wid-edit-tests.el (widget-test-moving-editable-list-item):
Test the feature.
This commit is contained in:
Mauro Aranda 2020-10-22 13:52:42 +02:00 committed by Lars Ingebrigtsen
parent 954a4decfc
commit c009a0a6f7
3 changed files with 55 additions and 4 deletions

View File

@ -1166,6 +1166,13 @@ window after starting). This variable defaults to nil.
+++
*** 'widget-choose' now supports menus in extended format.
---
*** The 'editable-list' widget now supports moving items up and down.
You can now move items up and down by deleting and then reinserting
them, using the DEL and INS buttons respectively. This is useful in
Custom buffers, for example, to change the order of the elements in a
list.
** Miscellaneous
---

View File

@ -2721,7 +2721,10 @@ Return an alist of (TYPE MATCH)."
(define-widget 'insert-button 'push-button
"An insert button for the `editable-list' widget."
:tag "INS"
:help-echo "Insert a new item into the list at this position."
:help-echo (lambda (widget)
(if (widget-get (widget-get widget :parent) :last-deleted)
"Insert back the last deleted item from this list, at this position."
"Insert a new item into the list at this position."))
:action 'widget-insert-button-action)
(defun widget-insert-button-action (widget &optional _event)
@ -2734,7 +2737,7 @@ Return an alist of (TYPE MATCH)."
(define-widget 'delete-button 'push-button
"A delete button for the `editable-list' widget."
:tag "DEL"
:help-echo "Delete this item from the list."
:help-echo "Delete this item from the list, saving it for later reinsertion."
:action 'widget-delete-button-action)
(defun widget-delete-button-action (widget &optional _event)
@ -2824,9 +2827,18 @@ Return an alist of (TYPE MATCH)."
(cons found value)))
(defun widget-editable-list-insert-before (widget before)
;; Insert a new child in the list of children.
"Insert a new widget as a child of WIDGET.
If there is a recently deleted child, the new widget is that deleted child.
Otherwise, the new widget is the default child of WIDGET.
The new widget gets inserted at the position of the BEFORE child."
(save-excursion
(let ((children (widget-get widget :children))
(last-deleted (when-let ((lst (widget-get widget :last-deleted)))
(prog1
(pop lst)
(widget-put widget :last-deleted lst))))
(inhibit-read-only t)
(inhibit-modification-hooks t))
(cond (before
@ -2834,7 +2846,11 @@ Return an alist of (TYPE MATCH)."
(t
(goto-char (widget-get widget :value-pos))))
(let ((child (widget-editable-list-entry-create
widget nil nil)))
widget (and last-deleted
(widget-apply last-deleted
:value-to-external
(widget-get last-deleted :value)))
last-deleted)))
(when (< (widget-get child :entry-from) (widget-get widget :from))
(set-marker (widget-get widget :from)
(widget-get child :entry-from)))
@ -2847,6 +2863,15 @@ Return an alist of (TYPE MATCH)."
(widget-apply widget :notify widget))
(defun widget-editable-list-delete-at (widget child)
"Delete the widget CHILD from the known children of widget WIDGET.
Save CHILD into the :last-deleted list, so it can be inserted later."
;; Save the current value of CHILD, to use if the user later inserts the
;; widget.
(widget-put child :value (widget-apply child :value-get))
(let ((lst (widget-get widget :last-deleted)))
(push child lst)
(widget-put widget :last-deleted lst))
;; Delete child from list of children.
(save-excursion
(let ((buttons (copy-sequence (widget-get widget :buttons)))

View File

@ -129,4 +129,23 @@
(widget-insert "And some non-widget text.")
(should (string= (widget-apply wid :value-get) "")))))
(ert-deftest widget-test-moving-editable-list-item ()
"Check that we can move an editable list item up or down, via delete+insert."
(with-temp-buffer
(widget-insert "Testing editable-list.\n\n")
(let ((lst (widget-create 'editable-list
:value '("beg" "end" "middle")
'(editable-field :value "unknown"))))
(use-local-map widget-keymap)
(widget-setup)
;; Go to the DEL button for the 2nd element and action it.
(goto-char (widget-get (nth 2 (widget-get lst :buttons)) :from))
(widget-apply-action (widget-at))
;; Go to the INS button and action it.
(goto-char (widget-get lst :to))
(widget-backward 1)
(widget-apply-action (widget-at))
;; Check that we effectively moved the item to the last position.
(should (equal (widget-value lst) '("beg" "middle" "end"))))))
;;; wid-edit-tests.el ends here