Mercurial > hg > xemacs-beta
view lisp/behavior.el @ 5353:38e24b8be4ea
Improve the lexical scoping in #'block, #'return-from.
lisp/ChangeLog addition:
2011-02-07 Aidan Kehoe <kehoea@parhasard.net>
* bytecomp.el:
* bytecomp.el (byte-compile-initial-macro-environment):
Shadow `block', `return-from' here, we implement them differently
when byte-compiling.
* bytecomp.el (byte-compile-active-blocks): New.
* bytecomp.el (byte-compile-block-1): New.
* bytecomp.el (byte-compile-return-from-1): New.
* bytecomp.el (return-from-1): New.
* bytecomp.el (block-1): New.
These are two aliases that exist to have their own associated
byte-compile functions, which functions implement `block' and
`return-from'.
* cl-extra.el (cl-macroexpand-all):
Fix a bug here when macros in the environment have been compiled.
* cl-macs.el (block):
* cl-macs.el (return):
* cl-macs.el (return-from):
Be more careful about lexical scope in these macros.
* cl.el:
* cl.el ('cl-block-wrapper): Removed.
* cl.el ('cl-block-throw): Removed.
These aren't needed in code generated by this XEmacs. They
shouldn't be needed in code generated by XEmacs 21.4, but if it
turns out the packages do need them, we can put them back.
2011-01-30 Mike Sperber <mike@xemacs.org>
* font-lock.el (font-lock-fontify-pending-extents): Don't fail if
`font-lock-mode' is unset, which can happen in the middle of
`revert-buffer'.
2011-01-23 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (delete):
* cl-macs.el (delq):
* cl-macs.el (remove):
* cl-macs.el (remq):
Don't use the compiler macro if these functions were given the
wrong number of arguments, as happens in lisp-tests.el.
* cl-seq.el (remove, remq): Removed.
I added these to subr.el, and forgot to remove them from here.
2011-01-22 Aidan Kehoe <kehoea@parhasard.net>
* bytecomp.el (byte-compile-setq, byte-compile-set):
Remove kludge allowing keywords' values to be set, all the code
that does that is gone.
* cl-compat.el (elt-satisfies-test-p):
* faces.el (set-face-parent):
* faces.el (face-doc-string):
* gtk-font-menu.el:
* gtk-font-menu.el (gtk-reset-device-font-menus):
* msw-font-menu.el:
* msw-font-menu.el (mswindows-reset-device-font-menus):
* package-get.el (package-get-installedp):
* select.el (select-convert-from-image-data):
* sound.el:
* sound.el (load-sound-file):
* x-font-menu.el (x-reset-device-font-menus-core):
Don't quote keywords, they're self-quoting, and the
win from backward-compatibility is sufficiently small now that the
style problem overrides it.
2011-01-22 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (block, return-from): Require that NAME be a symbol
in these macros, as always documented in the #'block docstring and
as required by Common Lisp.
* descr-text.el (unidata-initialize-unihan-database):
Correct the use of non-symbols in #'block and #'return-from in
this function.
2011-01-15 Aidan Kehoe <kehoea@parhasard.net>
* cl-extra.el (concatenate): Accept more complicated TYPEs in this
function, handing the sequences over to #'coerce if we don't
understand them here.
* cl-macs.el (inline): Don't proclaim #'concatenate as inline, its
compiler macro is more useful than doing that.
2011-01-11 Aidan Kehoe <kehoea@parhasard.net>
* subr.el (delete, delq, remove, remq): Move #'remove, #'remq
here, they don't belong in cl-seq.el; move #'delete, #'delq here
from fns.c, implement them in terms of #'delete*, allowing support
for sequences generally.
* update-elc.el (do-autoload-commands): Use #'delete*, not #'delq
here, now the latter's no longer dumped.
* cl-macs.el (delete, delq): Add compiler macros transforming
#'delete and #'delq to #'delete* calls.
2011-01-10 Aidan Kehoe <kehoea@parhasard.net>
* dialog.el (make-dialog-box): Correct a misplaced parenthesis
here, thank you Mats Lidell in 87zkr9gqrh.fsf@mail.contactor.se !
2011-01-02 Aidan Kehoe <kehoea@parhasard.net>
* dialog.el (make-dialog-box):
* list-mode.el (display-completion-list):
These functions used to use cl-parsing-keywords; change them to
use defun* instead, fixing the build. (Not sure what led to me
not including this change in d1b17a33450b!)
2011-01-02 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (define-star-compiler-macros):
Make sure the form has ITEM and LIST specified before attempting
to change to calls with explicit tests; necessary for some tests
in lisp-tests.el to compile correctly.
(stable-union, stable-intersection): Add compiler macros for these
functions, in the same way we do for most of the other functions
in cl-seq.el.
2011-01-01 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (dolist, dotimes, do-symbols, macrolet)
(symbol-macrolet):
Define these macros with defmacro* instead of parsing the argument
list by hand, for the sake of style and readability; use backquote
where appropriate, instead of calling #'list and and friends, for
the same reason.
2010-12-30 Aidan Kehoe <kehoea@parhasard.net>
* x-misc.el (device-x-display):
Provide this function, documented in the Lispref for years, but
not existing previously. Thank you Julian Bradfield, thank you
Jeff Mincy.
2010-12-30 Aidan Kehoe <kehoea@parhasard.net>
* cl-seq.el:
Move the heavy lifting from this file to C. Dump the
cl-parsing-keywords macro, but don't use defun* for the functions
we define that do take keywords, dynamic scope lossage makes that
not practical.
* subr.el (sort, fillarray): Move these aliases here.
(map-plist): #'nsublis is now built-in, but at this point #'eql
isn't necessarily available as a test; use #'eq.
* obsolete.el (cl-delete-duplicates): Make this available for old
compiler macros and old code.
(memql): Document that this is equivalent to #'member*, and worse.
* cl.el (adjoin, subst): Removed. These are in C.
2010-12-30 Aidan Kehoe <kehoea@parhasard.net>
* simple.el (assoc-ignore-case): Remove a duplicate definition of
this function (it's already in subr.el).
* iso8859-1.el (char-width):
On non-Mule, make this function equivalent to that produced by
(constantly 1), but preserve its docstring.
* subr.el (subst-char-in-string): Define this in terms of
#'substitute, #'nsubstitute.
(string-width): Define this using #'reduce and #'char-width.
(char-width): Give this a simpler definition, it makes far more
sense to check for mule at load time and redefine, as we do in
iso8859-1.el.
(store-substring): Implement this in terms of #'replace, now
#'replace is cheap.
2010-12-30 Aidan Kehoe <kehoea@parhasard.net>
* update-elc.el (lisp-files-needed-for-byte-compilation)
(lisp-files-needing-early-byte-compilation):
cl-macs belongs in the former, not the latter, it is as
fundamental as bytecomp.el.
2010-12-30 Aidan Kehoe <kehoea@parhasard.net>
* cl.el:
Provde the Common Lisp program-error, type-error as error
symbols. This doesn't nearly go far enough for anyone using the
Common Lisp errors.
2010-12-29 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (delete-duplicates):
If the form has an incorrect number of arguments, don't attempt a
compiler macroexpansion.
2010-12-29 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (cl-safe-expr-p):
Forms that start with the symbol lambda are also safe.
2010-12-29 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (= < > <= >=):
For these functions' compiler macros, the optimisation is safe
even if the first and the last arguments have side effects, since
they're only used the once.
2010-12-29 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (inline-side-effect-free-compiler-macros):
Unroll a loop here at macro-expansion time, so these compiler
macros are compiled. Use #'eql instead of #'eq in a couple of
places for better style.
2010-12-29 Aidan Kehoe <kehoea@parhasard.net>
* cl-extra.el (notany, notevery): Avoid some dynamic scope
stupidity with local variable names in these functions, when they
weren't prefixed with cl-; go into some more detail in the doc
strings.
2010-12-29 Aidan Kehoe <kehoea@parhasard.net>
* byte-optimize.el (side-effect-free-fns): #'remove, #'remq are
free of side-effects.
(side-effect-and-error-free-fns):
Drop dot, dot-marker from the list.
2010-11-17 Aidan Kehoe <kehoea@parhasard.net>
* cl-extra.el (coerce):
In the argument list, name the first argument OBJECT, not X; the
former name was always used in the doc string and is clearer.
Handle vector type specifications which include the length of the
target sequence, error if there's a mismatch.
* cl-macs.el (cl-make-type-test): Handle type specifications
starting with the symbol 'eql.
2010-11-14 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (eql): Don't remove the byte-compile property of this
symbol. That was necessary to override a bug in bytecomp.el where
#'eql was confused with #'eq, which bug we no longer have.
If neither expression is constant, don't attempt to handle the
expression in this compiler macro, leave it to byte-compile-eql,
which produces better code anyway.
* bytecomp.el (eq): #'eql is not the function associated with the
byte-eq byte code.
(byte-compile-eql): Add an explicit compile method for this
function, for cases where the cl-macs compiler macro hasn't
reduced it to #'eq or #'equal.
2010-10-25 Aidan Kehoe <kehoea@parhasard.net>
Add compiler macros and compilation sanity-checking for various
functions that take keywords.
* byte-optimize.el (side-effect-free-fns): #'symbol-value is
side-effect free and not error free.
* bytecomp.el (byte-compile-normal-call): Check keyword argument
lists for sanity; store information about the positions where
keyword arguments start using the new byte-compile-keyword-start
property.
* cl-macs.el (cl-const-expr-val): Take a new optional argument,
cl-not-constant, defaulting to nil, in this function; return it if
the expression is not constant.
(cl-non-fixnum-number-p): Make this into a separate function, we
want to pass it to #'every.
(eql): Use it.
(define-star-compiler-macros): Use the same code to generate the
member*, assoc* and rassoc* compiler macros; special-case some
code in #'add-to-list in subr.el.
(remove, remq): Add compiler macros for these two functions, in
preparation for #'remove being in C.
(define-foo-if-compiler-macros): Transform (remove-if-not ...) calls to
(remove ... :if-not) at compile time, which will be a real win
once the latter is in C.
(define-substitute-if-compiler-macros)
(define-subst-if-compiler-macros): Similarly for these functions.
(delete-duplicates): Change this compiler macro to use
#'plists-equal; if we don't have information about the type of
SEQUENCE at compile time, don't bother attempting to inline the
call, the function will be in C soon enough.
(equalp): Remove an old commented-out compiler macro for this, if
we want to see it it's in version control.
(subst-char-in-string): Transform this to a call to nsubstitute or
nsubstitute, if that is appropriate.
* cl.el (ldiff): Don't call setf here, this makes for a load-time
dependency problem in cl-macs.el
2010-06-14 Stephen J. Turnbull <stephen@xemacs.org>
* term/vt100.el:
Refer to XEmacs, not GNU Emacs, in permissions.
* term/bg-mouse.el:
* term/sup-mouse.el:
Put copyright notice in canonical "Copyright DATE AUTHOR" form.
Refer to XEmacs, not GNU Emacs, in permissions.
* site-load.el:
Add permission boilerplate.
* mule/canna-leim.el:
* alist.el:
Refer to XEmacs, not APEL/this program, in permissions.
* mule/canna-leim.el:
Remove my copyright, I've assigned it to the FSF.
2010-06-14 Stephen J. Turnbull <stephen@xemacs.org>
* gtk.el:
* gtk-widget-accessors.el:
* gtk-package.el:
* gtk-marshal.el:
* gtk-compose.el:
* gnome.el:
Add copyright notice based on internal evidence.
2010-06-14 Stephen J. Turnbull <stephen@xemacs.org>
* easymenu.el: Add reference to COPYING to permission notice.
* gutter.el:
* gutter-items.el:
* menubar-items.el:
Fix typo "Xmacs" in permissions notice.
2010-06-14 Stephen J. Turnbull <stephen@xemacs.org>
* auto-save.el:
* font.el:
* fontconfig.el:
* mule/kinsoku.el:
Add "part of XEmacs" text to permission notice.
2010-10-14 Aidan Kehoe <kehoea@parhasard.net>
* byte-optimize.el (side-effect-free-fns):
* cl-macs.el (remf, getf):
* cl-extra.el (tailp, cl-set-getf, cl-do-remf):
* cl.el (ldiff, endp):
Tighten up Common Lisp compatibility for #'ldiff, #'endp, #'tailp;
add circularity checking for the first two.
#'cl-set-getf and #'cl-do-remf were Lisp implementations of
#'plist-put and #'plist-remprop; change the names to aliases,
changes the macros that use them to using #'plist-put and
#'plist-remprop directly.
2010-10-12 Aidan Kehoe <kehoea@parhasard.net>
* abbrev.el (fundamental-mode-abbrev-table, global-abbrev-table):
Create both these abbrev tables using the usual
#'define-abbrev-table calls, rather than attempting to
special-case them.
* cl-extra.el: Force cl-macs to be loaded here, if cl-extra.el is
being loaded interpreted. Previously other, later files would
redundantly call (load "cl-macs") when interpreted, it's more
reasonable to do it here, once.
* cmdloop.el (read-quoted-char-radix): Use defcustom here, we
don't have any dump-order dependencies that would prevent that.
* custom.el (eval-when-compile): Don't load cl-macs when
interpreted or when byte-compiling, rely on cl-extra.el in the
former case and the appropriate entry in bytecomp-load-hook in the
latter. Get rid of custom-declare-variable-list, we have no
dump-time dependencies that would require it.
* faces.el (eval-when-compile): Don't load cl-macs when
interpreted or when byte-compiling.
* packages.el: Remove some inaccurate comments.
* post-gc.el (cleanup-simple-finalizers): Use #'delete-if-not
here, now the order of preloaded-file-list has been changed to
make it available.
* subr.el (custom-declare-variable-list): Remove. No need for it.
Also remove a stub define-abbrev-table from this file, given the
current order of preloaded-file-list there's no need for it.
2010-10-10 Aidan Kehoe <kehoea@parhasard.net>
* bytecomp.el (byte-compile-constp) Forms quoted with FUNCTION are
also constant.
(byte-compile-initial-macro-environment): In #'the, if FORM is
constant and does not match TYPE, warn at byte-compile time.
2010-10-10 Aidan Kehoe <kehoea@parhasard.net>
* backquote.el (bq-vector-contents, bq-list*): Remove; the former
is equivalent to (append VECTOR nil), the latter to (list* ...).
(bq-process-2): Use (append VECTOR nil) instead of using
#'bq-vector-contents to convert to a list.
(bq-process-1): Now we use list* instead of bq-list
* subr.el (list*): Moved from cl.el, since it is now required to
be available the first time a backquoted form is encountered.
* cl.el (list*): Move to subr.el.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* test-harness.el (Check-Message):
Add an omitted comma here, thank you the buildbot.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* hash-table.el (hash-table-key-list, hash-table-value-list)
(hash-table-key-value-alist, hash-table-key-value-plist):
Remove some useless #'nreverse calls in these files; our hash
tables have no order, it's not helpful to pretend they do.
* behavior.el (read-behavior):
Do the same in this file, in some code evidently copied from
hash-table.el.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* info.el (Info-insert-dir):
* format.el (format-deannotate-region):
* files.el (cd, save-buffers-kill-emacs):
Use #'some, #'every and related functions for applying boolean
operations to lists, instead of rolling our own ones that cons and
don't short-circuit.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* bytecomp.el (byte-compile-initial-macro-environment):
* cl-macs.el (the):
Rephrase the docstring, make its implementation when compiling
files a little nicer.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* descr-text.el (unidata-initialize-unicodedata-database)
(unidata-initialize-unihan-database, describe-char-unicode-data)
(describe-char-unicode-data):
Wrap calls to the database functions with (with-fboundp ...),
avoiding byte compile warnings on builds without support for the
database functions.
(describe-char): (reduce #'max ...), not (apply #'max ...), no
need to cons needlessly.
(describe-char): Remove a redundant lambda wrapping
#'extent-properties.
(describe-char-unicode-data): Call #'nsubst when replacing "" with
nil in the result of #'split-string, instead of consing inside
mapcar.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* x-faces.el (x-available-font-sizes):
* specifier.el (let-specifier):
* package-ui.el (pui-add-required-packages):
* msw-faces.el (mswindows-available-font-sizes):
* modeline.el (modeline-minor-mode-menu):
* minibuf.el (minibuf-directory-files):
Replace the O2N (delq nil (mapcar (lambda (W) (and X Y)) Z)) with
the ON (mapcan (lambda (W) (and X (list Y))) Z) in these files.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (= < > <= >=):
When these functions are handed more than two arguments, and those
arguments have no side effects, transform to a series of two
argument calls, avoiding funcall in the byte-compiled code.
* mule/mule-cmds.el (finish-set-language-environment):
Take advantage of this change in a function called 256 times at
startup.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* bytecomp.el (byte-compile-function-form, byte-compile-quote)
(byte-compile-quote-form):
Warn at compile time, and error at runtime, if a (quote ...) or a
(function ...) form attempts to quote more than one object.
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* byte-optimize.el (byte-optimize-apply): Transform (apply 'nconc
(mapcar ...)) to (mapcan ...); warn about use of the first idiom.
* update-elc.el (do-autoload-commands):
* packages.el (packages-find-package-library-path):
* frame.el (frame-list):
* extents.el (extent-descendants):
* etags.el (buffer-tag-table-files):
* dumped-lisp.el (preloaded-file-list):
* device.el (device-list):
* bytecomp-runtime.el (proclaim-inline, proclaim-notinline)
Use #'mapcan, not (apply #'nconc (mapcar ...) in all these files.
* bytecomp-runtime.el (eval-when-compile, eval-and-compile):
In passing, mention that these macros also evaluate the body when
interpreted.
tests/ChangeLog addition:
2011-02-07 Aidan Kehoe <kehoea@parhasard.net>
* automated/lisp-tests.el:
Test lexical scope for `block', `return-from'; add a
Known-Bug-Expect-Failure for a contorted example that fails when
byte-compiled.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Mon, 07 Feb 2011 12:01:24 +0000 |
parents | 2def0d83a5e3 |
children | 308d34e9f07d |
line wrap: on
line source
;;; behavior.el --- consistent interface onto packages ;; Copyright (C) 2000, 2001, 2002, 2003 Ben Wing. ;; Author: Ben Wing ;; Maintainer: XEmacs Development Team ;; Keywords: internal, dumped ;; This file is part of XEmacs. ;; XEmacs is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; XEmacs is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with XEmacs; see the file COPYING. If not, write to the ;; Free Software Foundation, 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Synched up with: Not in FSF. ;;; Authorship: ;; Created July 2000 by Ben Wing. ;;; Commentary: ;; This file is dumped with XEmacs. ;; This file is part of the "Behaviors" project and is a work in progress. ;; The purpose of the project is to provide (a) a consistent interface (at ;; the API level) onto the functionality provided by packages, and (b) an ;; easy-to-use user interface for this functionality, something that ;; *really works*. ;; ;; First, what characteristics do/should packages have? (NOTE: In this ;; discussion below, `package' and `behavior' are being used more or less ;; interchangeably. Eventually this will get resolved.) ;; 1) A file, or one or more file, containing the code of the package. In ;; addition, a "head" file in the case that the package needs to be ;; loaded in order to get its functionality (e.g. "load-to-enable" ;; packages -- an abomination that is tolerated only with severe ;; displeasure). ;; 2) A Lisp name -- a fairly short symbol (2-3 words max), uncapitalized, ;; without use of excessive abbreviation and with words set off by ;; dashes. This should be the same as the name of the topmost custom ;; group associated with the package (see next item), and preferably the ;; same as the common prefix used for variables defined by your package ;; and the name of the head file of the package. ;; 3) Associated custom group listing the settings associated with the package. ;; 4) Enable and disable methods for turning on or off the functionality of ;; the package, if it's amenable to such a model. Most packages are of two ;; types: ;; ;; (a) They add some functionality to XEmacs, which is incorporated ;; into and makes changes to the normal functionality of XEmacs. Once the ;; package is enabled, the user doesn't have to do anything specific for ;; the package to do its thing -- it happens automatically if the user is ;; using the area whose behavior has been changed. These include packages ;; such as `avoid' (which makes the mouse poointer move when the cursor ;; gets too close), EFS (which adds the ability to treat an FTP site as ;; part of the local file system), the packages that supply the ;; mode-specific handling for various files, etc ;; ;; (b) They provide functionality in the form of specific command to be ;; invoked. This can be as simple as the `hippie-expand' command (tries ;; lots of different expansion methods for the text before point, to ;; try and get a result) and as complicated as GNUS or VM. ;; ;; Some packages might provide both -- you can enable them and they ;; incorporate some functionality into the XEmacs base, but while ;; they're enabled they provide certain commands. #### We need some ;; thought here, and case-by-case analysis, to determine if this really ;; makes sense -- can the enable/disable be removed and whatever needs ;; to happen incorporated as part of the command? can the ;; enable/disable just added to the commands? ;; ;; 5) Packages of type (b) just above will have a list of commands that can be ;; run. They should be in standard menubar format -- i.e. just like a ;; submenu, but without the initial string indidicating the name of the ;; menu. ;; 6) Short doc string, for use in a menu item. *NOT* necessarily the same ;; as the documentation for the Custom group, which is often too long. ;; 7) Long documentation. ;; ;; Good package etiquette: ;; ;; ;; -- Never mess with the menu yourself, or try to "cheat" by putting yourself ;; high up in the hierarchy, e.g. at the top-level or directly off a ;; top-level group that expects to contain only groups of groups, not ;; end-level groups. ;; ;; -- Never use the `override-behavior' commands or the like for specifying ;; (in an overriding fashion) the exact appearance of the hierarchies. ;; ;; -- For type (a), with enable/disable methods: ;; ;; (a) Loading the file should NOT DO ANYTHING. Not enable, not add hooks, ;; nothing. ;; (b) Both enable and disable hooks must exist. The disable hook must ;; completely reset the environment to how it was before the package ;; was enabled. This includes restoring the prior bindings for ;; modified key bindings. #### We need some helper function to assist ;; with remembering the old key bindings and putting them back only ;; when new key bindings haven't been made -- but recognize when those ;; new key bondings were attached as a result of loading another ;; package, so that after any order of loading and unloading a series ;; of packages, the original bindings will eventually occur. (Something ;; like `advice' for key definitions.) Replacement of functions should ;; happen through `advice'. ;; ;; We recognize that many packages out there don't follow these precepts at ;; all. Many or most of them are install-only, often happening ;; automatically when the file is loaded. Converting these will be a step ;; at a time: First, redo the latter type so that the initialization code ;; is put into a function and not run automatically upon load. Next step, ;; try to provide some sort of disable. Third step, work on making sure ;; that disable removes *everything* and enable puts it all back. Fourth ;; step, work on properly advising keys and functions. ;; ;; Comparison/Integration with Custom: ;; Custom only handles variable settings, and has no concept of standard ;; enable/disable methods for a package, a standard way of specifying ;; package documentation, or a list of commands associated with a package. ;; Also, its groups do not always map very well onto packages and the ;; resulting hierarchy is too big, confusing, difficult-to-navigate, and ;; incoherent. More generally it does not address at all the basic problem ;; that a hierarchy created in a decentralized fashion -- and by a large ;; number of authors, some more competent than others -- will inevitably be ;; incoherent when put together. ;; ;; In general, ease-of-use was not the overarching goal of Custom. The ;; primary goal of Custom seems to have been to provide a consistent interface ;; and get all the packages to use it. Ease-of-use -- or even following ;; established user-interface standards -- has taken a far-distant second, and ;; appears in many respects to be an afterthought that never had any serious ;; effort investigated into it. ;; ;; The eventual intent of this project is to integrate with custom. The final ;; intent of integration is that this project subsumes Custom completely, ;; making Custom the unified, user-friendly means of controlling XEmacs that ;; has never properly existed. However, that will take a lot of work. For ;; the meantime, the plan is to develop the Behavior subsystem independent of ;; Custom, with ease-of-use as the primary goal, and get it to the point where ;; it encompasses most packages out there, has stabilized its interface, and ;; works well. At that point, we will consider integration with Custom. (Note ;; that the hard part of the Behavior work is not actually behaviorizing the ;; packages, but developing the interface itself.) ;; ;; As for integrating with Custom -- ideally that would mean simply extending ;; defgroup, but that is not really possible given that backward-compatibility ;; would not work -- existing versions of `defgroup' give an error when ;; presented with an unknown keyword. In practice, then, this might mean that ;; a separate `define-behavior' command (or `defpackage', or the like) will ;; still exist. ;;; Code: ;; Hash table mapping behavior names to property lists, with entries for ;; :group, :custom-group, :short-doc, :require, :enable, :disable, ;; and :commands. (defconst behavior-hash-table (make-hash-table)) ;; Hash table mapping groups to property lists (entries for :group, :children, ;; :short-doc). (defconst behavior-group-hash-table (make-hash-table)) ;; Hash table with override information for groups. ;; :short-doc). (defconst behavior-override-hash-table (make-hash-table)) (defvar within-behavior-enabling-disabling nil) (defgroup behaviors nil "Behaviors -- high-level functionality interface.") ;; List of enabled behaviors. (defcustom enabled-behavior-list nil "List of currently enabled behaviors. Normally, don't set it directly; use `enable-behavior' or `disable-behavior'." :initialize #'set-default :set #'(lambda (sym val) (if within-behavior-enabling-disabling (set sym val) (let* ((old-val enabled-behavior-list) (disable-list (set-difference old-val val)) (enable-list (set-difference val old-val))) (dolist (b disable-list) (disable-behavior b t)) (dolist (b enable-list) (enable-behavior b t)) (assert (equal (sort (copy-sequence enabled-behavior-list) 'string-lessp) (sort (copy-sequence val) 'string-lessp)))))) :type '(repeat (symbol :tag "Behavior")) :group 'behaviors) (defvar behavior-history nil "History of entered behaviors.") (defun behavior-group-p (group) "Non-nil if GROUP is the name of a valid behavior group." (not (null (gethash group behavior-group-hash-table)))) (defun check-behavior-group (group) "Verify that GROUP is a valid behavior group, or nil. Return GROUP if so." (or (behavior-group-p group) (error 'invalid-argument "Invalid behavior group" group)) group) (defun* define-behavior (name doc-string &key group custom-group (short-doc (capitalize-string-as-title (replace-in-string (symbol-name name) "-" " "))) require enable disable commands &allow-other-keys) ;; We allow other keys to allow for the possibility of extensions by ;; later versions of XEmacs. Packages should be able to support those ;; extensions without worrying about causing problems with older versions ;; of XEmacs. "Define a behavior named NAME. DOC-STRING must be specified, a description of what the behavior does when it's enabled and how to further control it (typically through custom variables). Accepted keywords are :group Symbol naming the behavior group this behavior is within. :custom-group Symbol naming the custom group containing the options that can be set in association with this behavior. If not specified, the custom group with the same name as the behavior will be used, if it exists. :short-doc A \"pretty\" version of the name, for use in menus. If omitted a prettified name will be generated. :require A single symbol or a list of such symbols, which need to be present at enable time, or will be loaded using `require'. :enable A function of no variables, which turns the behavior on. :disable A function of no variables, which turns the behavior off. :commands A list of interactive commands that can be invoked in conjunction with the behavior. These will appear in a submenu along with the rest of the items for the behavior. Behaviors are assumed to be global, and to take effect immediately; if the underlying package is per-buffer, it may have to scan all existing buffers and frob them. When a behavior is disabled, it should completely go away *everywhere*, as if it were never invoked at all. The :disable keyword can be missing, although this is considered bad practice. In such a case, attempting to disable the behavior will signal an error unless you use the `force' option. The :enable keyword can be missing. This is useful for behaviors that are really a series of related commands without anything semantically corresponding to \"turning on\" or \"turning off\" the behavior. A behavior with no :enable and no :command is possible. This might be used, for example, by a behavior that encapsulates a series of related Lisp functions. Such behaviors may be handled specially, e.g. not displayed in the menus or displayed in a separate location, since they have no user-invocable behavior." (let ((entry (list :group (check-behavior-group group) :custom-group custom-group :short-doc short-doc :require require :enable enable :disable disable :commands commands))) (puthash name entry behavior-hash-table)) ;; update the children list of the group we're in (maybe nil). (unless (member name (getf (gethash group behavior-group-hash-table) :children)) (push name (getf (gethash group behavior-group-hash-table) :children)))) (defun* override-behavior (name &key short-doc group include demote-others) "Override the default properties of a behavior group NAME. Normally, groups are created and assigned properties by individual packages. The resulting hierarchy may not make much sense globally. This function allows the hierarchy and appearance of a group to be specified globally, and will take precendence over the properties assigned by `define-behavior-group'. This allows a global organization to be imposed on groups, while still allowing for graceful handling of new or unknown groups. NAME can be a symbol specifying a group name, or a list of \(PARENT [...] NAME), where a path from a particular parent is explicitly given. (This latter form allows the same name to be assigned to more than one group.) Accepted keywords are :short-doc A \"pretty\" version of the name, for use in menus. :group Parent group, if any. Should not be given if the parents are explicitly specified in NAME. :include A list of behaviors that are specifically included in this group, in addition to those that are included by the behaviors themselves. :demote-others If non-nil, exclude all behaviors not specified in the :include list and put them instead (i.e. \"demote\" them) to another group, usually a subgroup." (let ((entry (list :group (check-behavior-group group) :short-doc short-doc :include include :demote-others demote-others))) (puthash name entry behavior-override-hash-table))) (defun* define-behavior-group (name &key (short-doc (capitalize-string-as-title (replace-in-string (symbol-name name) "-" " "))) group) "Define a behavior group NAME. NAME can be a symbol specifying a group name, or a list of \(PARENT [...] NAME), where a path from a particular parent is explicitly given. (This latter form allows the same name to be assigned to more than one group.) Accepted keywords are :short-doc A \"pretty\" version of the name, for use in menus. If omitted a prettified name will be generated. :group Parent group, if any. Should not be given if the parents are explicitly specified in NAME." (let ((entry (list :group (check-behavior-group group) :short-doc short-doc))) (puthash name entry behavior-group-hash-table)) ;; update the children list of the parent (maybe nil). (push name (getf (gethash group behavior-group-hash-table) :children))) (defun read-behavior (prompt &optional must-match initial-contents history default-value) "Return a behavior symbol from the minibuffer, prompting with string PROMPT. If non-nil, optional second arg INITIAL-CONTENTS is a string to insert in the minibuffer before reading. Third arg HISTORY, if non-nil, specifies a history list. (It defaults to `behavior-history'.) Fourth arg DEFAULT-VALUE is the default value. If non-nil, it is used for history command, and as the value to return if the user enters the empty string." (let ((result (completing-read prompt (let (list) (maphash #'(lambda (key value) (push (cons (symbol-name key) value) list)) behavior-hash-table) list) nil must-match initial-contents (or history 'behavior-history) default-value))) (if (and result (stringp result)) (intern result) result))) (defun behavior-enabled-p (behavior) "Non-nil if BEHAVIOR (a symbol) if currently enabled." (memq behavior enabled-behavior-list)) (defun enable-behavior (behavior &optional force) "Enable the specified behavior." (interactive (list (read-behavior "Enable Behavior: " t) current-prefix-arg)) (let ((plist (gethash behavior behavior-hash-table))) (or plist (error 'invalid-argument "Not a behavior" behavior)) (or force (not (memq behavior enabled-behavior-list)) (error 'invalid-change "Behavior already enabled" behavior)) (let ((require (getf plist :require)) (enable (getf plist :enable))) (cond ((listp require) (mapc #'(lambda (sym) (require sym)) require)) ((symbolp require) (require require)) ((null require)) (t (error 'invalid-argument "Invalid :require spec" require))) (message "Enabling behavior %s..." behavior) (if enable (funcall enable)) (message "Enabling behavior %s...done" behavior) (let ((within-behavior-enabling-disabling t)) (customize-set-variable 'enabled-behavior-list (cons behavior enabled-behavior-list)))))) (defun disable-behavior (behavior &optional force) "Disable the specified behavior." (interactive (list (read-behavior "Disable Behavior: " t) current-prefix-arg)) (let ((plist (gethash behavior behavior-hash-table))) (or plist (error 'invalid-argument "Not a behavior" behavior)) (or force (memq behavior enabled-behavior-list) (error 'invalid-change "Behavior not enabled" behavior)) (let ((require (getf plist :require)) (disable (getf plist :disable))) (cond ((listp require) (mapc #'(lambda (sym) (require sym)) require)) ((symbolp require) (require require)) ((null require)) (t (error 'invalid-argument "Invalid :require spec" require))) (message "Disabling behavior %s..." behavior) (if disable (funcall disable)) (message "Disabling behavior %s...done" behavior) (let ((within-behavior-enabling-disabling t)) (customize-set-variable 'enabled-behavior-list (delq behavior enabled-behavior-list)))))) (defun compute-behavior-group-children (group hash) "Compute the actual children for GROUP and its subgroups. This takes into account the override information specified." (let* ((group-plist (gethash group behavior-group-hash-table)) (override (gethash group behavior-override-hash-table)) (children (getf group-plist :children))) ) ) (defun behavior-menu-filter-1 (menu group) (submenu-generate-accelerator-spec (let* ( ;;options ;;help (enable (menu-split-long-menu (menu-sort-menu (let ((group-plist (gethash group behavior-group-hash-table))) (loop for behavior in (getf group-plist :children) nconc (if (behavior-group-p behavior) (list (cons (getf (gethash behavior behavior-group-hash-table) :short-doc) (behavior-menu-filter-1 menu behavior))) (let* ((plist (gethash behavior behavior-hash-table)) (commands (getf plist :commands))) (nconc (if (getf plist :enable) `([,(format "%s (%s) [toggle]" (getf plist :short-doc) behavior) (if (memq ',behavior enabled-behavior-list) (disable-behavior ',behavior) (enable-behavior ',behavior)) :active ,(if (getf plist :disable) t (not (memq ',behavior enabled-behavior-list))) :style toggle :selected (memq ',behavior enabled-behavior-list)])) (cond ((null commands) nil) ((and (eq (length commands) 1) (vectorp (elt commands 0))) (let ((comm (copy-sequence (elt commands 0)))) (setf (elt comm 0) (format "%s (%s)" (elt comm 0) behavior)) (list comm))) (t (list (cons (format "%s (%s) Commands" (getf plist :short-doc) behavior) commands))))))))) )) ) ) enable) '(?p))) (defun behavior-menu-filter (menu) (append `(("%_Package Utilities" ("%_Set Download Site" ("%_Official Releases" :filter ,#'(lambda (&rest junk) (menu-split-long-menu (submenu-generate-accelerator-spec (package-ui-download-menu))))) ("%_Pre-Releases" :filter ,#'(lambda (&rest junk) (menu-split-long-menu (submenu-generate-accelerator-spec (package-ui-pre-release-download-menu))))) ("%_Site Releases" :filter ,#'(lambda (&rest junk) (menu-split-long-menu (submenu-generate-accelerator-spec (package-ui-site-release-download-menu)))))) "--:shadowEtchedIn" ["%_Update Package Index" package-get-update-base] ["%_List and Install" pui-list-packages] ["U%_pdate Installed Packages" package-get-update-all] ["%_Help" (Info-goto-node "(xemacs)Packages")]) "----") (behavior-menu-filter-1 menu nil))) ;; Initialize top-level group. (puthash nil '(:children nil :short-doc "Root") behavior-group-hash-table) (provide 'behavior) ;;; finder-inf.el ends here