mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 8f6f2705a38e2515b6c57fda12c5be29fb9a798f
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