comparison lisp/custom/wid-edit.el @ 161:28f395d8dc7a r20-3b7

Import from CVS: tag r20-3b7
author cvs
date Mon, 13 Aug 2007 09:42:26 +0200
parents 3bb7ccffb0c0
children 0132846995bd
comparison
equal deleted inserted replaced
160:1c55655d6702 161:28f395d8dc7a
2 ;; 2 ;;
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. 3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4 ;; 4 ;;
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Keywords: extensions 6 ;; Keywords: extensions
7 ;; Version: 1.9908 7 ;; Version: 1.9916
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10 ;; This file is part of GNU Emacs. 10 ;; This file is part of GNU Emacs.
11 11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify 12 ;; GNU Emacs is free software; you can redistribute it and/or modify
121 :link '(custom-manual "(widget)Top") 121 :link '(custom-manual "(widget)Top")
122 :link '(url-link :tag "Development Page" 122 :link '(url-link :tag "Development Page"
123 "http://www.dina.kvl.dk/~abraham/custom/") 123 "http://www.dina.kvl.dk/~abraham/custom/")
124 :prefix "widget-" 124 :prefix "widget-"
125 :group 'extensions 125 :group 'extensions
126 :group 'faces
127 :group 'hypermedia) 126 :group 'hypermedia)
127
128 (defgroup widget-documentation nil
129 "Options controling the display of documentation strings."
130 :group 'widgets)
131
132 (defgroup widget-faces nil
133 "Faces used by the widget library."
134 :group 'widgets
135 :group 'faces)
136
137 (defface widget-documentation-face '((((class color)
138 (background dark))
139 (:foreground "lime green"))
140 (((class color)
141 (background light))
142 (:foreground "dark green"))
143 (t nil))
144 "Face used for documentation text."
145 :group 'widget-documentation
146 :group 'widget-faces)
128 147
129 (defface widget-button-face '((t (:bold t))) 148 (defface widget-button-face '((t (:bold t)))
130 "Face used for widget buttons." 149 "Face used for widget buttons."
131 :group 'widgets) 150 :group 'widget-faces)
132 151
133 (defcustom widget-mouse-face 'highlight 152 (defcustom widget-mouse-face 'highlight
134 "Face used for widget buttons when the mouse is above them." 153 "Face used for widget buttons when the mouse is above them."
135 :type 'face 154 :type 'face
136 :group 'widgets) 155 :group 'widget-faces)
137 156
138 (defface widget-field-face '((((class grayscale color) 157 (defface widget-field-face '((((class grayscale color)
139 (background light)) 158 (background light))
140 (:background "gray85")) 159 (:background "gray85"))
141 (((class grayscale color) 160 (((class grayscale color)
142 (background dark)) 161 (background dark))
143 (:background "dim gray")) 162 (:background "dim gray"))
144 (t 163 (t
145 (:italic t))) 164 (:italic t)))
146 "Face used for editable fields." 165 "Face used for editable fields."
147 :group 'widgets) 166 :group 'widget-faces)
148 167
149 ;;; Utility functions. 168 ;;; Utility functions.
150 ;; 169 ;;
151 ;; These are not really widget specific. 170 ;; These are not really widget specific.
152 171
251 'front-sticky t 270 'front-sticky t
252 'rear-nonsticky nil 271 'rear-nonsticky nil
253 'start-open nil 272 'start-open nil
254 'end-open nil))) 273 'end-open nil)))
255 274
275 (defcustom widget-field-add-space
276 (or (< emacs-major-version 20)
277 (and (eq emacs-major-version 20)
278 (< emacs-minor-version 3))
279 (not (string-match "XEmacs" emacs-version)))
280 "Non-nil means add extra space at the end of editable text fields.
281
282 This is needed on all versions of Emacs, and on XEmacs before 20.3.
283 If you don't add the space, it will become impossible to edit a zero
284 size field."
285 :type 'boolean
286 :group 'widgets)
287
256 (defun widget-specify-field (widget from to) 288 (defun widget-specify-field (widget from to)
257 "Specify editable button for WIDGET between FROM and TO." 289 "Specify editable button for WIDGET between FROM and TO."
258 (put-text-property from to 'read-only nil) 290 (put-text-property from to 'read-only nil)
259 ;; Terminating space is not part of the field, but necessary in 291 ;; Terminating space is not part of the field, but necessary in
260 ;; order for local-map to work. Remove next sexp if local-map works 292 ;; order for local-map to work. Remove next sexp if local-map works
261 ;; at the end of the overlay. 293 ;; at the end of the overlay.
262 (save-excursion 294 (save-excursion
263 (goto-char to) 295 (goto-char to)
264 (insert-and-inherit " ") 296 (when widget-field-add-space
297 (insert-and-inherit " "))
265 (setq to (point))) 298 (setq to (point)))
266 (add-text-properties (1- to) to ;to (1+ to) 299 (add-text-properties (1- to) to ;to (1+ to)
267 '(front-sticky nil start-open t read-only to)) 300 '(front-sticky nil start-open t read-only to))
268 (add-text-properties (1- from) from 301 (add-text-properties (1- from) from
269 '(rear-nonsticky t end-open t read-only from)) 302 '(rear-nonsticky t end-open t read-only from))
313 (let ((face (widget-apply widget :sample-face-get))) 346 (let ((face (widget-apply widget :sample-face-get)))
314 (when face 347 (when face
315 (add-text-properties from to (list 'start-open t 348 (add-text-properties from to (list 'start-open t
316 'end-open t 349 'end-open t
317 'face face))))) 350 'face face)))))
318
319 (defun widget-specify-doc (widget from to) 351 (defun widget-specify-doc (widget from to)
320 ;; Specify documentation for WIDGET between FROM and TO. 352 ;; Specify documentation for WIDGET between FROM and TO.
321 (add-text-properties from to (list 'widget-doc widget 353 (add-text-properties from to (list 'widget-doc widget
322 'face 'widget-documentation-face))) 354 'face 'widget-documentation-face)))
323 355
345 (background light)) 377 (background light))
346 (:foreground "dark gray")) 378 (:foreground "dark gray"))
347 (t 379 (t
348 (:italic t))) 380 (:italic t)))
349 "Face used for inactive widgets." 381 "Face used for inactive widgets."
350 :group 'widgets) 382 :group 'widget-faces)
351 383
352 (defun widget-specify-inactive (widget from to) 384 (defun widget-specify-inactive (widget from to)
353 "Make WIDGET inactive for user modifications." 385 "Make WIDGET inactive for user modifications."
354 (unless (widget-get widget :inactive) 386 (unless (widget-get widget :inactive)
355 (let ((overlay (make-overlay from to nil t nil))) 387 (let ((overlay (make-overlay from to nil t nil)))
356 (overlay-put overlay 'face 'widget-inactive-face) 388 (overlay-put overlay 'face 'widget-inactive-face)
357 (overlay-put overlay 'mouse-face 'widget-inactive-face) 389 ;; This is disabled, as it makes the mouse cursor change shape.
390 ;; (overlay-put overlay 'mouse-face 'widget-inactive-face)
358 (overlay-put overlay 'evaporate t) 391 (overlay-put overlay 'evaporate t)
359 (overlay-put overlay 'priority 100) 392 (overlay-put overlay 'priority 100)
360 (overlay-put overlay (if (string-match "XEmacs" emacs-version) 393 (overlay-put overlay (if (string-match "XEmacs" emacs-version)
361 'read-only 394 'read-only
362 'modification-hooks) '(widget-overlay-inactive)) 395 'modification-hooks) '(widget-overlay-inactive))
471 (setq child (car children) 504 (setq child (car children)
472 children (cdr children)) 505 children (cdr children))
473 (when (eq (widget-get child :button) widget) 506 (when (eq (widget-get child :button) widget)
474 (throw 'child child))) 507 (throw 'child child)))
475 nil))) 508 nil)))
509
510 (defun widget-map-buttons (function &optional buffer maparg)
511 "Map FUNCTION over the buttons in BUFFER.
512 FUNCTION is called with the arguments WIDGET and MAPARG.
513
514 If FUNCTION returns non-nil, the walk is cancelled.
515
516 The arguments MAPARG, and BUFFER default to nil and (current-buffer),
517 respectively."
518 (let ((cur (point-min))
519 (widget nil)
520 (parent nil)
521 (overlays (if buffer
522 (save-excursion (set-buffer buffer) (overlay-lists))
523 (overlay-lists))))
524 (setq overlays (append (car overlays) (cdr overlays)))
525 (while (setq cur (pop overlays))
526 (setq widget (overlay-get cur 'button))
527 (if (and widget (funcall function widget maparg))
528 (setq overlays nil)))))
476 529
477 ;;; Glyphs. 530 ;;; Glyphs.
478 531
479 (defcustom widget-glyph-directory (concat data-directory "custom/") 532 (defcustom widget-glyph-directory (concat data-directory "custom/")
480 "Where widget glyphs are located. 533 "Where widget glyphs are located.
718 after-change-functions 771 after-change-functions
719 (from (point))) 772 (from (point)))
720 (apply 'insert args) 773 (apply 'insert args)
721 (widget-specify-text from (point)))) 774 (widget-specify-text from (point))))
722 775
776 (defun widget-convert-text (type from to
777 &optional button-from button-to
778 &rest args)
779 "Return a widget of type TYPE with endpoint FROM TO.
780 Optional ARGS are extra keyword arguments for TYPE.
781 and TO will be used as the widgets end points. If optional arguments
782 BUTTON-FROM and BUTTON-TO are given, these will be used as the widgets
783 button end points.
784 Optional ARGS are extra keyword arguments for TYPE."
785 (let ((widget (apply 'widget-convert type :delete 'widget-leave-text args))
786 (from (copy-marker from))
787 (to (copy-marker to)))
788 (widget-specify-text from to)
789 (set-marker-insertion-type from t)
790 (set-marker-insertion-type to nil)
791 (widget-put widget :from from)
792 (widget-put widget :to to)
793 (when button-from
794 (widget-specify-button widget button-from button-to))
795 widget))
796
797 (defun widget-convert-button (type from to &rest args)
798 "Return a widget of type TYPE with endpoint FROM TO.
799 Optional ARGS are extra keyword arguments for TYPE.
800 No text will be inserted to the buffer, instead the text between FROM
801 and TO will be used as the widgets end points, as well as the widgets
802 button end points."
803 (apply 'widget-convert-text type from to from to args))
804
805 (defun widget-leave-text (widget)
806 "Remove markers and overlays from WIDGET and its children."
807 (let ((from (widget-get widget :from))
808 (to (widget-get widget :to))
809 (button (widget-get widget :button-overlay))
810 (field (widget-get widget :field-overlay))
811 (children (widget-get widget :children)))
812 (set-marker from nil)
813 (set-marker to nil)
814 (delete-overlay button)
815 (delete-overlay field)
816 (mapcar 'widget-leave-text children)))
817
723 ;;; Keymap and Commands. 818 ;;; Keymap and Commands.
724 819
725 (defvar widget-keymap nil 820 (defvar widget-keymap nil
726 "Keymap containing useful binding for buffers containing widgets. 821 "Keymap containing useful binding for buffers containing widgets.
727 Recommended as a parent keymap for modes using widgets.") 822 Recommended as a parent keymap for modes using widgets.")
781 '((((class color)) 876 '((((class color))
782 (:foreground "red")) 877 (:foreground "red"))
783 (t 878 (t
784 (:bold t :underline t))) 879 (:bold t :underline t)))
785 "Face used for pressed buttons." 880 "Face used for pressed buttons."
786 :group 'widgets) 881 :group 'widget-faces)
787 882
788 (defun widget-button-click (event) 883 (defun widget-button-click (event)
789 "Invoke button below mouse pointer." 884 "Invoke button below mouse pointer."
790 (interactive "@e") 885 (interactive "@e")
791 (cond ((and (fboundp 'event-glyph) 886 (cond ((and (fboundp 'event-glyph)
890 (widget-apply-action button event) 985 (widget-apply-action button event)
891 (let ((command (lookup-key widget-global-map (this-command-keys)))) 986 (let ((command (lookup-key widget-global-map (this-command-keys))))
892 (when (commandp command) 987 (when (commandp command)
893 (call-interactively command)))))) 988 (call-interactively command))))))
894 989
990 (defun widget-tabable-at (&optional pos)
991 "Return the tabable widget at POS, or nil.
992 POS defaults to the value of (point)."
993 (unless pos
994 (setq pos (point)))
995 (let ((widget (or (get-char-property (point) 'button)
996 (get-char-property (point) 'field))))
997 (if widget
998 (let ((order (widget-get widget :tab-order)))
999 (if order
1000 (if (>= order 0)
1001 widget
1002 nil)
1003 widget))
1004 nil)))
1005
895 (defun widget-move (arg) 1006 (defun widget-move (arg)
896 "Move point to the ARG next field or button. 1007 "Move point to the ARG next field or button.
897 ARG may be negative to move backward." 1008 ARG may be negative to move backward."
898 (or (bobp) (> arg 0) (backward-char)) 1009 (or (bobp) (> arg 0) (backward-char))
899 (let ((pos (point)) 1010 (let ((pos (point))
900 (number arg) 1011 (number arg)
901 (old (or (get-char-property (point) 'button) 1012 (old (widget-tabable-at))
902 (get-char-property (point) 'field)))
903 new) 1013 new)
904 ;; Forward. 1014 ;; Forward.
905 (while (> arg 0) 1015 (while (> arg 0)
906 (if (eobp) 1016 (if (eobp)
907 (goto-char (point-min)) 1017 (goto-char (point-min))
908 (forward-char 1)) 1018 (forward-char 1))
909 (and (eq pos (point)) 1019 (and (eq pos (point))
910 (eq arg number) 1020 (eq arg number)
911 (error "No buttons or fields found")) 1021 (error "No buttons or fields found"))
912 (let ((new (or (get-char-property (point) 'button) 1022 (let ((new (widget-tabable-at)))
913 (get-char-property (point) 'field))))
914 (when new 1023 (when new
915 (unless (eq new old) 1024 (unless (eq new old)
916 (unless (and (widget-get new :tab-order) 1025 (setq arg (1- arg))
917 (< (widget-get new :tab-order) 0))
918 (setq arg (1- arg)))
919 (setq old new))))) 1026 (setq old new)))))
920 ;; Backward. 1027 ;; Backward.
921 (while (< arg 0) 1028 (while (< arg 0)
922 (if (bobp) 1029 (if (bobp)
923 (goto-char (point-max)) 1030 (goto-char (point-max))
924 (backward-char 1)) 1031 (backward-char 1))
925 (and (eq pos (point)) 1032 (and (eq pos (point))
926 (eq arg number) 1033 (eq arg number)
927 (error "No buttons or fields found")) 1034 (error "No buttons or fields found"))
928 (let ((new (or (get-char-property (point) 'button) 1035 (let ((new (widget-tabable-at)))
929 (get-char-property (point) 'field))))
930 (when new 1036 (when new
931 (unless (eq new old) 1037 (unless (eq new old)
932 (unless (and (widget-get new :tab-order) 1038 (setq arg (1+ arg))))))
933 (< (widget-get new :tab-order) 0)) 1039 (let ((new (widget-tabable-at)))
934 (setq arg (1+ arg))))))) 1040 (while (eq (widget-tabable-at) new)
935 (while (or (get-char-property (point) 'button) 1041 (backward-char)))
936 (get-char-property (point) 'field))
937 (backward-char))
938 (forward-char)) 1042 (forward-char))
939 (widget-echo-help (point)) 1043 (widget-echo-help (point))
940 (run-hooks 'widget-move-hook)) 1044 (run-hooks 'widget-move-hook))
941 1045
942 (defun widget-forward (arg) 1046 (defun widget-forward (arg)
1015 (setq field (car widget-field-new) 1119 (setq field (car widget-field-new)
1016 widget-field-new (cdr widget-field-new) 1120 widget-field-new (cdr widget-field-new)
1017 widget-field-list (cons field widget-field-list)) 1121 widget-field-list (cons field widget-field-list))
1018 (let ((from (car (widget-get field :field-overlay))) 1122 (let ((from (car (widget-get field :field-overlay)))
1019 (to (cdr (widget-get field :field-overlay)))) 1123 (to (cdr (widget-get field :field-overlay))))
1020 (widget-specify-field field from to) 1124 (widget-specify-field field
1125 (marker-position from) (marker-position to))
1021 (set-marker from nil) 1126 (set-marker from nil)
1022 (set-marker to nil)))) 1127 (set-marker to nil))))
1023 (widget-clear-undo) 1128 (widget-clear-undo)
1024 ;; We need to maintain text properties and size of the editing fields. 1129 ;; We need to maintain text properties and size of the editing fields.
1025 (make-local-variable 'after-change-functions) 1130 (make-local-variable 'after-change-functions)
1035 ;; The widget data before the change. 1140 ;; The widget data before the change.
1036 (make-variable-buffer-local 'widget-field-was) 1141 (make-variable-buffer-local 'widget-field-was)
1037 1142
1038 (defun widget-field-buffer (widget) 1143 (defun widget-field-buffer (widget)
1039 "Return the start of WIDGET's editing field." 1144 "Return the start of WIDGET's editing field."
1040 (overlay-buffer (widget-get widget :field-overlay))) 1145 (let ((overlay (widget-get widget :field-overlay)))
1146 (and overlay (overlay-buffer overlay))))
1041 1147
1042 (defun widget-field-start (widget) 1148 (defun widget-field-start (widget)
1043 "Return the start of WIDGET's editing field." 1149 "Return the start of WIDGET's editing field."
1044 (overlay-start (widget-get widget :field-overlay))) 1150 (let ((overlay (widget-get widget :field-overlay)))
1151 (and overlay (overlay-start overlay))))
1045 1152
1046 (defun widget-field-end (widget) 1153 (defun widget-field-end (widget)
1047 "Return the end of WIDGET's editing field." 1154 "Return the end of WIDGET's editing field."
1048 ;; Don't subtract one if local-map works at the end of the overlay. 1155 (let ((overlay (widget-get widget :field-overlay)))
1049 (1- (overlay-end (widget-get widget :field-overlay)))) 1156 ;; Don't subtract one if local-map works at the end of the overlay.
1157 (and overlay (if widget-field-add-space
1158 (1- (overlay-end overlay))
1159 (overlay-end overlay)))))
1050 1160
1051 (defun widget-field-find (pos) 1161 (defun widget-field-find (pos)
1052 "Return the field at POS. 1162 "Return the field at POS.
1053 Unlike (get-char-property POS 'field) this, works with empty fields too." 1163 Unlike (get-char-property POS 'field) this, works with empty fields too."
1054 (let ((fields widget-field-list) 1164 (let ((fields widget-field-list)
1070 (let ((field (widget-field-find from)) 1180 (let ((field (widget-field-find from))
1071 (other (widget-field-find to))) 1181 (other (widget-field-find to)))
1072 (when field 1182 (when field
1073 (unless (eq field other) 1183 (unless (eq field other)
1074 (debug "Change in different fields")) 1184 (debug "Change in different fields"))
1075 (let ((size (widget-get field :size))) 1185 (let ((size (widget-get field :size))
1186 (secret (widget-get field :secret)))
1076 (when size 1187 (when size
1077 (let ((begin (widget-field-start field)) 1188 (let ((begin (widget-field-start field))
1078 (end (widget-field-end field))) 1189 (end (widget-field-end field)))
1079 (cond ((< (- end begin) size) 1190 (cond ((< (- end begin) size)
1080 ;; Field too small. 1191 ;; Field too small.
1091 (setq begin (point))) 1202 (setq begin (point)))
1092 (save-excursion 1203 (save-excursion
1093 (goto-char end) 1204 (goto-char end)
1094 (while (and (eq (preceding-char) ?\ ) 1205 (while (and (eq (preceding-char) ?\ )
1095 (> (point) begin)) 1206 (> (point) begin))
1096 (delete-backward-char 1)))))))) 1207 (delete-backward-char 1)))))))
1208 (when secret
1209 (let ((begin (widget-field-start field))
1210 (end (widget-field-end field)))
1211 (when size
1212 (while (and (> end begin)
1213 (eq (char-after (1- end)) ?\ ))
1214 (setq end (1- end))))
1215 (while (< begin end)
1216 (let ((old (char-after begin)))
1217 (unless (eq old secret)
1218 (subst-char-in-region begin (1+ begin) old secret)
1219 (put-text-property begin (1+ begin) 'secret old))
1220 (setq begin (1+ begin)))))))
1097 (widget-apply field :notify field))) 1221 (widget-apply field :notify field)))
1098 (error (debug "After Change")))) 1222 (error (debug "After Change"))))
1099 1223
1100 ;;; Widget Functions 1224 ;;; Widget Functions
1101 ;; 1225 ;;
1251 (widget-put widget :to to))) 1375 (widget-put widget :to to)))
1252 (widget-clear-undo)) 1376 (widget-clear-undo))
1253 1377
1254 (defun widget-default-format-handler (widget escape) 1378 (defun widget-default-format-handler (widget escape)
1255 ;; We recognize the %h escape by default. 1379 ;; We recognize the %h escape by default.
1256 (let* ((buttons (widget-get widget :buttons)) 1380 (let* ((buttons (widget-get widget :buttons)))
1257 (doc-property (widget-get widget :documentation-property))
1258 (doc-try (cond ((widget-get widget :doc))
1259 ((symbolp doc-property)
1260 (documentation-property (widget-get widget :value)
1261 doc-property))
1262 (t
1263 (funcall doc-property (widget-get widget :value)))))
1264 (doc-text (and (stringp doc-try)
1265 (> (length doc-try) 1)
1266 doc-try)))
1267 (cond ((eq escape ?h) 1381 (cond ((eq escape ?h)
1268 (when doc-text 1382 (let* ((doc-property (widget-get widget :documentation-property))
1269 (and (eq (preceding-char) ?\n) 1383 (doc-try (cond ((widget-get widget :doc))
1270 (widget-get widget :indent) 1384 ((symbolp doc-property)
1271 (insert-char ? (widget-get widget :indent))) 1385 (documentation-property
1272 ;; The `*' in the beginning is redundant. 1386 (widget-get widget :value)
1273 (when (eq (aref doc-text 0) ?*) 1387 doc-property))
1274 (setq doc-text (substring doc-text 1))) 1388 (t
1275 ;; Get rid of trailing newlines. 1389 (funcall doc-property
1276 (when (string-match "\n+\\'" doc-text) 1390 (widget-get widget :value)))))
1277 (setq doc-text (substring doc-text 0 (match-beginning 0)))) 1391 (doc-text (and (stringp doc-try)
1278 (push (widget-create-child-and-convert 1392 (> (length doc-try) 1)
1279 widget 'documentation-string 1393 doc-try)))
1280 doc-text) 1394 (when doc-text
1281 buttons))) 1395 (and (eq (preceding-char) ?\n)
1396 (widget-get widget :indent)
1397 (insert-char ? (widget-get widget :indent)))
1398 ;; The `*' in the beginning is redundant.
1399 (when (eq (aref doc-text 0) ?*)
1400 (setq doc-text (substring doc-text 1)))
1401 ;; Get rid of trailing newlines.
1402 (when (string-match "\n+\\'" doc-text)
1403 (setq doc-text (substring doc-text 0 (match-beginning 0))))
1404 (push (widget-create-child-and-convert
1405 widget 'documentation-string
1406 doc-text)
1407 buttons))))
1282 (t 1408 (t
1283 (error "Unknown escape `%c'" escape))) 1409 (error "Unknown escape `%c'" escape)))
1284 (widget-put widget :buttons buttons))) 1410 (widget-put widget :buttons buttons)))
1285 1411
1286 (defun widget-default-button-face-get (widget) 1412 (defun widget-default-button-face-get (widget)
2464 (if (widget-value widget) 2590 (if (widget-value widget)
2465 (widget-glyph-insert widget on "down" "down-pushed") 2591 (widget-glyph-insert widget on "down" "down-pushed")
2466 (widget-glyph-insert widget off "right" "right-pushed") 2592 (widget-glyph-insert widget off "right" "right-pushed")
2467 (insert "...")))) 2593 (insert "..."))))
2468 2594
2595 ;;; The `documentation-link' Widget.
2596
2597 (define-widget 'documentation-link 'link
2598 "Link type used in documentation strings."
2599 :action 'widget-documentation-link-action)
2600
2601 (defun widget-documentation-link-action (widget &optional event)
2602 "Run apropos on WIDGET's value. Ignore optional argument EVENT."
2603 (apropos (concat "\\`" (regexp-quote (widget-get widget :value)) "\\'")))
2604
2605 (defcustom widget-documentation-links t
2606 "Add hyperlinks to documentation strings when non-nil."
2607 :type 'boolean
2608 :group 'widget-documentation)
2609
2610 (defcustom widget-documentation-link-regexp "`\\([^\n`' ]+\\)'"
2611 "Regexp for matching potential links in documentation strings.
2612 The first group should be the link itself."
2613 :type 'regexp
2614 :group 'widget-documentation)
2615
2616 (defcustom widget-documentation-link-p 'intern-soft
2617 "Predicate used to test if a string is useful as a link.
2618 The value should be a function. The function will be called one
2619 argument, a string, and should return non-nil if there should be a
2620 link for that string."
2621 :type 'function
2622 :options '(widget-documentation-link-p)
2623 :group 'widget-documentation)
2624
2625 (defcustom widget-documentation-link-type 'documentation-link
2626 "Widget type used for links in documentation strings."
2627 :type 'symbol
2628 :group 'widget-documentation)
2629
2630 (defun widget-documentation-link-add (widget from to)
2631 (widget-specify-doc widget from to)
2632 (when widget-documentation-links
2633 (let ((regexp widget-documentation-link-regexp)
2634 (predicate widget-documentation-link-p)
2635 (type widget-documentation-link-type)
2636 (buttons (widget-get widget :buttons)))
2637 (save-excursion
2638 (goto-char (point-min))
2639 (while (re-search-forward regexp to t)
2640 (let ((name (match-string 1))
2641 (begin (match-beginning 0))
2642 (end (match-end 0)))
2643 (when (funcall predicate name)
2644 (push (widget-convert-button type begin end :value name)
2645 buttons)))))
2646 (widget-put widget :buttons buttons))))
2647
2469 ;;; The `documentation-string' Widget. 2648 ;;; The `documentation-string' Widget.
2470
2471 (defface widget-documentation-face '((((class color)
2472 (background dark))
2473 (:foreground "lime green"))
2474 (((class color)
2475 (background light))
2476 (:foreground "dark green"))
2477 (t nil))
2478 "Face used for documentation text."
2479 :group 'widgets)
2480 2649
2481 (define-widget 'documentation-string 'item 2650 (define-widget 'documentation-string 'item
2482 "A documentation string." 2651 "A documentation string."
2483 :format "%v" 2652 :format "%v"
2484 :action 'widget-documentation-string-action 2653 :action 'widget-documentation-string-action
2486 :value-create 'widget-documentation-string-value-create) 2655 :value-create 'widget-documentation-string-value-create)
2487 2656
2488 (defun widget-documentation-string-value-create (widget) 2657 (defun widget-documentation-string-value-create (widget)
2489 ;; Insert documentation string. 2658 ;; Insert documentation string.
2490 (let ((doc (widget-value widget)) 2659 (let ((doc (widget-value widget))
2491 (shown (widget-get (widget-get widget :parent) :documentation-shown))) 2660 (shown (widget-get (widget-get widget :parent) :documentation-shown))
2661 (start (point)))
2492 (if (string-match "\n" doc) 2662 (if (string-match "\n" doc)
2493 (let ((before (substring doc 0 (match-beginning 0))) 2663 (let ((before (substring doc 0 (match-beginning 0)))
2494 (after (substring doc (match-beginning 0))) 2664 (after (substring doc (match-beginning 0)))
2495 (start (point))
2496 buttons) 2665 buttons)
2497 (insert before " ") 2666 (insert before " ")
2498 (widget-specify-doc widget start (point)) 2667 (widget-documentation-link-add widget start (point))
2499 (push (widget-create-child-and-convert 2668 (push (widget-create-child-and-convert
2500 widget 'visibility 2669 widget 'visibility
2501 :off nil 2670 :off nil
2502 :action 'widget-parent-action 2671 :action 'widget-parent-action
2503 shown) 2672 shown)
2504 buttons) 2673 buttons)
2505 (when shown 2674 (when shown
2506 (setq start (point)) 2675 (setq start (point))
2507 (insert after) 2676 (insert after)
2508 (widget-specify-doc widget start (point))) 2677 (widget-documentation-link-add widget start (point)))
2509 (widget-put widget :buttons buttons)) 2678 (widget-put widget :buttons buttons))
2510 (insert doc))) 2679 (insert doc)
2680 (widget-documentation-link-add widget start (point))))
2511 (insert "\n")) 2681 (insert "\n"))
2512 2682
2513 (defun widget-documentation-string-action (widget &rest ignore) 2683 (defun widget-documentation-string-action (widget &rest ignore)
2514 ;; Toggle documentation. 2684 ;; Toggle documentation.
2515 (let ((parent (widget-get widget :parent))) 2685 (let ((parent (widget-get widget :parent)))