summaryrefslogtreecommitdiff
path: root/recursive-narrow.el
blob: d93b7df30a69dfccf6524b770c885c8705e2ba55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
;;; recursive-narrow.el --- narrow-to-region that operates recursively

;; Copyright (C) 2010 Nathaniel Flath <flat0103@gmail.com>

;; Author: Nathaniel Flath <flat0103@gmail.com>
;; URL: http://github.com/nflath/recursive-narrow
;; Version: 20140811.1546
;; X-Original-Version: 20140801.1400
;; X-Original-Version: 1.3

;; This file is not part of GNU Emacs.

;;; Commentary:

;; This package defines two functions, recursive-narrow-to-region and
;; recursive-widen that replace the builtin functions narrow-to-region and
;; widen.  These functions operate the same way, except in the case of multiple
;; calls to recursive-narrow-to-region.  In this case, recursive-widen will go
;; to the previous buffer visibility, not make the entire buffer visible.

;;; Installation:

;; To install, put this file somewhere in your load-path and add the following
;; to your .emacs file:
;;
;; (require 'recursive-narrow)
;; (global-set-key (kbd "C-x n n") 'recursive-narrow-or-widen-dwim)
;; (global-set-key (kbd "C-x n w") 'recursive-widen-dwim)
;;

;;; License:

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 3
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Code:

(defgroup recursive-narrow nil
  "This module contains code for recursively narrowing and widening."
  :tag "User interface"
  :group 'recursive-narrow)

(defcustom recursive-narrow-dwim-functions nil
	"Functions to try for narrowing.
These functions do not get any arguments. They should narrow and
return non-nil if applicable."
	:type 'hook
	:group 'recursive-narrow)

(defvar recursive-narrow-buffers nil "List of buffer visibility settings.")

(defmacro recursive-narrow-save-position (body &optional unchanged)
	"Execute BODY and save the buffer visibility if changed.
Executes UNCHANGED if the buffer visibility has not changed."
	`(let ((previous-settings (cons (point-min) (point-max))))
		 ,body
		 (if (and (= (point-min) (car previous-settings))
							(= (point-max) (cdr previous-settings)))
				 ,unchanged
			;; We narrowed, so save the information
			(setq recursive-narrow-buffers
						(cons (cons (current-buffer) previous-settings)
									recursive-narrow-buffers)))))
	
(defun recursive-narrow-or-widen-dwim ()
  "If the region is active, narrow to that region.
Otherwise, narrow to the current function. If this has no effect,
widen the buffer. You can add more functions to
`recursive-narrow-dwim-functions'."
  (interactive)
  (recursive-narrow-save-position
	 (cond ((region-active-p) (narrow-to-region (region-beginning) (region-end)))
				 ((run-hook-with-args-until-success 'recursive-narrow-dwim-functions))
				 ((derived-mode-p 'prog-mode) (narrow-to-defun))
				 ((derived-mode-p 'org-mode) (org-narrow-to-subtree)))
	 ;; If we don't narrow
	 (progn
		 (message "Recursive buffers: %d" (length recursive-narrow-buffers))
		 (recursive-widen))))

(defun recursive-narrow-to-region (start end)
  "Replacement of `narrow-to-region'.
Performs the exact same function but also allows
`recursive-widen' to remove just one call to
`recursive-narrow-to-region'. START and END define the region."
  (interactive "r")
	(recursive-narrow-save-position (narrow-to-region start end)))

(defun recursive-narrow-to-defun (&optional arg)
  "Replacement of `narrow-to-defun'.
Performs the exact same function but also allows
`recursive-widen' to remove just one call to
`recursive-narrow-to-region'. Optional ARG is ignored."
  (interactive)
	(recursive-narrow-save-position
	 (narrow-to-defun)))

(defun recursive-widen ()
  "Replacement of widen that will only pop one level of visibility."
  (interactive)
  (let (widen-to)
    (if (assoc (current-buffer) recursive-narrow-buffers)
        (progn
          (setq widen-to (cdr (assoc (current-buffer) recursive-narrow-buffers)))
          (setq recursive-narrow-buffers (remove
                                          (assoc (current-buffer) recursive-narrow-buffers)
                                          recursive-narrow-buffers))
          (narrow-to-region (car widen-to) (cdr widen-to))
          (recenter))
      (widen))))


(global-set-key (kbd "C-x n w") 'recursive-widen)
(global-set-key (kbd "C-x n n") 'recursive-narrow-or-widen-dwim)

(provide 'recursive-narrow)

;;; recursive-narrow.el ends here