1;;; dired-single.el -- reuse the current dired buffer to visit another directory
2;; @(#) $Id: dired-single.el,v 1.6 2001/01/11 02:56:01 root Exp $
4;; This file is not part of Emacs
6;; Copyright (C) 2000-2001 by Joseph L. Casadonte Jr.
7;; Author: Joe Casadonte (emacs@northbound-train.com)
8;; Maintainer: Joe Casadonte (emacs@northbound-train.com)
9;; Created: August 17, 2000
10;; Latest Version: http://www.northbound-train.com/emacs.html
14;; This program is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation; either version 2, or (at your option)
19;; This program is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
24;; You should have received a copy of the GNU General Public License
25;; along with this program; see the file COPYING. If not, write to the
26;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27;; Boston, MA 02111-1307, USA.
28;;; **************************************************************************
32;; This package provides a way to reuse the current dired buffer to visit
33;; another directory (rather than creating a new buffer for the new directory).
34;; Optionally, it allows the user to specify a name that all such buffers will
35;; have, regardless of the directory they point to.
39;; Put this file on your Emacs-Lisp load path and add the following to your
40;; ~/.emacs startup file
42;; (require 'dired-single)
44;; See below for key-binding suggestions.
48;; M-x `joc-dired-single-buffer'
49;; Visits the selected directory in the current buffer, replacing the
50;; current contents with the contents of the new directory. This doesn't
51;; prevent you from having more than one dired buffer. The main difference
52;; is that a given dired buffer will not spawn off a new buffer every time
53;; a new directory is visited.
55;; If the variable joc-dired-use-magic-buffer is non-nil, and the current
56;; buffer's name is the same as that specified by the variable
57;; joc-dired-magic-buffer-name, then the new directory's buffer will retain
58;; that same name (i.e. not only will dired only use a single buffer, but
59;; its name will not change every time a new directory is entered).
61;; See below for key-binding recommendations.
63;; M-x `joc-dired-single-buffer-mouse'
64;; Essentially this is the same as joc-dired-single-buffer, except that the
65;; action is initiated by a mouse-click instead of a keystroke.
67;; See below for key-binding recommendations.
69;; M-x `joc-dired-magic-buffer'
70;; Switch to an existing buffer whose name is the value of
71;; joc-dired-magic-buffer-name. If no such buffer exists, launch dired in a
72;; new buffer and rename that buffer to the value of
73;; joc-dired-magic-buffer-name. If the current buffer is the magic buffer,
74;; it will prompt for a new directory to visit.
76;; See below for key-binding recommendations.
78;; M-x `joc-dired-toggle-buffer-name'
79;; Toggle between the `magic' buffer name and the `real' dired buffer
80;; name. Will also seek to uniquify the `real' buffer name.
82;; See below for key-binding recommendations.
84;;; Recomended Keybindings:
86;; To use the single-buffer feature most effectively, I recommend adding the
87;; following code to your .emacs file. Basically, it remaps the [Return] key
88;; to call the joc-dired-single-buffer function instead of its normal function
89;; (dired-advertised-find-file). Also, it maps the caret ("^") key
90;; to go up one directory, using the joc-dired-single-buffer command instead of
91;; the normal one (dired-up-directory), which has the same effect as hitting
92;; [Return] on the parent directory line ("..")). Finally, it maps a
93;; button-one click to the joc-dired-single-buffer-mouse function, which does
94;; some mouse selection stuff, and then calls into the main
95;; joc-dired-single-buffer function.
97;; NOTE: This should only be done for the dired-mode-map (NOT globally!).
99;; The following code will work whether or not dired has been loaded already.
101;; (defun my-dired-init ()
102;; "Bunch of stuff to run for dired, either immediately or when it's
104;; ;; <add other stuff here>
105;; (define-key dired-mode-map [return] 'joc-dired-single-buffer)
106;; (define-key dired-mode-map [mouse-1] 'joc-dired-single-buffer-mouse)
107;; (define-key dired-mode-map "^"
109;; (lambda nil (interactive) (joc-dired-single-buffer "..")))))
111;; ;; if dired's already loaded, then the keymap will be bound
112;; (if (boundp 'dired-mode-map)
113;; ;; we're good to go; just add our bindings
115;; ;; it's not loaded yet, so add our bindings to the load-hook
116;; (add-hook 'dired-load-hook 'my-dired-init))
118;; To use the magic-buffer function, you first need to start dired in a buffer
119;; whose name is the value of joc-dired-magic-buffer-name. Once the buffer
120;; has this name, it will keep it unless explicitly renamed. Use the function
121;; joc-dired-magic-buffer to start this initial dired magic buffer (or you can
122;; simply rename an existing dired buffer to the magic name). I bind this
123;; function globally, so that I can always get back to my magic buffer from
124;; anywhere. Likewise, I bind another key to bring the magic buffer up in the
125;; current default-directory, allowing me to move around fairly easily. Here's
126;; what I have in my .emacs file:
128;; (global-set-key [(f5)] 'joc-dired-magic-buffer)
129;; (global-set-key [(control f5)] (function
130;; (lambda nil (interactive)
131;; (joc-dired-magic-buffer default-directory))))
132;; (global-set-key [(shift f5)] (function
133;; (lambda nil (interactive)
134;; (message "Current directory is: %s" default-directory))))
135;; (global-set-key [(meta f5)] 'joc-dired-toggle-buffer-name)
137;; Of course, these are only suggestions.
141;; M-x `joc-dired-single-customize' to customize all package options.
143;; The following variables can be customized:
145;; o `joc-dired-use-magic-buffer'
146;; Boolean used to determine if the joc-dired-single functions should
147;; look for and retain a specific buffer name. The buffer name to look
148;; for is specified with joc-dired-magic-buffer-name.
150;; o `joc-dired-magic-buffer-name'
151;; Name of buffer to use if joc-dired-use-magic-buffer is true. Once a
152;; dired buffer has this name, it will always keep this name (unless it's
153;; explicitly renamed by you).
157;; o Nothing, at the moment.
161;; The single buffer code is loosely based on code posted to the NT-Emacs
162;; mailing list by Steve Kemp & Rob Davenport. The magic buffer name code
167;; Any comments, suggestions, bug reports or upgrade requests are welcome.
168;; Please send them to Joe Casadonte (emacs@northbound-train.com).
170;; This version of dired-single was developed and tested with NTEmacs 20.5.1
171;; and 2.7 under Windows NT 4.0 SP6 and Emacs 20.7.1 under Linux (RH7).
172;; Please, let me know if it works with other OS and versions of Emacs.
174;;; **************************************************************************
175;;; **************************************************************************
176;;; **************************************************************************
177;;; **************************************************************************
178;;; **************************************************************************
181;;; **************************************************************************
182;;; ***** customization routines
183;;; **************************************************************************
184(defgroup joc-dired-single nil
185 "joc-dired-single package customization"
188;; ---------------------------------------------------------------------------
189(defun joc-dired-single-customize ()
190 "Customization of the group joc-dired-single."
192 (customize-group "joc-dired-single"))
194;; ---------------------------------------------------------------------------
195(defcustom joc-dired-use-magic-buffer t
196 "Boolean used to determine if the joc-dired-single functions should
197 look for and retain a specific buffer name. The buffer name to look
198 for is specified with joc-dired-magic-buffer-name."
199 :group 'joc-dired-single
202;; ---------------------------------------------------------------------------
203(defcustom joc-dired-magic-buffer-name "*dired*"
204 "Name of buffer to use if joc-dired-use-magic-buffer is true. Once a
205 dired buffer has this name, it will always keep this name (unless it's
206 explicitly renamed by you)."
207 :group 'joc-dired-single
210;;; **************************************************************************
211;;; ***** version related routines
212;;; **************************************************************************
213(defconst joc-dired-single-version
215 "joc-dired-single version number.")
217;; ---------------------------------------------------------------------------
218(defun joc-dired-single-version-number ()
219 "Returns joc-dired-single version number."
220 (string-match "[0123456789.]+" joc-dired-single-version)
221 (match-string 0 joc-dired-single-version))
223;; ---------------------------------------------------------------------------
224(defun joc-dired-single-display-version ()
225 "Displays joc-dired-single version."
227 (message "joc-dired-single version <%s>." (joc-dired-single-version-number)))
229;;; **************************************************************************
230;;; ***** interactive functions
231;;; **************************************************************************
232(defun joc-dired-single-buffer (&optional default-dirname)
233 "Visits the selected directory in the current buffer, replacing the
234 current contents with the contents of the new directory. This doesn't
235 prevent you from having more than one dired buffer. The main difference
236 is that a given dired buffer will not spawn off a new buffer every time
237 a new directory is visited.
239 If the variable joc-dired-use-magic-buffer is non-nil, and the current
240 buffer's name is the same as that specified by the variable
241 joc-dired-magic-buffer-name, then the new directory's buffer will retain
242 that same name (i.e. not only will dired only use a single buffer, but
243 its name will not change every time a new directory is entered)."
245 ;; use arg passed in or find name of current line
246 (let ((name (or default-dirname (dired-get-filename))))
249 ;; See if the selection is a directory or not.
253 ;; assume directory if arg passed in
254 (if (or default-dirname (re-search-forward "^ d" eol t))
255 ;; save current buffer's name
256 (let ((current-buffer-name (buffer-name)))
257 ;; go ahead and read in the directory
258 (find-alternate-file name)
259 ;; if the saved buffer's name was the magic name, rename this buffer
260 (if (and joc-dired-use-magic-buffer
261 (string= current-buffer-name joc-dired-magic-buffer-name))
262 (rename-buffer joc-dired-magic-buffer-name)))
264 (find-file name)))))))
266;;;; ------------------------------------------------------------------------
267(defun joc-dired-single-buffer-mouse (click)
268 "Essentially this is the same as joc-dired-single-buffer, except that the
269 action is initiated by a mouse-click instead of a keystroke."
271 (let* ( (start (event-start click))
273 (pos (car (cdr start))) )
274 (select-window window)
276 (joc-dired-single-buffer))
278;;;; ------------------------------------------------------------------------
279(defun joc-dired-magic-buffer (&optional default-dirname)
280 "Switch to an existing buffer whose name is the value of
281 joc-dired-magic-buffer-name. If no such buffer exists, launch dired in a
282 new buffer and rename that buffer to the value of
283 joc-dired-magic-buffer-name. If the current buffer is the magic buffer,
284 it will prompt for a new directory to visit."
286 ;; do we not have one or are we already in it?
287 (let ((magic-dired-buffer (get-buffer joc-dired-magic-buffer-name)))
288 (if (or (eq magic-dired-buffer nil)
289 (eq magic-dired-buffer (current-buffer)))
290 ;; nothing to switch to
291 ;; get directory name to start in
292 (let ((dirname (or default-dirname
293 (read-file-name (format "Dired %s(directory): " "")
294 nil default-directory t))))
296 ;; make sure it's really a directory
297 (if (not (file-directory-p dirname))
298 (error "Error: <%s> is not a directory" dirname))
300 ;; do we need a new buffer?
301 (if (eq magic-dired-buffer nil)
302 ;; find the file in new buffer, current window
304 ;; just find in place of current buffer
305 (find-alternate-file dirname))
306 ;; rename the buffer, where ever we found it
307 (rename-buffer joc-dired-magic-buffer-name))
308 ;; we're not there (we have one already), so simply switch to it
309 (switch-to-buffer magic-dired-buffer)
310 ;; if called with a default, try it again
312 (joc-dired-magic-buffer default-dirname)))))
314;;;; ------------------------------------------------------------------------
315(defun joc-dired-toggle-buffer-name ()
316 "Toggle between the `magic' buffer name and the `real' dired buffer
317 name. Will also seek to uniquify the `real' buffer name."
320 ;; make sure it's a dired buffer
321 (if (not (string= major-mode "dired-mode"))
322 (error "Error: not a dired buffer"))
324 ;; do we have magic name currently?
325 (if (string= (buffer-name) joc-dired-magic-buffer-name)
327 (abbreviate-file-name
328 (expand-file-name (directory-file-name default-directory))) t)
330 ;; make sure the buffer doesn't currently exist
331 (let ((existing-buffer (get-buffer joc-dired-magic-buffer-name)))
333 (kill-buffer existing-buffer))
334 (rename-buffer joc-dired-magic-buffer-name))))
336;;; **************************************************************************
338;;; **************************************************************************
339(provide 'dired-single)
340;; dired-single.el ends here