dired-single.el 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. ;;; @(#) dired-single.el -- reuse the current dired buffer to visit another directory
  2. ;;; @(#) $Id: dired-single.el,v 1.7 2008/10/30 01:49:22 joe Exp $
  3. ;; This file is not part of Emacs
  4. ;; Copyright (C) 2000-2001 by Joseph L. Casadonte Jr.
  5. ;; Author: Joe Casadonte (emacs@northbound-train.com)
  6. ;; Maintainer: Joe Casadonte (emacs@northbound-train.com)
  7. ;; Created: August 17, 2000
  8. ;; Keywords: dired reuse buffer
  9. ;; Latest Version: http://www.northbound-train.com/emacs.html
  10. ;; COPYRIGHT NOTICE
  11. ;; This program is free software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 2, or (at your option)
  14. ;; any later version.
  15. ;; This program is distributed in the hope that it will be useful,
  16. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;; GNU General Public License for more details.
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with this program; see the file COPYING. If not, write to the
  21. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  22. ;; Boston, MA 02111-1307, USA.
  23. ;;; Commentary:
  24. ;;
  25. ;; This package provides a way to reuse the current dired buffer to visit
  26. ;; another directory (rather than creating a new buffer for the new directory).
  27. ;; Optionally, it allows the user to specify a name that all such buffers will
  28. ;; have, regardless of the directory they point to.
  29. ;;; Installation:
  30. ;;
  31. ;; Put this file on your Emacs-Lisp load path and add the following to your
  32. ;; ~/.emacs startup file
  33. ;;
  34. ;; (require 'dired-single)
  35. ;;
  36. ;; or you can load the package via autoload:
  37. ;;
  38. ;; (autoload 'dired-single-buffer "dired-single" "" t)
  39. ;; (autoload 'dired-single-buffer-mouse "dired-single" "" t)
  40. ;; (autoload 'dired-single-magic-buffer "dired-single" "" t)
  41. ;; (autoload 'dired-single-toggle-buffer-name "dired-single" "" t)
  42. ;;
  43. ;; To add a directory to your load-path, use something like the following:
  44. ;;
  45. ;; (setq load-path (cons (expand-file-name "/some/load/path") load-path))
  46. ;;
  47. ;; See below for key-binding suggestions.
  48. ;;; Usage:
  49. ;;
  50. ;; M-x `dired-single-buffer'
  51. ;; Visits the selected directory in the current buffer, replacing the
  52. ;; current contents with the contents of the new directory. This doesn't
  53. ;; prevent you from having more than one dired buffer. The main difference
  54. ;; is that a given dired buffer will not spawn off a new buffer every time
  55. ;; a new directory is visited.
  56. ;;
  57. ;; If the variable dired-single-use-magic-buffer is non-nil, and the current
  58. ;; buffer's name is the same as that specified by the variable
  59. ;; dired-single-magic-buffer-name, then the new directory's buffer will retain
  60. ;; that same name (i.e. not only will dired only use a single buffer, but
  61. ;; its name will not change every time a new directory is entered).
  62. ;;
  63. ;; See below for key-binding recommendations.
  64. ;;
  65. ;; M-x `dired-single-buffer-mouse'
  66. ;; Essentially this is the same as `dired-single-buffer', except that the
  67. ;; action is initiated by a mouse-click instead of a keystroke.
  68. ;;
  69. ;; See below for key-binding recommendations.
  70. ;;
  71. ;; M-x `dired-single-magic-buffer'
  72. ;; Switch to an existing buffer whose name is the value of
  73. ;; dired-single-magic-buffer-name. If no such buffer exists, launch dired in a
  74. ;; new buffer and rename that buffer to the value of
  75. ;; dired-single-magic-buffer-name. If the current buffer is the magic buffer,
  76. ;; it will prompt for a new directory to visit.
  77. ;;
  78. ;; See below for key-binding recommendations.
  79. ;;
  80. ;; M-x `dired-single-toggle-buffer-name'
  81. ;; Toggle between the 'magic' buffer name and the 'real' dired buffer
  82. ;; name. Will also seek to uniquify the 'real' buffer name.
  83. ;;
  84. ;; See below for key-binding recommendations.
  85. ;;; Recomended Keybindings:
  86. ;;
  87. ;; To use the single-buffer feature most effectively, I recommend adding the
  88. ;; following code to your .emacs file. Basically, it remaps the [Return] key
  89. ;; to call the `dired-single-buffer' function instead of its normal
  90. ;; function (`dired-advertised-find-file'). Also, it maps the caret ("^")
  91. ;; key to go up one directory, using the `dired-single-buffer' command
  92. ;; instead of the normal one (`dired-up-directory'), which has the same effect
  93. ;; as hitting [Return] on the parent directory line ("..")). Finally, it maps
  94. ;; a button-one click to the `dired-single-buffer-mouse' function, which
  95. ;; does some mouse selection stuff, and then calls into the main
  96. ;; `dired-single-buffer' function.
  97. ;;
  98. ;; NOTE: This should only be done for the `dired-mode-map' (NOT globally!).
  99. ;;
  100. ;; The following code will work whether or not dired has been loaded already.
  101. ;;
  102. ;; (defun my-dired-init ()
  103. ;; "Bunch of stuff to run for dired, either immediately or when it's
  104. ;; loaded."
  105. ;; ;; <add other stuff here>
  106. ;; (define-key dired-mode-map [return] 'dired-single-buffer)
  107. ;; (define-key dired-mode-map [mouse-1] 'dired-single-buffer-mouse)
  108. ;; (define-key dired-mode-map "^"
  109. ;; (function
  110. ;; (lambda nil (interactive) (dired-single-buffer "..")))))
  111. ;;
  112. ;; ;; if dired's already loaded, then the keymap will be bound
  113. ;; (if (boundp 'dired-mode-map)
  114. ;; ;; we're good to go; just add our bindings
  115. ;; (my-dired-init)
  116. ;; ;; it's not loaded yet, so add our bindings to the load-hook
  117. ;; (add-hook 'dired-load-hook 'my-dired-init))
  118. ;;
  119. ;; To use the magic-buffer function, you first need to start dired in a buffer
  120. ;; whose name is the value of dired-single-magic-buffer-name. Once the buffer
  121. ;; has this name, it will keep it unless explicitly renamed. Use the function
  122. ;; dired-single-magic-buffer to start this initial dired magic buffer (or you can
  123. ;; simply rename an existing dired buffer to the magic name). I bind this
  124. ;; function globally, so that I can always get back to my magic buffer from
  125. ;; anywhere. Likewise, I bind another key to bring the magic buffer up in the
  126. ;; current default-directory, allowing me to move around fairly easily. Here's
  127. ;; what I have in my .emacs file:
  128. ;;
  129. ;; (global-set-key [(f5)] 'dired-single-magic-buffer)
  130. ;; (global-set-key [(control f5)] (function
  131. ;; (lambda nil (interactive)
  132. ;; (dired-single-magic-buffer default-directory))))
  133. ;; (global-set-key [(shift f5)] (function
  134. ;; (lambda nil (interactive)
  135. ;; (message "Current directory is: %s" default-directory))))
  136. ;; (global-set-key [(meta f5)] 'dired-single-toggle-buffer-name)
  137. ;;
  138. ;; Of course, these are only suggestions.
  139. ;;; Customization:
  140. ;;
  141. ;; M-x `dired-single-customize' to customize all package options.
  142. ;;
  143. ;; The following variables can be customized:
  144. ;;
  145. ;; o `dired-single-use-magic-buffer'
  146. ;; Boolean used to determine if the dired-single functions should look
  147. ;; for and retain a specific buffer name. The buffer name to look for
  148. ;; is specified with `dired-single-magic-buffer-name'.
  149. ;;
  150. ;; o `dired-single-magic-buffer-name'
  151. ;; Name of buffer to use if `dired-single-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).
  154. ;;; To Do:
  155. ;;
  156. ;; o Nothing, at the moment.
  157. ;;; Credits:
  158. ;;
  159. ;; The single buffer code is loosely based on code posted to the NT-Emacs
  160. ;; mailing list by Steve Kemp & Rob Davenport. The magic buffer name code
  161. ;; is all mine.
  162. ;;; Comments:
  163. ;;
  164. ;; Any comments, suggestions, bug reports or upgrade requests are welcome.
  165. ;; Please send them to Joe Casadonte (emacs@northbound-train.com).
  166. ;;
  167. ;; This version of dired-single was developed and tested with NTEmacs 20.5.1
  168. ;; under Windows NT 4.0 SP6 and Emacs 20.7.1 under Linux (RH7). Please, let
  169. ;; me know if it works with other OS and versions of Emacs.
  170. ;;; Change Log:
  171. ;;
  172. ;; see http://www.northbound-train.com/emacs/dired-single.log
  173. ;;; **************************************************************************
  174. ;;; **************************************************************************
  175. ;;; **************************************************************************
  176. ;;; **************************************************************************
  177. ;;; **************************************************************************
  178. ;;; Code:
  179. (eval-when-compile
  180. (defvar byte-compile-dynamic nil) ; silence the old byte-compiler
  181. (set (make-local-variable 'byte-compile-dynamic) t))
  182. (eval-and-compile
  183. (autoload 'dired-get-filename "dired"))
  184. ;;; **************************************************************************
  185. ;;; ***** customization routines
  186. ;;; **************************************************************************
  187. (defgroup dired-single nil
  188. "dired-single package customization"
  189. :group 'tools)
  190. ;; ---------------------------------------------------------------------------
  191. (defun dired-single-customize ()
  192. "Customization of the group `dired-single'."
  193. (interactive)
  194. (customize-group "dired-single"))
  195. ;; ---------------------------------------------------------------------------
  196. (defcustom dired-single-use-magic-buffer t
  197. "Boolean that indicates the use of a single dired buffer name.
  198. It is used to determine if the dired-single functions should look for and
  199. retain a specific buffer name. The buffer name to look for is specified
  200. with `dired-single-magic-buffer-name'."
  201. :group 'dired-single
  202. :type 'boolean)
  203. ;; ---------------------------------------------------------------------------
  204. (defcustom dired-single-magic-buffer-name "*dired*"
  205. "Name of buffer to use if `dired-single-use-magic-buffer' is true.
  206. Once a dired buffer has this name, it will always keep this name (unless it's
  207. explicitly renamed by you)."
  208. :group 'dired-single
  209. :type 'string)
  210. ;; ---------------------------------------------------------------------------
  211. (defcustom dired-single-load-hook nil
  212. "Hook to run when package is loaded."
  213. :type 'hook
  214. :group 'dired-single)
  215. ;;; **************************************************************************
  216. ;;; ***** version related routines
  217. ;;; **************************************************************************
  218. (defconst dired-single-version
  219. "$Revision: 1.7 $"
  220. "Version number for dired-single package.")
  221. ;; ---------------------------------------------------------------------------
  222. (defun dired-single-version-number ()
  223. "Return dired-single version number."
  224. (string-match "[0123456789.]+" dired-single-version)
  225. (match-string 0 dired-single-version))
  226. ;; ---------------------------------------------------------------------------
  227. (defun dired-single-display-version ()
  228. "Display dired-single version."
  229. (interactive)
  230. (message "dired-single version <%s>." (dired-single-version-number)))
  231. ;;; **************************************************************************
  232. ;;; ***** interactive functions
  233. ;;; **************************************************************************
  234. ;;;###autoload
  235. (defun dired-single-buffer (&optional default-dirname)
  236. "Visit selected directory in current buffer.
  237. Visits the selected directory in the current buffer, replacing the
  238. current contents with the contents of the new directory. This doesn't
  239. prevent you from having more than one dired buffer. The main difference
  240. is that a given dired buffer will not spawn off a new buffer every time
  241. a new directory is visited.
  242. If the variable `dired-single-use-magic-buffer' is non-nil, and the current
  243. buffer's name is the same as that specified by the variable
  244. `dired-single-magic-buffer-name', then the new directory's buffer will retain
  245. that same name (i.e. not only will dired only use a single buffer, but
  246. its name will not change every time a new directory is entered).
  247. Optional argument DEFAULT-DIRNAME specifies the directory to visit; if not
  248. specified, the directory or file on the current line is used (assuming it's
  249. a dired buffer). If the current line represents a file, the file is visited
  250. in another window."
  251. (interactive)
  252. ;; use arg passed in or find name of current line
  253. (let ((name (or default-dirname (dired-get-filename nil t))))
  254. (save-excursion
  255. (save-match-data
  256. ;; See if the selection is a directory or not.
  257. (end-of-line)
  258. (let ((eol (point)))
  259. (beginning-of-line)
  260. ;; assume directory if arg passed in
  261. (if (or default-dirname (re-search-forward "^ d" eol t))
  262. ;; save current buffer's name
  263. (let ((current-buffer-name (buffer-name)))
  264. ;; go ahead and read in the directory
  265. (find-alternate-file name)
  266. ;; if the saved buffer's name was the magic name, rename this buffer
  267. (if (and dired-single-use-magic-buffer
  268. (string= current-buffer-name dired-single-magic-buffer-name))
  269. (rename-buffer dired-single-magic-buffer-name)))
  270. ;; it's just a file
  271. (find-file name)))))))
  272. ;;;; ------------------------------------------------------------------------
  273. ;;;###autoload
  274. (defun dired-single-buffer-mouse (click)
  275. "Mouse-initiated version of `dired-single-buffer' (which see).
  276. Argument CLICK is the mouse-click event."
  277. (interactive "e")
  278. (let* ( (start (event-start click))
  279. (window (car start))
  280. (pos (car (cdr start))) )
  281. (select-window window)
  282. (goto-char pos))
  283. (dired-single-buffer))
  284. ;;;; ------------------------------------------------------------------------
  285. ;;;###autoload
  286. (defun dired-single-magic-buffer (&optional default-dirname)
  287. "Switch to buffer whose name is the value of `dired-single-magic-buffer-name'.
  288. If no such buffer exists, launch dired in a new buffer and rename that buffer
  289. to the value of `dired-single-magic-buffer-name'. If the current buffer is the
  290. magic buffer, it will prompt for a new directory to visit.
  291. Optional argument DEFAULT-DIRNAME specifies the directory to visit (defaults to
  292. the currently displayed directory)."
  293. (interactive)
  294. ;; do we not have one or are we already in it?
  295. (let ((magic-dired-buffer (get-buffer dired-single-magic-buffer-name)))
  296. (if (or (eq magic-dired-buffer nil)
  297. (eq magic-dired-buffer (current-buffer)))
  298. ;; nothing to switch to
  299. ;; get directory name to start in
  300. (let ((dirname (or default-dirname
  301. (read-file-name (format "Dired %s(directory): " "")
  302. nil default-directory t))))
  303. ;; make sure it's really a directory
  304. (if (not (file-directory-p dirname))
  305. (error "Error: <%s> is not a directory" dirname))
  306. ;; do we need a new buffer?
  307. (if (eq magic-dired-buffer nil)
  308. ;; find the file in new buffer, current window
  309. (find-file dirname)
  310. ;; just find in place of current buffer
  311. (find-alternate-file dirname))
  312. ;; rename the buffer, where ever we found it
  313. (rename-buffer dired-single-magic-buffer-name))
  314. ;; we're not there (we have one already), so simply switch to it
  315. (switch-to-buffer magic-dired-buffer)
  316. ;; if called with a default, try it again
  317. (if default-dirname
  318. (dired-single-magic-buffer default-dirname)))))
  319. ;;;; ------------------------------------------------------------------------
  320. ;;;###autoload
  321. (defun dired-single-toggle-buffer-name ()
  322. "Toggle between the 'magic' buffer name and the 'real' dired buffer name.
  323. Will also seek to uniquify the 'real' buffer name."
  324. (interactive)
  325. ;; make sure it's a dired buffer
  326. (if (not (string= major-mode "dired-mode"))
  327. (error "Error: not a dired buffer"))
  328. ;; do we have magic name currently?
  329. (if (string= (buffer-name) dired-single-magic-buffer-name)
  330. (rename-buffer
  331. (abbreviate-file-name
  332. (expand-file-name (directory-file-name default-directory))) t)
  333. ;; make sure the buffer doesn't currently exist
  334. (let ((existing-buffer (get-buffer dired-single-magic-buffer-name)))
  335. (if existing-buffer
  336. (kill-buffer existing-buffer))
  337. (rename-buffer dired-single-magic-buffer-name))))
  338. ;;; **************************************************************************
  339. ;;; ***** we're done
  340. ;;; **************************************************************************
  341. (provide 'dired-single)
  342. (run-hooks 'dired-single-load-hook)
  343. ;;; dired-single.el ends here
  344. ;;; **************************************************************************
  345. ;;;; ***** EOF ***** EOF ***** EOF ***** EOF ***** EOF *************