* riece-addon.el (riece-command-list-addons): Adjust width of 2nd
[riece] / lisp / riece-addon.el
index 34796f1..154ad2e 100644 (file)
   :group 'riece-addon-list-faces)
 (defvar riece-addon-list-disabled-face 'riece-addon-list-disabled-face)
 
-(defface riece-addon-list-unsupported-face
-  '((((class color) (background dark))
-     (:foreground "PaleTurquoise"))
-    (t
-     ()))
-  "Face used for displaying the unsupported addon."
-  :group 'riece-addon-list-faces)
-(defvar riece-addon-list-unsupported-face 'riece-addon-list-unsupported-face)
-
 (defface riece-addon-list-uninstalled-face
   '((t
      (:italic t)))
   :group 'riece-addon-list-faces)
 (defvar riece-addon-list-uninstalled-face 'riece-addon-list-uninstalled-face)
 
+(defface riece-addon-list-unloaded-face
+  '((t
+     (:italic t :inverse-video t)))
+  "Face used for displaying the unloaded addon."
+  :group 'riece-addon-list-faces)
+(defvar riece-addon-list-unloaded-face 'riece-addon-list-unloaded-face)
+
 (defface riece-addon-list-description-face
   '((((class color)
       (background dark))
 (defcustom riece-addon-list-mark-face-alist
   '((?+ . riece-addon-list-enabled-face)
     (?- . riece-addon-list-disabled-face)
-    (?! . riece-addon-list-unsupported-face)
-    (?  . riece-addon-list-uninstalled-face))
+    (?? . riece-addon-list-uninstalled-face)
+    (?  . riece-addon-list-unloaded-face))
   "An alist mapping marks on riece-addon-list-buffer to faces."
   :type 'list
   :group 'riece-addon-list)
 
 (defcustom riece-addon-list-font-lock-keywords
-  '(("^\\([-+! ] [^:]+\\): \\(.*\\)"
+  '(("^\\([-+? ] \\S-+\\)\\s-+\\(.*\\)"
      (1 (cdr (assq (aref (match-string 1) 0)
                   riece-addon-list-mark-face-alist)))
      (2 riece-addon-list-description-face)))
   (let ((keymap (make-sparse-keymap)))
     (define-key keymap "+" 'riece-command-enable-addon)
     (define-key keymap "-" 'riece-command-disable-addon)
-    (define-key keymap "I" 'riece-command-insinuate-addon)
-    (define-key keymap "D" 'riece-command-uninstall-addon)
+    (define-key keymap "i" 'riece-command-insinuate-addon)
+    (define-key keymap "u" 'riece-command-uninstall-addon)
+    (define-key keymap "U" 'riece-command-unload-addon)
     (define-key keymap "n" 'next-line)
     (define-key keymap "p" 'previous-line)
     (define-key keymap " " 'scroll-up)
        dependencies)
     (while addons
       (require (car addons))           ;error will be reported here
-      (let* ((requires
-             (funcall (or (intern-soft
-                           (concat (symbol-name (car addons)) "-requires"))
-                          #'ignore)))
+      (let* ((requires-function
+             (intern-soft
+              (concat (symbol-name (car addons)) "-requires")))
+            (requires
+             (if (and requires-function
+                      (fboundp requires-function))
+                 (funcall requires-function)))
             (pointer requires)
             entry)
        ;; Increment succs' pred count.
   (riece-sort-addon-dependencies
    (riece-load-and-build-addon-dependencies addons)))
 
-(defun riece-insinuate-addon (addon &optional verbose)
-  (unless (assq addon riece-addon-dependencies)
-    (setq riece-addons (cons addon riece-addons)
-         riece-addon-dependencies (riece-resolve-addons
-                                   (copy-sequence riece-addons))))
+(defun riece-insinuate-addon-1 (addon verbose)
   (if (get addon 'riece-addon-insinuated)
       (if verbose
          (message "Add-on %S is already insinuated" addon))
+    (require addon)
     (funcall (intern (concat (symbol-name addon) "-insinuate")))
     (put addon 'riece-addon-insinuated t)
     (if verbose
-       (message "Add-on %S is insinuated" addon))))
+       (message "Add-on %S is insinuated" addon))
+    (unless (get addon 'riece-addon-default-disabled)
+      (riece-enable-addon addon t))))
+
+(defun riece-insinuate-addon (addon &optional verbose)
+  (unless (assq addon riece-addon-dependencies)
+    (setq riece-addons (cons addon riece-addons)
+         riece-save-variables-are-dirty t
+         riece-addon-dependencies
+         (riece-resolve-addons
+          (cons addon (mapcar #'car riece-addon-dependencies)))))
+  (let ((pointer riece-addon-dependencies)
+       addons)
+    (while pointer
+      (unless (get (car (car pointer)) 'riece-addon-insinuated)
+       (setq addons (cons (car (car pointer)) addons)))
+      (if (eq (car (car pointer)) addon)
+         (setq pointer nil)
+       (setq pointer (cdr pointer))))
+    (setq addons (nreverse addons))
+    (if (and (> (length addons) 1)
+            (eq verbose 'ask)
+            (not (y-or-n-p (format "%s will be insinuated.  Continue? "
+                                   (mapconcat #'symbol-name addons ", ")))))
+       (error "Insinuate operation was cancelled"))
+    (while addons
+      (riece-insinuate-addon-1 (car addons) verbose)
+      (setq addons (cdr addons)))))
 
 (defun riece-uninstall-addon (addon &optional verbose)
   (if (not (get addon 'riece-addon-insinuated))
       (if verbose
          (message "Add-on %S is not insinuated" addon))
     (let ((entry (assq addon riece-addon-dependencies))
-         (enabled (intern-soft (concat (symbol-name addon) "-enabled"))))
+         (uninstall (intern-soft (concat (symbol-name addon) "-uninstall"))))
       (if entry
          (if (cdr entry)
              (if (= (length (cdr entry)) 1)
-                 (error "%S depends %S" (car (cdr entry)) addon)
-               (error "%s depends %S" (mapconcat #'identity (cdr entry) ",")
+                 (error "%S depends on %S" (car (cdr entry)) addon)
+               (error "%s depend on %S"
+                      (mapconcat #'symbol-name (cdr entry) ", ")
                       addon))
-           (if (and enabled
-                    (symbol-value enabled))
-               (riece-disable-addon addon verbose))
-           (funcall (or (intern-soft (concat (symbol-name addon)
-                                             "-uninstall"))
-                        #'ignore))
+           (riece-disable-addon addon verbose)
+           (if (and uninstall
+                    (fboundp uninstall))
+               (funcall uninstall))
            (setq riece-addon-dependencies
                  (delq entry riece-addon-dependencies))
-           (remprop addon 'riece-addon-insinuated)
+           (put addon 'riece-addon-insinuated nil)
            (setq riece-addons (delq addon riece-addons)
-                 riece-addon-dependencies (riece-resolve-addons
-                                           (copy-sequence riece-addons)))))
+                 riece-save-variables-are-dirty t
+                 riece-addon-dependencies
+                 (riece-resolve-addons
+                  (delq addon (mapcar #'car riece-addon-dependencies))))))
       (if verbose
          (message "Add-on %S is uninstalled" addon)))))
 
 (defun riece-enable-addon (addon &optional verbose)
   (unless (get addon 'riece-addon-insinuated)
     (error "Add-on %S is not insinuated" addon))
-  (let ((enabled (intern-soft (concat (symbol-name addon) "-enabled"))))
-    (if (null enabled)
-       (if verbose
-           (message "Add-on %S doesn't support enable/disable" addon))
-      (if (symbol-value enabled)
-         (if verbose
-             (message "Add-on %S is already enabled" addon))
-       (funcall (intern (concat (symbol-name addon) "-enable")))
-       (if verbose
-           (message "Add-on %S enabled" addon))))))
+  (if (get addon 'riece-addon-enabled)
+      (if verbose
+         (message "Add-on %S is already enabled" addon))
+    (let ((enable (intern-soft (concat (symbol-name addon) "-enable"))))
+      (if (and enable
+              (fboundp enable))
+         (funcall enable))
+      (put addon 'riece-addon-enabled t)
+      (if verbose
+         (message "Add-on %S enabled" addon)))))
 
 (defun riece-disable-addon (addon &optional verbose)
   (unless (get addon 'riece-addon-insinuated)
     (error "Add-on %S is not insinuated" addon))
-  (let ((enabled (intern-soft (concat (symbol-name addon) "-enabled"))))
-    (if (null enabled)
-       (if verbose
-           (message "Add-on %S doesn't support enable/disable" addon))
-      (if (symbol-value enabled)
-         (progn
-           (funcall (intern (concat (symbol-name addon) "-disable")))
-           (if verbose
-               (message "Add-on %S disabled" addon)))
-       (if verbose
-           (message "Add-on %S is already enabled" addon))))))
+  (if (not (get addon 'riece-addon-enabled))
+      (if verbose
+         (message "Add-on %S is already disabled" addon))
+    (let ((disable (intern-soft (concat (symbol-name addon) "-disable"))))
+      (if (and disable
+              (fboundp disable))
+         (funcall disable))
+      (put addon 'riece-addon-enabled nil)
+      (if verbose
+         (message "Add-on %S disabled" addon)))))
 
 (put 'riece-addon-list-mode 'font-lock-defaults
      '(riece-addon-list-font-lock-keywords t))
@@ -289,20 +315,20 @@ All normal editing commands are turned off."
 
 (defun riece-command-list-addons ()
   (interactive)
-  (set-buffer (riece-get-buffer-create "*AddOns*" 'riece-addon-list-mode))
+  (set-buffer (riece-get-buffer-create "*AddOn*" 'riece-addon-list-mode))
   (riece-addon-list-mode)
   (let ((inhibit-read-only t)
        buffer-read-only
        (pointer riece-addon-dependencies)
        module-description-alist
-       description enabled point)
+       description point longest)
     (while pointer
-      
       (setq description (intern-soft (concat (symbol-name (car (car pointer)))
                                             "-description"))
            module-description-alist
            (cons (cons (car (car pointer))
-                       (if description
+                       (if (and description
+                                (boundp description))
                            (symbol-value description)
                          "(no description)"))
                  module-description-alist)
@@ -316,21 +342,26 @@ All normal editing commands are turned off."
       (setq pointer (cdr pointer)))
     (erase-buffer)
     (riece-kill-all-overlays)
+    (setq pointer module-description-alist
+         longest "")
+    (while pointer
+      (if (> (length (symbol-name (car (car pointer))))
+            (length longest))
+         (setq longest (symbol-name (car (car pointer)))))
+      (setq pointer (cdr pointer)))
     (setq pointer (sort module-description-alist
                        (lambda (entry1 entry2)
                          (string-lessp (symbol-name (car entry1))
                                        (symbol-name (car entry2))))))
     (while pointer
-      (setq enabled (intern-soft (concat (symbol-name (car (car pointer)))
-                                        "-enabled")))
       (setq point (point))
-      (insert (format "%c %S: %s\n"
-                     (if (not (get (car (car pointer))
-                                   'riece-addon-insinuated))
+      (insert (format (format "%%c %%-%dS %%s\n" (length longest))
+                     (if (not (featurep (car (car pointer))))
                          ? 
-                       (if (null enabled)
-                           ?!
-                         (if (symbol-value enabled)
+                       (if (not (get (car (car pointer))
+                                     'riece-addon-insinuated))
+                           ??
+                         (if (get (car (car pointer)) 'riece-addon-enabled)
                              ?+
                            ?-)))
                      (car (car pointer))
@@ -340,21 +371,32 @@ All normal editing commands are turned off."
     (insert "
 Symbols in the leftmost column:
 
-  +     The add-on is enabled.
-  -     The add-on is disabled.
-  !    The add-on doesn't support enable/disable operation.
-       The add-on is not insinuated.
+   +     The add-on is enabled.
+   -     The add-on is disabled.
+   ?     The add-on is not insinuated.
+         The add-on is not loaded.
 ")
     (insert (substitute-command-keys "
 Useful keys:
 
-  `\\[riece-command-enable-addon]' to enable the current add-on.
-  `\\[riece-command-disable-addon]' to disable the current add-on.
+   `\\[riece-command-enable-addon]' to enable the current add-on.
+   `\\[riece-command-disable-addon]' to disable the current add-on.
+   `\\[riece-command-insinuate-addon]' to insinuate the current add-on.
+   `\\[riece-command-uninstall-addon]' to uninstall the current add-on.
+   `\\[riece-command-unload-addon]' to unload the current add-on.
 "))
     (goto-char (point-min))
     (pop-to-buffer (current-buffer))
     (delete-other-windows)))
 
+(defun riece-addon-list-set-point (addon)
+  (let ((point (point-min)))
+    (while (and (not (eq (get-text-property point 'riece-addon) addon))
+               (setq point (next-single-property-change point
+                                                        'riece-addon))))
+    (if point
+       (goto-char point))))
+
 (defun riece-command-enable-addon (addon)
   (interactive
    (list
@@ -375,12 +417,7 @@ Useful keys:
   (riece-enable-addon addon t)
   (when (eq major-mode 'riece-addon-list-mode)
     (riece-command-list-addons)
-    (let ((point (point-min)))
-      (while (and (not (eq (get-text-property point 'riece-addon) addon))
-                 (setq point (next-single-property-change point
-                                                          'riece-addon))))
-      (if point
-         (goto-char point)))))
+    (riece-addon-list-set-point addon)))
 
 (defun riece-command-disable-addon (addon)
   (interactive
@@ -402,12 +439,7 @@ Useful keys:
   (riece-disable-addon addon t)
   (when (eq major-mode 'riece-addon-list-mode)
     (riece-command-list-addons)
-    (let ((point (point-min)))
-      (while (and (not (eq (get-text-property point 'riece-addon) addon))
-                 (setq point (next-single-property-change point
-                                                          'riece-addon))))
-      (if point
-         (goto-char point)))))
+    (riece-addon-list-set-point addon)))
 
 (defun riece-command-insinuate-addon (addon)
   (interactive
@@ -420,17 +452,12 @@ Useful keys:
                                    (list (symbol-name (car dependency))))
                                  riece-addon-modules)
                          (lambda (pointer)
-                           (get (car pointer) 'riece-addon-insinuated))
+                           (not (get (car pointer) 'riece-addon-insinuated)))
                          t)))))
-  (riece-insinuate-addon addon t)
+  (riece-insinuate-addon addon 'ask)
   (when (eq major-mode 'riece-addon-list-mode)
     (riece-command-list-addons)
-    (let ((point (point-min)))
-      (while (and (not (eq (get-text-property point 'riece-addon) addon))
-                 (setq point (next-single-property-change point
-                                                          'riece-addon))))
-      (if point
-         (goto-char point)))))
+    (riece-addon-list-set-point addon)))
 
 (defun riece-command-uninstall-addon (addon)
   (interactive
@@ -442,16 +469,35 @@ Useful keys:
                          (mapcar (lambda (dependency)
                                    (list (symbol-name (car dependency))))
                                  riece-addon-dependencies)
-                         nil t)))))
+                         (lambda (pointer)
+                           (get (car pointer) 'riece-addon-insinuated))
+                         t)))))
+  (riece-uninstall-addon addon t)
+  (when (eq major-mode 'riece-addon-list-mode)
+    (riece-command-list-addons)
+    (riece-addon-list-set-point addon)))
+
+(defun riece-command-unload-addon (addon)
+  (interactive
+   (list
+    (or (if (eq major-mode 'riece-addon-list-mode)
+           (get-text-property (point) 'riece-addon))
+       (intern-soft
+        (completing-read "Add-on: "
+                         (mapcar (lambda (dependency)
+                                   (list (symbol-name (car dependency))))
+                                 riece-addon-dependencies)
+                         (lambda (pointer)
+                           (get (car pointer) 'riece-addon-insinuated))
+                         t)))))
   (riece-uninstall-addon addon t)
+  (if (get addon 'riece-addon-not-unloadable)
+      (message "Add-on %S is not allowed to unload" addon)
+    (unload-feature addon)
+    (message "Add-on %S is unloaded" addon))
   (when (eq major-mode 'riece-addon-list-mode)
     (riece-command-list-addons)
-    (let ((point (point-min)))
-      (while (and (not (eq (get-text-property point 'riece-addon) addon))
-                 (setq point (next-single-property-change point
-                                                          'riece-addon))))
-      (if point
-         (goto-char point)))))
+    (riece-addon-list-set-point addon)))
 
 (provide 'riece-addon)