diff lisp/wid-edit.el @ 19022:904dcdbb8576

Synched with 1.9951.
author Per Abrahamsen <abraham@dina.kvl.dk>
date Mon, 28 Jul 1997 15:46:57 +0000
parents ac27714a02cf
children e4b14e6fd28f
line wrap: on
line diff
--- a/lisp/wid-edit.el	Mon Jul 28 15:10:21 1997 +0000
+++ b/lisp/wid-edit.el	Mon Jul 28 15:46:57 1997 +0000
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: extensions
-;; Version: 1.9945
+;; Version: 1.9951
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;; This file is part of GNU Emacs.
@@ -38,6 +38,7 @@
 (eval-and-compile
   (autoload 'pp-to-string "pp")
   (autoload 'Info-goto-node "info")
+  (autoload 'finder-commentary "finder" nil t)
 
   (when (string-match "XEmacs" emacs-version)
     (condition-case nil
@@ -101,27 +102,6 @@
 	(display-error obj buf)
 	(buffer-string buf)))))
 
-(when (let ((a "foo"))
-	(put-text-property 1 2 'foo 1 a)
-	(put-text-property 1 2 'bar 2 a)
-	(set-text-properties 1 2 nil a)
-	(text-properties-at 1 a))
-  ;; XEmacs 20.2 and earlier had a buggy set-text-properties.
-  (defun set-text-properties (start end props &optional buffer-or-string)
-    "Completely replace properties of text from START to END.
-The third argument PROPS is the new property list.
-The optional fourth argument, BUFFER-OR-STRING,
-is the string or buffer containing the text."
-    (map-extents #'(lambda (extent ignored)
-		     (remove-text-properties
-		      start end
-		      (list (extent-property extent 'text-prop)
-			    nil)
-		      buffer-or-string)
-		     nil)
-		 buffer-or-string start end nil nil 'text-prop)
-    (add-text-properties start end props buffer-or-string)))
-
 ;;; Customization.
 
 (defgroup widgets nil
@@ -352,18 +332,6 @@
 ;; 
 ;; These functions are for specifying text properties. 
 
-(defun widget-specify-none (from to)
-  ;; Clear all text properties between FROM and TO.
-  (set-text-properties from to nil))
-
-(defun widget-specify-text (from to)
-  ;; Default properties.
-  (add-text-properties from to (list 'read-only t
-				     'front-sticky t
-				     'rear-nonsticky nil
-				     'start-open nil
-				     'end-open nil)))
-
 (defcustom widget-field-add-space 
   (or (< emacs-major-version 20)
       (and (eq emacs-major-version 20)
@@ -378,9 +346,9 @@
   :group 'widgets)
 
 (defcustom widget-field-use-before-change
-  (or (> emacs-minor-version 34)
-      (>= emacs-major-version 20)
-      (string-match "XEmacs" emacs-version))
+  (and (or (> emacs-minor-version 34)
+	   (> emacs-major-version 19))
+       (not (string-match "XEmacs" emacs-version)))
   "Non-nil means use `before-change-functions' to track editable fields.
 This enables the use of undo, but doesn't work on Emacs 19.34 and earlier. 
 Using before hooks also means that the :notify function can't know the
@@ -390,7 +358,6 @@
 
 (defun widget-specify-field (widget from to)
   "Specify editable button for WIDGET between FROM and TO."
-  (put-text-property from to 'read-only nil)
   ;; Terminating space is not part of the field, but necessary in
   ;; order for local-map to work.  Remove next sexp if local-map works
   ;; at the end of the overlay.
@@ -401,14 +368,6 @@
 	  (widget-field-add-space
 	   (insert-and-inherit " ")))
     (setq to (point)))
-  (if (or widget-field-add-space
-	  (null (widget-get widget :size)))
-      (add-text-properties (1- to) to
-			   '(front-sticky nil start-open t read-only to))
-    (add-text-properties to (1+ to) 
-			 '(front-sticky nil start-open t read-only to)))
-  (add-text-properties (1- from) from 
-		       '(rear-nonsticky t end-open t read-only from))
   (let ((map (widget-get widget :keymap))
 	(face (or (widget-get widget :value-face) 'widget-field-face))
 	(help-echo (widget-get widget :help-echo))
@@ -461,8 +420,10 @@
 
 (defun widget-specify-doc (widget from to)
   ;; Specify documentation for WIDGET between FROM and TO.
-  (add-text-properties from to (list 'widget-doc widget
-				     'face widget-documentation-face)))
+  (let ((overlay (make-overlay from to nil t nil)))
+    (overlay-put overlay 'widget-doc widget)
+    (overlay-put overlay 'face widget-documentation-face)
+    (widget-put widget :doc-overlay overlay)))
 
 (defmacro widget-specify-insert (&rest form)
   ;; Execute FORM without inheriting any text properties.
@@ -474,7 +435,6 @@
 	   after-change-functions)
        (insert "<>")
        (narrow-to-region (- (point) 2) (point))
-       (widget-specify-none (point-min) (point-max))
        (goto-char (1+ (point-min)))
        (setq result (progn (,@ form)))
        (delete-region (point-min) (1+ (point-min)))
@@ -887,8 +847,7 @@
 	before-change-functions
 	after-change-functions
 	(from (point)))
-    (apply 'insert args)
-    (widget-specify-text from (point))))
+    (apply 'insert args)))
 
 (defun widget-convert-text (type from to
 				 &optional button-from button-to
@@ -902,7 +861,6 @@
   (let ((widget (apply 'widget-convert type :delete 'widget-leave-text args))
 	(from (copy-marker from))
 	(to (copy-marker to)))
-    (widget-specify-text from to)
     (set-marker-insertion-type from t)
     (set-marker-insertion-type to nil)
     (widget-put widget :from from)
@@ -925,6 +883,7 @@
 	(to (widget-get widget :to))
 	(button (widget-get widget :button-overlay))
 	(sample (widget-get widget :sample-overlay))
+	(doc (widget-get widget :doc-overlay))
 	(field (widget-get widget :field-overlay))
 	(children (widget-get widget :children)))
     (set-marker from nil)
@@ -933,6 +892,8 @@
       (delete-overlay button))
     (when sample
       (delete-overlay sample))
+    (when doc
+      (delete-overlay doc))
     (when field
       (delete-overlay field))
     (mapcar 'widget-leave-text children)))
@@ -1126,6 +1087,12 @@
 	    widget))
       nil)))
 
+(defcustom widget-use-overlay-change (string-match "XEmacs" emacs-version)
+  "If non-nil, use overlay change functions to tab around in the buffer.
+This is much faster, but doesn't work reliably on Emacs 19.34."
+  :type 'boolean
+  :group 'widgets)
+
 (defun widget-move (arg)
   "Move point to the ARG next field or button.
 ARG may be negative to move backward."
@@ -1136,9 +1103,12 @@
 	new)
     ;; Forward.
     (while (> arg 0)
-      (if (eobp)
-	  (goto-char (point-min))
-	(forward-char 1))
+      (cond ((eobp)
+	     (goto-char (point-min)))
+	    (widget-use-overlay-change
+	     (goto-char (next-overlay-change (point))))
+	    (t
+	     (forward-char 1)))
       (and (eq pos (point))
 	   (eq arg number)
 	   (error "No buttons or fields found"))
@@ -1149,9 +1119,12 @@
 	    (setq old new)))))
     ;; Backward.
     (while (< arg 0)
-      (if (bobp)
-	  (goto-char (point-max))
-	(backward-char 1))
+      (cond ((bobp)
+	     (goto-char (point-max)))
+	    (widget-use-overlay-change
+	     (goto-char (previous-overlay-change (point))))
+	    (t
+	     (backward-char 1)))
       (and (eq pos (point))
 	   (eq arg number)
 	   (error "No buttons or fields found"))
@@ -1187,7 +1160,9 @@
 	 (start (and field (widget-field-start field))))
     (if (and start (not (eq start (point))))
 	(goto-char start)
-      (call-interactively 'beginning-of-line))))
+      (call-interactively 'beginning-of-line)))
+  ;; XEmacs: preserve the region
+  (setq zmacs-region-stays t))
 
 (defun widget-end-of-line ()
   "Go to end of field or end of line, whichever is first."
@@ -1196,7 +1171,9 @@
 	 (end (and field (widget-field-end field))))
     (if (and end (not (eq end (point))))
 	(goto-char end)
-      (call-interactively 'end-of-line))))
+      (call-interactively 'end-of-line)))
+  ;; XEmacs: preserve the region
+  (setq zmacs-region-stays t))
 
 (defun widget-kill-line ()
   "Kill to end of field or end of line, whichever is first."
@@ -1250,14 +1227,7 @@
 	(set-marker from nil)
 	(set-marker to nil))))
   (widget-clear-undo)
-  ;; We need to maintain text properties and size of the editing fields.
-  (make-local-variable 'after-change-functions)
-  (setq after-change-functions
-	(if widget-field-list '(widget-after-change) nil))
-  (when widget-field-use-before-change
-    (make-local-variable 'before-change-functions)
-    (setq before-change-functions
-	  (if widget-field-list '(widget-before-change) nil))))
+  (widget-add-change))
 
 (defvar widget-field-last nil)
 ;; Last field containing point.
@@ -1302,13 +1272,29 @@
 	  (setq found field))))
     found))
 
-(defun widget-before-change (from &rest ignore)
+(defun widget-before-change (from to)
   ;; This is how, for example, a variable changes its state to `modified'.
   ;; when it is being edited.
-  (condition-case nil
-      (let ((field (widget-field-find from)))
-	(widget-apply field :notify field))
-    (error (debug "Before Change"))))
+  (let ((from-field (widget-field-find from))
+	(to-field (widget-field-find to)))
+    (cond ((not (eq from-field to-field))
+	   (add-hook 'post-command-hook 'widget-add-change nil t)
+	   (error "Change should be restricted to a single field"))
+	  ((null from-field)
+	   (add-hook 'post-command-hook 'widget-add-change nil t)
+	   (error "Attempt to change text outside editable field"))
+	  (widget-field-use-before-change
+	   (condition-case nil
+	       (widget-apply from-field :notify from-field)
+	     (error (debug "Before Change")))))))
+
+(defun widget-add-change ()
+  (make-local-hook 'post-command-hook)
+  (remove-hook 'post-command-hook 'widget-add-change t)
+  (make-local-hook 'before-change-functions)
+  (add-hook 'before-change-functions 'widget-before-change nil t)
+  (make-local-hook 'after-change-functions)
+  (add-hook 'after-change-functions 'widget-after-change nil t))
 
 (defun widget-after-change (from to old)
   ;; Adjust field size and text properties.
@@ -1504,7 +1490,6 @@
        (widget-apply widget :value-create)))
    (let ((from (copy-marker (point-min)))
 	 (to (copy-marker (point-max))))
-     (widget-specify-text from to)
      (set-marker-insertion-type from t)
      (set-marker-insertion-type to nil)
      (widget-put widget :from from)
@@ -1570,6 +1555,7 @@
 	(inactive-overlay (widget-get widget :inactive))
 	(button-overlay (widget-get widget :button-overlay))
 	(sample-overlay (widget-get widget :sample-overlay))
+	(doc-overlay (widget-get widget :doc-overlay))
 	before-change-functions
 	after-change-functions
 	(inhibit-read-only t))
@@ -1580,6 +1566,8 @@
       (delete-overlay button-overlay))
     (when sample-overlay
       (delete-overlay sample-overlay))
+    (when doc-overlay
+      (delete-overlay doc-overlay))
     (when (< from to)
       ;; Kludge: this doesn't need to be true for empty formats.
       (delete-region from to))
@@ -1822,6 +1810,16 @@
   "Find the Emacs Library file specified by WIDGET."
   (find-file (locate-library (widget-value widget))))
 
+;;; The `emacs-commentary-link' Widget.
+    
+(define-widget 'emacs-commentary-link 'link
+  "A link to Commentary in an Emacs Lisp library file."
+  :action 'widget-emacs-commentary-link-action)
+    
+(defun widget-emacs-commentary-link-action (widget &optional event)
+  "Find the Commentary section of the Emacs file specified by WIDGET."
+  (finder-commentary (widget-value widget)))
+
 ;;; The `editable-field' Widget.
 
 (define-widget 'editable-field 'default
@@ -2609,8 +2607,6 @@
 	(when (< (widget-get child :entry-from) (widget-get widget :from))
 	  (set-marker (widget-get widget :from)
 		      (widget-get child :entry-from)))
-	(widget-specify-text (widget-get child :entry-from)
-			     (widget-get child :entry-to))
 	(if (eq (car children) before)
 	    (widget-put widget :children (cons child children))
 	  (while (not (eq (car (cdr children)) before))
@@ -2684,7 +2680,6 @@
 				      (widget-get widget :buttons))))
      (let ((entry-from (copy-marker (point-min)))
 	   (entry-to (copy-marker (point-max))))
-       (widget-specify-text entry-from entry-to)
        (set-marker-insertion-type entry-from t)
        (set-marker-insertion-type entry-to nil)
        (widget-put child :entry-from entry-from)
@@ -2943,7 +2938,8 @@
   "A regular expression."
   :match 'widget-regexp-match
   :validate 'widget-regexp-validate
-  :value-face 'widget-single-line-field-face
+  ;; Doesn't work well with terminating newline.
+  ;; :value-face 'widget-single-line-field-face
   :tag "Regexp")
 
 (defun widget-regexp-match (widget value)
@@ -2969,7 +2965,8 @@
   :complete-function 'widget-file-complete
   :prompt-value 'widget-file-prompt-value
   :format "%{%t%}: %v"
-  :value-face 'widget-single-line-field-face
+  ;; Doesn't work well with terminating newline.
+  ;; :value-face 'widget-single-line-field-face
   :tag "File")
 
 (defun widget-file-complete ()
@@ -3386,11 +3383,14 @@
 	   (message "Making completion list...done")))))
 
 (defun widget-color-sample-face-get (widget)
-  (let ((symbol (intern (concat "fg:" (widget-value widget)))))
+  (let* ((value (condition-case nil
+		    (widget-value widget)
+		  (error (widget-get widget :value))))
+	 (symbol (intern (concat "fg:" value))))
     (if (string-match "XEmacs" emacs-version)
 	(prog1 symbol
 	  (or (find-face symbol)
-	      (set-face-foreground (make-face symbol) (widget-value widget))))
+	      (set-face-foreground (make-face symbol) value)))
       (condition-case nil
 	  (facemenu-get-face symbol)
 	(error 'default)))))
@@ -3414,14 +3414,21 @@
   ;; Prompt for a color.
   (let* ((tag (widget-apply widget :menu-tag-get))
 	 (prompt (concat tag ": "))
-	 (answer (cond ((string-match "XEmacs" emacs-version)
-			(read-color prompt))
-		       ((fboundp 'x-defined-colors)
-			(completing-read (concat tag ": ")
-					 (widget-color-choice-list) 
-					 nil nil nil 'widget-color-history))
-		       (t
-			(read-string prompt (widget-value widget))))))
+	 (value (widget-value widget))
+	 (start (widget-field-start widget))
+	 (pos (cond ((< (point) start)
+		     0)
+		    ((> (point) (+ start (length value)))
+		     (length value))
+		    (t
+		     (- (point) start))))
+	 (answer (if (commandp 'read-color)
+		     (read-color prompt)
+		   (completing-read (concat tag ": ")
+				    (widget-color-choice-list) 
+				    nil nil 
+				    (cons value pos)
+				    'widget-color-history))))
     (unless (zerop (length answer))
       (widget-value-set widget answer)
       (widget-setup)