Subject: bug#17401: 24.4.50; Narrow to {region,page,defun} in an indirect clone buffer in the other window

From: Phil Sainty <[email-masked]>
Date: Sun, 04 May 2014 22:38:09 +1200

I encountered a blog post by Zane Ashby detailing this idea, and it
was one of those "why did I never think of that?" moments, because
I was doing this manually on a regular basis.

http://demonastery.org/2013/04/emacs-narrow-to-region-indirect/

That post provides a function which creates a indirect clone of
the current buffer, and narrows to the marked region in that, so
that you have both the original un-narrowed buffer and the narrowed
indirect clone available simultaneously.

This is incredibly useful, and it seems like an obvious contender
for standard functionality in Emacs.

I'm attaching a patch which uses that approach to implement the
following functions and bindings:

C-x 4 n n: narrow-to-region-indirect-other-window
C-x 4 n p: narrow-to-page-indirect-other-window
C-x 4 n d: narrow-to-defun-indirect-other-window

It's still essentially Zane's code, so I've confirmed that he's
happy for me to send this, and am CCing this to him.

-Phil

In GNU Emacs 24.4.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.24.10)
 of 2014-05-03 on xerxes
Windowing system distributor `The X.Org Foundation', version 11.0.11300000
System Description:	Ubuntu 12.04.4 LTS

Configured using:
 `configure --prefix=/usr/local/src/emacs/usr/local --without-sound'

Configured features:
XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK DBUS GSETTINGS NOTIFY GNUTLS
LIBXML2 FREETYPE XFT ZLIB

Important settings:
  value of $LANG: en_NZ.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Recent input:
<help-echo> M-x r e p o r t - e m <tab> <return>

Recent messages:
For information about GNU Emacs and the GNU system, type C-h C-a.
user-error: End of history; no default available

Load-path shadows:
None found.

Features:
(shadow sort gnus-util mail-extr emacsbug message dired format-spec
rfc822 mml easymenu mml-sec mm-decode mm-bodies mm-encode mail-parse
rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045
ietf-drums mm-util help-fns mail-prsvr mail-utils time-date tooltip
electric uniquify ediff-hook vc-hooks lisp-float-type mwheel x-win x-dnd
tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment
lisp-mode prog-mode register page menu-bar rfn-eshadow timer select
scroll-bar mouse jit-lock font-lock syntax facemenu font-core frame cham
georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese hebrew greek romanian slovak czech european ethiopic
indian cyrillic chinese case-table epa-hook jka-cmpr-hook help simple
abbrev minibuffer nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote make-network-process
dbusbind gfilenotify dynamic-setting system-font-setting
font-render-setting move-toolbar gtk x-toolkit x multi-tty emacs)

Memory information:
((conses 16 74917 6338)
 (symbols 48 17834 0)
 (miscs 40 35 138)
 (strings 32 10321 4869)
 (string-bytes 1 288458)
 (vectors 16 9191)
 (vector-slots 8 374331 12806)
 (floats 8 63 98)
 (intervals 56 170 0)
 (buffers 960 11)
 (heap 1024 19710 771))

diff --git a/lisp/bindings.el b/lisp/bindings.el
index 7093b8e..e8352ef 100644
--- a/lisp/bindings.el
+++ b/lisp/bindings.el
@@ -1270,6 +1270,9 @@ if `inhibit-field-text-motion' is non-nil."
 
 (define-key ctl-x-4-map "a" 'add-change-log-entry-other-window)
 (define-key ctl-x-4-map "c" 'clone-indirect-buffer-other-window)
+(define-key ctl-x-4-map "nn" 'narrow-to-region-indirect-other-window)
+(define-key ctl-x-4-map "np" 'narrow-to-page-indirect-other-window)
+(define-key ctl-x-4-map "nd" 'narrow-to-defun-indirect-other-window)
 
 ;; Signal handlers
 (define-key special-event-map [sigusr1] 'ignore)
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 3ff65ff..7119ef6 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -556,6 +556,16 @@ Optional ARG is ignored."
       (re-search-backward "^\n" (- (point) 1) t)
       (narrow-to-region beg end))))
 
+(defun narrow-to-defun-indirect-other-window (&optional arg)
+  "`narrow-to-defun' in a cloned indirect buffer in the other window.
+
+See `clone-indirect-buffer'."
+  (interactive)
+  (let ((buf (clone-indirect-buffer nil nil)))
+    (with-current-buffer buf
+      (narrow-to-defun arg))
+    (pop-to-buffer buf)))
+
 (defvar insert-pair-alist
   '((?\( ?\)) (?\[ ?\]) (?\{ ?\}) (?\< ?\>) (?\" ?\") (?\' ?\') (?\` ?\'))
   "Alist of paired characters inserted by `insert-pair'.
diff --git a/lisp/simple.el b/lisp/simple.el
index 1484339..156d1bd 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -7570,6 +7570,16 @@ front of the list of recently selected ones."
   (let ((pop-up-windows t))
     (clone-indirect-buffer newname display-flag norecord)))
 
+(defun narrow-to-region-indirect-other-window (start end)
+  "`narrow-to-region' in a cloned indirect buffer in the other window.
+
+See `clone-indirect-buffer'."
+  (interactive "r")
+  (deactivate-mark)
+  (let ((buf (clone-indirect-buffer nil nil)))
+    (with-current-buffer buf
+      (narrow-to-region start end))
+    (pop-to-buffer buf)))
 
 ;;; Handling of Backspace and Delete keys.
 
diff --git a/lisp/textmodes/page.el b/lisp/textmodes/page.el
index d535108..866e96a 100644
--- a/lisp/textmodes/page.el
+++ b/lisp/textmodes/page.el
@@ -125,6 +125,16 @@ thus showing a page other than the one point was originally in."
 			(point)))))
 (put 'narrow-to-page 'disabled t)
 
+(defun narrow-to-page-indirect-other-window (&optional arg)
+  "`narrow-to-page' in a cloned indirect buffer in the other window.
+
+See `clone-indirect-buffer'."
+  (interactive "P")
+  (let ((buf (clone-indirect-buffer nil nil)))
+    (with-current-buffer buf
+      (narrow-to-page arg))
+    (pop-to-buffer buf)))
+
 (defun count-lines-page ()
   "Report number of lines on current page, and how many are before or after point."
   (interactive)