Subject: Re: bug#8730: bug#8781: bug#8730: bug#8781: 24.0.50; unload-feature don't restore default key

From: Juanma Barranquero <[email-masked]>
Date: Thu, 23 Jun 2011 12:17:02 +0200

I've implemented a variant of the change we discussed.

What I do, while unloading feature F, is to look for all buffers
having a major mode M defined in F.

If found, I follow back the chain of derivation until I find a major
mode M' which is not defined in F.

If found, I use M'; if not, I switch the buffer to  "(or (default
'major-mode) 'fundamental-mode)".

That's better IMHO, because text modes will be in text-mode,
programming modes will be in prog-mode, inferior modes will be in
comint-mode, etc.

There's an additional check, for cases where (default 'major-mode)
does the unexpected. For example, I have it set to a function that
calls `set-auto-mode', so funcalling it usually sets the buffer to the
same mode it already was. In that case, I default to fundamental-mode
again.

WDYT?

=== modified file 'lisp/loadhist.el'
--- lisp/loadhist.el	2011-06-08 07:17:26 +0000
+++ lisp/loadhist.el	2011-06-23 10:06:48 +0000
@@ -186,7 +186,8 @@
 	 restore-autoload
 	 (name (symbol-name feature))
          (unload-hook (intern-soft (concat name "-unload-hook")))
-	 (unload-func (intern-soft (concat name "-unload-function"))))
+	 (unload-func (intern-soft (concat name "-unload-function")))
+	 (default-mode (or (default-value 'major-mode) 'fundamental-mode)))
     ;; If FEATURE-unload-function is defined and returns non-nil,
     ;; don't try to do anything more; otherwise proceed normally.
     (unless (and (fboundp unload-func)
@@ -222,6 +223,24 @@
 		     (not (get (cdr y) 'autoload)))
 	    (setq auto-mode-alist
 		  (rassq-delete-all (cdr y) auto-mode-alist)))))
+
+      ;; Change major mode in all buffers using one defined in the
feature being unloaded.
+      (save-current-buffer
+        (dolist (buffer (buffer-list))
+          (set-buffer buffer)
+          (let ((proposed major-mode)
+                (original major-mode))
+            ;; Look for an antecessor mode not defined in the feature
we're processing
+            (while (and proposed (rassq proposed unload-function-defs-list))
+              (setq proposed (get proposed 'derived-mode-parent)))
+            (unless (eq proposed major-mode)
+              ;; Two cases: either proposed is nil, and we want to
switch to the default
+              ;; major mode, or proposed is not nil and not
major-mode, and so we use it.
+              (funcall (or proposed default-mode))
+              ;; This check protects agains the user having a weird
default major-mode;
+              ;; for example, one that calls set-auto-mode (been
here, done that).
+              (when (eq major-mode original) (funcall 'fundamental-mode))))))
+
       (when (fboundp 'elp-restore-function) ; remove ELP stuff first
 	(dolist (elt unload-function-defs-list)
 	  (when (symbolp elt)