diff --git a/lisp/bindings.el b/lisp/bindings.el index 2e32128274..109a1a411f 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -968,8 +968,8 @@ left-word (defvar-keymap narrow-map :doc "Keymap for narrowing commands." - "n" #'narrow-to-region - "w" #'widen + "n" #'soft-narrow-to-region + "w" #'soft-widen "g" #'goto-line-relative) (define-key ctl-x-map "n" narrow-map) diff --git a/lisp/isearch.el b/lisp/isearch.el index 31fcf01949..285c92f850 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1321,9 +1321,10 @@ isearch-mode ;; Pushing the initial state used to be before running isearch-mode-hook, ;; but a hook might set `isearch-push-state-function' used in ;; `isearch-push-state' to save mode-specific initial state. (Bug#4994) - (isearch-push-state) + (with-soft-narrow + (isearch-push-state) - (isearch-update) + (isearch-update)) (add-hook 'pre-command-hook 'isearch-pre-command-hook) (add-hook 'post-command-hook 'isearch-post-command-hook) @@ -1358,7 +1359,7 @@ isearch-update (if (and (null unread-command-events) (null executing-kbd-macro)) - (progn + (with-soft-narrow (if (not (input-pending-p)) (funcall (or isearch-message-function #'isearch-message))) (if (and isearch-slow-terminal-mode diff --git a/lisp/simple.el b/lisp/simple.el index 1e6e5e11e0..78d0804ee8 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -1647,6 +1647,14 @@ goto-line (widen)) (goto-char pos))) +(defmacro with-soft-narrow (&rest body) + (declare (indent 1) (debug t)) + `(let ((bounds (soft-narrow-bounds))) + (save-restriction + (when bounds + (narrow-to-region (car bounds) (cdr bounds))) + ,@body))) + (defun goto-line-relative (line &optional buffer) "Go to LINE, counting from line at (point-min). The line number is relative to the accessible portion of the narrowed @@ -1654,7 +1662,8 @@ goto-line-relative (declare (interactive-only forward-line)) (interactive (goto-line-read-args t)) (with-suppressed-warnings ((interactive-only goto-line)) - (goto-line line buffer t))) + (with-soft-narrow + (goto-line line buffer t)))) (defun count-words-region (start end &optional arg) "Count the number of words in the region. @@ -10707,6 +10716,40 @@ lax-plist-put "Change value in PLIST of PROP to VAL, comparing with `equal'." (declare (obsolete plist-put "29.1")) (plist-put plist prop val #'equal)) + +(defvar soft-narrow--overlays nil) + +(defun soft-widen () + (interactive) + (when soft-narrow--overlays + (with-soft-narrow + ;; If cursor is after the cdr ovl or before car ovl, + ;; move it inside. + (delete-overlay (car soft-narrow--overlays)) + (delete-overlay (cdr soft-narrow--overlays))) + (setq soft-narrow--overlays nil))) + +(defun soft-narrow-to-region (beg end) + (interactive "r") + (soft-widen) + (let ((o1 (make-overlay (point-min) beg)) + (o2 (make-overlay end (point-max) nil t t))) + (overlay-put o1 'invisible t) + (overlay-put o1 'read-only t) + (overlay-put o1 'modification-hooks '(soft-narrow--modif)) + (overlay-put o2 'invisible t) + (overlay-put o2 'read-only t) + (overlay-put o2 'modification-hooks '(soft-narrow--modif)) + (setq soft-narrow--overlays (cons o1 o2)))) + +(defun soft-narrow--modif (&rest _) + (user-error "Not allowed")) + +(defun soft-narrow-bounds () + (when soft-narrow--overlays + (cons (overlay-end (car soft-narrow--overlays)) + (overlay-start (cdr soft-narrow--overlays))))) + (provide 'simple)