aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Aranda2020-09-26 17:09:22 +0200
committerLars Ingebrigtsen2020-09-26 17:09:22 +0200
commit6cc0ff19ddeadeb47d475da1c38490497488355b (patch)
tree92ce3b883e060d3dfa6cff51b444f11c3cee189a
parent9b6f5642274b5b9ca0ad1b2e0e673d92b01fab6e (diff)
downloademacs-6cc0ff19ddeadeb47d475da1c38490497488355b.tar.gz
emacs-6cc0ff19ddeadeb47d475da1c38490497488355b.zip
Display some character widget values in a more user-friendly way
* lisp/wid-edit.el (widget-character--escape-sequences-alist): New variable. (widget-character--change-character-display): New function. Use the new variable. (widget-character-notify): New function, to keep track of the changes in the character widget, and display characters like tab, newline and spaces better. (character widget): Use widget-character-notify as the notify function. Use widget-character--change-character-display for the internal representation of value (bug#15925).
-rw-r--r--lisp/wid-edit.el66
1 files changed, 62 insertions, 4 deletions
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 8e2055f9185..0a2ddb0ea1d 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -1369,7 +1369,8 @@ Unlike (get-char-property POS \\='field), this works with empty fields too."
1369 (signal 'text-read-only 1369 (signal 'text-read-only
1370 '("Attempt to change text outside editable field"))) 1370 '("Attempt to change text outside editable field")))
1371 (widget-field-use-before-change 1371 (widget-field-use-before-change
1372 (widget-apply from-field :notify from-field)))))) 1372 (widget-apply from-field :notify
1373 from-field (list 'before-change from to)))))))
1373 1374
1374(defun widget-add-change () 1375(defun widget-add-change ()
1375 (remove-hook 'post-command-hook 'widget-add-change t) 1376 (remove-hook 'post-command-hook 'widget-add-change t)
@@ -1406,7 +1407,7 @@ Unlike (get-char-property POS \\='field), this works with empty fields too."
1406 (> (point) begin)) 1407 (> (point) begin))
1407 (delete-char -1))))))) 1408 (delete-char -1)))))))
1408 (widget-specify-secret field)) 1409 (widget-specify-secret field))
1409 (widget-apply field :notify field)))) 1410 (widget-apply field :notify field (list 'after-change from to)))))
1410 1411
1411;;; Widget Functions 1412;;; Widget Functions
1412;; 1413;;
@@ -3532,13 +3533,70 @@ To use this type, you must define :match or :match-alternatives."
3532 :value-to-internal (lambda (_widget value) 3533 :value-to-internal (lambda (_widget value)
3533 (if (stringp value) 3534 (if (stringp value)
3534 value 3535 value
3535 (char-to-string value))) 3536 (let ((disp
3537 (widget-character--change-character-display
3538 value)))
3539 (if disp
3540 (propertize (char-to-string value) 'display disp)
3541 (char-to-string value)))))
3536 :value-to-external (lambda (_widget value) 3542 :value-to-external (lambda (_widget value)
3537 (if (stringp value) 3543 (if (stringp value)
3538 (aref value 0) 3544 (aref value 0)
3539 value)) 3545 value))
3540 :match (lambda (_widget value) 3546 :match (lambda (_widget value)
3541 (characterp value))) 3547 (characterp value))
3548 :notify #'widget-character-notify)
3549
3550;; Only some escape sequences, not all of them. (Bug#15925)
3551(defvar widget-character--escape-sequences-alist
3552 '((?\t . ?t)
3553 (?\n . ?n)
3554 (?\s . ?s))
3555 "Alist that associates escape sequences to a character.
3556Each element has the form (ESCAPE-SEQUENCE . CHARACTER).
3557
3558The character widget uses this alist to display the
3559non-printable character represented by ESCAPE-SEQUENCE as \\CHARACTER,
3560since that makes it easier to see what's in the widget.")
3561
3562(defun widget-character--change-character-display (c)
3563 "Return a string to represent the character C, or nil.
3564
3565The character widget represents some characters (e.g., the newline character
3566or the tab character) specially, to make it easier for the user to see what's
3567in it. For those characters, return a string to display that character in a
3568more user-friendly way.
3569
3570For the caller, nil should mean that it is good enough to use the return value
3571of `char-to-string' for the representation of C."
3572 (let ((char (alist-get c widget-character--escape-sequences-alist)))
3573 (and char (propertize (format "\\%c" char) 'face 'escape-glyph))))
3574
3575(defun widget-character-notify (widget child &optional event)
3576 "Notify function for the character widget.
3577
3578This function allows the widget character to better display some characters,
3579like the newline character or the tab character."
3580 (when (eq (car-safe event) 'after-change)
3581 (let* ((start (nth 1 event))
3582 (end (nth 2 event))
3583 str)
3584 (if (eql start end)
3585 (when (char-equal (widget-value widget) ?\s)
3586 ;; The character widget is not really empty:
3587 ;; its value is a single space character.
3588 ;; We need to propertize it again, if it became empty for a while.
3589 (let ((ov (widget-get widget :field-overlay)))
3590 (put-text-property
3591 (overlay-start ov) (overlay-end ov)
3592 'display (widget-character--change-character-display ?\s))))
3593 (setq str (buffer-substring-no-properties start end))
3594 ;; This assumes the user enters one character at a time,
3595 ;; and does nothing crazy, like yanking a long string.
3596 (let ((disp (widget-character--change-character-display (aref str 0))))
3597 (when disp
3598 (put-text-property start end 'display disp))))))
3599 (widget-default-notify widget child event))
3542 3600
3543(define-widget 'list 'group 3601(define-widget 'list 'group
3544 "A Lisp list." 3602 "A Lisp list."