Update FSF's address.
[riece] / lisp / riece-addon.el
index a02d74e..74db7d9 100644 (file)
@@ -19,8 +19,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Code:
 
 
 ;;; Code:
 
 (require 'riece-options)
 (require 'riece-compat)
 (require 'riece-misc)
 (require 'riece-options)
 (require 'riece-compat)
 (require 'riece-misc)
+(require 'riece-addon-modules)
 
 (defgroup riece-addon-list nil
 
 (defgroup riece-addon-list nil
-  "Add-on management"
-  :tag "Addon"
-  :prefix "riece-"
+  "Add-on listing."
+  :tag "Addon list"
+  :prefix "riece-addon-list-"
   :group 'riece)
 
 (defgroup riece-addon-list-faces nil
   :group 'riece)
 
 (defgroup riece-addon-list-faces nil
-  "Faces for riece-addon-list-mode"
+  "Faces for riece-addon-list-mode."
   :tag "Faces"
   :tag "Faces"
-  :prefix "riece-addon-list"
-  :group 'riece-addon)
+  :prefix "riece-addon-list-"
+  :group 'riece-addon-list)
 
 (defface riece-addon-list-enabled-face
   '((((class color) (background dark))
 
 (defface riece-addon-list-enabled-face
   '((((class color) (background dark))
   '((((class color) (background dark))
      (:foreground "PaleTurquoise" :italic t))
     (t
   '((((class color) (background dark))
      (:foreground "PaleTurquoise" :italic t))
     (t
-     (:italic t)))
+     ()))
   "Face used for displaying the disabled addon."
   :group 'riece-addon-list-faces)
 (defvar riece-addon-list-disabled-face 'riece-addon-list-disabled-face)
 
   "Face used for displaying the disabled addon."
   :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."
+(defface riece-addon-list-uninstalled-face
+  '((t
+     (:italic t)))
+  "Face used for displaying the uninstalled addon."
   :group 'riece-addon-list-faces)
   :group 'riece-addon-list-faces)
-(defvar riece-addon-list-unsupported-face 'riece-addon-list-unsupported-face)
+(defvar riece-addon-list-uninstalled-face 'riece-addon-list-uninstalled-face)
 
 
-(defface riece-addon-list-unknown-face
+(defface riece-addon-list-unloaded-face
   '((t
   '((t
-     (:foreground "red")))
-  "Face used for displaying the unknown addon."
+     (:italic t :inverse-video t)))
+  "Face used for displaying the unloaded addon."
   :group 'riece-addon-list-faces)
   :group 'riece-addon-list-faces)
-(defvar riece-addon-list-unknown-face 'riece-addon-list-unknown-face)
+(defvar riece-addon-list-unloaded-face 'riece-addon-list-unloaded-face)
 
 (defface riece-addon-list-description-face
   '((((class color)
 
 (defface riece-addon-list-description-face
   '((((class color)
 (defcustom riece-addon-list-mark-face-alist
   '((?+ . riece-addon-list-enabled-face)
     (?- . riece-addon-list-disabled-face)
 (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-unknown-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
   "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)))
      (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)
   (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 "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)
     (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
        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.
             (pointer requires)
             entry)
        ;; Increment succs' pred count.
        ;; Merge pred's succs.
        (while pointer
          (if (setq entry (assq (car pointer) dependencies))
        ;; Merge pred's succs.
        (while pointer
          (if (setq entry (assq (car pointer) dependencies))
-             (setcdr (cdr entry)
-                     (cons (car addons) (nthcdr 2 entry)))
+             (setcdr (cdr entry) (cons (car addons) (nthcdr 2 entry)))
            (setq dependencies (cons (list (car pointer) 0 (car addons))
                                     dependencies)))
          (setq pointer (cdr pointer))))
       (setq addons (cdr addons)))
     dependencies))
 
            (setq dependencies (cons (list (car pointer) 0 (car addons))
                                     dependencies)))
          (setq pointer (cdr pointer))))
       (setq addons (cdr addons)))
     dependencies))
 
-(defun riece-resolve-addons (addons)
-  (let ((pointer addons)
-       dependencies queue)
-    ;; Uniquify, first.
-    (while pointer
-      (if (memq (car pointer) (cdr pointer))
-         (setcar pointer nil))
-      (setq pointer (cdr pointer)))
-    (setq dependencies (riece-load-and-build-addon-dependencies
-                       (delq nil addons))
-         pointer dependencies)
-    ;; Sort them.
+(defun riece-sort-addon-dependencies (dependencies)
+  (let ((pointer dependencies)
+       addons queue)
     (while pointer
       (if (zerop (nth 1 (car pointer)))
          (setq dependencies (delq (car pointer) dependencies)
                queue (cons (car pointer) queue)))
       (setq pointer (cdr pointer)))
     (while pointer
       (if (zerop (nth 1 (car pointer)))
          (setq dependencies (delq (car pointer) dependencies)
                queue (cons (car pointer) queue)))
       (setq pointer (cdr pointer)))
-    (setq addons nil)
     (while queue
     (while queue
-      (setq addons (cons (car (car queue)) addons)
+      (setq addons (cons (cons (car (car queue)) (nthcdr 2 (car queue)))
+                        addons)
            pointer (nthcdr 2 (car queue)))
       (while pointer
        (let* ((entry (assq (car pointer) dependencies))
               (count (1- (nth 1 entry))))
          (if (zerop count)
            pointer (nthcdr 2 (car queue)))
       (while pointer
        (let* ((entry (assq (car pointer) dependencies))
               (count (1- (nth 1 entry))))
          (if (zerop count)
-             (progn
-               (setq dependencies (delq entry dependencies)
-                     queue (nconc queue (list entry))))
+             (setq dependencies (delq entry dependencies)
+                   queue (nconc queue (list entry)))
            (setcar (cdr entry) count)))
        (setq pointer (cdr pointer)))
       (setq queue (cdr queue)))
     (if dependencies
            (setcar (cdr entry) count)))
        (setq pointer (cdr pointer)))
       (setq queue (cdr queue)))
     (if dependencies
-       (error "Circular add-on dependency found"))
+       (error "Circular add-on dependency found: %S" dependencies))
     (nreverse addons)))
 
     (nreverse addons)))
 
+(defun riece-resolve-addons (addons)
+  ;; Add files in riece-addon-directory to addons.
+  (if (file-directory-p riece-addon-directory)
+      (setq addons (nconc
+                   addons
+                   (mapcar
+                    (lambda (name)
+                      (unless (file-directory-p
+                               (expand-file-name name riece-addon-directory))
+                        (intern (file-name-sans-extension name))))
+                    (directory-files riece-addon-directory nil "\\`[^.]")))))
+  ;; Sort & uniquify.
+  (setq addons (sort addons (lambda (symbol1 symbol2)
+                             (string-lessp (symbol-name symbol1)
+                                           (symbol-name symbol2)))))
+  (let ((pointer addons))
+    (while pointer
+      (if (memq (car pointer) (cdr pointer))
+         (setcar pointer nil))
+      (setq pointer (cdr pointer)))
+    (delq nil addons))
+  ;; Build & resolve dependencies.
+  (riece-sort-addon-dependencies
+   (riece-load-and-build-addon-dependencies 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))
+    (unless (get addon 'riece-addon-default-disabled)
+      (riece-enable-addon addon t))))
+
 (defun riece-insinuate-addon (addon &optional verbose)
 (defun riece-insinuate-addon (addon &optional verbose)
-  (require addon)              ;implicit dependency
-  (funcall (intern (concat (symbol-name addon) "-insinuate")))
-  (if verbose
-      (message "Add-on %S is insinuated" addon)))
+  (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))
+         (uninstall (intern-soft (concat (symbol-name addon) "-uninstall"))))
+      (if entry
+         (if (cdr entry)
+             (if (= (length (cdr entry)) 1)
+                 (error "%S depends on %S" (car (cdr entry)) addon)
+               (error "%s depend on %S"
+                      (mapconcat #'symbol-name (cdr entry) ", ")
+                      addon))
+           (riece-disable-addon addon verbose)
+           (if (and uninstall
+                    (fboundp uninstall))
+               (funcall uninstall))
+           (setq riece-addon-dependencies
+                 (delq entry riece-addon-dependencies))
+           (put addon 'riece-addon-insinuated nil)
+           (setq riece-addons (delq addon 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)
 
 (defun riece-enable-addon (addon &optional verbose)
-  (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 "Can't enable add-on %S" addon))
-       (funcall (intern (concat (symbol-name addon) "-enable")))
-       (if verbose
-           (message "Add-on %S enabled" addon))))))
+  (unless (get addon 'riece-addon-insinuated)
+    (error "Add-on %S is not insinuated" 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)
 
 (defun riece-disable-addon (addon &optional verbose)
-  (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 "Can't disable add-on %S" addon))))))
+  (unless (get addon 'riece-addon-insinuated)
+    (error "Add-on %S is not insinuated" 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))
 
 (put 'riece-addon-list-mode 'font-lock-defaults
      '(riece-addon-list-font-lock-keywords t))
@@ -227,123 +308,196 @@ All normal editing commands are turned off."
   (use-local-map riece-addon-list-mode-map)
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(riece-addon-list-font-lock-keywords t))
   (use-local-map riece-addon-list-mode-map)
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(riece-addon-list-font-lock-keywords t))
-  ;; In XEmacs, auto-initialization of font-lock is not affective
-  ;; when buffer-file-name is not set.
+  ;; In XEmacs, auto-initialization of font-lock is not effective
+  ;; if buffer-file-name is not set.
   (font-lock-set-defaults)
   (run-hooks 'riece-addon-list-mode-hook))
 
 (defun riece-command-list-addons ()
   (interactive)
   (font-lock-set-defaults)
   (run-hooks 'riece-addon-list-mode-hook))
 
 (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
   (riece-addon-list-mode)
   (let ((inhibit-read-only t)
        buffer-read-only
-       (pointer (sort (copy-sequence riece-addons)
-                      (lambda (symbol1 symbol2)
-                                 (string-lessp (symbol-name symbol1)
-                                               (symbol-name symbol2)))))
-       enabled description point)
+       (pointer riece-addon-dependencies)
+       module-description-alist
+       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 (and description
+                                (boundp description))
+                           (symbol-value description)
+                         "(no description)"))
+                 module-description-alist)
+           pointer (cdr pointer)))
+    (setq pointer riece-addon-modules)
+    (while pointer
+      (unless (assq (car (car pointer))
+                   module-description-alist)
+       (setq module-description-alist
+             (cons (car pointer) module-description-alist)))
+      (setq pointer (cdr pointer)))
     (erase-buffer)
     (riece-kill-all-overlays)
     (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
     (while pointer
-      (setq enabled (intern-soft (concat (symbol-name (car pointer))
-                                        "-enabled"))
-           description (intern-soft (concat (symbol-name (car pointer))
-                                            "-description")))
       (setq point (point))
       (setq point (point))
-      (insert (format "%c %S: %s\n"
-                     (if (not (featurep (car pointer)))
-                         ??
-                       (if (null enabled)
-                           ?!
-                         (if (symbol-value enabled)
+      (insert (format (format "%%c %%-%dS %%s\n" (length longest))
+                     (if (not (featurep (car (car pointer))))
+                         ? 
+                       (if (not (get (car (car pointer))
+                                     'riece-addon-insinuated))
+                           ??
+                         (if (get (car (car pointer)) 'riece-addon-enabled)
                              ?+
                            ?-)))
                              ?+
                            ?-)))
-                     (car pointer)
-                     (if description
-                         (symbol-value description)
-                       "(no description)")))
-      (put-text-property point (point) 'riece-addon (car pointer))
+                     (car (car pointer))
+                     (cdr (car pointer))))
+      (put-text-property point (point) 'riece-addon (car (car pointer)))
       (setq pointer (cdr pointer)))
     (insert "
 Symbols in the leftmost column:
 
       (setq pointer (cdr pointer)))
     (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 status is unknown.
+   +     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:
 
 ")
     (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)))
 
 "))
     (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
     (or (if (eq major-mode 'riece-addon-list-mode)
            (get-text-property (point) 'riece-addon))
 (defun riece-command-enable-addon (addon)
   (interactive
    (list
     (or (if (eq major-mode 'riece-addon-list-mode)
            (get-text-property (point) 'riece-addon))
-       (completing-read "Add-on: "
-                        (mapcar (lambda (addon)
-                                  (list (symbol-name addon)))
-                                riece-addons)
-                        (lambda (pointer)
-                          (let ((enabled
-                                 (intern-soft (concat (symbol-name
-                                                       (car pointer))
-                                                      "-enabled"))))
-                            (and enabled
-                                 (null (symbol-value enabled)))))
-                        t))))
+       (intern-soft
+        (completing-read "Add-on: "
+                         (mapcar (lambda (dependency)
+                                   (list (symbol-name (car dependency))))
+                                 riece-addon-dependencies)
+                         (lambda (pointer)
+                           (let ((enabled
+                                  (intern-soft (concat (car pointer)
+                                                       "-enabled"))))
+                             (and enabled
+                                  (null (symbol-value enabled)))))
+                         t)))))
   (riece-enable-addon addon t)
   (riece-enable-addon addon t)
-  (let ((enabled (intern-soft (concat (symbol-name addon) "-enabled"))))
-    (if (and (eq major-mode 'riece-addon-list-mode)
-            (get-text-property (point) 'riece-addon)
-            enabled (symbol-value enabled))
-       (save-excursion
-         (beginning-of-line)
-         (let ((point (point))
-               (inhibit-read-only t)
-               buffer-read-only)
-           (delete-char 1)
-           (insert "+")
-           (put-text-property point (point) 'riece-addon addon))))))
+  (when (eq major-mode 'riece-addon-list-mode)
+    (riece-command-list-addons)
+    (riece-addon-list-set-point addon)))
 
 (defun riece-command-disable-addon (addon)
   (interactive
    (list
     (or (if (eq major-mode 'riece-addon-list-mode)
            (get-text-property (point) 'riece-addon))
 
 (defun riece-command-disable-addon (addon)
   (interactive
    (list
     (or (if (eq major-mode 'riece-addon-list-mode)
            (get-text-property (point) 'riece-addon))
-       (completing-read "Add-on: "
-                        (mapcar (lambda (addon)
-                                  (list (symbol-name addon)))
-                                riece-addons)
-                        (lambda (pointer)
-                          (let ((enabled
-                                 (intern-soft (concat (symbol-name
-                                                       (car pointer))
-                                                      "-enabled"))))
-                            (and enabled
-                                 (symbol-value enabled))))
-                        t))))
+       (intern-soft
+        (completing-read "Add-on: "
+                         (mapcar (lambda (dependency)
+                                   (list (symbol-name (car dependency))))
+                                 riece-addon-dependencies)
+                         (lambda (pointer)
+                           (let ((enabled
+                                  (intern-soft (concat (car pointer)
+                                                       "-enabled"))))
+                             (and enabled
+                                  (symbol-value enabled))))
+                         t)))))
   (riece-disable-addon addon t)
   (riece-disable-addon addon t)
-  (let ((enabled (intern-soft (concat (symbol-name addon) "-enabled"))))
-    (if (and (eq major-mode 'riece-addon-list-mode)
-            (get-text-property (point) 'riece-addon)
-            enabled (null (symbol-value enabled)))
-       (save-excursion
-         (beginning-of-line)
-         (let ((point (point))
-               (inhibit-read-only t)
-               buffer-read-only)
-           (delete-char 1)
-           (insert "-")
-           (put-text-property point (point) 'riece-addon addon))))))
+  (when (eq major-mode 'riece-addon-list-mode)
+    (riece-command-list-addons)
+    (riece-addon-list-set-point addon)))
+
+(defun riece-command-insinuate-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-modules)
+                         (lambda (pointer)
+                           (not (get (car pointer) 'riece-addon-insinuated)))
+                         t)))))
+  (riece-insinuate-addon addon 'ask)
+  (when (eq major-mode 'riece-addon-list-mode)
+    (riece-command-list-addons)
+    (riece-addon-list-set-point addon)))
+
+(defun riece-command-uninstall-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)
+  (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)
+    (riece-addon-list-set-point addon)))
 
 (provide 'riece-addon)
 
 
 (provide 'riece-addon)