commit | author | age
|
5cb5f7
|
1 |
;;; ztree-dir.el --- Text mode directory tree -*- lexical-binding: t; -*- |
C |
2 |
|
|
3 |
;; Copyright (C) 2013-2018 Free Software Foundation, Inc. |
|
4 |
;; |
|
5 |
;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com> |
|
6 |
;; |
|
7 |
;; Created: 2013-11-11 |
|
8 |
;; |
|
9 |
;; Keywords: files tools |
|
10 |
;; URL: https://github.com/fourier/ztree |
|
11 |
;; Compatibility: GNU Emacs 24.x |
|
12 |
;; |
|
13 |
;; This file is part of GNU Emacs. |
|
14 |
;; |
|
15 |
;; GNU Emacs is free software: you can redistribute it and/or modify |
|
16 |
;; it under the terms of the GNU General Public License as published by |
|
17 |
;; the Free Software Foundation, either version 3 of the License, or |
|
18 |
;; (at your option) any later version. |
|
19 |
;; |
|
20 |
;; GNU Emacs is distributed in the hope that it will be useful, |
|
21 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
22 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
23 |
;; GNU General Public License for more details. |
|
24 |
;; |
|
25 |
;; You should have received a copy of the GNU General Public License |
|
26 |
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
|
27 |
;; |
|
28 |
;;; Commentary: |
|
29 |
;; |
|
30 |
;; Add the following to your .emacs file: |
|
31 |
;; |
|
32 |
;; (push (substitute-in-file-name "path-to-ztree-directory") load-path) |
|
33 |
;; (require 'ztree-dir) |
|
34 |
;; |
|
35 |
;; Call the ztree interactive function: |
|
36 |
;; M-x ztree-dir |
|
37 |
;; Open/close directories with double-click, Enter or Space keys |
|
38 |
;; |
|
39 |
;;; Issues: |
|
40 |
;; |
|
41 |
;;; TODO: |
|
42 |
;; 1) Add some file-handling and marking abilities |
|
43 |
;; |
|
44 |
;;; Code: |
|
45 |
|
|
46 |
(require 'ztree-util) |
|
47 |
(require 'ztree-view) |
|
48 |
(eval-when-compile (require 'cl-lib)) |
|
49 |
|
|
50 |
;; |
|
51 |
;; Constants |
|
52 |
;; |
|
53 |
|
|
54 |
(defconst ztree-hidden-files-regexp "^\\." |
|
55 |
"Hidden files regexp. |
|
56 |
By default all filest starting with dot `.', including . and ..") |
|
57 |
|
|
58 |
;; |
|
59 |
;; Configurable variables |
|
60 |
;; |
|
61 |
|
|
62 |
(defvar ztree-dir-move-focus nil |
|
63 |
"Defines if move focus to opened window on hard-action command (RETURN) on a file.") |
|
64 |
|
|
65 |
(defvar-local ztree-dir-filter-list (list ztree-hidden-files-regexp) |
|
66 |
"List of regexp file names to filter out. |
|
67 |
By default paths starting with dot (like .git) are ignored. |
|
68 |
One could add own filters in the following way: |
|
69 |
|
|
70 |
(setq-default ztree-dir-filter-list (cons \"^.*\\.pyc\" ztree-dir-filter-list)) |
|
71 |
") |
|
72 |
|
|
73 |
(defvar-local ztree-dir-show-filtered-files nil |
|
74 |
"Show or not files from the filtered list.") |
|
75 |
|
|
76 |
|
|
77 |
;; |
|
78 |
;; Faces |
|
79 |
;; |
|
80 |
|
|
81 |
(defface ztreep-header-face |
|
82 |
'((((type tty pc) (class color)) :foreground "lightblue" :weight bold) |
|
83 |
(((background dark)) (:height 1.2 :foreground "lightblue" :weight bold)) |
|
84 |
(t :height 1.2 :foreground "darkblue" :weight bold)) |
|
85 |
"*Face used for the header in Ztree buffer." |
|
86 |
:group 'Ztree :group 'font-lock-highlighting-faces) |
|
87 |
(defvar ztreep-header-face 'ztreep-header-face) |
|
88 |
|
|
89 |
|
|
90 |
(define-minor-mode ztreedir-mode |
|
91 |
"A minor mode for displaying the directory trees in text mode." |
|
92 |
;; initial value |
|
93 |
nil |
|
94 |
;; modeline name |
|
95 |
" Dir" |
|
96 |
;; The minor mode keymap |
|
97 |
`( |
|
98 |
(,(kbd "H") . ztree-dir-toggle-show-filtered-files) |
|
99 |
(,(kbd ">") . ztree-dir-narrow-to-dir) |
|
100 |
(,(kbd "<") . ztree-dir-widen-to-parent) |
|
101 |
(,(kbd "d") . ztree-dir-open-dired-at-point))) |
|
102 |
|
|
103 |
|
|
104 |
|
|
105 |
|
|
106 |
;; |
|
107 |
;; File bindings to the directory tree control |
|
108 |
;; |
|
109 |
|
|
110 |
(defun ztree-insert-buffer-header () |
|
111 |
"Insert the header to the ztree buffer." |
|
112 |
(let ((start (point))) |
|
113 |
(insert "Directory tree") |
|
114 |
(insert "\n") |
|
115 |
(insert "==============") |
|
116 |
(set-text-properties start (point) '(face ztreep-header-face))) |
|
117 |
(insert "\n")) |
|
118 |
|
|
119 |
(defun ztree-file-not-hidden (filename) |
|
120 |
"Determines if the file with FILENAME should be visible." |
|
121 |
(let ((name (ztree-file-short-name filename))) |
|
122 |
(and (not (or (string= name ".") (string= name ".."))) |
|
123 |
(or |
|
124 |
ztree-dir-show-filtered-files |
|
125 |
(not (cl-find-if (lambda (rx) (string-match rx name)) ztree-dir-filter-list)))))) |
|
126 |
|
|
127 |
|
|
128 |
(defun ztree-find-file (node hard) |
|
129 |
"Find the file at NODE. |
|
130 |
|
|
131 |
If HARD is non-nil, the file is opened in another window. |
|
132 |
Otherwise, the ztree window is used to find the file." |
|
133 |
(when (and (stringp node) (file-readable-p node)) |
|
134 |
(cond ((and hard ztree-dir-move-focus) |
|
135 |
(find-file-other-window node)) |
|
136 |
(hard |
|
137 |
(save-selected-window (find-file-other-window node))) |
|
138 |
(t |
|
139 |
(find-file node))))) |
|
140 |
|
|
141 |
|
|
142 |
(defun ztree-dir-toggle-show-filtered-files () |
|
143 |
"Toggle visibility of the filtered files." |
|
144 |
(interactive) |
|
145 |
(setq ztree-dir-show-filtered-files (not ztree-dir-show-filtered-files)) |
|
146 |
(message (concat (if ztree-dir-show-filtered-files "Show" "Hide") " filtered files")) |
|
147 |
(ztree-refresh-buffer)) |
|
148 |
|
|
149 |
|
|
150 |
(defun ztree-dir-directory-files (path) |
|
151 |
"Return the list of files/directories for the given PATH." |
|
152 |
;; remove . and .. from the list of files to avoid infinite |
|
153 |
;; recursion |
|
154 |
(cl-remove-if (lambda (x) (string-match-p "/\\.\\.?$" x)) |
|
155 |
(directory-files path 'full))) |
|
156 |
|
|
157 |
|
|
158 |
(defun ztree-dir-change-directory (node) |
|
159 |
"Change the start node to NODE and update current directory." |
|
160 |
(ztree-change-start-node node) |
|
161 |
(setq default-directory node)) |
|
162 |
|
|
163 |
|
|
164 |
(defun ztree-dir-narrow-to-dir () |
|
165 |
"Interactive command to narrow the current directory buffer. |
|
166 |
The buffer is narrowed to the directory under the cursor. |
|
167 |
If the cursor is on a file, the buffer is narrowed to the parent directory." |
|
168 |
(interactive) |
|
169 |
(let* ((line (line-number-at-pos)) |
|
170 |
(node (ztree-find-node-in-line line)) |
|
171 |
(parent (ztree-get-parent-for-line line))) |
|
172 |
(if (file-directory-p node) |
|
173 |
(ztree-dir-change-directory node) |
|
174 |
(when parent |
|
175 |
(ztree-dir-change-directory (ztree-find-node-in-line parent)))))) |
|
176 |
|
|
177 |
|
|
178 |
(defun ztree-dir-widen-to-parent () |
|
179 |
"Interactive command to widen the current directory buffer to parent. |
|
180 |
The buffer is widened to the parent of the directory of the current buffer. |
|
181 |
This allows to jump to the parent directory if this directory is one level |
|
182 |
up of the opened." |
|
183 |
(interactive) |
|
184 |
(let* ((node ztree-start-node) |
|
185 |
(parent (file-name-directory (directory-file-name node)))) |
|
186 |
(when parent |
|
187 |
(ztree-dir-change-directory parent)))) |
|
188 |
|
|
189 |
|
|
190 |
(defun ztree-dir-open-dired-at-point () |
|
191 |
"If the point is on a directory, open DIRED with this directory. |
|
192 |
Otherwise open DIRED with the parent directory" |
|
193 |
(interactive) |
|
194 |
(let* ((line (line-number-at-pos)) |
|
195 |
(node (ztree-find-node-in-line line)) |
|
196 |
(parent (ztree-get-parent-for-line line))) |
|
197 |
(cond ((and node (file-directory-p node)) |
|
198 |
(dired node)) |
|
199 |
(parent |
|
200 |
(dired (ztree-find-node-in-line parent)))))) |
|
201 |
|
|
202 |
|
|
203 |
;;;###autoload |
|
204 |
(defun ztree-dir (path) |
|
205 |
"Create an interactive buffer with the directory tree of the PATH given." |
|
206 |
(interactive "DDirectory: ") |
|
207 |
(when (and (file-exists-p path) (file-directory-p path)) |
|
208 |
(let ((buf-name (concat "*Directory " path " tree*"))) |
|
209 |
(ztree-view buf-name |
|
210 |
(expand-file-name (substitute-in-file-name path)) |
|
211 |
#'ztree-file-not-hidden |
|
212 |
#'ztree-insert-buffer-header |
|
213 |
#'ztree-file-short-name |
|
214 |
#'file-directory-p |
|
215 |
#'string-equal |
|
216 |
#'ztree-dir-directory-files |
|
217 |
nil ; face |
|
218 |
#'ztree-find-file) ; action |
|
219 |
(ztreedir-mode)))) |
|
220 |
|
|
221 |
|
|
222 |
|
|
223 |
(provide 'ztree-dir) |
|
224 |
;;; ztree-dir.el ends here |