emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Custom themes


From: Luc Teirlinck
Subject: Re: Custom themes
Date: Mon, 27 Jun 2005 20:21:10 -0500 (CDT)

I took a somewhat more detailed look at the Custom Themes code.  It
definitely is unfinished work that is _not_ currently in progress.
>From looking at past threads, I believe that Alex Schroeder just gave
up on it and decided that color-theme.el was the way to go.  The
problem with color-theme.el is that it bypasses Custom and creates
variables which Custom considers rogue.  I have the impression that
the new etheme.el proposed by Seong-Kook Shin does the same.

The patches below correct the five bugs I pointed out, as well as a
sixth misfeature, namely the fact that Custom was not able to find the
Custom Theme files in subdirectories of the user's home directory,
unless the user explicitly added them to load-path.

Custom themes without my patches are completely unusable, because
there is not only no documentation, but also not a single interactive
command to work with them.

After my patches, which in addition to the bug fixes make two
functions into interactive commands, Custom Themes are "kind of"
usable, but not to a degree that they would be ready to be documented
in the Emacs manual.  Too many problems remain.

I did provide all the docs in the buffers created by `M-x
custom-create-theme': now it explains how to do create a Theme file in
a way that, I believe, can be understood.  The resulting Theme file
explains how it is supposed to be used, in a way that, I hope, is
understandable to somebody who did not create the file himself.

You can interactively enable a theme and disable it again.  It works.
However, first example of a bug: if you then want to re-enable it
using `M-x require-theme', it has no effect, although you can
re-enable it by manually loading the Theme File.  (This type of
workaround works for most bugs).  I know how to fix this bug, but I do
not want to mess with the code _too_ much, because I am unsure about
its exact intentions.  Second bug.  If you load Theme1 setting VAR
from a standard value of 0 to 1, then load Theme2 setting it to 2 and
then unload Theme2, the new value is 0.  I believe that it should be
1.  To restore Theme1's values (to obtain the result I believe should
be obtained automatically by unloading Theme2), you have to again load
the Theme1 theme file manually.

There would be a lot less bugs if instead of using `require-theme' as
the main interactive Theme enabling command, one would instead use a
command that unconditionally loads the Theme file (the workaround to
most bugs is to do exactly that).  I did not implement that because
that _definitely_ does not _seem_ to be the intended use of the code
(I do not know _why_ the current code seems to insist on using the
buggish `require-theme').

Minibuffer completion for `custom-do-theme-reset' will not work well
unless a patch for minibuf.c that I will submit separately is applied.
This is a bug in minibuf.c, it has nothing to do with Custom themes.
I will discuss this separately.

I do not have the time to do any more substantial work on this, but I
believe that my patches, if installed, will at least help people to get
started.

Here are the patches.  I can install if desired.

===File ~/custom.el-diff====================================
*** custom.el   13 Apr 2005 13:49:27 -0500      1.83
--- custom.el   27 Jun 2005 17:53:50 -0500      
***************
*** 560,566 ****
              (t (condition-case nil (load load) (error nil))))))))
  
  (defvar custom-known-themes '(user standard)
!    "Themes that have been define with `deftheme'.
  The default value is the list (user standard).  The theme `standard'
  contains the Emacs standard settings from the original Lisp files.  The
  theme `user' contains all the the settings the user customized and saved.
