;;; dirtree.el --- Directory tree views ;; ;; Author: Mark Triggs ;; ;; This file 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 2, or (at your option) ;; any later version. ;; ;; This file 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., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;; ;; ;; Commentary: ;; ;; This uses tree-widget to display a directory tree that you can quickly ;; navigate and use to find files. Bind `dirtree-switch' to a key to use it. ;; ;;; Code: ;; (require 'tree-widget) (defvar dirtree-hide-directories "\\({arch}\\|\\.arch-ids\\|CVS\\)" "Don't expand directories matching this regular expression") (defun dirtree-expandable-p (directory) (not (string-match dirtree-hide-directories directory))) (defvar dirtree-directory-trees (make-hash-table :test #'equal)) (defun dirtree-directory-tree (directory &optional force) (when (or force (not (gethash directory dirtree-directory-trees))) (puthash directory (dirtree-build-directory-tree directory) dirtree-directory-trees)) (gethash directory dirtree-directory-trees)) (defun dirtree-build-directory-tree (path &optional base) (let ((full-path (if base (concat base "/" path) path))) (if (file-directory-p full-path) `(tree-widget :open ,(dirtree-expandable-p full-path) :tag ,path ,@(mapcar (lambda (entry) (dirtree-build-directory-tree entry full-path)) (remove-if (lambda (entry) (string-match "^\\.+$" entry)) (directory-files full-path)))) `(tree-widget :tag ,(propertize path :full-path full-path))))) (defun dirtree-insert-directory-tree (directory &optional reload) (widget-create 'tree-widget :open t :no-leaf-handle "" :node (dirtree-directory-tree directory reload))) (defun dirtree-normalise-directory (directory) (replace-regexp-in-string "/*$" "" directory)) (defvar dirtree-last-dir nil "The last directory viewed with dirtree.") (defun dirtree-build-buffer (directory &optional reload) (setq dirtree-last-dir directory) (let ((window-configuration (current-window-configuration))) (let ((buffer (get-buffer-create "*dirtree*"))) (with-current-buffer buffer (let ((inhibit-read-only t)) (erase-buffer) (dirtree-insert-directory-tree directory reload) (dirtree-mode) (goto-char (point-min)) (set (make-local-variable 'dirtree-root) directory))) buffer))) (defun dirtree-switch (&optional directory) (interactive (list (if (or current-prefix-arg (not dirtree-last-dir)) (dirtree-normalise-directory (expand-file-name (read-directory-name "Directory? "))) dirtree-last-dir))) (let ((window-configuration (current-window-configuration))) (delete-other-windows) (split-window-horizontally) (switch-to-buffer (or (and (not current-prefix-arg) (get-buffer "*dirtree*")) (dirtree-build-buffer directory))) (set (make-local-variable 'dirtree-window-configuration) window-configuration))) (defun dirtree-find-file-at-point () (interactive) (let ((file (get-text-property (1- (line-end-position)) :full-path))) (when file (dirtree-quit) (find-file file)))) (defun dirtree-quit () (interactive) (set-window-configuration dirtree-window-configuration) (when (string= (buffer-name (current-buffer)) "*dirtree*") (bury-buffer))) (defun dirtree-move-up-dir () (interactive) (unless (string= dirtree-root "/") (setq dirtree-root (file-name-directory dirtree-root))) (dirtree-refresh t)) (defun dirtree-new-directory (&optional directory) (interactive (list (dirtree-normalise-directory (expand-file-name (read-directory-name "Directory? " dirtree-last-dir) dirtree-last-dir)))) (setq dirtree-root directory) (dirtree-refresh t)) (defun dirtree-refresh (&optional no-reload) (interactive) (let ((window-configuration dirtree-window-configuration)) (dirtree-build-buffer dirtree-root (not no-reload)) (set (make-local-variable 'dirtree-window-configuration) window-configuration))) (defun dirtree-next-file () (interactive) (next-line 1) (beginning-of-line) (search-forward-regexp "-[-,] " nil t) (goto-char (match-end 0))) (defun dirtree-prev-file () (interactive) (next-line -1) (beginning-of-line) (search-forward-regexp "-[-,] " nil t) (goto-char (match-end 0))) (defvar dirtree-mode-map (make-sparse-keymap) "The keymap for dirtree") (define-key dirtree-mode-map (kbd "RET") 'dirtree-find-file-at-point) (define-key dirtree-mode-map (kbd "q") 'dirtree-quit) (define-key dirtree-mode-map (kbd "^") 'dirtree-move-up-dir) (define-key dirtree-mode-map (kbd "g") 'dirtree-refresh) (define-key dirtree-mode-map (kbd "f") 'dirtree-new-directory) (define-key dirtree-mode-map (kbd "TAB") 'widget-forward) (define-key dirtree-mode-map [backtab] 'widget-backward) (define-key dirtree-mode-map (kbd "n") 'dirtree-next-file) (define-key dirtree-mode-map (kbd "p") 'dirtree-prev-file) (define-derived-mode dirtree-mode fundamental-mode "dirtree" "Mode for showing directory trees." (use-local-map dirtree-mode-map) (setq buffer-read-only t)) (provide 'dirtree) ;;; dirtree.el ends here