Subject: 24.3.50; [PATCH] Enable narrowing to defun with function header comments also visible
From: Phil Sainty <[email-masked]>
To: [email-masked]
Date: Fri, 03 Jan 2014 21:57:22 +1300
List-Id: <debbugs-submit.debbugs.gnu.org>

For languages where the programmer must resort to function header
comments to describe a function, I've always found it frustrating
that `narrow-to-defun' cuts out this often-critical information.

This patch provides a new function `narrow-to-defun-including-comments'
to keep these comments visible when narrowing.

As there may be multiple per-line comments instead of a single block
comment, I'm skipping back past ALL preceding comments. That seemed
reasonable instead of trying to guess how the author has structured
their comments. Stopping at an empty line would *probably* be okay,
but in the end I figured that potentially showing too much seemed
better than showing too little.

(I've included a check for page breaks within the comments, however,
as I was confident about excluding anything before one of those.)

I didn't think it was wise to encourage users to modify the behaviour
of `narrow-to-defun' itself (I certainly have programmatic uses for
that), so instead I've indicated the way to remap the interactive
bindings for users who wish to use this as standard.

-Phil
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 3ff4f64..4e2dd45 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -444,10 +444,32 @@ it marks the next defun after the ones already marked."
 	     (beginning-of-defun))
 	   (re-search-backward "^\n" (- (point) 1) t)))))
 
+(defvar narrow-to-defun-include-comments nil
+  "If non-nil, `narrow-to-defun' will also show comments preceding the defun.
+
+You should call `narrow-to-defun-including-comments' instead of setting
+this value manually.")
+
+(defun narrow-to-defun-including-comments ()
+  "Make text outside current defun and its preceding comments invisible.
+The current defun is the one that contains point or follows point.
+
+If you wish to always use this interactively instead of `narrow-to-defun',
+you should remap its key bindings:
+
+ (global-set-key [remap narrow-to-defun] 'narrow-to-defun-including-comments)"
+  (interactive)
+  (let ((narrow-to-defun-include-comments t))
+    (narrow-to-defun)))
+
 (defun narrow-to-defun (&optional _arg)
   "Make text outside current defun invisible.
-The defun visible is the one that contains point or follows point.
-Optional ARG is ignored."
+The current defun is the one that contains point or follows point.
+
+Optional ARG is ignored.
+
+To make any comments preceding the defun visible as well, call
+`narrow-to-defun-including-comments' instead."
   (interactive)
   (save-excursion
     (widen)
@@ -484,6 +506,18 @@ Optional ARG is ignored."
 	(setq end (point))
 	(beginning-of-defun)
 	(setq beg (point)))
+      (when narrow-to-defun-include-comments
+	(goto-char beg)
+	;; Move back past all preceding comments (and whitespace).
+	(when (forward-comment -1)
+	  (while (forward-comment -1))
+	  ;; Move forwards past any page breaks within these comments.
+	  (when (and page-delimiter (not (string= page-delimiter "")))
+	    (while (re-search-forward page-delimiter beg t)))
+	  ;; Lastly, move past any empty lines.
+	  (skip-chars-forward "[:space:]\n")
+	  (beginning-of-line)
+	  (setq beg (point))))
       (goto-char end)
       (re-search-backward "^\n" (- (point) 1) t)
       (narrow-to-region beg end))))