--- 560,566 ----
              (t (condition-case nil (load load) (error nil))))))))
  
  (defvar custom-known-themes '(user standard)
!    "Themes that have been defined with `deftheme'.
  The default value is the list (user standard).  The theme `standard'
  contains the Emacs standard settings from the original Lisp files.  The
  theme `user' contains all the the settings the user customized and saved.
***************
*** 926,931 ****
--- 926,944 ----
  (defvar custom-loaded-themes nil
    "Themes in the order they are loaded.")
  
+ (defcustom custom-theme-directory
+   (if (eq system-type 'ms-dos)
+        ;; MS-DOS cannot have initial dot.
+        "~/_emacs.d/"
+       "~/.emacs.d/")
+   "Directory in which Custom theme files should be written.
+ `require-theme' searches this directory in addition to load-path.
+ The command `customize-create-theme' writes the files it produces
+ into this directory."
+   :type 'string
+   :group 'customize
+   :version "22.1")
+ 
  (defun custom-theme-loaded-p (theme)
    "Return non-nil when THEME has been loaded."
    (memq theme custom-loaded-themes))
***************
*** 949,956 ****
  by `custom-make-theme-feature'."
    ;; Note we do no check for validity of the theme here.
    ;; This allows to pull in themes by a file-name convention
!   (require (or (get theme 'theme-feature)
!              (custom-make-theme-feature theme))))
  
  (defun custom-remove-theme (spec-alist theme)
    "Delete all elements from SPEC-ALIST whose car is THEME."
--- 962,973 ----
  by `custom-make-theme-feature'."
    ;; Note we do no check for validity of the theme here.
    ;; This allows to pull in themes by a file-name convention
!   (interactive "SAdd theme: ")
!   (let ((load-path (if (file-directory-p custom-theme-directory)
!                      (cons custom-theme-directory load-path)
!                    load-path)))
!     (require (or (get theme 'theme-feature)
!                (custom-make-theme-feature theme)))))
  
  (defun custom-remove-theme (spec-alist theme)
    "Delete all elements from SPEC-ALIST whose car is THEME."
***************
*** 970,975 ****
--- 987,994 ----
  face is set to the `user' theme.
  
  See `custom-known-themes' for a list of known themes."
+   (interactive
+    (list (intern (completing-read "Theme to remove: " custom-known-themes))))
    (let (spec-list)
      (mapatoms (lambda (symbol)
                ;; This works even if symbol is both a variable and a
============================================================

===File ~/cus-theme.el-diff=================================
*** cus-theme.el        17 Apr 2005 15:28:09 -0500      1.8
--- cus-theme.el        27 Jun 2005 18:56:42 -0500      
***************
*** 31,36 ****
--- 31,48 ----
  (eval-when-compile
    (require 'wid-edit))
  
+ (define-derived-mode custom-new-theme-mode nil "New-Theme"
+   "Major mode for the buffer created by `customize-create-theme'.
+ Do not call this mode function yourself.  It is only meant for internal
+ use by `customize-create-theme'."
+   (set-keymap-parent custom-new-theme-mode-map widget-keymap))
+ (put 'custom-new-theme-mode 'mode-class 'special)
+ 
+ (defvar custom-theme-name)
+ (defvar custom-theme-variables)
+ (defvar custom-theme-faces)
+ (defvar custom-theme-description)
+ 
  ;;;###autoload
  (defun customize-create-theme ()
    "Create a custom theme."
***************
*** 38,52 ****
    (if (get-buffer "*New Custom Theme*")
        (kill-buffer "*New Custom Theme*"))
    (switch-to-buffer "*New Custom Theme*")
!   (kill-all-local-variables)
    (make-local-variable 'custom-theme-name)
    (make-local-variable 'custom-theme-variables)
    (make-local-variable 'custom-theme-faces)
    (make-local-variable 'custom-theme-description)
-   (let ((inhibit-read-only t))
-     (erase-buffer))
    (widget-insert "This buffer helps you write a custom theme elisp file.
! This will help you share your customizations with other people.\n\n")
    (widget-insert "Theme name: ")
    (setq custom-theme-name
        (widget-create 'editable-field
--- 50,72 ----
    (if (get-buffer "*New Custom Theme*")
        (kill-buffer "*New Custom Theme*"))
    (switch-to-buffer "*New Custom Theme*")
!   (let ((inhibit-read-only t))
!     (erase-buffer))
!   (custom-new-theme-mode)
    (make-local-variable 'custom-theme-name)
    (make-local-variable 'custom-theme-variables)
    (make-local-variable 'custom-theme-faces)
    (make-local-variable 'custom-theme-description)
    (widget-insert "This buffer helps you write a custom theme elisp file.
! This will help you share your customizations with other people.
! 
! Just insert the names of all variables and faces you want the theme
! to include.  Then clicking mouse-2 or pressing RET on the [Done] button
! will write a theme file that sets all these variables and faces to their
! current values.  It will write that file into the directory given by the
! variable `custom-theme-directory', usually \"~/.emacs.d/\".
! 
! To undo all your edits to the buffer, use the [Reset] button.\n\n")
    (widget-insert "Theme name: ")
    (setq custom-theme-name
        (widget-create 'editable-field
***************
*** 81,87 ****
                           (bury-buffer))
                 "Bury Buffer")
    (widget-insert "\n")
-   (use-local-map widget-keymap)
    (widget-setup))
  
  (defun custom-theme-write (&rest ignore)
--- 101,106 ----
***************
*** 90,98 ****
--- 109,144 ----
        (variables (widget-value custom-theme-variables))
        (faces (widget-value custom-theme-faces)))
      (switch-to-buffer (concat name "-theme.el"))
+     (emacs-lisp-mode)
+     (unless (file-exists-p custom-theme-directory)
+       (make-directory (file-name-as-directory custom-theme-directory) t))
+     (setq default-directory custom-theme-directory)
      (setq buffer-file-name (expand-file-name (concat name "-theme.el")))
      (let ((inhibit-read-only t))
        (erase-buffer))
+     (insert (format ";; This file is the Custom theme file for the theme %s.
+ 
+ ;; If enabled, it sets the variables and faces listed below to the given
+ ;; values.  To enable it, type `M-x require-theme RET %s'.
+ ;; To reset all variables and faces back to their prior values, type
+ ;; `M-x custom-do-theme-reset RET %s'.
+ 
+ ;; You can also write `(require-theme %s)' in your .emacs file.
+ ;; If you do that before the `custom-set-variables' and `custom-set-faces'
+ ;; forms, any values explicitly given in these forms take precedence.
+ ;; If you write it after these forms, the theme takes precedence.
+ 
+ ;; For the above to work, this file should be in a directory in `load-path',
+ ;; or in the directory given by `custom-theme-directory' (usually
+ ;; \"~/.emacs.d/\"), which is the directory in which `custom-theme-create'
+ ;; writes the theme files it produces.
+ 
+ ;; *Please note*: this feature is experimental and needs more work.
+ ;; In Emacs 22, it does not work very well, unless you do only very
+ ;; basic things.  It is expected to work better in future Emacs versions.
+ ;; In situations where `require-theme' does not seem to work, you can
+ ;; just directly load this theme file to get the intended results.\n\n"
+                   name name name name name))
      (insert "(deftheme " name)
      (when doc
        (newline)
***************
*** 100,106 ****
      (insert  ")\n")
      (custom-theme-write-variables name variables)
      (custom-theme-write-faces name faces)
!     (insert "\n(provide-theme '" name ")\n")))
  
  (defun custom-theme-write-variables (theme vars)
    "Write a `custom-theme-set-variables' command for THEME.
--- 146,153 ----
      (insert  ")\n")
      (custom-theme-write-variables name variables)
      (custom-theme-write-faces name faces)
!     (insert "\n(provide-theme '" name ")\n")
!     (save-buffer)))
  
  (defun custom-theme-write-variables (theme vars)
    "Write a `custom-theme-set-variables' command for THEME.
============================================================




reply via email to

[Prev in Thread] Current Thread [Next in Thread]