Mercurial > hg > xemacs-beta
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))) |