diff options
| author | Chong Yidong | 2012-11-24 11:46:29 +0800 |
|---|---|---|
| committer | Chong Yidong | 2012-11-24 11:46:29 +0800 |
| commit | 0917cc542f31c47ee6cc4ecff85dc2a698d98873 (patch) | |
| tree | 7aee8454c1f0ae1a44659870f0fc123056220391 | |
| parent | d125ca15f3751f36a1ec49e3d9f9de1735b43698 (diff) | |
| download | emacs-0917cc542f31c47ee6cc4ecff85dc2a698d98873.tar.gz emacs-0917cc542f31c47ee6cc4ecff85dc2a698d98873.zip | |
Fix dependency sorting in custom-theme-set-variables.
* lisp/custom.el (custom-theme-set-variables): Use a topological sort
for ordering by custom dependencies.
(custom--sort-vars, custom--sort-vars-1): New functions.
Fixes: debbugs:12952
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/custom.el | 79 |
2 files changed, 61 insertions, 24 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c127bfd42e6..75004181ee1 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2012-11-24 Chong Yidong <cyd@gnu.org> | ||
| 2 | |||
| 3 | * custom.el (custom-theme-set-variables): Use a topological sort | ||
| 4 | for ordering by custom dependencies (Bug#12952). | ||
| 5 | (custom--sort-vars, custom--sort-vars-1): New functions. | ||
| 6 | |||
| 1 | 2012-11-24 Stefan Monnier <monnier@iro.umontreal.ca> | 7 | 2012-11-24 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 8 | ||
| 3 | * emacs-lisp/bytecomp.el (byte-compile-file): Setup default value for | 9 | * emacs-lisp/bytecomp.el (byte-compile-file): Setup default value for |
diff --git a/lisp/custom.el b/lisp/custom.el index dc810e3c97d..8dfcf4bc14c 100644 --- a/lisp/custom.el +++ b/lisp/custom.el | |||
| @@ -948,7 +948,6 @@ prior to evaluating EXP). | |||
| 948 | 948 | ||
| 949 | COMMENT is a comment string about SYMBOL." | 949 | COMMENT is a comment string about SYMBOL." |
| 950 | (custom-check-theme theme) | 950 | (custom-check-theme theme) |
| 951 | |||
| 952 | ;; Process all the needed autoloads before anything else, so that the | 951 | ;; Process all the needed autoloads before anything else, so that the |
| 953 | ;; subsequent code has all the info it needs (e.g. which var corresponds | 952 | ;; subsequent code has all the info it needs (e.g. which var corresponds |
| 954 | ;; to a minor mode), regardless of the ordering of the variables. | 953 | ;; to a minor mode), regardless of the ordering of the variables. |
| @@ -958,29 +957,7 @@ COMMENT is a comment string about SYMBOL." | |||
| 958 | (memq (get symbol 'custom-autoload) '(nil noset))) | 957 | (memq (get symbol 'custom-autoload) '(nil noset))) |
| 959 | ;; This symbol needs to be autoloaded, even just for a `set'. | 958 | ;; This symbol needs to be autoloaded, even just for a `set'. |
| 960 | (custom-load-symbol symbol)))) | 959 | (custom-load-symbol symbol)))) |
| 961 | 960 | (setq args (custom--sort-vars args)) | |
| 962 | ;; Move minor modes and variables with explicit requires to the end. | ||
| 963 | (setq args | ||
| 964 | (sort args | ||
| 965 | (lambda (a1 a2) | ||
| 966 | (let* ((sym1 (car a1)) | ||
| 967 | (sym2 (car a2)) | ||
| 968 | (1-then-2 (memq sym1 (get sym2 'custom-dependencies))) | ||
| 969 | (2-then-1 (memq sym2 (get sym1 'custom-dependencies)))) | ||
| 970 | (cond ((and 1-then-2 2-then-1) | ||
| 971 | (error "Circular custom dependency between `%s' and `%s'" | ||
| 972 | sym1 sym2)) | ||
| 973 | (2-then-1 nil) | ||
| 974 | ;; 1 is a dependency of 2, so needs to be set first. | ||
| 975 | (1-then-2) | ||
| 976 | ;; Put minor modes and symbols with :require last. | ||
| 977 | ;; Putting minor modes last ensures that the mode | ||
| 978 | ;; function will see other customized values rather | ||
| 979 | ;; than default values. | ||
| 980 | (t (or (nth 3 a2) | ||
| 981 | (eq (get sym2 'custom-set) | ||
| 982 | 'custom-set-minor-mode)))))))) | ||
| 983 | |||
| 984 | (dolist (entry args) | 961 | (dolist (entry args) |
| 985 | (unless (listp entry) | 962 | (unless (listp entry) |
| 986 | (error "Incompatible Custom theme spec")) | 963 | (error "Incompatible Custom theme spec")) |
| @@ -1014,6 +991,60 @@ COMMENT is a comment string about SYMBOL." | |||
| 1014 | (and (or now (default-boundp symbol)) | 991 | (and (or now (default-boundp symbol)) |
| 1015 | (put symbol 'variable-comment comment))))))) | 992 | (put symbol 'variable-comment comment))))))) |
| 1016 | 993 | ||
| 994 | (defvar custom--sort-vars-table) | ||
| 995 | (defvar custom--sort-vars-result) | ||
| 996 | |||
| 997 | (defun custom--sort-vars (vars) | ||
| 998 | "Sort VARS based on custom dependencies. | ||
| 999 | VARS is a list whose elements have the same form as the ARGS | ||
| 1000 | arguments to `custom-theme-set-variables'. Return the sorted | ||
| 1001 | list, in which A occurs before B if B was defined with a | ||
| 1002 | `:set-after' keyword specifying A (see `defcustom')." | ||
| 1003 | (let ((custom--sort-vars-table (make-hash-table)) | ||
| 1004 | (dependants (make-hash-table)) | ||
| 1005 | (custom--sort-vars-result nil) | ||
| 1006 | last) | ||
| 1007 | ;; Construct a pair of tables keyed with the symbols of VARS. | ||
| 1008 | (dolist (var vars) | ||
| 1009 | (puthash (car var) (cons t var) custom--sort-vars-table) | ||
| 1010 | (puthash (car var) var dependants)) | ||
| 1011 | ;; From the second table, remove symbols that are depended-on. | ||
| 1012 | (dolist (var vars) | ||
| 1013 | (dolist (dep (get (car var) 'custom-dependencies)) | ||
| 1014 | (remhash dep dependants))) | ||
| 1015 | ;; If a variable is "stand-alone", put it last if it's a minor | ||
| 1016 | ;; mode or has a :require flag. This is not really necessary, but | ||
| 1017 | ;; putting minor modes last helps ensure that the mode function | ||
| 1018 | ;; sees other customized values rather than default values. | ||
| 1019 | (maphash (lambda (sym var) | ||
| 1020 | (when (and (null (get sym 'custom-dependencies)) | ||
| 1021 | (or (nth 3 var) | ||
| 1022 | (eq (get sym 'custom-set) | ||
| 1023 | 'custom-set-minor-mode))) | ||
| 1024 | (remhash sym dependants) | ||
| 1025 | (push var last))) | ||
| 1026 | dependants) | ||
| 1027 | ;; The remaining symbols depend on others but are not | ||
| 1028 | ;; depended-upon. Do a depth-first topological sort. | ||
| 1029 | (maphash #'custom--sort-vars-1 dependants) | ||
| 1030 | (nreverse (append last custom--sort-vars-result)))) | ||
| 1031 | |||
| 1032 | (defun custom--sort-vars-1 (sym &optional _ignored) | ||
| 1033 | (let ((elt (gethash sym custom--sort-vars-table))) | ||
| 1034 | ;; The car of the hash table value is nil if the variable has | ||
| 1035 | ;; already been processed, `dependant' if it is a dependant in the | ||
| 1036 | ;; current graph descent, and t otherwise. | ||
| 1037 | (when elt | ||
| 1038 | (cond | ||
| 1039 | ((eq (car elt) 'dependant) | ||
| 1040 | (error "Circular custom dependency on `%s'" sym)) | ||
| 1041 | ((car elt) | ||
| 1042 | (setcar elt 'dependant) | ||
| 1043 | (dolist (dep (get sym 'custom-dependencies)) | ||
| 1044 | (custom--sort-vars-1 dep)) | ||
| 1045 | (setcar elt nil) | ||
| 1046 | (push (cdr elt) custom--sort-vars-result)))))) | ||
| 1047 | |||
| 1017 | 1048 | ||
| 1018 | ;;; Defining themes. | 1049 | ;;; Defining themes. |
| 1019 | 1050 | ||