From 228001795ab15936cd2e8d1fec38ec15b77c5b91 Mon Sep 17 00:00:00 2001 From: Mauro Aranda Date: Tue, 15 Aug 2023 19:35:39 -0300 Subject: [PATCH] Specialize default-get for alist widgets (Bug#63290) * lisp/wid-edit.el (widget-list-default-get) (widget-alist-default-get): New functions. (list, alist): Use it. * test/lisp/cus-edit-tests.el (cus-edit-test-bug63290-option) (cus-edit-test-bug63290-option-2): New test options. (cus-edit-test-bug63290): New test. * test/lisp/wid-edit-tests.el (widget-test-alist-default-value-1) (widget-test-alist-default-value-2, widget-test-alist-default-value-3) (widget-test-alist-default-value-4): New tests. --- lisp/wid-edit.el | 32 ++++++++++++++++++++++++++- test/lisp/cus-edit-tests.el | 43 +++++++++++++++++++++++++++++++++++++ test/lisp/wid-edit-tests.el | 31 ++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 47531113ba8..5dbdd7127aa 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el @@ -3812,8 +3812,19 @@ widget-character-notify (define-widget 'list 'group "A Lisp list." :tag "List" + :default-get #'widget-list-default-get :format "%{%t%}:\n%v") +(defun widget-list-default-get (widget) + "Return the default external value for a list WIDGET. + +The default value is the one stored in the :value property, even if it is nil, +or a list with the default value of each component of the list WIDGET." + (widget-apply widget :value-to-external + (if (widget-member widget :value) + (widget-get widget :value) + (widget-group-default-get widget)))) + (define-widget 'vector 'group "A Lisp vector." :tag "Vector" @@ -3942,7 +3953,6 @@ widget-plist-convert-option value-type widget-plist-value-type)) `(group :format "Key: %v" :inline t ,key-type ,value-type))) - ;;; The `alist' Widget. ;; ;; Association lists. @@ -3952,6 +3962,7 @@ 'alist :key-type '(sexp :tag "Key") :value-type '(sexp :tag "Value") :convert-widget 'widget-alist-convert-widget + :default-get #'widget-alist-default-get :tag "Alist") (defvar widget-alist-value-type) ;Dynamic variable @@ -3986,6 +3997,25 @@ widget-alist-convert-option (setq key-type `(const ,option) value-type widget-alist-value-type)) `(cons :format "Key: %v" ,key-type ,value-type))) + +(defun widget-alist-default-get (widget) + "Return the default value for WIDGET, an alist widget. + +The default value may be one of: +- The one stored in the :value property, even if it is nil. +- If WIDGET has options available, an alist consisting of the +default values for each option. +- nil, otherwise." + (widget-apply widget :value-to-external + (cond ((widget-member widget :value) + (widget-get widget :value)) + ((widget-get widget :options) + (mapcar #'widget-default-get + ;; Last one is the editable-list part, and + ;; we don't want those showing up as + ;; part of the default value. (Bug#63290) + (butlast (widget-get widget :args)))) + (t nil)))) (define-widget 'choice 'menu-choice "A union of several sexp types. diff --git a/test/lisp/cus-edit-tests.el b/test/lisp/cus-edit-tests.el index eca35d7c96a..3a788f19745 100644 --- a/test/lisp/cus-edit-tests.el +++ b/test/lisp/cus-edit-tests.el @@ -92,5 +92,48 @@ test-setopt (buffer-substring-no-properties (point-min) (point-max))))) (should (string-search "Value `:foo' does not match type number" warn-txt)))) + +(defcustom cus-edit-test-bug63290-option nil + "Choice option for testing Bug#63290." + :type '(choice (alist + :key-type (string :tag "key") + :value-type (string :tag "value")) + (const :tag "auto" auto))) + +(defcustom cus-edit-test-bug63290-option2 'some + "Choice option for testing Bug#63290." + :type '(choice + (const :tag "some" some) + (alist + :key-type (string :tag "key") + :value-type (string :tag "value")))) + +(ert-deftest cus-edit-test-bug63290 () + "Test that changing a choice value back to an alist respects its nil value." + (customize-variable 'cus-edit-test-bug63290-option) + (search-forward "Value") + ;; Simulate changing the value. + (let* ((choice (widget-at)) + (args (widget-get choice :args)) + (list-opt (car (widget-get choice :children))) + (const-opt (nth 1 args))) + (widget-put choice :explicit-choice const-opt) + (widget-value-set choice (widget-default-get const-opt)) + (widget-put choice :explicit-choice list-opt) + (widget-value-set choice (widget-default-get list-opt))) + ;; No empty key/value pairs should show up. + (should-not (search-forward "key" nil t)) + (customize-variable 'cus-edit-test-bug63290-option2) + (search-forward "Value") + ;; Simulate changing the value. + (let* ((choice (widget-at)) + (args (widget-get choice :args)) + (const-opt (car (widget-get choice :children))) + (list-opt (nth 1 args))) + (widget-put choice :explicit-choice list-opt) + (widget-value-set choice (widget-default-get list-opt))) + ;; No empty key/value pairs should show up. + (should-not (search-forward "key" nil t))) + (provide 'cus-edit-tests) ;;; cus-edit-tests.el ends here diff --git a/test/lisp/wid-edit-tests.el b/test/lisp/wid-edit-tests.el index b379c7c91a8..ebfe729bc9a 100644 --- a/test/lisp/wid-edit-tests.el +++ b/test/lisp/wid-edit-tests.el @@ -349,4 +349,35 @@ widget-test-color-match (should-not (widget-apply widget :match "someundefinedcolorihope")) (should-not (widget-apply widget :match "#11223")))) +(ert-deftest widget-test-alist-default-value-1 () + "Test getting the default value for an alist widget with options." + (with-temp-buffer + (let ((w (widget-create '(alist :key-type string + :value-type integer + :options (("0" (integer))))))) + (should (equal '(("0" . 0)) (widget-default-get w)))))) + +(ert-deftest widget-test-alist-default-value-2 () + "Test getting the default value for an alist widget without :value." + (with-temp-buffer + (let ((w (widget-create '(alist :key-type string + :value-type integer)))) + (should-not (widget-default-get w))))) + +(ert-deftest widget-test-alist-default-value-3 () + "Test getting the default value for an alist widget with nil :value." + (with-temp-buffer + (let ((w (widget-create '(alist :key-type string + :value-type integer + :value nil)))) + (should-not (widget-default-get w))))) + +(ert-deftest widget-test-alist-default-value-4 () + "Test getting the default value for an alist widget with non-nil :value." + (with-temp-buffer + (let ((w (widget-create '(alist :key-type string + :value-type integer + :value (("1" . 1) ("2" . 2)))))) + (should (equal '(("1" . 1) ("2" . 2)) (widget-default-get w)))))) + ;;; wid-edit-tests.el ends here -- 2.34.1