aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2018-06-21 23:30:11 -0400
committerStefan Monnier2018-06-21 23:30:11 -0400
commita5511956b483e22cfebc0ebeb54d83c95f852648 (patch)
treef708410de024fafadde9317447ea999734c44fd7
parent8a7475ca796ecd5816fab9f11baf07bcc395d951 (diff)
downloademacs-a5511956b483e22cfebc0ebeb54d83c95f852648.tar.gz
emacs-a5511956b483e22cfebc0ebeb54d83c95f852648.zip
New functions to switch back and forth to another major mode
* subr.el (major-mode--suspended): New var. (major-mode-suspend, major-mode-restore): New funs, extracted from doc-view. * doc-view.el (doc-view--previous-major-mode): Remove. (doc-view-mode): Use major-mode-suspend. (doc-view-fallback-mode): Use major-mode-restore. * hexl-mode.el (hexl-mode--minor-mode-p, hexl-mode--setq-local): Remove. (hexl-mode): Use major-mode-suspend and hexl-follow-ascii-mode. (hexl-mode-exit): Use major-mode-restore. (hexl-activate-ruler, hexl-follow-line): Don't bother trying to preserve earlier state, now that entering/leaving hexl-mode kills local vars. (hexl-follow-ascii-mode): New proper local minor mode. (hexl-follow-ascii): Rewrite, using it. * image-mode.el (image-mode-previous-major-mode): Remove. (image-mode): Use major-mode-suspend. (image-mode-to-text): Use major-mode-restore.
-rw-r--r--etc/NEWS4
-rw-r--r--lisp/doc-view.el19
-rw-r--r--lisp/hexl.el161
-rw-r--r--lisp/image-mode.el26
-rw-r--r--lisp/subr.el34
5 files changed, 98 insertions, 146 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 537e99c90e8..83e106ced8c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -658,6 +658,10 @@ manual for more details.
658 658
659* Lisp Changes in Emacs 27.1 659* Lisp Changes in Emacs 27.1
660 660
661** New functions 'major-mode-suspend' and 'major-mode-restore'
662Used when switching temporarily to another major mode, e.g. for hexl-mode,
663or to switch between c-mode and image-mode in XPM.
664
661+++ 665+++
662** New macro 'dolist-with-progress-reporter'. 666** New macro 'dolist-with-progress-reporter'.
663This works like 'dolist', but reports progress similar to 667This works like 'dolist', but reports progress similar to
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index dfc4d887ae3..970e12402d0 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -354,9 +354,6 @@ of the page moves to the previous page."
354(defvar doc-view--pending-cache-flush nil 354(defvar doc-view--pending-cache-flush nil
355 "Only used internally.") 355 "Only used internally.")
356 356
357(defvar doc-view--previous-major-mode nil
358 "Only used internally.")
359
360(defvar doc-view--buffer-file-name nil 357(defvar doc-view--buffer-file-name nil
361 "Only used internally. 358 "Only used internally.
362The file name used for conversion. Normally it's the same as 359The file name used for conversion. Normally it's the same as
@@ -1752,12 +1749,7 @@ toggle between displaying the document or editing it as text.
1752 ;; returns nil for tar members. 1749 ;; returns nil for tar members.
1753 (doc-view-fallback-mode) 1750 (doc-view-fallback-mode)
1754 1751
1755 (let* ((prev-major-mode (if (derived-mode-p 'doc-view-mode) 1752 (major-mode-suspend)
1756 doc-view--previous-major-mode
1757 (unless (eq major-mode 'fundamental-mode)
1758 major-mode))))
1759 (kill-all-local-variables)
1760 (setq-local doc-view--previous-major-mode prev-major-mode))
1761 1753
1762 (dolist (var doc-view-saved-settings) 1754 (dolist (var doc-view-saved-settings)
1763 (set (make-local-variable (car var)) (cdr var))) 1755 (set (make-local-variable (car var)) (cdr var)))
@@ -1848,14 +1840,7 @@ toggle between displaying the document or editing it as text.
1848 '(doc-view-resolution 1840 '(doc-view-resolution
1849 image-mode-winprops-alist))))) 1841 image-mode-winprops-alist)))))
1850 (remove-overlays (point-min) (point-max) 'doc-view t) 1842 (remove-overlays (point-min) (point-max) 'doc-view t)
1851 (if doc-view--previous-major-mode 1843 (major-mode-restore '(doc-view-mode-maybe doc-view-mode))
1852 (funcall doc-view--previous-major-mode)
1853 (let ((auto-mode-alist
1854 (rassq-delete-all
1855 'doc-view-mode-maybe
1856 (rassq-delete-all 'doc-view-mode
1857 (copy-alist auto-mode-alist)))))
1858 (normal-mode)))
1859 (when vars 1844 (when vars
1860 (setq-local doc-view-saved-settings vars)))) 1845 (setq-local doc-view-saved-settings vars))))
1861 1846
diff --git a/lisp/hexl.el b/lisp/hexl.el
index 2c1a7de48a7..f37be9d4102 100644
--- a/lisp/hexl.el
+++ b/lisp/hexl.el
@@ -58,53 +58,45 @@
58 (const 16) 58 (const 16)
59 (const 32) 59 (const 32)
60 (const 64)) 60 (const 64))
61 :group 'hexl
62 :version "24.3") 61 :version "24.3")
63 62
64(defcustom hexl-program "hexl" 63(defcustom hexl-program "hexl"
65 "The program that will hexlify and dehexlify its stdin. 64 "The program that will hexlify and dehexlify its stdin.
66`hexl-program' will always be concatenated with `hexl-options' 65`hexl-program' will always be concatenated with `hexl-options'
67and \"-de\" when dehexlifying a buffer." 66and \"-de\" when dehexlifying a buffer."
68 :type 'string 67 :type 'string)
69 :group 'hexl)
70 68
71(defcustom hexl-iso "" 69(defcustom hexl-iso ""
72 "If your Emacs can handle ISO characters, this should be set to 70 "If your Emacs can handle ISO characters, this should be set to
73\"-iso\" otherwise it should be \"\"." 71\"-iso\" otherwise it should be \"\"."
74 :type 'string 72 :type 'string)
75 :group 'hexl)
76 73
77(defcustom hexl-options (format "-hex %s" hexl-iso) 74(defcustom hexl-options (format "-hex %s" hexl-iso)
78 "Space separated options to `hexl-program' that suit your needs. 75 "Space separated options to `hexl-program' that suit your needs.
79Quoting cannot be used, so the arguments cannot themselves contain spaces. 76Quoting cannot be used, so the arguments cannot themselves contain spaces.
80If you wish to set the `-group-by-X-bits' options, set `hexl-bits' instead, 77If you wish to set the `-group-by-X-bits' options, set `hexl-bits' instead,
81as that will override any bit grouping options set here." 78as that will override any bit grouping options set here."
82 :type 'string 79 :type 'string)
83 :group 'hexl)
84 80
85(defcustom hexl-follow-ascii t 81(defcustom hexl-follow-ascii t
86 "If non-nil then highlight the ASCII character corresponding to point." 82 "If non-nil then highlight the ASCII character corresponding to point."
87 :type 'boolean 83 :type 'boolean
88 :group 'hexl
89 :version "20.3") 84 :version "20.3")
90 85
91(defcustom hexl-mode-hook '(hexl-follow-line hexl-activate-ruler) 86(defcustom hexl-mode-hook '(hexl-follow-line hexl-activate-ruler)
92 "Normal hook run when entering Hexl mode." 87 "Normal hook run when entering Hexl mode."
93 :type 'hook 88 :type 'hook
94 :options '(hexl-follow-line hexl-activate-ruler eldoc-mode) 89 :options '(hexl-follow-line hexl-activate-ruler eldoc-mode))
95 :group 'hexl)
96 90
97(defface hexl-address-region 91(defface hexl-address-region
98 '((t (:inherit header-line))) 92 '((t (:inherit header-line)))
99 "Face used in address area of Hexl mode buffer." 93 "Face used in address area of Hexl mode buffer.")
100 :group 'hexl)
101 94
102(defface hexl-ascii-region 95(defface hexl-ascii-region
103 '((t (:inherit header-line))) 96 '((t (:inherit header-line)))
104 "Face used in ASCII area of Hexl mode buffer." 97 "Face used in ASCII area of Hexl mode buffer.")
105 :group 'hexl)
106 98
107(defvar hexl-max-address 0 99(defvar-local hexl-max-address 0
108 "Maximum offset into hexl buffer.") 100 "Maximum offset into hexl buffer.")
109 101
110(defvar hexl-mode-map 102(defvar hexl-mode-map
@@ -252,24 +244,6 @@ as that will override any bit grouping options set here."
252 "The length of a hexl display line (varies with `hexl-bits')." 244 "The length of a hexl display line (varies with `hexl-bits')."
253 (+ 60 (/ 128 (or hexl-bits 16)))) 245 (+ 60 (/ 128 (or hexl-bits 16))))
254 246
255(defun hexl-mode--minor-mode-p (var)
256 (memq var '(ruler-mode hl-line-mode)))
257
258(defun hexl-mode--setq-local (var val)
259 ;; `var' can be either a symbol or a pair, in which case the `car'
260 ;; is the getter function and the `cdr' is the corresponding setter.
261 (unless (or (member var hexl-mode--old-var-vals)
262 (assoc var hexl-mode--old-var-vals))
263 (push (if (or (consp var) (boundp var))
264 (cons var
265 (if (consp var) (funcall (car var)) (symbol-value var)))
266 var)
267 hexl-mode--old-var-vals))
268 (cond
269 ((consp var) (funcall (cdr var) val))
270 ((hexl-mode--minor-mode-p var) (funcall var (if val 1 -1)))
271 (t (set (make-local-variable var) val))))
272
273;;;###autoload 247;;;###autoload
274(defun hexl-mode (&optional arg) 248(defun hexl-mode (&optional arg)
275 "\\<hexl-mode-map>A mode for editing binary files in hex dump format. 249 "\\<hexl-mode-map>A mode for editing binary files in hex dump format.
@@ -364,35 +338,33 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
364 (or (bolp) (setq original-point (1- original-point)))) 338 (or (bolp) (setq original-point (1- original-point))))
365 (hexlify-buffer) 339 (hexlify-buffer)
366 (restore-buffer-modified-p modified)) 340 (restore-buffer-modified-p modified))
367 (set (make-local-variable 'hexl-max-address) 341 (setq hexl-max-address
368 (+ (* (/ (1- (buffer-size)) (hexl-line-displen)) 16) 15)) 342 (+ (* (/ (1- (buffer-size)) (hexl-line-displen)) 16) 15))
369 (condition-case nil 343 (condition-case nil
370 (hexl-goto-address original-point) 344 (hexl-goto-address original-point)
371 (error nil))) 345 (error nil)))
372 346
373 ;; We do not turn off the old major mode; instead we just 347 (let ((max-address hexl-max-address))
374 ;; override most of it. That way, we can restore it perfectly. 348 (major-mode-suspend)
349 (setq hexl-max-address max-address))
375 350
376 (hexl-mode--setq-local '(current-local-map . use-local-map) hexl-mode-map) 351 (use-local-map hexl-mode-map)
377 352
378 (hexl-mode--setq-local 'mode-name "Hexl") 353 (setq-local mode-name "Hexl")
379 (hexl-mode--setq-local 'isearch-search-fun-function 354 (setq-local isearch-search-fun-function #'hexl-isearch-search-function)
380 'hexl-isearch-search-function) 355 (setq-local major-mode 'hexl-mode)
381 (hexl-mode--setq-local 'major-mode 'hexl-mode)
382 356
383 (hexl-mode--setq-local '(syntax-table . set-syntax-table) 357 ;; (set-syntax-table (standard-syntax-table))
384 (standard-syntax-table))
385 358
386 (add-hook 'write-contents-functions 'hexl-save-buffer nil t) 359 (add-hook 'write-contents-functions #'hexl-save-buffer nil t)
387 360
388 (hexl-mode--setq-local 'require-final-newline nil) 361 (setq-local require-final-newline nil)
389 362
390 363
391 (hexl-mode--setq-local 'font-lock-defaults '(hexl-font-lock-keywords t)) 364 (setq-local font-lock-defaults '(hexl-font-lock-keywords t))
392 365
393 (hexl-mode--setq-local 'revert-buffer-function 366 (setq-local revert-buffer-function #'hexl-revert-buffer-function)
394 #'hexl-revert-buffer-function) 367 (add-hook 'change-major-mode-hook #'hexl-maybe-dehexlify-buffer nil t)
395 (add-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer nil t)
396 368
397 ;; Set a callback function for eldoc. 369 ;; Set a callback function for eldoc.
398 (add-function :before-until (local 'eldoc-documentation-function) 370 (add-function :before-until (local 'eldoc-documentation-function)
@@ -401,7 +373,7 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
401 (eldoc-remove-command "hexl-save-buffer" 373 (eldoc-remove-command "hexl-save-buffer"
402 "hexl-current-address") 374 "hexl-current-address")
403 375
404 (if hexl-follow-ascii (hexl-follow-ascii 1))) 376 (if hexl-follow-ascii (hexl-follow-ascii-mode 1)))
405 (run-mode-hooks 'hexl-mode-hook)) 377 (run-mode-hooks 'hexl-mode-hook))
406 378
407 379
@@ -469,6 +441,7 @@ and edit the file in `hexl-mode'."
469 (hexl-mode))) 441 (hexl-mode)))
470 442
471(defun hexl-revert-buffer-function (_ignore-auto _noconfirm) 443(defun hexl-revert-buffer-function (_ignore-auto _noconfirm)
444 ;; FIXME: We don't obey revert-buffer-preserve-modes!
472 (let ((coding-system-for-read 'no-conversion) 445 (let ((coding-system-for-read 'no-conversion)
473 revert-buffer-function) 446 revert-buffer-function)
474 ;; Call the original `revert-buffer' without code conversion; also 447 ;; Call the original `revert-buffer' without code conversion; also
@@ -481,7 +454,7 @@ and edit the file in `hexl-mode'."
481 ;; already hexl-mode. 454 ;; already hexl-mode.
482 ;; 2. reset change-major-mode-hook in case that `hexl-mode' 455 ;; 2. reset change-major-mode-hook in case that `hexl-mode'
483 ;; previously added hexl-maybe-dehexlify-buffer to it. 456 ;; previously added hexl-maybe-dehexlify-buffer to it.
484 (remove-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer t) 457 (remove-hook 'change-major-mode-hook #'hexl-maybe-dehexlify-buffer t)
485 (setq major-mode 'fundamental-mode) 458 (setq major-mode 'fundamental-mode)
486 (hexl-mode))) 459 (hexl-mode)))
487 460
@@ -494,7 +467,7 @@ With arg, don't unhexlify buffer."
494 (inhibit-read-only t) 467 (inhibit-read-only t)
495 (original-point (1+ (hexl-current-address)))) 468 (original-point (1+ (hexl-current-address))))
496 (dehexlify-buffer) 469 (dehexlify-buffer)
497 (remove-hook 'write-contents-functions 'hexl-save-buffer t) 470 (remove-hook 'write-contents-functions #'hexl-save-buffer t)
498 (restore-buffer-modified-p modified) 471 (restore-buffer-modified-p modified)
499 (goto-char original-point) 472 (goto-char original-point)
500 ;; Maybe adjust point for the removed CR characters. 473 ;; Maybe adjust point for the removed CR characters.
@@ -504,27 +477,8 @@ With arg, don't unhexlify buffer."
504 (or (bobp) (setq original-point (1+ original-point)))) 477 (or (bobp) (setq original-point (1+ original-point))))
505 (goto-char original-point))) 478 (goto-char original-point)))
506 479
507 (remove-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer t) 480 (remove-hook 'change-major-mode-hook #'hexl-maybe-dehexlify-buffer t)
508 (remove-hook 'post-command-hook 'hexl-follow-ascii-find t) 481 (major-mode-restore))
509 (setq hexl-ascii-overlay nil)
510
511 (let ((mms ()))
512 (dolist (varval hexl-mode--old-var-vals)
513 (let* ((bound (consp varval))
514 (var (if bound (car varval) varval))
515 (val (cdr-safe varval)))
516 (cond
517 ((consp var) (funcall (cdr var) val))
518 ((hexl-mode--minor-mode-p var) (push (cons var val) mms))
519 (bound (set (make-local-variable var) val))
520 (t (kill-local-variable var)))))
521 (kill-local-variable 'hexl-mode--old-var-vals)
522 ;; Enable/disable minor modes. Do it after having reset the other vars,
523 ;; since some of them may affect the minor modes.
524 (dolist (mm mms)
525 (funcall (car mm) (if (cdr mm) 1 -1))))
526
527 (force-mode-line-update))
528 482
529(defun hexl-maybe-dehexlify-buffer () 483(defun hexl-maybe-dehexlify-buffer ()
530 "Convert a hexl format buffer to binary. 484 "Convert a hexl format buffer to binary.
@@ -534,7 +488,7 @@ Ask the user for confirmation."
534 (inhibit-read-only t) 488 (inhibit-read-only t)
535 (original-point (1+ (hexl-current-address)))) 489 (original-point (1+ (hexl-current-address))))
536 (dehexlify-buffer) 490 (dehexlify-buffer)
537 (remove-hook 'write-contents-functions 'hexl-save-buffer t) 491 (remove-hook 'write-contents-functions #'hexl-save-buffer t)
538 (restore-buffer-modified-p modified) 492 (restore-buffer-modified-p modified)
539 (goto-char original-point)))) 493 (goto-char original-point))))
540 494
@@ -1041,48 +995,47 @@ Embedded whitespace, dashes, and periods in the string are ignored."
1041 (error "Decimal number out of range") 995 (error "Decimal number out of range")
1042 (hexl-insert-multibyte-char num arg)))) 996 (hexl-insert-multibyte-char num arg))))
1043 997
1044(defun hexl-follow-ascii (&optional arg) 998(define-minor-mode hexl-follow-ascii-mode
1045 "Toggle following ASCII in Hexl buffers. 999 "Minor mode to follow ASCII in current Hexl buffer.
1046With prefix ARG, turn on following if and only if ARG is positive.
1047When following is enabled, the ASCII character corresponding to the 1000When following is enabled, the ASCII character corresponding to the
1048element under the point is highlighted. 1001element under the point is highlighted.
1049Customize the variable `hexl-follow-ascii' to disable this feature." 1002The default activation is controlled by `hexl-follow-ascii'."
1050 (interactive "P") 1003 (if hexl-follow-ascii-mode
1004 ;; turn it on
1005 (progn
1006 (unless hexl-ascii-overlay
1007 (setq hexl-ascii-overlay (make-overlay (point) (point)))
1008 (overlay-put hexl-ascii-overlay 'face 'highlight))
1009 (add-hook 'post-command-hook #'hexl-follow-ascii-find nil t))
1010 ;; turn it off
1011 (when hexl-ascii-overlay
1012 (delete-overlay hexl-ascii-overlay)
1013 (setq hexl-ascii-overlay nil))
1014 (remove-hook 'post-command-hook #'hexl-follow-ascii-find t)))
1015
1016(define-minor-mode hexl-follow-ascii
1017 "Toggle following ASCII in Hexl buffers.
1018Like `hexl-follow-ascii-mode' but remembers the choice globally."
1019 :global t
1051 (let ((on-p (if arg 1020 (let ((on-p (if arg
1052 (> (prefix-numeric-value arg) 0) 1021 (> (prefix-numeric-value arg) 0)
1053 (not hexl-ascii-overlay)))) 1022 (not hexl-ascii-overlay))))
1054 1023 (hexl-follow-ascii-mode (if on-p 1 -1))
1055 (if on-p 1024 ;; Remember this choice globally for later use.
1056 ;; turn it on 1025 (setq hexl-follow-ascii hexl-follow-ascii-mode)))
1057 (if (not hexl-ascii-overlay)
1058 (progn
1059 (setq hexl-ascii-overlay (make-overlay 1 1)
1060 hexl-follow-ascii t)
1061 (overlay-put hexl-ascii-overlay 'face 'highlight)
1062 (add-hook 'post-command-hook 'hexl-follow-ascii-find nil t)))
1063 ;; turn it off
1064 (if hexl-ascii-overlay
1065 (progn
1066 (delete-overlay hexl-ascii-overlay)
1067 (setq hexl-ascii-overlay nil
1068 hexl-follow-ascii nil)
1069 (remove-hook 'post-command-hook 'hexl-follow-ascii-find t)
1070 )))))
1071 1026
1072(defun hexl-activate-ruler () 1027(defun hexl-activate-ruler ()
1073 "Activate `ruler-mode'." 1028 "Activate `ruler-mode'."
1074 (require 'ruler-mode) 1029 (require 'ruler-mode)
1075 (hexl-mode--setq-local 'ruler-mode-ruler-function 1030 (setq-local ruler-mode-ruler-function #'hexl-mode-ruler)
1076 #'hexl-mode-ruler) 1031 (ruler-mode 1))
1077 (hexl-mode--setq-local 'ruler-mode t))
1078 1032
1079(defun hexl-follow-line () 1033(defun hexl-follow-line ()
1080 "Activate `hl-line-mode'." 1034 "Activate `hl-line-mode'."
1081 (require 'hl-line) 1035 (require 'hl-line)
1082 (hexl-mode--setq-local 'hl-line-range-function 1036 (setq-local hl-line-range-function #'hexl-highlight-line-range)
1083 #'hexl-highlight-line-range) 1037 (setq-local hl-line-face 'highlight) ;FIXME: Why?
1084 (hexl-mode--setq-local 'hl-line-face 'highlight) 1038 (hl-line-mode 1))
1085 (hexl-mode--setq-local 'hl-line-mode t))
1086 1039
1087(defun hexl-highlight-line-range () 1040(defun hexl-highlight-line-range ()
1088 "Return the range of address region for the point. 1041 "Return the range of address region for the point.
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index c504afa6970..0925c6ef9c5 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -412,9 +412,6 @@ call."
412(defvar-local image-multi-frame nil 412(defvar-local image-multi-frame nil
413 "Non-nil if image for the current Image mode buffer has multiple frames.") 413 "Non-nil if image for the current Image mode buffer has multiple frames.")
414 414
415(defvar image-mode-previous-major-mode nil
416 "Internal variable to keep the previous non-image major mode.")
417
418(defvar image-mode-map 415(defvar image-mode-map
419 (let ((map (make-sparse-keymap))) 416 (let ((map (make-sparse-keymap)))
420 (define-key map "\C-c\C-c" 'image-toggle-display) 417 (define-key map "\C-c\C-c" 'image-toggle-display)
@@ -551,7 +548,7 @@ Key bindings:
551 (unless (display-images-p) 548 (unless (display-images-p)
552 (error "Display does not support images")) 549 (error "Display does not support images"))
553 550
554 (kill-all-local-variables) 551 (major-mode-suspend)
555 (setq major-mode 'image-mode) 552 (setq major-mode 'image-mode)
556 553
557 (if (not (image-get-display-property)) 554 (if (not (image-get-display-property))
@@ -641,26 +638,7 @@ A non-mage major mode found from `auto-mode-alist' or fundamental mode
641displays an image file as text." 638displays an image file as text."
642 ;; image-mode-as-text = normal-mode + image-minor-mode 639 ;; image-mode-as-text = normal-mode + image-minor-mode
643 (let ((previous-image-type image-type)) ; preserve `image-type' 640 (let ((previous-image-type image-type)) ; preserve `image-type'
644 (if image-mode-previous-major-mode 641 (major-mode-restore '(image-mode image-mode-maybe image-mode-as-text))
645 ;; Restore previous major mode that was already found by this
646 ;; function and cached in `image-mode-previous-major-mode'
647 (funcall image-mode-previous-major-mode)
648 (let ((auto-mode-alist
649 (delq nil (mapcar
650 (lambda (elt)
651 (unless (memq (or (car-safe (cdr elt)) (cdr elt))
652 '(image-mode image-mode-maybe image-mode-as-text))
653 elt))
654 auto-mode-alist)))
655 (magic-fallback-mode-alist
656 (delq nil (mapcar
657 (lambda (elt)
658 (unless (memq (or (car-safe (cdr elt)) (cdr elt))
659 '(image-mode image-mode-maybe image-mode-as-text))
660 elt))
661 magic-fallback-mode-alist))))
662 (normal-mode)
663 (setq-local image-mode-previous-major-mode major-mode)))
664 ;; Restore `image-type' after `kill-all-local-variables' in `normal-mode'. 642 ;; Restore `image-type' after `kill-all-local-variables' in `normal-mode'.
665 (setq image-type previous-image-type) 643 (setq image-type previous-image-type)
666 ;; Enable image minor mode with `C-c C-c'. 644 ;; Enable image minor mode with `C-c C-c'.
diff --git a/lisp/subr.el b/lisp/subr.el
index 7ac1c912818..ca184d8fc81 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1866,7 +1866,7 @@ running their FOO-mode-hook."
1866 (push hook delayed-mode-hooks)) 1866 (push hook delayed-mode-hooks))
1867 ;; Normal case, just run the hook as before plus any delayed hooks. 1867 ;; Normal case, just run the hook as before plus any delayed hooks.
1868 (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) 1868 (setq hooks (nconc (nreverse delayed-mode-hooks) hooks))
1869 (and syntax-propertize-function 1869 (and (bound-and-true-p syntax-propertize-function)
1870 (not (local-variable-p 'parse-sexp-lookup-properties)) 1870 (not (local-variable-p 'parse-sexp-lookup-properties))
1871 ;; `syntax-propertize' sets `parse-sexp-lookup-properties' for us, but 1871 ;; `syntax-propertize' sets `parse-sexp-lookup-properties' for us, but
1872 ;; in order for the sexp primitives to automatically call 1872 ;; in order for the sexp primitives to automatically call
@@ -1908,6 +1908,36 @@ If you just want to check `major-mode', use `derived-mode-p'."
1908 "Non-nil if the current major mode is derived from one of MODES. 1908 "Non-nil if the current major mode is derived from one of MODES.
1909Uses the `derived-mode-parent' property of the symbol to trace backwards." 1909Uses the `derived-mode-parent' property of the symbol to trace backwards."
1910 (apply #'provided-mode-derived-p major-mode modes)) 1910 (apply #'provided-mode-derived-p major-mode modes))
1911
1912(defvar-local major-mode--suspended nil)
1913(put 'major-mode--suspended 'permanent-local t)
1914
1915(defun major-mode-suspend ()
1916 "Exit current major, remembering it."
1917 (let* ((prev-major-mode (or major-mode--suspended
1918 (unless (eq major-mode 'fundamental-mode)
1919 major-mode))))
1920 (kill-all-local-variables)
1921 (setq-local major-mode--suspended prev-major-mode)))
1922
1923(defun major-mode-restore (&optional avoided-modes)
1924 "Restore major mode earlier suspended with `major-mode-suspend'.
1925If there was no earlier suspended major mode, then fallback to `normal-mode',
1926tho trying to avoid AVOIDED-MODES."
1927 (if major-mode--suspended
1928 (funcall (prog1 major-mode--suspended
1929 (kill-local-variable 'major-mode--suspended)))
1930 (let ((auto-mode-alist
1931 (let ((alist (copy-sequence auto-mode-alist)))
1932 (dolist (mode avoided-modes)
1933 (setq alist (rassq-delete-all mode alist)))
1934 alist))
1935 (magic-fallback-mode-alist
1936 (let ((alist (copy-sequence magic-fallback-mode-alist)))
1937 (dolist (mode avoided-modes)
1938 (setq alist (rassq-delete-all mode alist)))
1939 alist)))
1940 (normal-mode))))
1911 1941
1912;;;; Minor modes. 1942;;;; Minor modes.
1913 1943
@@ -3034,6 +3064,8 @@ This function is like `insert', except it honors the variables
3034 (inhibit-read-only inhibit-read-only) 3064 (inhibit-read-only inhibit-read-only)
3035 end) 3065 end)
3036 3066
3067 ;; FIXME: This throws away any yank-undo-function set by previous calls
3068 ;; to insert-for-yank-1 within the loop of insert-for-yank!
3037 (setq yank-undo-function t) 3069 (setq yank-undo-function t)
3038 (if (nth 0 handler) ; FUNCTION 3070 (if (nth 0 handler) ; FUNCTION
3039 (funcall (car handler) param) 3071 (funcall (car handler) param)