comparison lisp/custom/wid-edit.el @ 173:8eaf7971accc r20-3b13

Import from CVS: tag r20-3b13
author cvs
date Mon, 13 Aug 2007 09:49:09 +0200
parents 85ec50267440
children 9ad43877534d
comparison
equal deleted inserted replaced
172:a38aed19690b 173:8eaf7971accc
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.9940 7 ;; Version: 1.9951
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
36 ;;; Compatibility. 36 ;;; Compatibility.
37 37
38 (eval-and-compile 38 (eval-and-compile
39 (autoload 'pp-to-string "pp") 39 (autoload 'pp-to-string "pp")
40 (autoload 'Info-goto-node "info") 40 (autoload 'Info-goto-node "info")
41 (autoload 'finder-commentary "finder" nil t)
41 42
42 (when (string-match "XEmacs" emacs-version) 43 (when (string-match "XEmacs" emacs-version)
43 (condition-case nil 44 (condition-case nil
44 (require 'overlay) 45 (require 'overlay)
45 (error (load-library "x-overlay")))) 46 (error (load-library "x-overlay"))))
99 (let ((buf (get-buffer-create " *error-message*"))) 100 (let ((buf (get-buffer-create " *error-message*")))
100 (erase-buffer buf) 101 (erase-buffer buf)
101 (display-error obj buf) 102 (display-error obj buf)
102 (buffer-string buf))))) 103 (buffer-string buf)))))
103 104
104 (when (let ((a "foo"))
105 (put-text-property 1 2 'foo 1 a)
106 (put-text-property 1 2 'bar 2 a)
107 (set-text-properties 1 2 nil a)
108 (text-properties-at 1 a))
109 ;; XEmacs 20.2 and earlier had a buggy set-text-properties.
110 (defun set-text-properties (start end props &optional buffer-or-string)
111 "Completely replace properties of text from START to END.
112 The third argument PROPS is the new property list.
113 The optional fourth argument, BUFFER-OR-STRING,
114 is the string or buffer containing the text."
115 (map-extents #'(lambda (extent ignored)
116 (remove-text-properties
117 start end
118 (list (extent-property extent 'text-prop)
119 nil)
120 buffer-or-string)
121 nil)
122 buffer-or-string start end nil nil 'text-prop)
123 (add-text-properties start end props buffer-or-string)))
124
125 ;;; Customization. 105 ;;; Customization.
126 106
127 (defgroup widgets nil 107 (defgroup widgets nil
128 "Customization support for the Widget Library." 108 "Customization support for the Widget Library."
129 :link '(custom-manual "(widget)Top") 109 :link '(custom-manual "(widget)Top")
130 :link '(url-link :tag "Development Page" 110 :link '(url-link :tag "Development Page"
131 "http://www.dina.kvl.dk/~abraham/custom/") 111 "http://www.dina.kvl.dk/~abraham/custom/")
112 :link '(emacs-library-link :tag "Lisp File" "widget.el")
132 :prefix "widget-" 113 :prefix "widget-"
133 :group 'extensions 114 :group 'extensions
134 :group 'hypermedia) 115 :group 'hypermedia)
135 116
136 (defgroup widget-documentation nil 117 (defgroup widget-documentation nil
155 (t nil)) 136 (t nil))
156 "Face used for documentation text." 137 "Face used for documentation text."
157 :group 'widget-documentation 138 :group 'widget-documentation
158 :group 'widget-faces) 139 :group 'widget-faces)
159 140
141 (defvar widget-button-face 'widget-button-face
142 "Face used for buttons in widges.
143 This exists as a variable so it can be set locally in certain buffers.")
144
160 (defface widget-button-face '((t (:bold t))) 145 (defface widget-button-face '((t (:bold t)))
161 "Face used for widget buttons." 146 "Face used for widget buttons."
162 :group 'widget-faces) 147 :group 'widget-faces)
163 148
164 (defcustom widget-mouse-face 'highlight 149 (defcustom widget-mouse-face 'highlight
234 "Largest number of items allowed in a popup-menu. 219 "Largest number of items allowed in a popup-menu.
235 Larger menus are read through the minibuffer." 220 Larger menus are read through the minibuffer."
236 :group 'widgets 221 :group 'widgets
237 :type 'integer) 222 :type 'integer)
238 223
239 (defcustom widget-menu-minibuffer-flag nil 224 (defcustom widget-menu-minibuffer-flag (string-match "XEmacs" emacs-version)
240 "*Control how to ask for a choice from the keyboard. 225 "*Control how to ask for a choice from the keyboard.
241 Non-nil means use the minibuffer; 226 Non-nil means use the minibuffer;
242 nil means read a single character." 227 nil means read a single character."
243 :group 'widgets 228 :group 'widgets
244 :type 'boolean) 229 :type 'boolean)
297 map choice (next-digit ?0) 282 map choice (next-digit ?0)
298 value) 283 value)
299 ;; Define SPC as a prefix char to get to this menu. 284 ;; Define SPC as a prefix char to get to this menu.
300 (define-key overriding-terminal-local-map " " 285 (define-key overriding-terminal-local-map " "
301 (setq map (make-sparse-keymap title))) 286 (setq map (make-sparse-keymap title)))
302 (while items 287 (save-excursion
303 (setq choice (car items) items (cdr items)) 288 (set-buffer (get-buffer-create " widget-choose"))
304 (if (consp choice) 289 (erase-buffer)
305 (let* ((name (car choice)) 290 (insert "Available choices:\n\n")
306 (function (cdr choice)) 291 (while items
307 (character (aref name 0))) 292 (setq choice (car items) items (cdr items))
308 ;; Pick a character for this choice; 293 (if (consp choice)
309 ;; avoid duplication. 294 (let* ((name (car choice))
310 (when (lookup-key map (vector character)) 295 (function (cdr choice)))
311 (setq character (downcase character)) 296 (insert (format "%c = %s\n" next-digit name))
312 (when (lookup-key map (vector character)) 297 (define-key map (vector next-digit) function)))
313 (setq character next-digit 298 ;; Allocate digits to disabled alternatives
314 next-digit (1+ next-digit)))) 299 ;; so that the digit of a given alternative never varies.
315 (define-key map (vector character) 300 (setq next-digit (1+ next-digit)))
316 (cons (format "%c = %s" character name) function))))) 301 (insert "\nC-g = Quit"))
317 (define-key map [?\C-g] '("Quit" . keyboard-quit)) 302 (define-key map [?\C-g] 'keyboard-quit)
318 (define-key map [t] 'keyboard-quit) 303 (define-key map [t] 'keyboard-quit)
319 (setcdr map (nreverse (cdr map))) 304 (setcdr map (nreverse (cdr map)))
320 ;; Unread a SPC to lead to our new menu. 305 ;; Unread a SPC to lead to our new menu.
321 (setq unread-command-events (cons ?\ unread-command-events)) 306 (setq unread-command-events (cons ?\ unread-command-events))
322 ;; Read a char with the menu, and return the result 307 ;; Read a char with the menu, and return the result
323 ;; that corresponds to it. 308 ;; that corresponds to it.
324 (setq value 309 (save-window-excursion
325 (lookup-key overriding-terminal-local-map 310 (display-buffer (get-buffer " widget-choose"))
326 (read-key-sequence title) t)) 311 (let ((cursor-in-echo-area t))
312 (setq value
313 (lookup-key overriding-terminal-local-map
314 (read-key-sequence title) t))))
327 (when (eq value 'keyboard-quit) 315 (when (eq value 'keyboard-quit)
328 (error "Canceled")) 316 (error "Canceled"))
329 value)))) 317 value))))
330 318
331 (defun widget-remove-if (predictate list) 319 (defun widget-remove-if (predictate list)
338 326
339 ;;; Widget text specifications. 327 ;;; Widget text specifications.
340 ;; 328 ;;
341 ;; These functions are for specifying text properties. 329 ;; These functions are for specifying text properties.
342 330
343 (defun widget-specify-none (from to)
344 ;; Clear all text properties between FROM and TO.
345 (set-text-properties from to nil))
346
347 (defun widget-specify-text (from to)
348 ;; Default properties.
349 (add-text-properties from to (list 'read-only t
350 'front-sticky t
351 'rear-nonsticky nil
352 'start-open nil
353 'end-open nil)))
354
355 (defcustom widget-field-add-space 331 (defcustom widget-field-add-space
356 (or (< emacs-major-version 20) 332 (or (< emacs-major-version 20)
357 (and (eq emacs-major-version 20) 333 (and (eq emacs-major-version 20)
358 (< emacs-minor-version 3)) 334 (< emacs-minor-version 3))
359 (not (string-match "XEmacs" emacs-version))) 335 (not (string-match "XEmacs" emacs-version)))
364 size field." 340 size field."
365 :type 'boolean 341 :type 'boolean
366 :group 'widgets) 342 :group 'widgets)
367 343
368 (defcustom widget-field-use-before-change 344 (defcustom widget-field-use-before-change
369 (or (> emacs-minor-version 34) 345 (and (or (> emacs-minor-version 34)
370 (> emacs-major-version 20) 346 (> emacs-major-version 19))
371 (string-match "XEmacs" emacs-version)) 347 (not (string-match "XEmacs" emacs-version)))
372 "Non-nil means use `before-change-functions' to track editable fields. 348 "Non-nil means use `before-change-functions' to track editable fields.
373 This enables the use of undo, but doesn'f work on Emacs 19.34 and earlier. 349 This enables the use of undo, but doesn't work on Emacs 19.34 and earlier.
374 Using before hooks also means that the :notify function can't know the 350 Using before hooks also means that the :notify function can't know the
375 new value." 351 new value."
376 :type 'boolean 352 :type 'boolean
377 :group 'widgets) 353 :group 'widgets)
378 354
379 (defun widget-specify-field (widget from to) 355 (defun widget-specify-field (widget from to)
380 "Specify editable button for WIDGET between FROM and TO." 356 "Specify editable button for WIDGET between FROM and TO."
381 (put-text-property from to 'read-only nil)
382 ;; Terminating space is not part of the field, but necessary in 357 ;; Terminating space is not part of the field, but necessary in
383 ;; order for local-map to work. Remove next sexp if local-map works 358 ;; order for local-map to work. Remove next sexp if local-map works
384 ;; at the end of the overlay. 359 ;; at the end of the overlay.
385 (save-excursion 360 (save-excursion
386 (goto-char to) 361 (goto-char to)
387 (when widget-field-add-space 362 (cond ((null (widget-get widget :size))
388 (insert-and-inherit " ")) 363 (forward-char 1))
364 (widget-field-add-space
365 (insert-and-inherit " ")))
389 (setq to (point))) 366 (setq to (point)))
390 (if widget-field-add-space
391 (add-text-properties (1- to) to
392 '(front-sticky nil start-open t read-only to))
393 (add-text-properties to (1+ to)
394 '(front-sticky nil start-open t read-only to)))
395 (add-text-properties (1- from) from
396 '(rear-nonsticky t end-open t read-only from))
397 (let ((map (widget-get widget :keymap)) 367 (let ((map (widget-get widget :keymap))
398 (face (or (widget-get widget :value-face) 'widget-field-face)) 368 (face (or (widget-get widget :value-face) 'widget-field-face))
399 (help-echo (widget-get widget :help-echo)) 369 (help-echo (widget-get widget :help-echo))
400 (overlay (make-overlay from to nil nil t))) 370 (overlay (make-overlay from to nil
371 nil (or (not widget-field-add-space)
372 (widget-get widget :size)))))
401 (unless (or (stringp help-echo) (null help-echo)) 373 (unless (or (stringp help-echo) (null help-echo))
402 (setq help-echo 'widget-mouse-help)) 374 (setq help-echo 'widget-mouse-help))
403 (widget-put widget :field-overlay overlay) 375 (widget-put widget :field-overlay overlay)
404 (overlay-put overlay 'detachable nil) 376 (overlay-put overlay 'detachable nil)
405 (overlay-put overlay 'field widget) 377 (overlay-put overlay 'field widget)
435 (t 407 (t
436 (format "(widget %S :help-echo %S)" widget help-echo))))) 408 (format "(widget %S :help-echo %S)" widget help-echo)))))
437 409
438 (defun widget-specify-sample (widget from to) 410 (defun widget-specify-sample (widget from to)
439 ;; Specify sample for WIDGET between FROM and TO. 411 ;; Specify sample for WIDGET between FROM and TO.
440 (let ((face (widget-apply widget :sample-face-get))) 412 (let ((face (widget-apply widget :sample-face-get))
441 (when face 413 (overlay (make-overlay from to nil t nil)))
442 (add-text-properties from to (list 'start-open t 414 (overlay-put overlay 'face face)
443 'end-open t 415 (widget-put widget :sample-overlay overlay)))
444 'face face))))) 416
445 (defun widget-specify-doc (widget from to) 417 (defun widget-specify-doc (widget from to)
446 ;; Specify documentation for WIDGET between FROM and TO. 418 ;; Specify documentation for WIDGET between FROM and TO.
447 (add-text-properties from to (list 'widget-doc widget 419 (let ((overlay (make-overlay from to nil t nil)))
448 'face widget-documentation-face))) 420 (overlay-put overlay 'widget-doc widget)
421 (overlay-put overlay 'face widget-documentation-face)
422 (widget-put widget :doc-overlay overlay)))
449 423
450 (defmacro widget-specify-insert (&rest form) 424 (defmacro widget-specify-insert (&rest form)
451 ;; Execute FORM without inheriting any text properties. 425 ;; Execute FORM without inheriting any text properties.
452 (` 426 (`
453 (save-restriction 427 (save-restriction
455 result 429 result
456 before-change-functions 430 before-change-functions
457 after-change-functions) 431 after-change-functions)
458 (insert "<>") 432 (insert "<>")
459 (narrow-to-region (- (point) 2) (point)) 433 (narrow-to-region (- (point) 2) (point))
460 (widget-specify-none (point-min) (point-max))
461 (goto-char (1+ (point-min))) 434 (goto-char (1+ (point-min)))
462 (setq result (progn (,@ form))) 435 (setq result (progn (,@ form)))
463 (delete-region (point-min) (1+ (point-min))) 436 (delete-region (point-min) (1+ (point-min)))
464 (delete-region (1- (point-max)) (point-max)) 437 (delete-region (1- (point-max)) (point-max))
465 (goto-char (point-max)) 438 (goto-char (point-max))
868 "Call `insert' with ARGS and make the text read only." 841 "Call `insert' with ARGS and make the text read only."
869 (let ((inhibit-read-only t) 842 (let ((inhibit-read-only t)
870 before-change-functions 843 before-change-functions
871 after-change-functions 844 after-change-functions
872 (from (point))) 845 (from (point)))
873 (apply 'insert args) 846 (apply 'insert args)))
874 (widget-specify-text from (point))))
875 847
876 (defun widget-convert-text (type from to 848 (defun widget-convert-text (type from to
877 &optional button-from button-to 849 &optional button-from button-to
878 &rest args) 850 &rest args)
879 "Return a widget of type TYPE with endpoint FROM TO. 851 "Return a widget of type TYPE with endpoint FROM TO.
883 button end points. 855 button end points.
884 Optional ARGS are extra keyword arguments for TYPE." 856 Optional ARGS are extra keyword arguments for TYPE."
885 (let ((widget (apply 'widget-convert type :delete 'widget-leave-text args)) 857 (let ((widget (apply 'widget-convert type :delete 'widget-leave-text args))
886 (from (copy-marker from)) 858 (from (copy-marker from))
887 (to (copy-marker to))) 859 (to (copy-marker to)))
888 (widget-specify-text from to)
889 (set-marker-insertion-type from t) 860 (set-marker-insertion-type from t)
890 (set-marker-insertion-type to nil) 861 (set-marker-insertion-type to nil)
891 (widget-put widget :from from) 862 (widget-put widget :from from)
892 (widget-put widget :to to) 863 (widget-put widget :to to)
893 (when button-from 864 (when button-from
905 (defun widget-leave-text (widget) 876 (defun widget-leave-text (widget)
906 "Remove markers and overlays from WIDGET and its children." 877 "Remove markers and overlays from WIDGET and its children."
907 (let ((from (widget-get widget :from)) 878 (let ((from (widget-get widget :from))
908 (to (widget-get widget :to)) 879 (to (widget-get widget :to))
909 (button (widget-get widget :button-overlay)) 880 (button (widget-get widget :button-overlay))
881 (sample (widget-get widget :sample-overlay))
882 (doc (widget-get widget :doc-overlay))
910 (field (widget-get widget :field-overlay)) 883 (field (widget-get widget :field-overlay))
911 (children (widget-get widget :children))) 884 (children (widget-get widget :children)))
912 (set-marker from nil) 885 (set-marker from nil)
913 (set-marker to nil) 886 (set-marker to nil)
914 (when button 887 (when button
915 (delete-overlay button)) 888 (delete-overlay button))
889 (when sample
890 (delete-overlay sample))
891 (when doc
892 (delete-overlay doc))
916 (when field 893 (when field
917 (delete-overlay field)) 894 (delete-overlay field))
918 (mapcar 'widget-leave-text children))) 895 (mapcar 'widget-leave-text children)))
919 896
920 ;;; Keymap and Commands. 897 ;;; Keymap and Commands.
1104 widget 1081 widget
1105 nil) 1082 nil)
1106 widget)) 1083 widget))
1107 nil))) 1084 nil)))
1108 1085
1086 (defcustom widget-use-overlay-change (string-match "XEmacs" emacs-version)
1087 "If non-nil, use overlay change functions to tab around in the buffer.
1088 This is much faster, but doesn't work reliably on Emacs 19.34."
1089 :type 'boolean
1090 :group 'widgets)
1091
1109 (defun widget-move (arg) 1092 (defun widget-move (arg)
1110 "Move point to the ARG next field or button. 1093 "Move point to the ARG next field or button.
1111 ARG may be negative to move backward." 1094 ARG may be negative to move backward."
1112 (or (bobp) (> arg 0) (backward-char)) 1095 (or (bobp) (> arg 0) (backward-char))
1113 (let ((pos (point)) 1096 (let ((pos (point))
1114 (number arg) 1097 (number arg)
1115 (old (widget-tabable-at)) 1098 (old (widget-tabable-at))
1116 new) 1099 new)
1117 ;; Forward. 1100 ;; Forward.
1118 (while (> arg 0) 1101 (while (> arg 0)
1119 (if (eobp) 1102 (cond ((eobp)
1120 (goto-char (point-min)) 1103 (goto-char (point-min)))
1121 (forward-char 1)) 1104 (widget-use-overlay-change
1105 (goto-char (next-overlay-change (point))))
1106 (t
1107 (forward-char 1)))
1122 (and (eq pos (point)) 1108 (and (eq pos (point))
1123 (eq arg number) 1109 (eq arg number)
1124 (error "No buttons or fields found")) 1110 (error "No buttons or fields found"))
1125 (let ((new (widget-tabable-at))) 1111 (let ((new (widget-tabable-at)))
1126 (when new 1112 (when new
1127 (unless (eq new old) 1113 (unless (eq new old)
1128 (setq arg (1- arg)) 1114 (setq arg (1- arg))
1129 (setq old new))))) 1115 (setq old new)))))
1130 ;; Backward. 1116 ;; Backward.
1131 (while (< arg 0) 1117 (while (< arg 0)
1132 (if (bobp) 1118 (cond ((bobp)
1133 (goto-char (point-max)) 1119 (goto-char (point-max)))
1134 (backward-char 1)) 1120 (widget-use-overlay-change
1121 (goto-char (previous-overlay-change (point))))
1122 (t
1123 (backward-char 1)))
1135 (and (eq pos (point)) 1124 (and (eq pos (point))
1136 (eq arg number) 1125 (eq arg number)
1137 (error "No buttons or fields found")) 1126 (error "No buttons or fields found"))
1138 (let ((new (widget-tabable-at))) 1127 (let ((new (widget-tabable-at)))
1139 (when new 1128 (when new
1165 (interactive) 1154 (interactive)
1166 (let* ((field (widget-field-find (point))) 1155 (let* ((field (widget-field-find (point)))
1167 (start (and field (widget-field-start field)))) 1156 (start (and field (widget-field-start field))))
1168 (if (and start (not (eq start (point)))) 1157 (if (and start (not (eq start (point))))
1169 (goto-char start) 1158 (goto-char start)
1170 (call-interactively 'beginning-of-line)))) 1159 (call-interactively 'beginning-of-line)))
1160 ;; XEmacs: preserve the region
1161 (setq zmacs-region-stays t))
1171 1162
1172 (defun widget-end-of-line () 1163 (defun widget-end-of-line ()
1173 "Go to end of field or end of line, whichever is first." 1164 "Go to end of field or end of line, whichever is first."
1174 (interactive) 1165 (interactive)
1175 (let* ((field (widget-field-find (point))) 1166 (let* ((field (widget-field-find (point)))
1176 (end (and field (widget-field-end field)))) 1167 (end (and field (widget-field-end field))))
1177 (if (and end (not (eq end (point)))) 1168 (if (and end (not (eq end (point))))
1178 (goto-char end) 1169 (goto-char end)
1179 (call-interactively 'end-of-line)))) 1170 (call-interactively 'end-of-line)))
1171 ;; XEmacs: preserve the region
1172 (setq zmacs-region-stays t))
1180 1173
1181 (defun widget-kill-line () 1174 (defun widget-kill-line ()
1182 "Kill to end of field or end of line, whichever is first." 1175 "Kill to end of field or end of line, whichever is first."
1183 (interactive) 1176 (interactive)
1184 (let* ((field (widget-field-find (point))) 1177 (let* ((field (widget-field-find (point)))
1228 (widget-specify-field field 1221 (widget-specify-field field
1229 (marker-position from) (marker-position to)) 1222 (marker-position from) (marker-position to))
1230 (set-marker from nil) 1223 (set-marker from nil)
1231 (set-marker to nil)))) 1224 (set-marker to nil))))
1232 (widget-clear-undo) 1225 (widget-clear-undo)
1233 ;; We need to maintain text properties and size of the editing fields. 1226 (widget-add-change))
1234 (make-local-variable 'after-change-functions)
1235 (setq after-change-functions
1236 (if widget-field-list '(widget-after-change) nil))
1237 (when widget-field-use-before-change
1238 (make-local-variable 'before-change-functions)
1239 (setq before-change-functions
1240 (if widget-field-list '(widget-before-change) nil))))
1241 1227
1242 (defvar widget-field-last nil) 1228 (defvar widget-field-last nil)
1243 ;; Last field containing point. 1229 ;; Last field containing point.
1244 (make-variable-buffer-local 'widget-field-last) 1230 (make-variable-buffer-local 'widget-field-last)
1245 1231
1259 1245
1260 (defun widget-field-end (widget) 1246 (defun widget-field-end (widget)
1261 "Return the end of WIDGET's editing field." 1247 "Return the end of WIDGET's editing field."
1262 (let ((overlay (widget-get widget :field-overlay))) 1248 (let ((overlay (widget-get widget :field-overlay)))
1263 ;; Don't subtract one if local-map works at the end of the overlay. 1249 ;; Don't subtract one if local-map works at the end of the overlay.
1264 (and overlay (if widget-field-add-space 1250 (and overlay (if (or widget-field-add-space
1251 (null (widget-get widget :size)))
1265 (1- (overlay-end overlay)) 1252 (1- (overlay-end overlay))
1266 (overlay-end overlay))))) 1253 (overlay-end overlay)))))
1267 1254
1268 (defun widget-field-find (pos) 1255 (defun widget-field-find (pos)
1269 "Return the field at POS. 1256 "Return the field at POS.
1279 (when found 1266 (when found
1280 (debug "Overlapping fields")) 1267 (debug "Overlapping fields"))
1281 (setq found field)))) 1268 (setq found field))))
1282 found)) 1269 found))
1283 1270
1284 (defun widget-before-change (from &rest ignore) 1271 (defun widget-before-change (from to)
1285 ;; This is how, for example, a variable changes its state to `modified'. 1272 ;; This is how, for example, a variable changes its state to `modified'.
1286 ;; when it is being edited. 1273 ;; when it is being edited.
1287 (condition-case nil 1274 (let ((from-field (widget-field-find from))
1288 (let ((field (widget-field-find from))) 1275 (to-field (widget-field-find to)))
1289 (widget-apply field :notify field)) 1276 (cond ((not (eq from-field to-field))
1290 (error (debug "Before Change")))) 1277 (add-hook 'post-command-hook 'widget-add-change nil t)
1278 (error "Change should be restricted to a single field"))
1279 ((null from-field)
1280 (add-hook 'post-command-hook 'widget-add-change nil t)
1281 (error "Attempt to change text outside editable field"))
1282 (widget-field-use-before-change
1283 (condition-case nil
1284 (widget-apply from-field :notify from-field)
1285 (error (debug "Before Change")))))))
1286
1287 (defun widget-add-change ()
1288 (make-local-hook 'post-command-hook)
1289 (remove-hook 'post-command-hook 'widget-add-change t)
1290 (make-local-hook 'before-change-functions)
1291 (add-hook 'before-change-functions 'widget-before-change nil t)
1292 (make-local-hook 'after-change-functions)
1293 (add-hook 'after-change-functions 'widget-after-change nil t))
1291 1294
1292 (defun widget-after-change (from to old) 1295 (defun widget-after-change (from to old)
1293 ;; Adjust field size and text properties. 1296 ;; Adjust field size and text properties.
1294 (condition-case nil 1297 (condition-case nil
1295 (let ((field (widget-field-find from)) 1298 (let ((field (widget-field-find from))
1481 (when value-pos 1484 (when value-pos
1482 (goto-char value-pos) 1485 (goto-char value-pos)
1483 (widget-apply widget :value-create))) 1486 (widget-apply widget :value-create)))
1484 (let ((from (copy-marker (point-min))) 1487 (let ((from (copy-marker (point-min)))
1485 (to (copy-marker (point-max)))) 1488 (to (copy-marker (point-max))))
1486 (widget-specify-text from to)
1487 (set-marker-insertion-type from t) 1489 (set-marker-insertion-type from t)
1488 (set-marker-insertion-type to nil) 1490 (set-marker-insertion-type to nil)
1489 (widget-put widget :from from) 1491 (widget-put widget :from from)
1490 (widget-put widget :to to))) 1492 (widget-put widget :to to)))
1491 (widget-clear-undo)) 1493 (widget-clear-undo))
1528 buttons)))) 1530 buttons))))
1529 (t 1531 (t
1530 (error "Unknown escape `%c'" escape))) 1532 (error "Unknown escape `%c'" escape)))
1531 (widget-put widget :buttons buttons))) 1533 (widget-put widget :buttons buttons)))
1532 1534
1533 (defvar widget-button-face nil
1534 "Face to use for buttons.
1535 This is a variable so that it can be buffer-local.")
1536
1537 (defun widget-default-button-face-get (widget) 1535 (defun widget-default-button-face-get (widget)
1538 ;; Use :button-face or widget-button-face 1536 ;; Use :button-face or widget-button-face
1539 (or (widget-get widget :button-face) 1537 (or (widget-get widget :button-face)
1540 (let ((parent (widget-get widget :parent))) 1538 (let ((parent (widget-get widget :parent)))
1541 (if parent 1539 (if parent
1542 (widget-apply parent :button-face-get) 1540 (widget-apply parent :button-face-get)
1543 'widget-button-face)))) 1541 widget-button-face))))
1544 1542
1545 (defun widget-default-sample-face-get (widget) 1543 (defun widget-default-sample-face-get (widget)
1546 ;; Use :sample-face. 1544 ;; Use :sample-face.
1547 (widget-get widget :sample-face)) 1545 (widget-get widget :sample-face))
1548 1546
1550 ;; Remove widget from the buffer. 1548 ;; Remove widget from the buffer.
1551 (let ((from (widget-get widget :from)) 1549 (let ((from (widget-get widget :from))
1552 (to (widget-get widget :to)) 1550 (to (widget-get widget :to))
1553 (inactive-overlay (widget-get widget :inactive)) 1551 (inactive-overlay (widget-get widget :inactive))
1554 (button-overlay (widget-get widget :button-overlay)) 1552 (button-overlay (widget-get widget :button-overlay))
1553 (sample-overlay (widget-get widget :sample-overlay))
1554 (doc-overlay (widget-get widget :doc-overlay))
1555 before-change-functions 1555 before-change-functions
1556 after-change-functions 1556 after-change-functions
1557 (inhibit-read-only t)) 1557 (inhibit-read-only t))
1558 (widget-apply widget :value-delete) 1558 (widget-apply widget :value-delete)
1559 (when inactive-overlay 1559 (when inactive-overlay
1560 (delete-overlay inactive-overlay)) 1560 (delete-overlay inactive-overlay))
1561 (when button-overlay 1561 (when button-overlay
1562 (delete-overlay button-overlay)) 1562 (delete-overlay button-overlay))
1563 (when sample-overlay
1564 (delete-overlay sample-overlay))
1565 (when doc-overlay
1566 (delete-overlay doc-overlay))
1563 (when (< from to) 1567 (when (< from to)
1564 ;; Kludge: this doesn't need to be true for empty formats. 1568 ;; Kludge: this doesn't need to be true for empty formats.
1565 (delete-region from to)) 1569 (delete-region from to))
1566 (set-marker from nil) 1570 (set-marker from nil)
1567 (set-marker to nil)) 1571 (set-marker to nil))
1779 1783
1780 (defun widget-url-link-action (widget &optional event) 1784 (defun widget-url-link-action (widget &optional event)
1781 "Open the url specified by WIDGET." 1785 "Open the url specified by WIDGET."
1782 (require 'browse-url) 1786 (require 'browse-url)
1783 (funcall browse-url-browser-function (widget-value widget))) 1787 (funcall browse-url-browser-function (widget-value widget)))
1788
1789 ;;; The `file-link' Widget.
1790
1791 (define-widget 'file-link 'link
1792 "A link to a file."
1793 :action 'widget-file-link-action)
1794
1795 (defun widget-file-link-action (widget &optional event)
1796 "Find the file specified by WIDGET."
1797 (find-file (widget-value widget)))
1798
1799 ;;; The `emacs-library-link' Widget.
1800
1801 (define-widget 'emacs-library-link 'link
1802 "A link to an Emacs Lisp library file."
1803 :action 'widget-emacs-library-link-action)
1804
1805 (defun widget-emacs-library-link-action (widget &optional event)
1806 "Find the Emacs Library file specified by WIDGET."
1807 (find-file (locate-library (widget-value widget))))
1808
1809 ;;; The `emacs-commentary-link' Widget.
1810
1811 (define-widget 'emacs-commentary-link 'link
1812 "A link to Commentary in an Emacs Lisp library file."
1813 :action 'widget-emacs-commentary-link-action)
1814
1815 (defun widget-emacs-commentary-link-action (widget &optional event)
1816 "Find the Commentary section of the Emacs file specified by WIDGET."
1817 (finder-commentary (widget-value widget)))
1784 1818
1785 ;;; The `editable-field' Widget. 1819 ;;; The `editable-field' Widget.
1786 1820
1787 (define-widget 'editable-field 'default 1821 (define-widget 'editable-field 'default
1788 "An editable text field." 1822 "An editable text field."
2024 (widget-value-set widget 2058 (widget-value-set widget
2025 (widget-apply current :value-to-external 2059 (widget-apply current :value-to-external
2026 (widget-get current :value))) 2060 (widget-get current :value)))
2027 (widget-setup) 2061 (widget-setup)
2028 (widget-apply widget :notify widget event))) 2062 (widget-apply widget :notify widget event)))
2029 (run-hooks 'widget-edit-hook)) 2063 (run-hook-with-args 'widget-edit-functions widget))
2030 2064
2031 (defun widget-choice-validate (widget) 2065 (defun widget-choice-validate (widget)
2032 ;; Valid if we have made a valid choice. 2066 ;; Valid if we have made a valid choice.
2033 (let ((void (widget-get widget :void)) 2067 (let ((void (widget-get widget :void))
2034 (choice (widget-get widget :choice)) 2068 (choice (widget-get widget :choice))
2080 2114
2081 (defun widget-toggle-action (widget &optional event) 2115 (defun widget-toggle-action (widget &optional event)
2082 ;; Toggle value. 2116 ;; Toggle value.
2083 (widget-value-set widget (not (widget-value widget))) 2117 (widget-value-set widget (not (widget-value widget)))
2084 (widget-apply widget :notify widget event) 2118 (widget-apply widget :notify widget event)
2085 (run-hooks 'widget-edit-hook)) 2119 (run-hook-with-args 'widget-edit-functions widget))
2086 2120
2087 ;;; The `checkbox' Widget. 2121 ;;; The `checkbox' Widget.
2088 2122
2089 (define-widget 'checkbox 'toggle 2123 (define-widget 'checkbox 'toggle
2090 "A checkbox toggle." 2124 "A checkbox toggle."
2567 (let ((child (widget-editable-list-entry-create 2601 (let ((child (widget-editable-list-entry-create
2568 widget nil nil))) 2602 widget nil nil)))
2569 (when (< (widget-get child :entry-from) (widget-get widget :from)) 2603 (when (< (widget-get child :entry-from) (widget-get widget :from))
2570 (set-marker (widget-get widget :from) 2604 (set-marker (widget-get widget :from)
2571 (widget-get child :entry-from))) 2605 (widget-get child :entry-from)))
2572 (widget-specify-text (widget-get child :entry-from)
2573 (widget-get child :entry-to))
2574 (if (eq (car children) before) 2606 (if (eq (car children) before)
2575 (widget-put widget :children (cons child children)) 2607 (widget-put widget :children (cons child children))
2576 (while (not (eq (car (cdr children)) before)) 2608 (while (not (eq (car (cdr children)) before))
2577 (setq children (cdr children))) 2609 (setq children (cdr children)))
2578 (setcdr children (cons child (cdr children))))))) 2610 (setcdr children (cons child (cdr children)))))))
2642 :buttons (cons delete 2674 :buttons (cons delete
2643 (cons insert 2675 (cons insert
2644 (widget-get widget :buttons)))) 2676 (widget-get widget :buttons))))
2645 (let ((entry-from (copy-marker (point-min))) 2677 (let ((entry-from (copy-marker (point-min)))
2646 (entry-to (copy-marker (point-max)))) 2678 (entry-to (copy-marker (point-max))))
2647 (widget-specify-text entry-from entry-to)
2648 (set-marker-insertion-type entry-from t) 2679 (set-marker-insertion-type entry-from t)
2649 (set-marker-insertion-type entry-to nil) 2680 (set-marker-insertion-type entry-to nil)
2650 (widget-put child :entry-from entry-from) 2681 (widget-put child :entry-from entry-from)
2651 (widget-put child :entry-to entry-to))) 2682 (widget-put child :entry-to entry-to)))
2652 (widget-put insert :widget child) 2683 (widget-put insert :widget child)
2901 2932
2902 (define-widget 'regexp 'string 2933 (define-widget 'regexp 'string
2903 "A regular expression." 2934 "A regular expression."
2904 :match 'widget-regexp-match 2935 :match 'widget-regexp-match
2905 :validate 'widget-regexp-validate 2936 :validate 'widget-regexp-validate
2906 :value-face 'widget-single-line-field-face 2937 ;; Doesn't work well with terminating newline.
2938 ;; :value-face 'widget-single-line-field-face
2907 :tag "Regexp") 2939 :tag "Regexp")
2908 2940
2909 (defun widget-regexp-match (widget value) 2941 (defun widget-regexp-match (widget value)
2910 ;; Match valid regexps. 2942 ;; Match valid regexps.
2911 (and (stringp value) 2943 (and (stringp value)
2927 "A file widget. 2959 "A file widget.
2928 It will read a file name from the minibuffer when invoked." 2960 It will read a file name from the minibuffer when invoked."
2929 :complete-function 'widget-file-complete 2961 :complete-function 'widget-file-complete
2930 :prompt-value 'widget-file-prompt-value 2962 :prompt-value 'widget-file-prompt-value
2931 :format "%{%t%}: %v" 2963 :format "%{%t%}: %v"
2932 :value-face 'widget-single-line-field-face 2964 ;; Doesn't work well with terminating newline.
2965 ;; :value-face 'widget-single-line-field-face
2933 :tag "File") 2966 :tag "File")
2934 2967
2935 (defun widget-file-complete () 2968 (defun widget-file-complete ()
2936 "Perform completion on file name preceding point." 2969 "Perform completion on file name preceding point."
2937 (interactive) 2970 (interactive)
3313 ;; Toggle a boolean. 3346 ;; Toggle a boolean.
3314 (y-or-n-p prompt)) 3347 (y-or-n-p prompt))
3315 3348
3316 ;;; The `color' Widget. 3349 ;;; The `color' Widget.
3317 3350
3318 (define-widget 'color-item 'choice-item 3351 (define-widget 'color 'editable-field
3319 "A color name (with sample)." 3352 "Choose a color name (with sample)."
3320 :format "%v (%{sample%})\n" 3353 :format "%t: %v (%{sample%})\n"
3321 :sample-face-get 'widget-color-item-button-face-get) 3354 :size 10
3322 3355 :tag "Color"
3323 (defun widget-color-item-button-face-get (widget) 3356 :value "black"
3324 (let ((symbol (intern (concat "fg:" (widget-value widget))))) 3357 :complete 'widget-color-complete
3358 :sample-face-get 'widget-color-sample-face-get
3359 :notify 'widget-color-notify
3360 :action 'widget-color-action)
3361
3362 (defun widget-color-complete (widget)
3363 "Complete the color in WIDGET."
3364 (let* ((prefix (buffer-substring-no-properties (widget-field-start widget)
3365 (point)))
3366 (list (widget-color-choice-list))
3367 (completion (try-completion prefix list)))
3368 (cond ((eq completion t)
3369 (message "Exact match."))
3370 ((null completion)
3371 (error "Can't find completion for \"%s\"" prefix))
3372 ((not (string-equal prefix completion))
3373 (insert-and-inherit (substring completion (length prefix))))
3374 (t
3375 (message "Making completion list...")
3376 (let ((list (all-completions prefix list nil)))
3377 (with-output-to-temp-buffer "*Completions*"
3378 (display-completion-list list)))
3379 (message "Making completion list...done")))))
3380
3381 (defun widget-color-sample-face-get (widget)
3382 (let* ((value (condition-case nil
3383 (widget-value widget)
3384 (error (widget-get widget :value))))
3385 (symbol (intern (concat "fg:" value))))
3325 (if (string-match "XEmacs" emacs-version) 3386 (if (string-match "XEmacs" emacs-version)
3326 (prog1 symbol 3387 (prog1 symbol
3327 (or (find-face symbol) 3388 (or (find-face symbol)
3328 (set-face-foreground (make-face symbol) (widget-value widget)))) 3389 (set-face-foreground (make-face symbol) value)))
3329 (condition-case nil 3390 (condition-case nil
3330 (facemenu-get-face symbol) 3391 (facemenu-get-face symbol)
3331 (error 'default))))) 3392 (error 'default)))))
3332 3393
3333 (define-widget 'color 'push-button
3334 "Choose a color name (with sample)."
3335 :format "%[%t%]: %v"
3336 :tag "Color"
3337 :value "black"
3338 :value-create 'widget-color-value-create
3339 :value-delete 'widget-children-value-delete
3340 :value-get 'widget-color-value-get
3341 :value-set 'widget-color-value-set
3342 :action 'widget-color-action
3343 :match 'widget-field-match
3344 :tag "Color")
3345
3346 (defvar widget-color-choice-list nil) 3394 (defvar widget-color-choice-list nil)
3347 ;; Variable holding the possible colors. 3395 ;; Variable holding the possible colors.
3348 3396
3349 (defun widget-color-choice-list () 3397 (defun widget-color-choice-list ()
3350 (unless widget-color-choice-list 3398 (unless widget-color-choice-list
3351 (setq widget-color-choice-list 3399 (setq widget-color-choice-list
3352 (mapcar '(lambda (color) (list color)) 3400 (if (fboundp 'read-color-completion-table)
3353 (x-defined-colors)))) 3401 (read-color-completion-table)
3402 (mapcar '(lambda (color) (list color))
3403 (x-defined-colors)))))
3354 widget-color-choice-list) 3404 widget-color-choice-list)
3355
3356 (defun widget-color-value-create (widget)
3357 (let ((child (widget-create-child-and-convert
3358 widget 'color-item (widget-get widget :value))))
3359 (widget-put widget :children (list child))))
3360
3361 (defun widget-color-value-get (widget)
3362 ;; Pass command to first child.
3363 (widget-apply (car (widget-get widget :children)) :value-get))
3364
3365 (defun widget-color-value-set (widget value)
3366 ;; Pass command to first child.
3367 (widget-apply (car (widget-get widget :children)) :value-set value))
3368 3405
3369 (defvar widget-color-history nil 3406 (defvar widget-color-history nil
3370 "History of entered colors") 3407 "History of entered colors")
3371 3408
3372 (defun widget-color-action (widget &optional event) 3409 (defun widget-color-action (widget &optional event)
3373 ;; Prompt for a color. 3410 ;; Prompt for a color.
3374 (let* ((tag (widget-apply widget :menu-tag-get)) 3411 (let* ((tag (widget-apply widget :menu-tag-get))
3375 (prompt (concat tag ": ")) 3412 (prompt (concat tag ": "))
3376 (answer (cond ((string-match "XEmacs" emacs-version) 3413 (value (widget-value widget))
3377 (read-color prompt)) 3414 (start (widget-field-start widget))
3378 ((fboundp 'x-defined-colors) 3415 (pos (cond ((< (point) start)
3379 (completing-read (concat tag ": ") 3416 0)
3380 (widget-color-choice-list) 3417 ((> (point) (+ start (length value)))
3381 nil nil nil 'widget-color-history)) 3418 (length value))
3382 (t 3419 (t
3383 (read-string prompt (widget-value widget)))))) 3420 (- (point) start))))
3421 (answer (if (commandp 'read-color)
3422 (read-color prompt)
3423 (completing-read (concat tag ": ")
3424 (widget-color-choice-list)
3425 nil nil
3426 (cons value pos)
3427 'widget-color-history))))
3384 (unless (zerop (length answer)) 3428 (unless (zerop (length answer))
3385 (widget-value-set widget answer) 3429 (widget-value-set widget answer)
3386 (widget-setup) 3430 (widget-setup)
3387 (widget-apply widget :notify widget event)))) 3431 (widget-apply widget :notify widget event))))
3432
3433 (defun widget-color-notify (widget child &optional event)
3434 "Update the sample, and notofy the parent."
3435 (overlay-put (widget-get widget :sample-overlay)
3436 'face (widget-apply widget :sample-face-get))
3437 (widget-default-notify widget child event))
3388 3438
3389 ;;; The Help Echo 3439 ;;; The Help Echo
3390 3440
3391 (defun widget-echo-help-mouse () 3441 (defun widget-echo-help-mouse ()
3392 "Display the help message for the widget under the mouse. 3442 "Display the help message for the widget under the mouse.