Synched with custom 1.90.

This commit is contained in:
Per Abrahamsen 1997-04-24 16:53:55 +00:00
parent ee82af565d
commit 6d528fc505
5 changed files with 622 additions and 158 deletions

View file

@ -4,7 +4,7 @@
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, faces
;; Version: 1.84
;; Version: 1.90
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;; This file is part of GNU Emacs.
@ -26,6 +26,8 @@
;;; Commentary:
;;
;; This file implements the code to create and edit customize buffers.
;;
;; See `custom.el'.
;;; Code:
@ -33,6 +35,11 @@
(require 'cus-face)
(require 'wid-edit)
(require 'easymenu)
(eval-when-compile (require 'cl))
(condition-case nil
(require 'cus-load)
(error nil))
(defun custom-face-display-set (face spec &optional frame)
(face-spec-set face spec frame))
@ -355,10 +362,30 @@ Return a list suitable for use in `interactive'."
(if v
(format "Customize variable (default %s): " v)
"Customize variable: ")
obarray 'boundp t))
obarray (lambda (symbol)
(and (boundp symbol)
(or (get symbol 'custom-type)
(user-variable-p symbol))))))
(list (if (equal val "")
v (intern val)))))
(defun custom-menu-filter (menu widget)
"Convert MENU to the form used by `widget-choose'.
MENU should be in the same format as `custom-variable-menu'.
WIDGET is the widget to apply the filter entries of MENU on."
(let ((result nil)
current name action filter)
(while menu
(setq current (car menu)
name (nth 0 current)
action (nth 1 current)
filter (nth 2 current)
menu (cdr menu))
(if (or (null filter) (funcall filter widget))
(push (cons name action) result)
(push name result)))
(nreverse result)))
;;; Unlispify.
(defvar custom-prefix-list nil
@ -552,6 +579,74 @@ when the action is chosen.")
;;; The Customize Commands
(defun custom-prompt-variable (prompt-var prompt-val)
"Prompt for a variable and a value and return them as a list.
PROMPT-VAR is the prompt for the variable, and PROMPT-VAL is the
prompt for the value. The %s escape in PROMPT-VAL is replaced with
the name of the variable.
If the variable has a `variable-interactive' property, that is used as if
it were the arg to `interactive' (which see) to interactively read the value.
If the variable has a `custom-type' property, it must be a widget and the
`:prompt-value' property of that widget will be used for reading the value."
(let* ((var (read-variable prompt-var))
(minibuffer-help-form '(describe-variable var)))
(list var
(let ((prop (get var 'variable-interactive))
(type (get var 'custom-type))
(prompt (format prompt-val var)))
(unless (listp type)
(setq type (list type)))
(cond (prop
;; Use VAR's `variable-interactive' property
;; as an interactive spec for prompting.
(call-interactively (list 'lambda '(arg)
(list 'interactive prop)
'arg)))
(type
(widget-prompt-value type
prompt
(if (boundp var)
(symbol-value var))
(not (boundp var))))
(t
(eval-minibuffer prompt)))))))
;;;###autoload
(defun custom-set-value (var val)
"Set VARIABLE to VALUE. VALUE is a Lisp object.
If VARIABLE has a `variable-interactive' property, that is used as if
it were the arg to `interactive' (which see) to interactively read the value.
If VARIABLE has a `custom-type' property, it must be a widget and the
`:prompt-value' property of that widget will be used for reading the value."
(interactive (custom-prompt-variable "Set variable: "
"Set %s to value: "))
(set var val))
;;;###autoload
(defun custom-set-variable (var val)
"Set the default for VARIABLE to VALUE. VALUE is a Lisp object.
If VARIABLE has a `custom-set' property, that is used for setting
VARIABLE, otherwise `set-default' is used.
The `customized-value' property of the VARIABLE will be set to a list
with a quoted VALUE as its sole list member.
If VARIABLE has a `variable-interactive' property, that is used as if
it were the arg to `interactive' (which see) to interactively read the value.
If VARIABLE has a `custom-type' property, it must be a widget and the
`:prompt-value' property of that widget will be used for reading the value. "
(interactive (custom-prompt-variable "Set variable: "
"Set customized value for %s to: "))
(funcall (or (get var 'custom-set) 'set-default) var val)
(put var 'customized-value (list (custom-quote val))))
;;;###autoload
(defun customize (symbol)
"Customize SYMBOL, which must be a customization group."
@ -567,6 +662,21 @@ when the action is chosen.")
(setq symbol (intern symbol))))
(custom-buffer-create (list (list symbol 'custom-group))))
;;;###autoload
(defun customize-other-window (symbol)
"Customize SYMBOL, which must be a customization group."
(interactive (list (completing-read "Customize group: (default emacs) "
obarray
(lambda (symbol)
(get symbol 'custom-group))
t)))
(when (stringp symbol)
(if (string-equal "" symbol)
(setq symbol 'emacs)
(setq symbol (intern symbol))))
(custom-buffer-create-other-window (list (list symbol 'custom-group))))
;;;###autoload
(defun customize-variable (symbol)
"Customize SYMBOL, which must be a variable."
@ -617,7 +727,24 @@ If SYMBOL is nil, customize all faces."
;;;###autoload
(defun customize-customized ()
"Customize all already customized user options."
"Customize all user options set since the last save in this session."
(interactive)
(let ((found nil))
(mapatoms (lambda (symbol)
(and (get symbol 'customized-face)
(custom-facep symbol)
(setq found (cons (list symbol 'custom-face) found)))
(and (get symbol 'customized-value)
(boundp symbol)
(setq found
(cons (list symbol 'custom-variable) found)))))
(if found
(custom-buffer-create found)
(error "No customized user options"))))
;;;###autoload
(defun customize-saved ()
"Customize all already saved user options."
(interactive)
(let ((found nil))
(mapatoms (lambda (symbol)
@ -630,7 +757,7 @@ If SYMBOL is nil, customize all faces."
(cons (list symbol 'custom-variable) found)))))
(if found
(custom-buffer-create found)
(error "No customized user options"))))
(error "No saved user options"))))
;;;###autoload
(defun customize-apropos (regexp &optional all)
@ -657,6 +784,8 @@ user-settable."
(custom-buffer-create found)
(error "No matches"))))
;;; Buffer.
;;;###autoload
(defun custom-buffer-create (options)
"Create a buffer containing OPTIONS.
@ -667,6 +796,7 @@ that option."
(switch-to-buffer (get-buffer-create "*Customization*"))
(custom-buffer-create-internal options))
;;;###autoload
(defun custom-buffer-create-other-window (options)
"Create a buffer containing OPTIONS.
OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
@ -758,6 +888,7 @@ Make the modifications default for future sessions."
(message "Creating customization setup...")
(widget-setup)
(goto-char (point-min))
(forward-line 3) ;Kludge: bob is writable in XEmacs.
(message "Creating customization buffer...done"))
;;; Modification of Basic Widgets.
@ -939,6 +1070,7 @@ The list should be sorted most significant first."
"Show and manipulate state for a customization option."
:format "%v"
:action 'widget-choice-item-action
:notify 'ignore
:value-get 'ignore
:value-create 'custom-magic-value-create
:value-delete 'widget-children-value-delete)
@ -998,15 +1130,7 @@ Change the state of this item."
(defun custom-level-action (widget &optional event)
"Toggle visibility for parent to WIDGET."
(let* ((parent (widget-get widget :parent))
(state (widget-get parent :custom-state)))
(cond ((memq state '(invalid modified))
(error "There are unset changes"))
((eq state 'hidden)
(widget-put parent :custom-state 'unknown))
(t
(widget-put parent :custom-state 'hidden)))
(custom-redraw parent)))
(custom-toggle-hide (widget-get widget :parent)))
;;; The `custom' Widget.
@ -1094,14 +1218,20 @@ Change the state of this item."
(defun custom-redraw (widget)
"Redraw WIDGET with current settings."
(let ((pos (point))
(let ((line (count-lines (point-min) (point)))
(column (current-column))
(pos (point))
(from (marker-position (widget-get widget :from)))
(to (marker-position (widget-get widget :to))))
(save-excursion
(widget-value-set widget (widget-value widget))
(custom-redraw-magic widget))
(when (and (>= pos from) (<= pos to))
(goto-char pos))))
(condition-case nil
(progn
(goto-line line)
(move-to-column column))
(error nil)))))
(defun custom-redraw-magic (widget)
"Redraw WIDGET state with current settings."
@ -1150,6 +1280,17 @@ Change the state of this item."
"Load all dependencies for WIDGET."
(custom-load-symbol (widget-value widget)))
(defun custom-toggle-hide (widget)
"Toggle visibility of WIDGET."
(let ((state (widget-get widget :custom-state)))
(cond ((memq state '(invalid modified))
(error "There are unset changes"))
((eq state 'hidden)
(widget-put widget :custom-state 'unknown))
(t
(widget-put widget :custom-state 'hidden)))
(custom-redraw widget)))
;;; The `custom-variable' Widget.
(defface custom-variable-sample-face '((t (:underline t)))
@ -1203,8 +1344,10 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
(tag (widget-get widget :tag))
(type (custom-variable-type symbol))
(conv (widget-convert type))
(get (or (get symbol 'custom-get) 'default-value))
(set (or (get symbol 'custom-set) 'set-default))
(value (if (default-boundp symbol)
(default-value symbol)
(funcall get symbol)
(widget-get conv :value))))
;; If the widget is new, the child determine whether it is hidden.
(cond (state)
@ -1234,7 +1377,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
((get symbol 'factory-value)
(car (get symbol 'factory-value)))
((default-boundp symbol)
(custom-quote (default-value symbol)))
(custom-quote (funcall get symbol)))
(t
(custom-quote (widget-get conv :value))))))
(push (widget-create-child-and-convert
@ -1266,8 +1409,9 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
(defun custom-variable-state-set (widget)
"Set the state of WIDGET."
(let* ((symbol (widget-value widget))
(get (or (get symbol 'custom-get) 'default-value))
(value (if (default-boundp symbol)
(default-value symbol)
(funcall get symbol)
(widget-get widget :value)))
tmp
(state (cond ((setq tmp (get symbol 'customized-value))
@ -1292,29 +1436,52 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
(widget-put widget :custom-state state)))
(defvar custom-variable-menu
'(("Edit" . custom-variable-edit)
("Edit Lisp" . custom-variable-edit-lisp)
("Set" . custom-variable-set)
("Save" . custom-variable-save)
("Reset to Current" . custom-redraw)
("Reset to Saved" . custom-variable-reset-saved)
("Reset to Factory Settings" . custom-variable-reset-factory))
'(("Hide" custom-toggle-hide
(lambda (widget)
(not (memq (widget-get widget :custom-state) '(modified invalid)))))
("Edit" custom-variable-edit
(lambda (widget)
(not (eq (widget-get widget :custom-form) 'edit))))
("Edit Lisp" custom-variable-edit-lisp
(lambda (widget)
(not (eq (widget-get widget :custom-form) 'lisp))))
("Set" custom-variable-set
(lambda (widget)
(eq (widget-get widget :custom-state) 'modified)))
("Save" custom-variable-save
(lambda (widget)
(memq (widget-get widget :custom-state) '(modified set changed rogue))))
("Reset to Current" custom-redraw
(lambda (widget)
(and (default-boundp (widget-value widget))
(memq (widget-get widget :custom-state) '(modified)))))
("Reset to Saved" custom-variable-reset-saved
(lambda (widget)
(and (get (widget-value widget) 'saved-value)
(memq (widget-get widget :custom-state)
'(modified set changed rogue)))))
("Reset to Factory Settings" custom-variable-reset-factory
(lambda (widget)
(and (get (widget-value widget) 'factory-value)
(memq (widget-get widget :custom-state)
'(modified set changed saved rogue))))))
"Alist of actions for the `custom-variable' widget.
The key is a string containing the name of the action, the value is a
lisp function taking the widget as an element which will be called
when the action is chosen.")
Each entry has the form (NAME ACTION FILTER) where NAME is the name of
the menu entry, ACTION is the function to call on the widget when the
menu is selected, and FILTER is a predicate which takes a `custom-variable'
widget as an argument, and returns non-nil if ACTION is valid on that
widget. If FILTER is nil, ACTION is always valid.")
(defun custom-variable-action (widget &optional event)
"Show the menu for `custom-variable' WIDGET.
Optional EVENT is the location for the menu."
(if (eq (widget-get widget :custom-state) 'hidden)
(progn
(widget-put widget :custom-state 'unknown)
(custom-redraw widget))
(custom-toggle-hide widget)
(let* ((completion-ignore-case t)
(answer (widget-choose (custom-unlispify-tag-name
(widget-get widget :value))
custom-variable-menu
(custom-menu-filter custom-variable-menu
widget)
event)))
(if answer
(funcall answer widget)))))
@ -1333,32 +1500,34 @@ Optional EVENT is the location for the menu."
(defun custom-variable-set (widget)
"Set the current value for the variable being edited by WIDGET."
(let ((form (widget-get widget :custom-form))
(state (widget-get widget :custom-state))
(child (car (widget-get widget :children)))
(symbol (widget-value widget))
val)
(let* ((form (widget-get widget :custom-form))
(state (widget-get widget :custom-state))
(child (car (widget-get widget :children)))
(symbol (widget-value widget))
(set (or (get symbol 'custom-set) 'set-default))
val)
(cond ((eq state 'hidden)
(error "Cannot set hidden variable."))
((setq val (widget-apply child :validate))
(goto-char (widget-get val :from))
(error "%s" (widget-get val :error)))
((eq form 'lisp)
(set-default symbol (eval (setq val (widget-value child))))
(funcall set symbol (eval (setq val (widget-value child))))
(put symbol 'customized-value (list val)))
(t
(set-default symbol (setq val (widget-value child)))
(funcall set symbol (setq val (widget-value child)))
(put symbol 'customized-value (list (custom-quote val)))))
(custom-variable-state-set widget)
(custom-redraw-magic widget)))
(defun custom-variable-save (widget)
"Set the default value for the variable being edited by WIDGET."
(let ((form (widget-get widget :custom-form))
(state (widget-get widget :custom-state))
(child (car (widget-get widget :children)))
(symbol (widget-value widget))
val)
(let* ((form (widget-get widget :custom-form))
(state (widget-get widget :custom-state))
(child (car (widget-get widget :children)))
(symbol (widget-value widget))
(set (or (get symbol 'custom-set) 'set-default))
val)
(cond ((eq state 'hidden)
(error "Cannot set hidden variable."))
((setq val (widget-apply child :validate))
@ -1366,12 +1535,12 @@ Optional EVENT is the location for the menu."
(error "%s" (widget-get val :error)))
((eq form 'lisp)
(put symbol 'saved-value (list (widget-value child)))
(set-default symbol (eval (widget-value child))))
(funcall set symbol (eval (widget-value child))))
(t
(put symbol
'saved-value (list (custom-quote (widget-value
child))))
(set-default symbol (widget-value child))))
(funcall set symbol (widget-value child))))
(put symbol 'customized-value nil)
(custom-save-all)
(custom-variable-state-set widget)
@ -1379,10 +1548,11 @@ Optional EVENT is the location for the menu."
(defun custom-variable-reset-saved (widget)
"Restore the saved value for the variable being edited by WIDGET."
(let ((symbol (widget-value widget)))
(let* ((symbol (widget-value widget))
(set (or (get symbol 'custom-set) 'set-default)))
(if (get symbol 'saved-value)
(condition-case nil
(set-default symbol (eval (car (get symbol 'saved-value))))
(funcall set symbol (eval (car (get symbol 'saved-value))))
(error nil))
(error "No saved value for %s" symbol))
(put symbol 'customized-value nil)
@ -1391,9 +1561,10 @@ Optional EVENT is the location for the menu."
(defun custom-variable-reset-factory (widget)
"Restore the factory setting for the variable being edited by WIDGET."
(let ((symbol (widget-value widget)))
(let* ((symbol (widget-value widget))
(set (or (get symbol 'custom-set) 'set-default)))
(if (get symbol 'factory-value)
(set-default symbol (eval (car (get symbol 'factory-value))))
(funcall set symbol (eval (car (get symbol 'factory-value))))
(error "No factory default for %S" symbol))
(put symbol 'customized-value nil)
(when (get symbol 'saved-value)
@ -1550,9 +1721,7 @@ Match frames with dark backgrounds.")
(defun custom-display-unselected-match (widget value)
"Non-nil if VALUE is an unselected display specification."
(and (listp value)
(eq (length value) 2)
(not (custom-display-match-frame value (selected-frame)))))
(not (custom-display-match-frame value (selected-frame))))
(define-widget 'custom-face-selected 'group
"Edit the attributes of the selected display in a face specification."
@ -1600,17 +1769,32 @@ Match frames with dark backgrounds.")
(message "Creating face editor...done")))
(defvar custom-face-menu
'(("Edit Selected" . custom-face-edit-selected)
("Edit All" . custom-face-edit-all)
("Edit Lisp" . custom-face-edit-lisp)
("Set" . custom-face-set)
("Save" . custom-face-save)
("Reset to Saved" . custom-face-reset-saved)
("Reset to Factory Setting" . custom-face-reset-factory))
'(("Hide" custom-toggle-hide
(lambda (widget)
(not (memq (widget-get widget :custom-state) '(modified invalid)))))
("Edit Selected" custom-face-edit-selected
(lambda (widget)
(not (eq (widget-get widget :custom-form) 'selected))))
("Edit All" custom-face-edit-all
(lambda (widget)
(not (eq (widget-get widget :custom-form) 'all))))
("Edit Lisp" custom-face-edit-lisp
(lambda (widget)
(not (eq (widget-get widget :custom-form) 'lisp))))
("Set" custom-face-set)
("Save" custom-face-save)
("Reset to Saved" custom-face-reset-saved
(lambda (widget)
(get (widget-value widget) 'saved-face)))
("Reset to Factory Setting" custom-face-reset-factory
(lambda (widget)
(get (widget-value widget) 'factory-face))))
"Alist of actions for the `custom-face' widget.
The key is a string containing the name of the action, the value is a
lisp function taking the widget as an element which will be called
when the action is chosen.")
Each entry has the form (NAME ACTION FILTER) where NAME is the name of
the menu entry, ACTION is the function to call on the widget when the
menu is selected, and FILTER is a predicate which takes a `custom-face'
widget as an argument, and returns non-nil if ACTION is valid on that
widget. If FILTER is nil, ACTION is always valid.")
(defun custom-face-edit-selected (widget)
"Edit selected attributes of the value of WIDGET."
@ -1646,13 +1830,13 @@ when the action is chosen.")
"Show the menu for `custom-face' WIDGET.
Optional EVENT is the location for the menu."
(if (eq (widget-get widget :custom-state) 'hidden)
(progn
(widget-put widget :custom-state 'unknown)
(custom-redraw widget))
(custom-toggle-hide widget)
(let* ((completion-ignore-case t)
(symbol (widget-get widget :value))
(answer (widget-choose (custom-unlispify-tag-name symbol)
custom-face-menu event)))
(custom-menu-filter custom-face-menu
widget)
event)))
(if answer
(funcall answer widget)))))
@ -1865,27 +2049,44 @@ and so forth. The remaining group tags are shown with
(message "Creating group... done")))))
(defvar custom-group-menu
'(("Set" . custom-group-set)
("Save" . custom-group-save)
("Reset to Current" . custom-group-reset-current)
("Reset to Saved" . custom-group-reset-saved)
("Reset to Factory" . custom-group-reset-factory))
'(("Hide" custom-toggle-hide
(lambda (widget)
(not (memq (widget-get widget :custom-state) '(modified invalid)))))
("Set" custom-group-set
(lambda (widget)
(eq (widget-get widget :custom-state) 'modified)))
("Save" custom-group-save
(lambda (widget)
(memq (widget-get widget :custom-state) '(modified set))))
("Reset to Current" custom-group-reset-current
(lambda (widget)
(and (default-boundp (widget-value widget))
(memq (widget-get widget :custom-state) '(modified)))))
("Reset to Saved" custom-group-reset-saved
(lambda (widget)
(and (get (widget-value widget) 'saved-value)
(memq (widget-get widget :custom-state) '(modified set)))))
("Reset to Factory" custom-group-reset-factory
(lambda (widget)
(and (get (widget-value widget) 'factory-value)
(memq (widget-get widget :custom-state) '(modified set saved))))))
"Alist of actions for the `custom-group' widget.
The key is a string containing the name of the action, the value is a
lisp function taking the widget as an element which will be called
when the action is chosen.")
Each entry has the form (NAME ACTION FILTER) where NAME is the name of
the menu entry, ACTION is the function to call on the widget when the
menu is selected, and FILTER is a predicate which takes a `custom-group'
widget as an argument, and returns non-nil if ACTION is valid on that
widget. If FILTER is nil, ACTION is always valid.")
(defun custom-group-action (widget &optional event)
"Show the menu for `custom-group' WIDGET.
Optional EVENT is the location for the menu."
(if (eq (widget-get widget :custom-state) 'hidden)
(progn
(widget-put widget :custom-state 'unknown)
(custom-redraw widget))
(custom-toggle-hide widget)
(let* ((completion-ignore-case t)
(answer (widget-choose (custom-unlispify-tag-name
(widget-get widget :value))
custom-group-menu
(custom-menu-filter custom-group-menu
widget)
event)))
(if answer
(funcall answer widget)))))
@ -1986,17 +2187,26 @@ Leave point at the location of the call, or after the last expression."
(princ "\n"))
(princ "(custom-set-variables")
(mapatoms (lambda (symbol)
(let ((value (get symbol 'saved-value)))
(let ((value (get symbol 'saved-value))
(requests (get symbol 'custom-requests))
(now (not (or (get symbol 'factory-value)
(and (not (boundp symbol))
(not (get symbol 'force-value)))))))
(when value
(princ "\n '(")
(princ symbol)
(princ " ")
(prin1 (car value))
(if (or (get symbol 'factory-value)
(and (not (boundp symbol))
(not (get symbol 'force-value))))
(princ ")")
(princ " t)"))))))
(cond (requests
(if now
(princ " t ")
(princ " nil "))
(prin1 requests)
(princ ")"))
(now
(princ " t)"))
(t
(princ ")")))))))
(princ ")")
(unless (looking-at "\n")
(princ "\n")))))
@ -2037,6 +2247,22 @@ Leave point at the location of the call, or after the last expression."
(unless (looking-at "\n")
(princ "\n")))))
;;;###autoload
(defun custom-save-customized ()
"Save all user options which have been set in this session."
(interactive)
(mapatoms (lambda (symbol)
(let ((face (get symbol 'customized-face))
(value (get symbol 'customized-value)))
(when face
(put symbol 'saved-face face)
(put symbol 'customized-face nil))
(when value
(put symbol 'saved-value value)
(put symbol 'customized-value nil)))))
;; We really should update all custom buffers here.
(custom-save-all))
;;;###autoload
(defun custom-save-all ()
"Save all customizations in `custom-file'."
@ -2178,7 +2404,7 @@ The format is suitable for use with `easy-menu-define'."
(easy-menu-define custom-mode-customize-menu
custom-mode-map
"Menu used in customization buffers."
"Menu used to customize customization buffers."
(customize-menu-create 'customize))
(easy-menu-define custom-mode-menu

View file

@ -4,7 +4,7 @@
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, faces
;; Version: 1.84
;; Version: 1.90
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;; This file is part of GNU Emacs.
@ -38,7 +38,9 @@
(require 'widget)
(define-widget-keywords :prefix :tag :load :link :options :type :group)
(define-widget-keywords :initialize :set :get :require :prefix :tag
:load :link :options :type :group)
(defvar custom-define-hook nil
;; Customize information for this option is in `cus-edit.el'.
@ -46,14 +48,62 @@
;;; The `defcustom' Macro.
(defun custom-declare-variable (symbol value doc &rest args)
"Like `defcustom', but SYMBOL and VALUE are evaluated as normal arguments."
;; Bind this variable unless it already is bound.
(defun custom-initialize-default (symbol value)
"Initialize SYMBOL with VALUE.
This will do nothing if symbol already has a default binding.
Otherwise, if symbol has a `saved-value' property, it will evaluate
the car of that and used as the default binding for symbol.
Otherwise, VALUE will be evaluated and used as the default binding for
symbol."
(unless (default-boundp symbol)
;; Use the saved value if it exists, otherwise the factory setting.
(set-default symbol (if (get symbol 'saved-value)
(eval (car (get symbol 'saved-value)))
(eval value))))
(eval value)))))
(defun custom-initialize-set (symbol value)
"Initialize SYMBOL with VALUE.
Like `custom-initialize-default', but use the function specified by
`:set' to initialize SYMBOL."
(unless (default-boundp symbol)
(funcall (or (get symbol 'custom-set) 'set-default)
symbol
(if (get symbol 'saved-value)
(eval (car (get symbol 'saved-value)))
(eval value)))))
(defun custom-initialize-reset (symbol value)
"Initialize SYMBOL with VALUE.
Like `custom-initialize-set', but use the function specified by
`:get' to reinitialize SYMBOL if it is already bound."
(funcall (or (get symbol 'custom-set) 'set-default)
symbol
(cond ((default-boundp symbol)
(funcall (or (get symbol 'custom-get) 'default-value)
symbol))
((get symbol 'saved-value)
(eval (car (get symbol 'saved-value))))
(t
(eval value)))))
(defun custom-initialize-changed (symbol value)
"Initialize SYMBOL with VALUE.
Like `custom-initialize-reset', but only use the `:set' function if the
not using the factory setting. Otherwise, use the `set-default'."
(cond ((default-boundp symbol)
(funcall (or (get symbol 'custom-set) 'set-default)
symbol
(funcall (or (get symbol 'custom-get) 'default-value)
symbol)))
((get symbol 'saved-value)
(funcall (or (get symbol 'custom-set) 'set-default)
symbol
(eval (car (get symbol 'saved-value)))))
(t
(set-default symbol (eval value)))))
(defun custom-declare-variable (symbol value doc &rest args)
"Like `defcustom', but SYMBOL and VALUE are evaluated as normal arguments."
;; Remember the factory setting.
(put symbol 'factory-value (list value))
;; Maybe this option was rogue in an earlier version. It no longer is.
@ -62,29 +112,42 @@
(put symbol 'force-value nil))
(when doc
(put symbol 'variable-documentation doc))
(while args
(let ((arg (car args)))
(setq args (cdr args))
(unless (symbolp arg)
(error "Junk in args %S" args))
(let ((keyword arg)
(value (car args)))
(unless args
(error "Keyword %s is missing an argument" keyword))
(let ((initialize 'custom-initialize-set)
(requests nil))
(while args
(let ((arg (car args)))
(setq args (cdr args))
(cond ((eq keyword :type)
(put symbol 'custom-type value))
((eq keyword :options)
(if (get symbol 'custom-options)
;; Slow safe code to avoid duplicates.
(mapcar (lambda (option)
(custom-add-option symbol option))
value)
;; Fast code for the common case.
(put symbol 'custom-options (copy-sequence value))))
(t
(custom-handle-keyword symbol keyword value
'custom-variable))))))
(unless (symbolp arg)
(error "Junk in args %S" args))
(let ((keyword arg)
(value (car args)))
(unless args
(error "Keyword %s is missing an argument" keyword))
(setq args (cdr args))
(cond ((eq keyword :initialize)
(setq initialize value))
((eq keyword :set)
(put symbol 'custom-set value))
((eq keyword :get)
(put symbol 'custom-get value))
((eq keyword :require)
(push value requests))
((eq keyword :type)
(put symbol 'custom-type value))
((eq keyword :options)
(if (get symbol 'custom-options)
;; Slow safe code to avoid duplicates.
(mapcar (lambda (option)
(custom-add-option symbol option))
value)
;; Fast code for the common case.
(put symbol 'custom-options (copy-sequence value))))
(t
(custom-handle-keyword symbol keyword value
'custom-variable))))))
(put symbol 'custom-requests requests)
;; Do the actual initialization.
(funcall initialize symbol value))
(run-hooks 'custom-define-hook)
symbol)
@ -100,10 +163,25 @@ The remaining arguments should have the form
The following KEYWORD's are defined:
:type VALUE should be a widget type.
:type VALUE should be a widget type for editing the symbols value.
The default is `sexp'.
:options VALUE should be a list of valid members of the widget type.
:group VALUE should be a customization group.
Add SYMBOL to that group.
:initialize VALUE should be a function used to initialize the
variable. It takes two arguments, the symbol and value
given in the `defcustom' call. The default is
`custom-initialize-default'
:set VALUE should be a function to set the value of the symbol.
It takes two arguments, the symbol to set and the value to
give it. The default is `set-default'.
:get VALUE should be a function to extract the value of symbol.
The function takes one argument, a symbol, and should return
the current value for that symbol. The default is
`default-value'.
:require VALUE should be a feature symbol. Each feature will be
required after initialization, of the the user have saved this
option.
Read the section about customization in the Emacs Lisp manual for more
information."
@ -163,6 +241,9 @@ information."
(defun custom-declare-group (symbol members doc &rest args)
"Like `defgroup', but SYMBOL is evaluated as a normal argument."
(while members
(apply 'custom-add-to-group symbol (car members))
(setq members (cdr members)))
(put symbol 'custom-group (nconc members (get symbol 'custom-group)))
(when doc
(put symbol 'group-documentation doc))
@ -285,17 +366,22 @@ the default value for the SYMBOL."
(while args
(let ((entry (car args)))
(if (listp entry)
(let ((symbol (nth 0 entry))
(value (nth 1 entry))
(now (nth 2 entry)))
(let* ((symbol (nth 0 entry))
(value (nth 1 entry))
(now (nth 2 entry))
(requests (nth 3 entry))
(set (or (get symbol 'custom-set) 'set-default)))
(put symbol 'saved-value (list value))
(cond (now
;; Rogue variable, set it now.
(put symbol 'force-value t)
(set-default symbol (eval value)))
(funcall set symbol (eval value)))
((default-boundp symbol)
;; Something already set this, overwrite it.
(set-default symbol (eval value))))
(funcall set symbol (eval value))))
(when requests
(put symbol 'custom-requests requests)
(mapcar 'require requests))
(setq args (cdr args)))
;; Old format, a plist of SYMBOL VALUE pairs.
(message "Warning: old format `custom-set-variables'")

View file

@ -4,7 +4,7 @@
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: extensions
;; Version: 1.84
;; Version: 1.90
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
@ -16,7 +16,7 @@
(require 'easymenu)
(require 'custom)
(require 'wid-edit)
(require 'cl)
(eval-when-compile (require 'cl))
(defgroup widget-browse nil
"Customization support for browsing widgets."
@ -245,6 +245,37 @@ VALUE is assumed to be a list of widgets."
(put :button 'widget-keyword-printer 'widget-browse-widget)
(put :args 'widget-keyword-printer 'widget-browse-sexps)
;;; Widget Minor Mode.
(defvar widget-minor-mode nil
"I non-nil, we are in Widget Minor Mode.")
(make-variable-buffer-local 'widget-minor-mode)
(defvar widget-minor-mode-map nil
"Keymap used in Widget Minor Mode.")
(unless widget-minor-mode-map
(setq widget-minor-mode-map (make-sparse-keymap))
(set-keymap-parent widget-minor-mode-map widget-keymap))
;;;###autoload
(defun widget-minor-mode (&optional arg)
"Togle minor mode for traversing widgets.
With arg, turn widget mode on if and only if arg is positive."
(interactive "P")
(cond ((null arg)
(setq widget-minor-mode (not widget-minor-mode)))
((<= 0 arg)
(setq widget-minor-mode nil))
(t
(setq widget-minor-mode t)))
(force-mode-line-update))
(add-to-list 'minor-mode-alist '(widget-minor-mode " Widget"))
(add-to-list 'minor-mode-map-alist
(cons 'widget-minor-mode widget-minor-mode-map))
;;; The End:
(provide 'wid-browse)

View file

@ -4,7 +4,7 @@
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: extensions
;; Version: 1.84
;; Version: 1.90
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;; This file is part of GNU Emacs.
@ -32,8 +32,7 @@
(require 'widget)
(eval-when-compile
(require 'cl))
(eval-when-compile (require 'cl))
;;; Compatibility.
@ -75,7 +74,7 @@ and `end-open' if it should sticky to the front."
;; We have the old custom-library, hack around it!
(defmacro defgroup (&rest args) nil)
(defmacro defcustom (var value doc &rest args)
`(defvar ,var ,value ,doc))
(` (defvar (, var) (, value) (, doc))))
(defmacro defface (&rest args) nil)
(define-widget-keywords :prefix :tag :load :link :options :type :group)
(when (fboundp 'copy-face)
@ -134,7 +133,7 @@ into the buffer visible in the event's window."
(defface widget-field-face '((((class grayscale color)
(background light))
(:background "light gray"))
(:background "gray85"))
(((class grayscale color)
(background dark))
(:background "dark gray"))
@ -184,7 +183,9 @@ Larger menus are read through the minibuffer."
"Choose an item from a list.
First argument TITLE is the name of the list.
Second argument ITEMS is an alist (NAME . VALUE).
Second argument ITEMS is an list whose members are either
(NAME . VALUE), to indicate selectable items, or just strings to
indicate unselectable items.
Optional third argument EVENT is an input event.
The user is asked to choose between each NAME from the items alist,
@ -205,7 +206,9 @@ minibuffer."
(mapcar
(function
(lambda (x)
(vector (car x) (list (car x)) t)))
(if (stringp x)
(vector x nil nil)
(vector (car x) (list (car x)) t))))
items)))))
(setq val (and val
(listp (event-object val))
@ -213,6 +216,7 @@ minibuffer."
(car (event-object val))))
(cdr (assoc val items))))
(t
(setq items (remove-if 'stringp items))
(let ((val (completing-read (concat title ": ") items nil t)))
(if (stringp val)
(let ((try (try-completion val items)))
@ -235,6 +239,22 @@ This is only meaningful for radio buttons or checkboxes in a list."
(throw 'child child)))
nil)))
;;; Helper functions.
;;
;; These are widget specific.
;;;###autoload
(defun widget-prompt-value (widget prompt &optional value unbound)
"Prompt for a value matching WIDGET, using PROMPT.
The current value is assumed to be VALUE, unless UNBOUND is non-nil."
(unless (listp widget)
(setq widget (list widget)))
(setq widget (widget-convert widget))
(let ((answer (widget-apply widget :prompt-value prompt value unbound)))
(unless (widget-apply widget :match answer)
(error "Value does not match %S type." (car widget)))
answer))
;;; Widget text specifications.
;;
;; These functions are for specifying text properties.
@ -388,7 +408,8 @@ This is only meaningful for radio buttons or checkboxes in a list."
(defmacro widget-specify-insert (&rest form)
;; Execute FORM without inheriting any text properties.
`(save-restriction
(`
(save-restriction
(let ((inhibit-read-only t)
result
after-change-functions)
@ -396,11 +417,11 @@ This is only meaningful for radio buttons or checkboxes in a list."
(narrow-to-region (- (point) 2) (point))
(widget-specify-none (point-min) (point-max))
(goto-char (1+ (point-min)))
(setq result (progn ,@form))
(setq result (progn (,@ form)))
(delete-region (point-min) (1+ (point-min)))
(delete-region (1- (point-max)) (point-max))
(goto-char (point-max))
result)))
result))))
(defface widget-inactive-face '((((class grayscale color)
(background dark))
@ -418,7 +439,8 @@ This is only meaningful for radio buttons or checkboxes in a list."
(unless (widget-get widget :inactive)
(let ((overlay (make-overlay from to nil t nil)))
(overlay-put overlay 'face 'widget-inactive-face)
(overlay-put overlay 'evaporate 't)
(overlay-put overlay 'evaporate t)
(overlay-put overlay 'priority 100)
(overlay-put overlay (if (string-match "XEmacs" emacs-version)
'read-only
'modification-hooks) '(widget-overlay-inactive))
@ -503,7 +525,7 @@ ARGS are passed as extra arguments to the function."
(if (widget-apply widget :active)
(widget-apply widget :action event)
(error "Attempt to perform action on inactive widget")))
;;; Glyphs.
(defcustom widget-glyph-directory (concat data-directory "custom/")
@ -800,8 +822,9 @@ ARG may be negative to move backward."
(t
(error "No buttons or fields found"))))))
(setq button (widget-at (point)))
(if (and button (widget-get button :tab-order)
(< (widget-get button :tab-order) 0))
(if (or (and button (widget-get button :tab-order)
(< (widget-get button :tab-order) 0))
(and button (not (widget-apply button :active))))
(setq arg (1+ arg))))))
(while (< arg 0)
(if (= (point-min) (point))
@ -838,8 +861,9 @@ ARG may be negative to move backward."
(button (goto-char button))
(field (goto-char field)))
(setq button (widget-at (point)))
(if (and button (widget-get button :tab-order)
(< (widget-get button :tab-order) 0))
(if (or (and button (widget-get button :tab-order)
(< (widget-get button :tab-order) 0))
(and button (not (widget-apply button :active))))
(setq arg (1- arg)))))
(widget-echo-help (point))
(run-hooks 'widget-move-hook))
@ -1016,7 +1040,8 @@ With optional ARG, move across that many fields."
:activate 'widget-specify-active
:deactivate 'widget-default-deactivate
:action 'widget-default-action
:notify 'widget-default-notify)
:notify 'widget-default-notify
:prompt-value 'widget-default-prompt-value)
(defun widget-default-create (widget)
"Create WIDGET at point in the current buffer."
@ -1087,7 +1112,8 @@ With optional ARG, move across that many fields."
(set-marker-insertion-type from t)
(set-marker-insertion-type to nil)
(widget-put widget :from from)
(widget-put widget :to to))))
(widget-put widget :to to)))
(widget-clear-undo))
(defun widget-default-format-handler (widget escape)
;; We recognize the %h escape by default.
@ -1149,7 +1175,8 @@ With optional ARG, move across that many fields."
;; Kludge: this doesn't need to be true for empty formats.
(delete-region from to))
(set-marker from nil)
(set-marker to nil)))
(set-marker to nil))
(widget-clear-undo))
(defun widget-default-value-set (widget value)
;; Recreate widget with new value.
@ -1194,6 +1221,14 @@ With optional ARG, move across that many fields."
;; Pass notification to parent.
(widget-default-action widget event))
(defun widget-default-prompt-value (widget prompt value unbound)
;; Read an arbitrary value. Stolen from `set-variable'.
;; (let ((initial (if unbound
;; nil
;; ;; It would be nice if we could do a `(cons val 1)' here.
;; (prin1-to-string (custom-quote value))))))
(eval-minibuffer prompt ))
;;; The `item' Widget.
(define-widget 'item 'default
@ -1297,7 +1332,17 @@ With optional ARG, move across that many fields."
(defun widget-info-link-action (widget &optional event)
"Open the info node specified by WIDGET."
(Info-goto-node (widget-value widget)))
(Info-goto-node (widget-value widget))
;; Steal button release event.
(if (and (fboundp 'button-press-event-p)
(fboundp 'next-command-event))
;; XEmacs
(and event
(button-press-event-p event)
(next-command-event))
;; Emacs
(when (memq 'down (event-modifiers event))
(read-event))))
;;; The `url-link' Widget.
@ -1507,11 +1552,8 @@ With optional ARG, move across that many fields."
(widget-value-set widget
(widget-apply current :value-to-external
(widget-get current :value)))
(widget-apply widget :notify widget event)
(widget-setup)))
;; Notify parent.
(widget-apply widget :notify widget event)
(widget-clear-undo))
(widget-apply widget :notify widget event)
(widget-setup))))
(defun widget-choice-validate (widget)
;; Valid if we have made a valid choice.
@ -1567,7 +1609,7 @@ With optional ARG, move across that many fields."
;; Toggle value.
(widget-value-set widget (not (widget-value widget)))
(widget-apply widget :notify widget event))
;;; The `checkbox' Widget.
(define-widget 'checkbox 'toggle
@ -2222,9 +2264,14 @@ With optional ARG, move across that many fields."
(define-widget 'const 'item
"An immutable sexp."
:prompt-value 'widget-const-prompt-value
:format "%t\n%d")
(define-widget 'function-item 'item
(defun widget-const-prompt-value (widget prompt value unbound)
;; Return the value of the const.
(widget-value widget))
(define-widget 'function-item 'const
"An immutable function name."
:format "%v\n%h"
:documentation-property (lambda (symbol)
@ -2232,28 +2279,67 @@ With optional ARG, move across that many fields."
(documentation symbol t)
(error nil))))
(define-widget 'variable-item 'item
(define-widget 'variable-item 'const
"An immutable variable name."
:format "%v\n%h"
:documentation-property 'variable-documentation)
(define-widget 'string 'editable-field
"A string"
:prompt-value 'widget-string-prompt-value
:tag "String"
:format "%[%t%]: %v")
(defvar widget-string-prompt-value-history nil
"History of input to `widget-string-prompt-value'.")
(defun widget-string-prompt-value (widget prompt value unbound)
;; Read a string.
(read-string prompt (if unbound nil (cons value 1))
'widget-string-prompt-value-history))
(define-widget 'regexp 'string
"A regular expression."
;; Should do validation.
:match 'widget-regexp-match
:validate 'widget-regexp-validate
:tag "Regexp")
(defun widget-regexp-match (widget value)
;; Match valid regexps.
(and (stringp value)
(condition-case data
(prog1 t
(string-match value ""))
(error nil))))
(defun widget-regexp-validate (widget)
"Check that the value of WIDGET is a valid regexp."
(let ((val (widget-value widget)))
(condition-case data
(prog1 nil
(string-match val ""))
(error (widget-put widget :error (error-message-string data))
widget))))
(define-widget 'file 'string
"A file widget.
It will read a file name from the minibuffer when activated."
:prompt-value 'widget-file-prompt-value
:format "%[%t%]: %v"
:tag "File"
:action 'widget-file-action)
(defun widget-file-prompt-value (widget prompt value unbound)
;; Read file from minibuffer.
(abbreviate-file-name
(if unbound
(read-file-name prompt)
(let ((prompt2 (concat prompt "(default `" value "') "))
(dir (file-name-directory value))
(file (file-name-nondirectory value))
(must-match (widget-get widget :must-match)))
(read-file-name prompt2 dir nil must-match file)))))
(defun widget-file-action (widget &optional event)
;; Read a file name from the minibuffer.
(let* ((value (widget-value widget))
@ -2303,7 +2389,8 @@ It will read a directory name from the minibuffer when activated."
:validate 'widget-sexp-validate
:match (lambda (widget value) t)
:value-to-internal 'widget-sexp-value-to-internal
:value-to-external (lambda (widget value) (read value)))
:value-to-external (lambda (widget value) (read value))
:prompt-value 'widget-sexp-prompt-value)
(defun widget-sexp-value-to-internal (widget value)
;; Use pp for printer representation.
@ -2337,6 +2424,24 @@ It will read a directory name from the minibuffer when activated."
(error (widget-put widget :error (error-message-string data))
widget)))))
(defvar widget-sexp-prompt-value-history nil
"History of input to `widget-sexp-prompt-value'.")
(defun widget-sexp-prompt-value (widget prompt value unbound)
;; Read an arbitrary sexp.
(let ((found (read-string prompt
(if unbound nil (cons (prin1-to-string value) 1))
'widget-sexp-prompt-value)))
(let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*"))))
(erase-buffer)
(insert found)
(goto-char (point-min))
(let ((answer (read buffer)))
(unless (eobp)
(error "Junk at end of expression: %s"
(buffer-substring (point) (point-max))))
answer))))
(define-widget 'integer 'sexp
"An integer."
:tag "Integer"
@ -2354,7 +2459,8 @@ It will read a directory name from the minibuffer when activated."
:value 0
:size 1
:format "%{%t%}: %v\n"
:type-error "This field should contain a character"
:valid-regexp "\\`.\\'"
:error "This field should contain a single character"
:value-to-internal (lambda (widget value)
(if (integerp value)
(char-to-string value)
@ -2432,8 +2538,20 @@ It will read a directory name from the minibuffer when activated."
(define-widget 'boolean 'toggle
"To be nil or non-nil, that is the question."
:tag "Boolean"
:prompt-value 'widget-boolean-prompt-value
:format "%{%t%}: %[%v%]\n")
(defun widget-boolean-prompt-value (widget prompt value unbound)
;; Toggle a boolean.
(cond (unbound
(y-or-n-p prompt))
(value
(message "Off")
nil)
(t
(message "On")
t)))
;;; The `color' Widget.
(define-widget 'color-item 'choice-item

View file

@ -4,7 +4,7 @@
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, extensions, faces, hypermedia
;; Version: 1.84
;; Version: 1.90
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;; This file is part of GNU Emacs.
@ -44,8 +44,8 @@
(set (car keywords) (car keywords)))
(setq keywords (cdr keywords)))))))
(define-widget-keywords :text-format :deactivate :active :inactive
:activate :sibling-args :delete-button-args
(define-widget-keywords :prompt-value :text-format :deactivate :active
:inactive :activate :sibling-args :delete-button-args
:insert-button-args :append-button-args :button-args
:tag-glyph :off-glyph :on-glyph :valid-regexp
:secret :sample-face :sample-face-get :case-fold :widget-doc
@ -66,9 +66,11 @@
(autoload 'widget-apply "wid-edit")
(autoload 'widget-create "wid-edit")
(autoload 'widget-insert "wid-edit")
(autoload 'widget-prompt-value "wid-edit")
(autoload 'widget-browse "wid-browse" nil t)
(autoload 'widget-browse-other-window "wid-browse" nil t)
(autoload 'widget-browse-at "wid-browse" nil t))
(autoload 'widget-browse-at "wid-browse" nil t)
(autoload 'widget-minor-mode "wid-browse" nil t))
(defun define-widget (name class doc &rest args)
"Define a new widget type named NAME from CLASS.
@ -85,7 +87,8 @@ create identical widgets:
The third argument DOC is a documentation string for the widget."
(put name 'widget-type (cons class args))
(put name 'widget-documentation doc))
(put name 'widget-documentation doc)
name)
;;; The End.