1
by Joerg Jaspert
Import upstream version 2.21 |
1 |
;;; ecb-file-browser.el --- the file-browser of Emacs
|
2 |
||
3 |
;; Copyright (C) 2000 - 2003 Jesper Nordenberg,
|
|
4 |
;; Klaus Berndl,
|
|
5 |
;; Free Software Foundation, Inc.
|
|
6 |
||
7 |
;; Author: Jesper Nordenberg <mayhem@home.se>
|
|
8 |
;; Klaus Berndl <klaus.berndl@sdm.de>
|
|
9 |
;; Maintainer: Klaus Berndl <klaus.berndl@sdm.de>
|
|
10 |
;; Keywords: browser, code, programming, tools
|
|
11 |
;; Created: 2000
|
|
12 |
||
13 |
;; This program is free software; you can redistribute it and/or modify it under
|
|
14 |
;; the terms of the GNU General Public License as published by the Free Software
|
|
15 |
;; Foundation; either version 2, or (at your option) any later version.
|
|
16 |
||
17 |
;; This program is distributed in the hope that it will be useful, but WITHOUT
|
|
18 |
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
19 |
;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
20 |
;; details.
|
|
21 |
||
22 |
;; You should have received a copy of the GNU General Public License along with
|
|
23 |
;; GNU Emacs; see the file COPYING. If not, write to the Free Software
|
|
24 |
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
25 |
||
26 |
;; $Id: ecb-file-browser.el,v 1.10 2004/02/16 08:56:41 berndl Exp $
|
|
27 |
||
28 |
;;; Commentary:
|
|
29 |
||
30 |
;; This file contains the code of the file-browser of ECB
|
|
31 |
||
32 |
(require 'ecb-util) |
|
33 |
(require 'tree-buffer) |
|
34 |
(require 'ecb-mode-line) |
|
35 |
(require 'ecb-navigate) |
|
36 |
(require 'ecb-face) |
|
37 |
(require 'ecb-speedbar) |
|
38 |
(require 'ecb-layout) |
|
39 |
||
40 |
;; various loads
|
|
41 |
(require 'assoc) |
|
42 |
||
43 |
(eval-when-compile |
|
44 |
;; to avoid compiler grips
|
|
45 |
(require 'cl)) |
|
46 |
||
47 |
(eval-when-compile |
|
48 |
(require 'silentcomp)) |
|
49 |
||
50 |
(silentcomp-defun ecb-speedbar-update-contents) |
|
51 |
||
52 |
(defvar ecb-path-selected-directory nil |
|
53 |
"Path to currently selected directory.") |
|
54 |
||
55 |
(defvar ecb-path-selected-source nil |
|
56 |
"Path to currently selected source.") |
|
57 |
||
58 |
(defun ecb-file-browser-initialize () |
|
59 |
(setq ecb-path-selected-directory nil |
|
60 |
ecb-path-selected-source nil)) |
|
61 |
||
62 |
;;====================================================
|
|
63 |
;; Customization
|
|
64 |
;;====================================================
|
|
65 |
||
66 |
||
67 |
(defgroup ecb-directories nil |
|
68 |
"Settings for the directories-buffer in the Emacs code browser."
|
|
69 |
:group 'ecb |
|
70 |
:prefix "ecb-") |
|
71 |
||
72 |
(defgroup ecb-sources nil |
|
73 |
"Settings for the sources-buffers in the Emacs code browser."
|
|
74 |
:group 'ecb |
|
75 |
:prefix "ecb-") |
|
76 |
||
77 |
(defgroup ecb-history nil |
|
78 |
"Settings for the history-buffer in the Emacs code browser."
|
|
79 |
:group 'ecb |
|
80 |
:prefix "ecb-") |
|
81 |
||
82 |
(defcustom ecb-source-path nil |
|
83 |
"*Paths where to find code sources.
|
|
84 |
Each path can have an optional alias that is used as it's display name. If no
|
|
85 |
alias is set, the path is used as display name."
|
|
86 |
:group 'ecb-directories |
|
87 |
:group 'ecb-most-important |
|
88 |
:initialize 'custom-initialize-default |
|
89 |
:set (function (lambda (symbol value) |
|
90 |
(set symbol value) |
|
91 |
(if (and ecb-minor-mode |
|
92 |
(functionp 'ecb-update-directories-buffer)) |
|
93 |
(ecb-update-directories-buffer)))) |
|
94 |
:type '(repeat (choice :tag "Display type" |
|
95 |
:menu-tag "Display type" |
|
96 |
(directory :tag "Path") |
|
97 |
(list :tag "Path with alias" |
|
98 |
(directory :tag "Path") |
|
99 |
(string :tag "Alias"))))) |
|
100 |
||
101 |
||
102 |
(defcustom ecb-add-path-for-not-matching-files '(t . nil) |
|
103 |
"*Add path of a file to `ecb-source-path' if not already contained. |
|
104 |
This is done during the auto. windows synchronization which happens if a file
|
|
105 |
is opened not via the file/directory-browser of ECB. In such a situation ECB
|
|
106 |
adds the path of the new file auto. to `ecb-source-path' at least temporally |
|
107 |
for the current Emacs session. This option defines two things:
|
|
108 |
1. Should only the root-part \(which means for Unix-like systems always '/'
|
|
109 |
and for windows-like systems the drive) of the new file be added as
|
|
110 |
source-path to `ecb-source-path' or the whole directory-part? |
|
111 |
2. Should this path be added for future sessions too?
|
|
112 |
||
113 |
The value of this option is a cons-cell where the car is a boolean for 1. and
|
|
114 |
the cdr is a boolean for 2.
|
|
115 |
||
116 |
A value of not nil for the car \(1.) is reasonably if a user often opens files
|
|
117 |
not via the ECB-browser which are not located in any of the paths of
|
|
118 |
`ecb-source-path' because then only one path for each drive \(windows) or the |
|
119 |
root-path \(unix) is added to the directory buffer of ECB."
|
|
120 |
:group 'ecb-directories |
|
121 |
:type '(cons (boolean :tag "Add only root path") |
|
122 |
(boolean :tag "Ask for saving for future sessions"))) |
|
123 |
||
124 |
||
125 |
(defvar ecb-source-path-functions nil |
|
126 |
"List of functions to call for finding sources.
|
|
127 |
Each time the function `ecb-update-directories-buffer' is called, the |
|
128 |
functions in this variable will be evaluated. Such a function must return
|
|
129 |
either nil or a list of strings where each string is a path.") |
|
130 |
||
131 |
||
132 |
(defcustom ecb-display-default-dir-after-start t |
|
133 |
"*Automatically display current default-directory after activating ECB.
|
|
134 |
If a file-buffer is displayed in the edit-window then ECB synchronizes its
|
|
135 |
tree-buffers to this file-buffer - at least if the option `ecb-window-sync' it |
|
136 |
not nil. So for this situation `ecb-display-default-dir-after-start' takes no |
|
137 |
effect but this option is for the case if no file-buffer is displayed in the
|
|
138 |
edit-window after startup:
|
|
139 |
||
140 |
If true then ECB selects autom. the current default-directory after activation
|
|
141 |
even if no file-buffer is displayed in the edit-window. This is useful if ECB
|
|
142 |
is autom. activated after startup of Emacs and Emacs is started without a
|
|
143 |
file-argument. So the directory from which the startup has performed is auto.
|
|
144 |
selected in the ECB-directories buffer and the ECB-sources buffer displays the
|
|
145 |
contents of this directory."
|
|
146 |
:group 'ecb-directories |
|
147 |
:type 'boolean) |
|
148 |
||
149 |
||
150 |
(defcustom ecb-show-sources-in-directories-buffer '("left7" "left13" |
|
151 |
"left14" "left15") |
|
152 |
"*Show source files in directories buffer.
|
|
153 |
The value is either 'always or 'never or a list of layout-names for which
|
|
154 |
layouts sources should be displayed in the directories window."
|
|
155 |
:group 'ecb-directories |
|
156 |
:initialize 'custom-initialize-default |
|
157 |
:set (function (lambda (symbol value) |
|
158 |
(set symbol value) |
|
159 |
(if (and ecb-minor-mode |
|
160 |
(functionp 'ecb-set-selected-directory) |
|
161 |
ecb-path-selected-directory) |
|
162 |
(ecb-set-selected-directory ecb-path-selected-directory t)))) |
|
163 |
:type '(radio (const :tag "Always" :value always) |
|
164 |
(const :tag "Never" :value never) |
|
165 |
(repeat :tag "With these layouts" |
|
166 |
(string :tag "Layout name")))) |
|
167 |
||
168 |
||
169 |
(defcustom ecb-directories-update-speedbar 'auto |
|
170 |
"*Update an integrated speedbar after selecting a directory.
|
|
171 |
If not nil then an integrated speedbar will be updated after selecting a
|
|
172 |
directory in the ECB-directories-buffer so the speedbar displays the contents
|
|
173 |
of that directory.
|
|
174 |
||
175 |
Of course this option makes only sense if the integrated speedbar is displayed
|
|
176 |
in addition to the ECB-directories-buffer.
|
|
177 |
||
178 |
This option can have the following values:
|
|
179 |
- t: Always update speedbar.
|
|
180 |
- nil: Never update speedbar.
|
|
181 |
- auto: Update when senseful \(see scenarios below)
|
|
182 |
- <function>: A user-defined function. The function is called after a
|
|
183 |
directory is selected, gets the selected directory as argument and has to
|
|
184 |
return nil if the the integrated speedbar should NOT be updated.
|
|
185 |
||
186 |
Two example-scenarios where different values for this option can be senseful:
|
|
187 |
||
188 |
If `ecb-show-sources-in-directories-buffer' is not nil or you have a layout |
|
189 |
where an ECB-sources-buffer is visible then you probably want to use the
|
|
190 |
ECB-directories-buffer \(and/or the ECB-sources-buffer) for directory- and
|
|
191 |
file-browsing. If you have in addition an integrated speedbar running then you
|
|
192 |
probably want to use speedbar instead of the ECB-methods-buffer for
|
|
193 |
source-content-browsing. In this case you probably want the speedbar not be
|
|
194 |
updated because you do not need speedbar reflecting the current-directory
|
|
195 |
contents but only the contents of the currently selected source-file and the
|
|
196 |
integrated speedbar updates itself autom. for the latter one!
|
|
197 |
||
198 |
If `ecb-show-sources-in-directories-buffer' is nil and there is also no |
|
199 |
ECB-sources-buffer visible in the current layout then you probably want to use
|
|
200 |
an integrated speedbar for browsing directory-contents \(i.e. the files) and
|
|
201 |
file-contents \(instead of the ECB-methods-buffer for example). In this case
|
|
202 |
you probably want the speedbar updated because you need speedbar reflecting
|
|
203 |
the current-directory contents so you can select files.
|
|
204 |
||
205 |
The value 'auto \(see above) takes exactly these two scenarios into account."
|
|
206 |
:group 'ecb-directories |
|
207 |
:type '(radio (const :tag "Always" :value t) |
|
208 |
(const :tag "Never" :value nil) |
|
209 |
(const :tag "Automatic" :value auto) |
|
210 |
(function :tag "Custom function"))) |
|
211 |
||
212 |
||
213 |
(defun ecb-show-sources-in-directories-buffer-p () |
|
214 |
(cond ((equal ecb-show-sources-in-directories-buffer 'never) |
|
215 |
nil) |
|
216 |
((equal ecb-show-sources-in-directories-buffer 'always) |
|
217 |
t) |
|
218 |
(t |
|
219 |
(and (listp ecb-show-sources-in-directories-buffer) |
|
220 |
(member ecb-layout-name |
|
221 |
ecb-show-sources-in-directories-buffer))))) |
|
222 |
||
223 |
(defcustom ecb-cache-directory-contents '((".*" . 50)) |
|
224 |
"*Cache contents of certain directories.
|
|
225 |
This can be useful if `ecb-source-path' contains directories with many files |
|
226 |
and subdirs, especially if these directories are mounted net-drives \(\"many\"
|
|
227 |
means here something > 1000, dependent of the speed of the net-connection and
|
|
228 |
the machine). For these directories actualizing the sources- and/or directories-
|
|
229 |
buffer of ECB \(if displayed in current layout!) can slow down dramatically so
|
|
230 |
a caching increases speed a lot.
|
|
231 |
|
|
232 |
The value of this option is a list where the each element is a cons-cell and
|
|
233 |
looks like:
|
|
234 |
\(<dir-regexp> . <filenumber threshold>)
|
|
235 |
<dir-regexp>: Regular expression a directory must match to be cached.
|
|
236 |
<filenumber threshold>: Number of directory contents must exceed this number.
|
|
237 |
||
238 |
A directory will only be cached if and only if the directory-name matches
|
|
239 |
one regexp of this option and its content-number exceeds the related
|
|
240 |
threshold AND the directory-name does not match and regexp of
|
|
241 |
`ecb-cache-directory-contents-not'! |
|
242 |
||
243 |
The cache entry for a certain directory will be refreshed and actualized only
|
|
244 |
by using the POWER-click \(see `ecb-primary-secondary-mouse-buttons') in the |
|
245 |
directories-buffer of ECB.
|
|
246 |
||
247 |
Examples:
|
|
248 |
||
249 |
A value of \(\(\"/usr/home/john_smith/bigdir*\" . 1000)) means the contents of
|
|
250 |
every subdirectory of the home-directory of John Smith will be cached if the
|
|
251 |
directory contains more than 1000 entries and its name begins with \"bigdir\".
|
|
252 |
||
253 |
A value of \(\(\".*\" . 1000)) caches every directory which has more than 1000
|
|
254 |
entries.
|
|
255 |
||
256 |
A value of \(\(\".*\" . 0)) caches every directory regardless of the number of
|
|
257 |
entries.
|
|
258 |
||
259 |
Please note: If you want your home-dir being cached then you MUST NOT use
|
|
260 |
\"~\" because ECB tries always to match full path-names!"
|
|
261 |
:group 'ecb-directories |
|
262 |
:group 'ecb-most-important |
|
263 |
:type `(repeat (cons (regexp :tag "Directory-regexp") |
|
264 |
(integer :tag "Filenumber threshold" :value 1000)))) |
|
265 |
||
266 |
||
267 |
(defcustom ecb-cache-directory-contents-not nil |
|
268 |
"*Do not cache the contents of certain directories.
|
|
269 |
The value of this option is a list where the each element is a regular
|
|
270 |
expression a directory must match if it should not being cached.
|
|
271 |
||
272 |
If a directory-name matches at least one of the regexps of this option the
|
|
273 |
directory-contents will never being cached. See `ecb-cache-directory-contents' |
|
274 |
to see when a directory will be cached.
|
|
275 |
||
276 |
This option can be useful when normally all directories with a certain amount
|
|
277 |
of content \(files and subdirs) should be cached but some special directories
|
|
278 |
not. This can be achieved by:
|
|
279 |
- setting `ecb-cache-directory-contents' to \(\".*\" . 500): Caches all |
|
280 |
directories with more then 500 entries
|
|
281 |
- setting `ecb-cache-directory-contents-not' to a value which matches these |
|
282 |
directories which should not being cached \(e.g. \(\"/usr/home/john_smith\")
|
|
283 |
excludes the HOME-directory of John Smith from being cached).
|
|
284 |
||
285 |
Please note: If you want your home-dir exclude from being cached then you MUST
|
|
286 |
NOT use \"~\" because ECB tries always to match full path-names!"
|
|
287 |
:group 'ecb-directories |
|
288 |
:type `(repeat (regexp :tag "Directory-regexp"))) |
|
289 |
||
290 |
||
291 |
(defcustom ecb-directories-buffer-name " *ECB Directories*" |
|
292 |
"*Name of the ECB directory buffer.
|
|
293 |
Because it is not a normal buffer for editing you should enclose the name with
|
|
294 |
stars, e.g. \"*ECB Directories*\".
|
|
295 |
||
296 |
If it is necessary for you you can get emacs-lisp access to the buffer-object of
|
|
297 |
the ECB-directory-buffer by this name, e.g. by a call of `set-buffer'. |
|
298 |
||
299 |
Changes for this option at runtime will take affect only after deactivating and
|
|
300 |
then activating ECB again!"
|
|
301 |
:group 'ecb-directories |
|
302 |
:type 'string) |
|
303 |
||
304 |
||
305 |
(defcustom ecb-excluded-directories-regexp "^\\(CVS\\|\\.[^xX]*\\)$" |
|
306 |
"*Directories that should not be included in the directories list.
|
|
307 |
The value of this variable should be a regular expression."
|
|
308 |
:group 'ecb-directories |
|
309 |
:type 'regexp) |
|
310 |
||
311 |
||
312 |
(defcustom ecb-auto-expand-directory-tree 'best |
|
313 |
"*Automatically expand the directory tree to the current source file.
|
|
314 |
There are three options:
|
|
315 |
- best: Expand the best-matching source-path
|
|
316 |
- first: Expand the first matching source-path
|
|
317 |
- nil: Do not automatically expand the directory tree."
|
|
318 |
:group 'ecb-directories |
|
319 |
:type '(radio (const :tag "Best matching" |
|
320 |
:value best) |
|
321 |
(const :tag "First matching" |
|
322 |
:value first) |
|
323 |
(const :tag "No auto. expand" |
|
324 |
:value nil))) |
|
325 |
||
326 |
||
327 |
(defcustom ecb-sources-buffer-name " *ECB Sources*" |
|
328 |
"*Name of the ECB sources buffer.
|
|
329 |
Because it is not a normal buffer for editing you should enclose the name with
|
|
330 |
stars, e.g. \"*ECB Sources*\".
|
|
331 |
||
332 |
If it is necessary for you you can get emacs-lisp access to the buffer-object of
|
|
333 |
the ECB-sources-buffer by this name, e.g. by a call of `set-buffer'. |
|
334 |
||
335 |
Changes for this option at runtime will take affect only after deactivating and
|
|
336 |
then activating ECB again!"
|
|
337 |
:group 'ecb-sources |
|
338 |
:type 'string) |
|
339 |
||
340 |
||
341 |
(defcustom ecb-sources-exclude-cvsignore nil |
|
342 |
"*Specify if files contained in a .cvsignore should be excluded.
|
|
343 |
Value is a list of regular expressions or nil. If you want to exclude files
|
|
344 |
listed in a .cvsignore-file from being displayed in the ecb-sources-buffer
|
|
345 |
then specify a regexp for such a directory.
|
|
346 |
||
347 |
If you want to exclude the contents of .cvsignore-files for every directory
|
|
348 |
then you should add one regexp \".*\" which matches every directory.
|
|
349 |
||
350 |
If you never want to exclude the contents of .cvsignore-files then set this
|
|
351 |
option to nil. This is the default."
|
|
352 |
:group 'ecb-sources |
|
353 |
:group 'ecb-directories |
|
354 |
:type '(repeat (regexp :tag "Directory-regexp"))) |
|
355 |
||
356 |
||
357 |
(defcustom ecb-source-file-regexps |
|
358 |
'((".*" . ("\\(^\\(\\.\\|#\\)\\|\\(~$\\|\\.\\(elc\\|obj\\|o\\|class\\|lib\\|dll\\|a\\|so\\|cache\\)$\\)\\)" |
|
359 |
"^\\.\\(emacs\\|gnus\\)$"))) |
|
360 |
"*Specifies which files are shown as source files.
|
|
361 |
This is done on directory-base, which means for each directory-regexp the
|
|
362 |
files to display can be specified. If more than one directory-regexp matches
|
|
363 |
the current selected directory then always the first one \(and its related
|
|
364 |
file-exclude/include-regexps) is used! If no directory-regexp matches then all
|
|
365 |
files are displayed for the currently selected directory.
|
|
366 |
||
367 |
Important note: It is recommended that the *LAST* element of this list should
|
|
368 |
contain an always matching directory-regexp \(\".*\")!
|
|
369 |
||
370 |
So the value of this option is a list of cons-cells where the car is a
|
|
371 |
directory regexp and the cdr is a 2 element list where the first element is a
|
|
372 |
exclude regexp and the second element is a include regexp. A file is displayed
|
|
373 |
in the sources-buffer of ECB iff: The file does not match the exclude regexp
|
|
374 |
OR the file matches the include regexp.
|
|
375 |
||
376 |
But regardless of the value of this option a file F is never displayed in the
|
|
377 |
sources-buffer if the directory matches `ecb-sources-exclude-cvsignore' |
|
378 |
and the directory contains a file .cvsignore which contains F as an entry!
|
|
379 |
||
380 |
There are three predefined and useful combinations of an exclude and include
|
|
381 |
regexp:
|
|
382 |
- All files
|
|
383 |
- All, but no backup, object, lib or ini-files \(except .emacs and .gnus). This
|
|
384 |
means all files except those starting with \".\", \"#\" or ending with
|
|
385 |
\"~\", \".elc\", \".obj\", \".o\", \".lib\", \".dll\", \".a\", \".so\".
|
|
386 |
(but including .emacs and .gnus)
|
|
387 |
- Common source file types (.c, .java etc.)
|
|
388 |
In addition to these predefined values a custom exclude and include
|
|
389 |
combination can be defined.
|
|
390 |
||
391 |
Tips for the directory- and file-regexps: \"$^\" matches no files/directories,
|
|
392 |
\".*\" matches all files/directories."
|
|
393 |
:group 'ecb-sources |
|
394 |
:group 'ecb-most-important |
|
395 |
:type '(repeat (cons :tag "Directory file-spec" |
|
396 |
(regexp :tag "Directory regexp") |
|
397 |
(choice :tag "Files to display" |
|
398 |
:menu-tag "Files to display" |
|
399 |
(const :tag "All files" |
|
400 |
:value ("" "")) |
|
401 |
(const :tag "All, but no backups, objects, etc..." |
|
402 |
:value ("\\(^\\(\\.\\|#\\)\\|\\(~$\\|\\.\\(elc\\|obj\\|o\\|class\\|lib\\|dll\\|a\\|so\\|cache\\)$\\)\\)" "^\\.\\(x?emacs\\|gnus\\)$")) |
|
403 |
(const :tag "Common source file types" |
|
404 |
:value ("" "\\(\\(M\\|m\\)akefile\\|.*\\.\\(java\\|el\\|c\\|cc\\|h\\|hh\\|txt\\|html\\|texi\\|info\\|bnf\\)\\)$")) |
|
405 |
(list :tag "Custom" |
|
406 |
(regexp :tag "Exclude regexp" |
|
407 |
:value "") |
|
408 |
(regexp :tag "Include regexp" |
|
409 |
:value "")))))) |
|
410 |
||
411 |
||
412 |
(defcustom ecb-show-source-file-extension t |
|
413 |
"*Show the file extension of source files."
|
|
414 |
:group 'ecb-sources |
|
415 |
:type 'boolean) |
|
416 |
||
417 |
||
418 |
(defcustom ecb-sources-sort-method 'name |
|
419 |
"*Defines how the source files are sorted.
|
|
420 |
- 'name: Sorting by name.
|
|
421 |
- 'extension: Sorting first by name and then by extension.
|
|
422 |
- nil: No sorting, means source files are displayed in the sequence returned by
|
|
423 |
`directory-files' \(called without sorting)." |
|
424 |
:group 'ecb-sources |
|
425 |
:type '(radio (const :tag "By name" |
|
426 |
:value name) |
|
427 |
(const :tag "By extension" |
|
428 |
:value extension) |
|
429 |
(const :tag "No sorting" |
|
430 |
:value nil))) |
|
431 |
||
432 |
||
433 |
(defcustom ecb-history-buffer-name " *ECB History*" |
|
434 |
"*Name of the ECB history buffer.
|
|
435 |
Because it is not a normal buffer for editing you should enclose the name with
|
|
436 |
stars, e.g. \"*ECB History*\".
|
|
437 |
||
438 |
If it is necessary for you you can get emacs-lisp access to the buffer-object of
|
|
439 |
the ECB-history-buffer by this name, e.g. by a call of `set-buffer'. |
|
440 |
||
441 |
Changes for this option at runtime will take affect only after deactivating and
|
|
442 |
then activating ECB again!"
|
|
443 |
:group 'ecb-history |
|
444 |
:type 'string) |
|
445 |
||
446 |
||
447 |
(defcustom ecb-sort-history-items nil |
|
448 |
"*Sorts the items in the history buffer."
|
|
449 |
:group 'ecb-history |
|
450 |
:type 'boolean) |
|
451 |
||
452 |
(defcustom ecb-kill-buffer-clears-history nil |
|
453 |
"*Define if `kill-buffer' should also clear the history. |
|
454 |
There are three options:
|
|
455 |
- auto: Removes automatically the corresponding history-entry after the buffer
|
|
456 |
has been killed.
|
|
457 |
- ask: Asks, if the history-entry should be removed after the kill.
|
|
458 |
- nil: `kill-buffer' does not affect the history \(this is the default)." |
|
459 |
:group 'ecb-history |
|
460 |
:type '(radio (const :tag "Remove history entry automatically" |
|
461 |
:value auto) |
|
462 |
(const :tag "Ask if history entry should be removed" |
|
463 |
:value ask) |
|
464 |
(const :tag "Do not clear the history" |
|
465 |
:value nil))) |
|
466 |
||
467 |
||
468 |
(defcustom ecb-history-item-name 'buffer-name |
|
469 |
"*The name to use for items in the history buffer."
|
|
470 |
:group 'ecb-history |
|
471 |
:type '(radio (const :tag "Buffer name" |
|
472 |
:value buffer-name) |
|
473 |
(const :tag "File name" |
|
474 |
:value file-name))) |
|
475 |
||
476 |
(defcustom ecb-directories-menu-user-extension |
|
477 |
'(("Version Control" |
|
478 |
(ecb-dir-popup-cvs-status "CVS Status" ) |
|
479 |
(ecb-dir-popup-cvs-examine "CVS Examine") |
|
480 |
(ecb-dir-popup-cvs-update "CVS Update"))) |
|
481 |
"*Static user extensions for the popup-menu of the directories buffer.
|
|
482 |
Value is a list of elements of the following type: Each element defines a new
|
|
483 |
menu-entry and is either:
|
|
484 |
||
485 |
a) Menu-command: A list containing two sub-elements, whereas the first is the
|
|
486 |
function \(a function symbol) being called if the menu-entry is selected
|
|
487 |
and the second is the name of the menu-entry.
|
|
488 |
b) Separator: A one-element-list and the element is the string \"---\": Then a
|
|
489 |
non-selectable menu-separator is displayed.
|
|
490 |
c) Submenu: A list where the first element is the title of the submenu
|
|
491 |
displayed in the main-menu and all other elements are either menu-commands
|
|
492 |
\(see a) or separators \(see b).
|
|
493 |
||
494 |
The function of a menu-command must follow the following guidelines: Such a
|
|
495 |
function must be defined with the macro `tree-buffer-defpopup-command! This
|
|
496 |
macro defines a new popup-command whereas the newly defined command gets one
|
|
497 |
argument NODE. See the docstring of `tree-buffer-defpopup-command' for further |
|
498 |
details.
|
|
499 |
||
500 |
Example for the definition of such a popupmenu-command:
|
|
501 |
||
502 |
\(tree-buffer-defpopup-command ecb-my-special-dir-popup-function
|
|
503 |
\"Prints the name of the directory of the node under point.\"
|
|
504 |
\(let \(\(node-data=dir \(tree-node-get-data node)))
|
|
505 |
\(message \"Dir under node: %s\" node-data=dir)))
|
|
506 |
||
507 |
Per default the static user-extensions are added at the beginning of the
|
|
508 |
built-in menu-entries of `ecb-directories-menu' but the whole menu can be |
|
509 |
re-arranged with `ecb-directories-menu-sorter'. |
|
510 |
||
511 |
These menu-extensions are static. A dynamic menu-extension can be achieved via
|
|
512 |
`ecb-directories-menu-user-extension-function'." |
|
513 |
:group 'ecb-directories |
|
514 |
:type '(repeat (choice :tag "Menu-entry" :menu-tag "Menu-entry" |
|
515 |
:value (ignore "") |
|
516 |
(const :tag "Separator" :value ("---")) |
|
517 |
(list :tag "Menu-command" |
|
518 |
(function :tag "Function" :value ignore) |
|
519 |
(string :tag "Entry-name")) |
|
520 |
(cons :tag "Submenu" |
|
521 |
(string :tag "Submenu-title") |
|
522 |
(repeat (choice :tag "Submenu-entry" :menu-tag "Submenu-entry" |
|
523 |
:value (ignore "") |
|
524 |
(const :tag "Separator" :value ("---")) |
|
525 |
(list :tag "Submenu-command" |
|
526 |
(function :tag "Function" |
|
527 |
:value ignore) |
|
528 |
(string :tag "Entry-name")))))))) |
|
529 |
||
530 |
(defcustom ecb-directories-menu-user-extension-function nil |
|
531 |
"*Dynamic user extensions for the popup-menu of the directories buffer.
|
|
532 |
A function which has to return a list in the same format like the option
|
|
533 |
`ecb-directories-menu-user-extension'. This function is called when the user |
|
534 |
opens the popup-menu for the directories buffer.
|
|
535 |
||
536 |
Per default the dynamic user-extensions are added in front of the static
|
|
537 |
extensions of `ecb-directories-menu-user-extension' but the whole menu can be |
|
538 |
re-arranged with `ecb-directories-menu-sorter'." |
|
539 |
:group 'ecb-directories |
|
540 |
:type 'function) |
|
541 |
||
542 |
(defcustom ecb-sources-menu-user-extension |
|
543 |
'(("Version control" |
|
544 |
(ecb-file-popup-ediff-revision "Ediff against revision") |
|
545 |
("---") |
|
546 |
(ecb-file-popup-vc-next-action "Check In/Out") |
|
547 |
(ecb-file-popup-vc-log "Revision history") |
|
548 |
(ecb-file-popup-vc-annotate "Annotate") |
|
549 |
(ecb-file-popup-vc-diff "Diff against last version"))) |
|
550 |
"*Static user extensions for the popup-menu of the sources buffer.
|
|
551 |
For further explanations see `ecb-directories-menu-user-extension'. |
|
552 |
||
553 |
The node-argument of a menu-function contains as data the filename of the
|
|
554 |
source for which the popup-menu has been opened.
|
|
555 |
||
556 |
Per default the static user-extensions are added at the beginning of the
|
|
557 |
built-in menu-entries of `ecb-sources-menu' but the whole menu can be |
|
558 |
re-arranged with `ecb-sources-menu-sorter'." |
|
559 |
:group 'ecb-sources |
|
560 |
:type '(repeat (choice :tag "Menu-entry" :menu-tag "Menu-entry" |
|
561 |
:value (ignore "") |
|
562 |
(const :tag "Separator" :value ("---")) |
|
563 |
(list :tag "Menu-command" |
|
564 |
(function :tag "Function" :value ignore) |
|
565 |
(string :tag "Entry-name")) |
|
566 |
(cons :tag "Submenu" |
|
567 |
(string :tag "Submenu-title") |
|
568 |
(repeat (choice :tag "Submenu-entry" :menu-tag "Submenu-entry" |
|
569 |
:value (ignore "") |
|
570 |
(const :tag "Separator" :value ("---")) |
|
571 |
(list :tag "Submenu-command" |
|
572 |
(function :tag "Function" |
|
573 |
:value ignore) |
|
574 |
(string :tag "Entry-name")))))))) |
|
575 |
||
576 |
(defcustom ecb-sources-menu-user-extension-function nil |
|
577 |
"*Dynamic user extensions for the popup-menu of the sources buffer.
|
|
578 |
A function which has to return a list in the same format like the option
|
|
579 |
`ecb-sources-menu-user-extension'. This function is called when the user |
|
580 |
opens the popup-menu for the sources buffer.
|
|
581 |
||
582 |
Per default the dynamic user-extensions are added in front of the static
|
|
583 |
extensions of `ecb-sources-menu-user-extension' but the whole menu can be |
|
584 |
re-arranged with `ecb-sources-menu-sorter'." |
|
585 |
:group 'ecb-sources |
|
586 |
:type 'function) |
|
587 |
||
588 |
(defcustom ecb-history-menu-user-extension |
|
589 |
'(("Version control" |
|
590 |
(ecb-file-popup-ediff-revision "Ediff against revision") |
|
591 |
("---") |
|
592 |
(ecb-file-popup-vc-next-action "Check In/Out") |
|
593 |
(ecb-file-popup-vc-log "Revision history") |
|
594 |
(ecb-file-popup-vc-annotate "Annotate") |
|
595 |
(ecb-file-popup-vc-diff "Diff against last version"))) |
|
596 |
"*Static user extensions for the popup-menu of the history buffer.
|
|
597 |
For further explanations see `ecb-directories-menu-user-extension'. |
|
598 |
||
599 |
The node-argument of a menu-function contains as data the filename of the
|
|
600 |
source for which the popup-menu has been opened.
|
|
601 |
||
602 |
Per default the static user-extensions are added at the beginning of the
|
|
603 |
built-in menu-entries of `ecb-history-menu' but the whole menu can be |
|
604 |
re-arranged with `ecb-history-menu-sorter'." |
|
605 |
:group 'ecb-history |
|
606 |
:type '(repeat (choice :tag "Menu-entry" :menu-tag "Menu-entry" |
|
607 |
:value (ignore "") |
|
608 |
(const :tag "Separator" :value ("---")) |
|
609 |
(list :tag "Menu-command" |
|
610 |
(function :tag "Function" :value ignore) |
|
611 |
(string :tag "Entry-name")) |
|
612 |
(cons :tag "Submenu" |
|
613 |
(string :tag "Submenu-title") |
|
614 |
(repeat (choice :tag "Submenu-entry" :menu-tag "Submenu-entry" |
|
615 |
:value (ignore "") |
|
616 |
(const :tag "Separator" :value ("---")) |
|
617 |
(list :tag "Submenu-command" |
|
618 |
(function :tag "Function" |
|
619 |
:value ignore) |
|
620 |
(string :tag "Entry-name")))))))) |
|
621 |
||
622 |
||
623 |
(defcustom ecb-history-menu-user-extension-function nil |
|
624 |
"*Dynamic user extensions for the popup-menu of the history buffer.
|
|
625 |
A function which has to return a list in the same format like the option
|
|
626 |
`ecb-history-menu-user-extension'. This function is called when the user |
|
627 |
opens the popup-menu for the history buffer.
|
|
628 |
||
629 |
Per default the dynamic user-extensions are added in front of the static
|
|
630 |
extensions of `ecb-history-menu-user-extension' but the whole menu can be |
|
631 |
re-arranged with `ecb-history-menu-sorter'." |
|
632 |
:group 'ecb-history |
|
633 |
:type 'function) |
|
634 |
||
635 |
(defcustom ecb-directories-menu-sorter nil |
|
636 |
"*Function which re-sorts the menu-entries of the directories buffer.
|
|
637 |
If a function then this function is called to re-arrange the menu-entries of
|
|
638 |
the combined menu-entries of the user-menu-extensions of
|
|
639 |
`ecb-directories-menu-user-extension' and the built-in-menu |
|
640 |
`ecb-directories-menu'. If nil then no special sorting will be done and the |
|
641 |
user-extensions are placed in front of the built-in-entries.
|
|
642 |
||
643 |
The function get one argument, a list of menu-entries. For the format of this
|
|
644 |
argument see `ecb-directories-menu-user-extension'. The function must return a |
|
645 |
new list in the same format. Of course this function can not only re-arrange
|
|
646 |
the entries but also delete entries or add new entries."
|
|
647 |
:group 'ecb-directories |
|
648 |
:type '(choice :tag "Menu-sorter" :menu-tag "Menu-sorter" |
|
649 |
(const :tag "No special sorting" :value nil) |
|
650 |
(function :tag "Sort-function" :value identity))) |
|
651 |
||
652 |
||
653 |
(defcustom ecb-sources-menu-sorter nil |
|
654 |
"*Function which re-sorts the menu-entries of the directories buffer.
|
|
655 |
If a function then this function is called to sort the menu-entries of the
|
|
656 |
combined menu-entries of the user-menu-extensions of
|
|
657 |
`ecb-sources-menu-user-extension' and the built-in-menu |
|
658 |
`ecb-sources-menu'. If nil then no special sorting will be done and the |
|
659 |
user-extensions are placed in front of the built-in-entries.
|
|
660 |
||
661 |
For the guidelines for such a sorter-function see
|
|
662 |
`ecb-directories-menu-sorter'." |
|
663 |
:group 'ecb-sources |
|
664 |
:type '(choice :tag "Menu-sorter" :menu-tag "Menu-sorter" |
|
665 |
(const :tag "No special sorting" :value nil) |
|
666 |
(function :tag "Sort-function" :value identity))) |
|
667 |
||
668 |
||
669 |
(defcustom ecb-history-menu-sorter nil |
|
670 |
"*Function which re-sorts the menu-entries of the directories buffer.
|
|
671 |
If a function then this function is called to sort the menu-entries of the
|
|
672 |
combined menu-entries of the user-menu-extensions of
|
|
673 |
`ecb-history-menu-user-extension' and the built-in-menu |
|
674 |
`ecb-history-menu'. If nil then no special sorting will be done and the |
|
675 |
user-extensions are placed in front of the built-in-entries.
|
|
676 |
||
677 |
For the guidelines for such a sorter-function see
|
|
678 |
`ecb-directories-menu-sorter'." |
|
679 |
:group 'ecb-history |
|
680 |
:type '(choice :tag "Menu-sorter" :menu-tag "Menu-sorter" |
|
681 |
(const :tag "No special sorting" :value nil) |
|
682 |
(function :tag "Sort-function" :value identity))) |
|
683 |
||
684 |
||
685 |
(defcustom ecb-directories-buffer-after-create-hook nil |
|
686 |
"*Local hook running after the creation of the directories-buffer.
|
|
687 |
Every function of this hook is called once without arguments direct after
|
|
688 |
creating the directories-buffer of ECB and it's local key-map. So for example a
|
|
689 |
function could be added which performs calls of `local-set-key' to define new |
|
690 |
key-bindings only for the directories-buffer of ECB.
|
|
691 |
||
692 |
The following keys must not be rebind in the directories-buffer:
|
|
693 |
<F2>, <F3> and <F4>"
|
|
694 |
:group 'ecb-directories |
|
695 |
:type 'hook) |
|
696 |
||
697 |
||
698 |
(defcustom ecb-sources-buffer-after-create-hook nil |
|
699 |
"*Local hook running after the creation of the sources-buffer.
|
|
700 |
Every function of this hook is called once without arguments direct after
|
|
701 |
creating the sources-buffer of ECB and it's local key-map. So for example a
|
|
702 |
function could be added which performs calls of `local-set-key' to define new |
|
703 |
key-bindings only for the sources-buffer of ECB."
|
|
704 |
:group 'ecb-sources |
|
705 |
:type 'hook) |
|
706 |
||
707 |
||
708 |
(defcustom ecb-history-buffer-after-create-hook nil |
|
709 |
"*Local hook running after the creation of the history-buffer.
|
|
710 |
Every function of this hook is called once without arguments direct after
|
|
711 |
creating the history-buffer of ECB and it's local key-map. So for example a
|
|
712 |
function could be added which performs calls of `local-set-key' to define new |
|
713 |
key-bindings only for the history-buffer of ECB."
|
|
714 |
:group 'ecb-history |
|
715 |
:type 'hook) |
|
716 |
||
717 |
||
718 |
;;====================================================
|
|
719 |
;; Internals
|
|
720 |
;;====================================================
|
|
721 |
||
722 |
(defmacro ecb-exec-in-directories-window (&rest body) |
|
723 |
`(unwind-protect |
|
724 |
(when (ecb-window-select ecb-directories-buffer-name) |
|
725 |
,@body) |
|
726 |
))
|
|
727 |
||
728 |
||
729 |
(defmacro ecb-exec-in-sources-window (&rest body) |
|
730 |
`(unwind-protect |
|
731 |
(when (ecb-window-select ecb-sources-buffer-name) |
|
732 |
,@body) |
|
733 |
))
|
|
734 |
||
735 |
||
736 |
(defmacro ecb-exec-in-history-window (&rest body) |
|
737 |
`(unwind-protect |
|
738 |
(when (ecb-window-select ecb-history-buffer-name) |
|
739 |
,@body) |
|
740 |
))
|
|
741 |
||
742 |
||
743 |
||
744 |
(defun ecb-expand-directory-tree (path node) |
|
745 |
(catch 'exit |
|
746 |
(dolist (child (tree-node-get-children node)) |
|
747 |
(let ((data (tree-node-get-data child))) |
|
748 |
(when (and (>= (length path) (length data)) |
|
749 |
(string= (substring path 0 (length data)) data) |
|
750 |
(or (= (length path) (length data)) |
|
751 |
(eq (elt path (length data)) ecb-directory-sep-char))) |
|
752 |
(let ((was-expanded (tree-node-is-expanded child))) |
|
753 |
(tree-node-set-expanded child t) |
|
754 |
(ecb-update-directory-node child) |
|
755 |
(throw 'exit |
|
756 |
(or (when (> (length path) (length data)) |
|
757 |
(ecb-expand-directory-tree path child)) |
|
758 |
(not was-expanded))))))))) |
|
759 |
||
760 |
||
761 |
(defvar ecb-files-and-subdirs-cache nil |
|
762 |
"Cache for every directory all subdirs and files. This is an alist where an
|
|
763 |
element looks like:
|
|
764 |
\(<directory> . \(<file-list> . <subdirs-list>))") |
|
765 |
||
766 |
||
767 |
(defun ecb-files-and-subdirs-cache-add (cache-elem) |
|
768 |
(if (not (ecb-files-and-subdirs-cache-get (car cache-elem))) |
|
769 |
(setq ecb-files-and-subdirs-cache |
|
770 |
(cons cache-elem ecb-files-and-subdirs-cache)))) |
|
771 |
||
772 |
||
773 |
(defun ecb-files-and-subdirs-cache-get (dir) |
|
774 |
(cdr (assoc dir ecb-files-and-subdirs-cache))) |
|
775 |
||
776 |
||
777 |
(defun ecb-files-and-subdirs-cache-remove (dir) |
|
778 |
(let ((elem (assoc dir ecb-files-and-subdirs-cache))) |
|
779 |
(if elem |
|
780 |
(setq ecb-files-and-subdirs-cache |
|
781 |
(delete elem ecb-files-and-subdirs-cache))))) |
|
782 |
||
783 |
||
784 |
(defun ecb-clear-files-and-subdirs-cache () |
|
785 |
(setq ecb-files-and-subdirs-cache nil)) |
|
786 |
||
787 |
||
788 |
(defun ecb-check-directory-for-caching (dir number-of-contents) |
|
789 |
"Return not nil if DIR matches not any regexp of the option
|
|
790 |
`ecb-cache-directory-contents-not' but matches at least one regexp in |
|
791 |
`ecb-cache-directory-contents' and NUMBER-OF-CONTENTS is greater then the |
|
792 |
related threshold."
|
|
793 |
(and (not (catch 'exit |
|
794 |
(dolist (elem ecb-cache-directory-contents-not) |
|
795 |
(let ((case-fold-search t)) |
|
796 |
(save-match-data |
|
797 |
(if (string-match (car elem) dir) |
|
798 |
(throw 'exit (car elem)))) |
|
799 |
nil)))) |
|
800 |
(catch 'exit |
|
801 |
(dolist (elem ecb-cache-directory-contents) |
|
802 |
(let ((case-fold-search t)) |
|
803 |
(save-match-data |
|
804 |
(if (and (string-match (car elem) dir) |
|
805 |
(> number-of-contents (cdr elem))) |
|
806 |
(throw 'exit (car elem)))) |
|
807 |
nil))))) |
|
808 |
||
809 |
||
810 |
(defun ecb-check-directory-for-source-regexps (dir) |
|
811 |
"Return the related source-exclude-include-regexps of
|
|
812 |
`ecb-source-file-regexps' if DIR matches any directory-regexp in |
|
813 |
`ecb-source-file-regexps'." |
|
814 |
(catch 'exit |
|
815 |
(dolist (elem ecb-source-file-regexps) |
|
816 |
(let ((case-fold-search t)) |
|
817 |
(save-match-data |
|
818 |
(if (string-match (car elem) dir) |
|
819 |
(throw 'exit (cdr elem)))) |
|
820 |
nil)))) |
|
821 |
||
822 |
||
823 |
(defun ecb-files-from-cvsignore (dir) |
|
824 |
"Return an expanded list of filenames which are excluded by the .cvsignore
|
|
825 |
file in current directory."
|
|
826 |
(let ((cvsignore-content (ecb-file-content-as-string |
|
827 |
(expand-file-name ".cvsignore" dir))) |
|
828 |
(files nil)) |
|
829 |
(when cvsignore-content |
|
830 |
(dolist (f (split-string cvsignore-content)) |
|
831 |
(setq files (append (directory-files dir nil (wildcard-to-regexp f) t) |
|
832 |
files))) |
|
833 |
files))) |
|
834 |
||
835 |
||
836 |
(defun ecb-check-directory-for-cvsignore-exclude (dir) |
|
837 |
"Return not nil if DIR matches a regexp in `ecb-sources-exclude-cvsignore'." |
|
838 |
(catch 'exit |
|
839 |
(dolist (elem ecb-sources-exclude-cvsignore) |
|
840 |
(let ((case-fold-search t)) |
|
841 |
(save-match-data |
|
842 |
(if (string-match elem dir) |
|
843 |
(throw 'exit elem))) |
|
844 |
nil)))) |
|
845 |
||
846 |
||
847 |
(defun ecb-get-files-and-subdirs (dir) |
|
848 |
"Return a cons cell where car is a list of all files to display in DIR and
|
|
849 |
cdr is a list of all subdirs to display in DIR. Both lists are sorted
|
|
850 |
according to `ecb-sources-sort-method'." |
|
851 |
(or (ecb-files-and-subdirs-cache-get dir) |
|
852 |
;; dir is not cached
|
|
853 |
(let ((files (directory-files dir nil nil t)) |
|
854 |
(source-regexps (or (ecb-check-directory-for-source-regexps |
|
855 |
(ecb-fix-filename dir)) |
|
856 |
'("" ""))) |
|
857 |
(cvsignore-files (if (ecb-check-directory-for-cvsignore-exclude dir) |
|
858 |
(ecb-files-from-cvsignore dir))) |
|
859 |
sorted-files source-files subdirs cache-elem) |
|
860 |
;; if necessary sort FILES
|
|
861 |
(setq sorted-files |
|
862 |
(cond ((equal ecb-sources-sort-method 'name) |
|
863 |
(sort files 'string<)) |
|
864 |
((equal ecb-sources-sort-method 'extension) |
|
865 |
(sort files (function |
|
866 |
(lambda(a b) |
|
867 |
(let ((ext-a (file-name-extension a t)) |
|
868 |
(ext-b (file-name-extension b t))) |
|
869 |
(if (string= ext-a ext-b) |
|
870 |
(string< a b) |
|
871 |
(string< ext-a ext-b))))))) |
|
872 |
(t files))) |
|
873 |
;; divide real files and subdirs. For really large directories (~ >=
|
|
874 |
;; 2000 entries) this is the performance-bottleneck in the
|
|
875 |
;; file-browser of ECB.
|
|
876 |
(dolist (file sorted-files) |
|
877 |
(if (file-directory-p (ecb-fix-filename dir file)) |
|
878 |
(if (not (string-match ecb-excluded-directories-regexp file)) |
|
879 |
(setq subdirs (append subdirs (list file)))) |
|
880 |
(if (and (not (member file cvsignore-files)) |
|
881 |
(or (string-match (cadr source-regexps) file) |
|
882 |
(not (string-match (car source-regexps) file)))) |
|
883 |
(setq source-files (append source-files (list file)))))) |
|
884 |
||
885 |
(setq cache-elem (cons dir (cons source-files subdirs))) |
|
886 |
;; check if this directory must be cached
|
|
887 |
(if (ecb-check-directory-for-caching dir (length sorted-files)) |
|
888 |
(ecb-files-and-subdirs-cache-add cache-elem)) |
|
889 |
;; return the result
|
|
890 |
(cdr cache-elem)))) |
|
891 |
||
892 |
||
893 |
(defvar ecb-sources-cache nil |
|
894 |
"Cache for the contents of the buffer `ecb-sources-buffer-name'. This is an |
|
895 |
alist where every element is a cons cell which looks like:
|
|
896 |
\(<directory> . <cache-entry>) whereas <cache-entry> is a cons-cell too which
|
|
897 |
contains as car a 3-elem list \(tree-buffer-root <copy of tree-buffer-nodes>
|
|
898 |
buffer-string) for a full \(i.e. all files) cache and as cdr a 4-elem list
|
|
899 |
\(tree-buffer-root, tree-buffer-nodes, sources-buffer-string, <filter>) for a
|
|
900 |
filtered cache where <filter> is another cons-cell \(<filter-regexp> .
|
|
901 |
<filter-display>).") |
|
902 |
||
903 |
||
904 |
(defun ecb-sources-cache-remove (dir) |
|
905 |
"Remove the cache-entry for DIR in `ecb-sources-cache'." |
|
906 |
(let ((cache-elem (assoc dir ecb-sources-cache))) |
|
907 |
(if cache-elem |
|
908 |
(setq ecb-sources-cache (delq cache-elem ecb-sources-cache))))) |
|
909 |
||
910 |
||
911 |
(defun ecb-sources-cache-add-full (dir cache-elem-full) |
|
912 |
"Add the full sources-cache CACHE-ELEM-FULL for DIR to
|
|
913 |
`ecb-sources-cache'. If there is already a full cache-entry then replace it." |
|
914 |
(let ((elem (assoc dir ecb-sources-cache))) |
|
915 |
(if (not elem) |
|
916 |
(setq ecb-sources-cache |
|
917 |
(cons (cons dir (cons cache-elem-full nil)) |
|
918 |
ecb-sources-cache)) |
|
919 |
(setcdr elem (cons cache-elem-full |
|
920 |
(cdr (cdr elem))))))) |
|
921 |
||
922 |
(defun ecb-sources-cache-add-filtered (dir cache-elem-filtered) |
|
923 |
"Add the filtered sources-cache CACHE-ELEM-FILTERED for DIR to
|
|
924 |
`ecb-sources-cache'. If there is already a filtered cache-entry then replace |
|
925 |
it."
|
|
926 |
(let ((elem (assoc dir ecb-sources-cache))) |
|
927 |
(if (not elem) |
|
928 |
(setq ecb-sources-cache |
|
929 |
(cons (cons dir (cons nil cache-elem-filtered)) |
|
930 |
ecb-sources-cache)) |
|
931 |
(setcdr elem (cons (car (cdr elem)) |
|
932 |
cache-elem-filtered))))) |
|
933 |
||
934 |
(defun ecb-sources-cache-get-full (dir) |
|
935 |
"Return the full value of a cached-directory DIR, means the 3-element-list
|
|
936 |
\(tree-buffer-root, tree-buffer-nodes, sources-buffer-string). If no
|
|
937 |
cache-entry for DIR is available then nil is returned."
|
|
938 |
(car (cdr (assoc dir ecb-sources-cache)))) |
|
939 |
||
940 |
(defun ecb-sources-cache-get-filtered (dir) |
|
941 |
"Return the filtered value of a cached-directory DIR, means the
|
|
942 |
4-element-list \(tree-buffer-root, tree-buffer-nodes, sources-buffer-string,
|
|
943 |
filter-regexp). If no cache-entry for DIR is available then nil is returned."
|
|
944 |
(cdr (cdr (assoc dir ecb-sources-cache)))) |
|
945 |
||
946 |
(defun ecb-sources-cache-clear () |
|
947 |
"Clear the whole cache of `ecb-sources-cache'." |
|
948 |
(setq ecb-sources-cache nil)) |
|
949 |
||
950 |
||
951 |
(defun ecb-update-sources-buffer (dir-before-update) |
|
952 |
"Updates the sources-buffer with all sources contained in
|
|
953 |
`ecb-path-selected-directory' - the contents are either newly computed or come |
|
954 |
from the `ecb-sources-cache'. DIR-BEFORE-UPDATE is the directory which was |
|
955 |
selected before this update."
|
|
956 |
||
957 |
;; Here we add a cache-mechanism which caches for each path the node-tree
|
|
958 |
;; and the whole buffer-string of the sources-buffer. A cache-elem would be
|
|
959 |
;; removed from the cache if a directory is POWER-clicked in the directories
|
|
960 |
;; buffer because this is the only way to synchronize the sources-buffer
|
|
961 |
;; with the disk-contents of the clicked directory. This works because the
|
|
962 |
;; tree of the sources-buffer contains only not expandable nodes (see the
|
|
963 |
;; comment in `ecb-rebuild-methods-buffer-with-tagcache'). If we would
|
|
964 |
;; make the nodes in the Sources-buffer "expandable" this caching would not
|
|
965 |
;; work!
|
|
966 |
||
967 |
(ecb-exec-in-sources-window |
|
968 |
;; if we have a filtered cache we must display it - otherwise we use the
|
|
969 |
;; full cache if there is any
|
|
970 |
(let ((cache-elem (or (ecb-sources-cache-get-filtered ecb-path-selected-directory) |
|
971 |
(ecb-sources-cache-get-full ecb-path-selected-directory)))) |
|
972 |
(if cache-elem |
|
973 |
(progn |
|
974 |
(tree-buffer-set-root (nth 0 cache-elem)) |
|
975 |
(tree-buffer-update nil (cons (nth 2 cache-elem) |
|
976 |
(nth 1 cache-elem)))) |
|
977 |
(let ((new-tree (tree-node-new-root)) |
|
978 |
(old-children (tree-node-get-children (tree-buffer-get-root))) |
|
979 |
(new-cache-elem nil)) |
|
980 |
;; building up the new files-tree
|
|
981 |
(ecb-tree-node-add-files |
|
982 |
new-tree
|
|
983 |
ecb-path-selected-directory
|
|
984 |
(car (ecb-get-files-and-subdirs ecb-path-selected-directory)) |
|
985 |
0 ecb-show-source-file-extension old-children t) |
|
986 |
||
987 |
;; updating the buffer itself
|
|
988 |
(tree-buffer-set-root new-tree) |
|
989 |
(tree-buffer-update) |
|
990 |
||
991 |
;; check if the sources buffer for this directory must be
|
|
992 |
;; cached: If yes update the cache
|
|
993 |
(when (ecb-check-directory-for-caching |
|
994 |
ecb-path-selected-directory
|
|
995 |
(length tree-buffer-nodes)) |
|
996 |
(setq new-cache-elem (list (tree-buffer-get-root) |
|
997 |
(ecb-copy-list tree-buffer-nodes) |
|
998 |
(buffer-substring (point-min) |
|
999 |
(point-max)))) |
|
1000 |
(ecb-sources-cache-add-full ecb-path-selected-directory |
|
1001 |
new-cache-elem)))) |
|
1002 |
||
1003 |
(when (not (string= dir-before-update ecb-path-selected-directory)) |
|
1004 |
(tree-buffer-scroll (point-min) (point-min)))))) |
|
1005 |
||
1006 |
(defun ecb-sources-filter-by-ext (ext-str) |
|
1007 |
"Filter the sources by extension EXT-STR."
|
|
1008 |
(if (= (length ext-str) 0) |
|
1009 |
(ecb-apply-filter-to-sources-buffer |
|
1010 |
"^[^.]+$" ;; matches only filenames with no extension |
|
1011 |
"No ext.") |
|
1012 |
(ecb-apply-filter-to-sources-buffer |
|
1013 |
(format "\\.%s\\'" ext-str) |
|
1014 |
(format "*.%s" ext-str)))) |
|
1015 |
||
1016 |
(tree-buffer-defpopup-command ecb-popup-sources-filter-by-ext |
|
1017 |
"Filter the sources by extension by popup."
|
|
1018 |
(ecb-sources-filter-by-ext |
|
1019 |
(read-string "Insert the filter-extension without leading dot: " |
|
1020 |
(and node |
|
1021 |
(file-name-extension (tree-node-get-data node)))))) |
|
1022 |
||
1023 |
(defun ecb-sources-filter-by-regexp () |
|
1024 |
"Filter the sources by a regexp. Ask for the regexp."
|
|
1025 |
(let ((regexp-str (read-string "Insert the filter-regexp: "))) |
|
1026 |
(if (> (length regexp-str) 0) |
|
1027 |
(ecb-apply-filter-to-sources-buffer regexp-str)))) |
|
1028 |
||
1029 |
(tree-buffer-defpopup-command ecb-popup-sources-filter-by-regexp |
|
1030 |
"Filter the sources by regexp by popup."
|
|
1031 |
(ecb-sources-filter-by-regexp)) |
|
1032 |
||
1033 |
(tree-buffer-defpopup-command ecb-popup-sources-filter-none |
|
1034 |
"Remove any filter from the sources by popup."
|
|
1035 |
(ecb-apply-filter-to-sources-buffer nil)) |
|
1036 |
||
1037 |
||
1038 |
(defun ecb-sources-filter () |
|
1039 |
"Apply a filter to the sources-buffer to reduce the number of entries.
|
|
1040 |
So you get a better overlooking. There are three choices:
|
|
1041 |
- Filter by extension: Just insert the extension you want the Sources-buffer
|
|
1042 |
being filtered. Insert the extension without leading dot!
|
|
1043 |
- Filter by regexp: Insert the filter as regular expression.
|
|
1044 |
- No filter: This means to display an entry for every file in the current
|
|
1045 |
selected directory \(all except these filter already filtered out by
|
|
1046 |
`ecb-source-file-regexps' and `ecb-sources-exclude-cvsignore'). |
|
1047 |
Such a filter is only applied to the current selected directory, i.e. each
|
|
1048 |
directory has its own filtered sources-buffer."
|
|
1049 |
(interactive) |
|
1050 |
(let ((choice (ecb-query-string "Filter sources by:" |
|
1051 |
'("extension" "regexp" "nothing")))) |
|
1052 |
(cond ((string= choice "extension") |
|
1053 |
(ecb-sources-filter-by-ext |
|
1054 |
(read-string "Insert the filter-extension without leading dot: "))) |
|
1055 |
((string= choice "regexp") |
|
1056 |
(ecb-sources-filter-by-regexp)) |
|
1057 |
(t (ecb-apply-filter-to-sources-buffer nil))))) |
|
1058 |
||
1059 |
(defun ecb-sources-filter-modeline-prefix (buffer-name sel-dir sel-source) |
|
1060 |
"Compute a mode-line prefix for the Sources-buffer so the current filter
|
|
1061 |
applied to the sources is displayed. This function is only for using by
|
|
1062 |
the option `ecb-mode-line-prefixes'." |
|
1063 |
(let ((filtered-cache-elem (ecb-sources-cache-get-filtered sel-dir))) |
|
1064 |
(if (null filtered-cache-elem) |
|
1065 |
nil ;; no prefix if no filter |
|
1066 |
(format "[Filter: %s]" (cdr (nth 3 filtered-cache-elem)))))) |
|
1067 |
||
1068 |
(defun ecb-apply-filter-to-sources-buffer (filter-regexp &optional filter-display) |
|
1069 |
"Apply the regular expression FILTER-REGEXP to the files of
|
|
1070 |
`ecb-path-selected-directory' and display only the filtered files in the |
|
1071 |
Sources-buffer. If FILTER-REGEXP is nil then any applied filter is removed and
|
|
1072 |
all files are displayed."
|
|
1073 |
(save-selected-window |
|
1074 |
(ecb-exec-in-sources-window |
|
1075 |
(if (null filter-regexp) |
|
1076 |
;; no filtering
|
|
1077 |
(progn |
|
1078 |
;; remove the filtered cache by setting it to nil
|
|
1079 |
(ecb-sources-cache-add-filtered ecb-path-selected-directory nil) |
|
1080 |
;; update the sources buffer - because the filtered cache is nil
|
|
1081 |
;; the full sources are displayed.
|
|
1082 |
(ecb-update-sources-buffer ecb-path-selected-directory) |
|
1083 |
(tree-buffer-highlight-node-data ecb-path-selected-source)) |
|
1084 |
;; apply the filter-regexp
|
|
1085 |
(let ((new-tree (tree-node-new-root)) |
|
1086 |
(old-children (tree-node-get-children (tree-buffer-get-root))) |
|
1087 |
(all-files (car (ecb-get-files-and-subdirs ecb-path-selected-directory))) |
|
1088 |
(filtered-files nil)) |
|
1089 |
(dolist (file all-files) |
|
1090 |
(if (string-match filter-regexp file) |
|
1091 |
(setq filtered-files |
|
1092 |
(cons file filtered-files)))) |
|
1093 |
;; building up the new files-tree
|
|
1094 |
(ecb-tree-node-add-files |
|
1095 |
new-tree
|
|
1096 |
ecb-path-selected-directory
|
|
1097 |
(nreverse filtered-files) |
|
1098 |
0 ecb-show-source-file-extension old-children t) |
|
1099 |
||
1100 |
;; updating the buffer itself
|
|
1101 |
(tree-buffer-set-root new-tree) |
|
1102 |
(tree-buffer-update) |
|
1103 |
(tree-buffer-scroll (point-min) (point-min)) |
|
1104 |
(tree-buffer-highlight-node-data ecb-path-selected-source) |
|
1105 |
||
1106 |
;; add the new filter to the cache, so the next call to
|
|
1107 |
;; `ecb-update-sources-buffer' displays the filtered sources.
|
|
1108 |
(ecb-sources-cache-add-filtered ecb-path-selected-directory |
|
1109 |
(list (tree-buffer-get-root) |
|
1110 |
(ecb-copy-list tree-buffer-nodes) |
|
1111 |
(buffer-string) |
|
1112 |
(cons filter-regexp |
|
1113 |
(or filter-display |
|
1114 |
filter-regexp)))))))) |
|
1115 |
;; now we update the mode-lines so the current filter (can be no filter) is
|
|
1116 |
;; displayed in the mode-line. See `ecb-sources-filter-modeline-prefix'.
|
|
1117 |
(ecb-mode-line-format)) |
|
1118 |
||
1119 |
||
1120 |
(defun ecb-set-selected-directory (path &optional force) |
|
1121 |
"Set the contents of the ECB-directories and -sources buffer correct for the
|
|
1122 |
value of PATH. If PATH is equal to the value of `ecb-path-selected-directory' |
|
1123 |
then nothing is done unless first optional argument FORCE is not nil."
|
|
1124 |
(let ((last-dir ecb-path-selected-directory)) |
|
1125 |
(save-selected-window |
|
1126 |
(setq ecb-path-selected-directory (ecb-fix-filename path)) |
|
1127 |
;; if ecb-path-selected-directory has not changed then there is no need
|
|
1128 |
;; to do anything here because neither the content of directory buffer
|
|
1129 |
;; nor the content of the sources buffer can have been changed!
|
|
1130 |
(when (or force (not (string= last-dir ecb-path-selected-directory))) |
|
1131 |
(when (or (not (ecb-show-sources-in-directories-buffer-p)) |
|
1132 |
ecb-auto-expand-directory-tree) |
|
1133 |
(ecb-exec-in-directories-window |
|
1134 |
(let (start) |
|
1135 |
(when ecb-auto-expand-directory-tree |
|
1136 |
;; Expand tree to show selected directory
|
|
1137 |
(setq start |
|
1138 |
(if (equal ecb-auto-expand-directory-tree 'best) |
|
1139 |
;; If none of the source-paths in the buffer
|
|
1140 |
;; `ecb-directories-buffer-name' matches then nil
|
|
1141 |
;; otherwise the node of the best matching source-path
|
|
1142 |
(cdar (sort (delete nil |
|
1143 |
(mapcar (lambda (elem) |
|
1144 |
(let ((data (tree-node-get-data elem))) |
|
1145 |
(save-match-data |
|
1146 |
(if (string-match |
|
1147 |
(concat "^" |
|
1148 |
(regexp-quote data)) |
|
1149 |
ecb-path-selected-directory) |
|
1150 |
(cons data elem) |
|
1151 |
nil)))) |
|
1152 |
(tree-node-get-children (tree-buffer-get-root)))) |
|
1153 |
(lambda (lhs rhs) |
|
1154 |
(> (length (car lhs)) (length (car rhs)))))) |
|
1155 |
;; we start at the root node
|
|
1156 |
(tree-buffer-get-root))) |
|
1157 |
(when (and (equal ecb-auto-expand-directory-tree 'best) |
|
1158 |
start) |
|
1159 |
;; expand the best-match node itself
|
|
1160 |
(tree-node-set-expanded start t) |
|
1161 |
;; This functions ensures a correct expandable-state of
|
|
1162 |
;; start-node
|
|
1163 |
(ecb-update-directory-node start)) |
|
1164 |
;; start recursive expanding of either the best-matching node or
|
|
1165 |
;; the root-node itself.
|
|
1166 |
(ecb-expand-directory-tree ecb-path-selected-directory |
|
1167 |
(or start |
|
1168 |
(tree-buffer-get-root))) |
|
1169 |
(tree-buffer-update)) |
|
1170 |
(when (not (ecb-show-sources-in-directories-buffer-p)) |
|
1171 |
(tree-buffer-highlight-node-data ecb-path-selected-directory |
|
1172 |
start))))) |
|
1173 |
;; now we update the sources buffer for `ecb-path-selected-directory'
|
|
1174 |
(ecb-update-sources-buffer last-dir)))) |
|
1175 |
||
1176 |
;; set the default-directory of each tree-buffer to current selected
|
|
1177 |
;; directory so we can open files via find-file from each tree-buffer.
|
|
1178 |
;; is this necessary if neither dir.- nor sources-buffer-contents have been
|
|
1179 |
;; changed? I think not but anyway, doesn't matter, costs are very low.
|
|
1180 |
(save-excursion |
|
1181 |
(dolist (buf ecb-tree-buffers) |
|
1182 |
(set-buffer buf) |
|
1183 |
(setq default-directory |
|
1184 |
(concat ecb-path-selected-directory |
|
1185 |
(and (not (= (aref ecb-path-selected-directory |
|
1186 |
(1- (length ecb-path-selected-directory))) |
|
1187 |
ecb-directory-sep-char)) |
|
1188 |
ecb-directory-sep-string))))) |
|
1189 |
;; set the modelines of all visible tree-buffers new
|
|
1190 |
(ecb-mode-line-format)) |
|
1191 |
||
1192 |
||
1193 |
(defun ecb-get-source-name (filename) |
|
1194 |
"Returns the source name of a file."
|
|
1195 |
(let ((f (file-name-nondirectory filename))) |
|
1196 |
(if ecb-show-source-file-extension |
|
1197 |
f
|
|
1198 |
(file-name-sans-extension f)))) |
|
1199 |
||
1200 |
||
1201 |
(defun ecb-select-source-file (filename &optional force) |
|
1202 |
"Updates the directories, sources and history buffers to match the filename
|
|
1203 |
given. If FORCE is not nil then the update of the directories buffer is done
|
|
1204 |
even if current directory is equal to `ecb-path-selected-directory'." |
|
1205 |
(save-selected-window |
|
1206 |
(ecb-set-selected-directory (file-name-directory filename) force) |
|
1207 |
(setq ecb-path-selected-source filename) |
|
1208 |
||
1209 |
;; Update directory buffer
|
|
1210 |
(when (ecb-show-sources-in-directories-buffer-p) |
|
1211 |
(ecb-exec-in-directories-window |
|
1212 |
(tree-buffer-highlight-node-data ecb-path-selected-source))) |
|
1213 |
||
1214 |
;; Update source buffer
|
|
1215 |
(ecb-exec-in-sources-window |
|
1216 |
(tree-buffer-highlight-node-data ecb-path-selected-source)) |
|
1217 |
||
1218 |
;; Update history buffer always regardless of visibility of history window
|
|
1219 |
(ecb-add-item-to-history-buffer ecb-path-selected-source) |
|
1220 |
(ecb-sort-history-buffer) |
|
1221 |
;; Update the history window only if it is visible
|
|
1222 |
(ecb-update-history-window ecb-path-selected-source))) |
|
1223 |
||
1224 |
||
1225 |
(defvar ecb-history-filter nil |
|
1226 |
"A cons-cell where car is the filter-function and the cdr is a string how
|
|
1227 |
the current active filter should be displayed in the modeline of the
|
|
1228 |
History-buffer. The filter-function gets the filename of an existing
|
|
1229 |
file-buffer and has to return not nil if for this filename a history-entry
|
|
1230 |
should be added.") |
|
1231 |
||
1232 |
(defun ecb-reset-history-filter () |
|
1233 |
"Reset the `ecb-history-filter' so all file-buffers are displayed." |
|
1234 |
(setq ecb-history-filter '(identity . nil))) |
|
1235 |
||
1236 |
(ecb-reset-history-filter) |
|
1237 |
||
1238 |
(defun ecb-add-all-buffers-to-history () |
|
1239 |
"Add all current file-buffers to the history-buffer of ECB.
|
|
1240 |
If `ecb-sort-history-items' is not nil then afterwards the history is sorted |
|
1241 |
alphabetically. Otherwise the most recently used buffers are on the top of the
|
|
1242 |
history and the seldom used buffers at the bottom."
|
|
1243 |
(interactive) |
|
1244 |
(ecb-reset-history-filter) |
|
1245 |
(ecb-add-buffers-to-history)) |
|
1246 |
||
1247 |
(defun ecb-add-buffers-to-history () |
|
1248 |
"Add exactly these currently existing file-buffers to the history-buffer
|
|
1249 |
which are not filtered out by current value of `ecb-history-filter'." |
|
1250 |
;; first we clear out the history buffer
|
|
1251 |
(save-excursion |
|
1252 |
(set-buffer ecb-history-buffer-name) |
|
1253 |
(tree-buffer-clear)) |
|
1254 |
(mapc (function (lambda (buf) |
|
1255 |
(when (buffer-file-name buf) |
|
1256 |
(ecb-add-item-to-history-buffer |
|
1257 |
(buffer-file-name buf))))) |
|
1258 |
(reverse (buffer-list))) |
|
1259 |
(ecb-sort-history-buffer) |
|
1260 |
(ecb-update-history-window (buffer-file-name ecb-last-source-buffer)) |
|
1261 |
;; now the modeline has to display the current filter
|
|
1262 |
(ecb-mode-line-format)) |
|
1263 |
||
1264 |
||
1265 |
(defun ecb-history-filter-modeline-prefix (buffer-name sel-dir sel-source) |
|
1266 |
"Compute a mode-line prefix for the History-buffer so the current filter
|
|
1267 |
applied to the history-entries is displayed. This function is only for using
|
|
1268 |
by the option `ecb-mode-line-prefixes'." |
|
1269 |
(and (cdr ecb-history-filter) |
|
1270 |
(format "[Filter: %s]" (cdr ecb-history-filter)))) |
|
1271 |
||
1272 |
||
1273 |
(defun ecb-add-item-to-history-buffer (filename) |
|
1274 |
"Add a new item for FILENAME to the history buffer if the current filter of
|
|
1275 |
`ecb-history-filter' does not filter out this file." |
|
1276 |
(save-excursion |
|
1277 |
(ecb-buffer-select ecb-history-buffer-name) |
|
1278 |
(tree-node-remove-child-data (tree-buffer-get-root) filename) |
|
1279 |
(when (funcall (car ecb-history-filter) |
|
1280 |
filename) |
|
1281 |
(tree-node-add-child-first |
|
1282 |
(tree-buffer-get-root) |
|
1283 |
(tree-node-new |
|
1284 |
(if (eq ecb-history-item-name 'buffer-name) |
|
1285 |
(let ((b (get-file-buffer filename))) |
|
1286 |
(if b |
|
1287 |
(buffer-name b) |
|
1288 |
(ecb-get-source-name filename))) |
|
1289 |
(ecb-get-source-name filename)) |
|
1290 |
0
|
|
1291 |
filename t))))) |
|
1292 |
||
1293 |
||
1294 |
(defun ecb-sort-history-buffer () |
|
1295 |
"Sort the history buffer according to `ecb-sort-history-items'." |
|
1296 |
(when ecb-sort-history-items |
|
1297 |
(save-excursion |
|
1298 |
(ecb-buffer-select ecb-history-buffer-name) |
|
1299 |
(tree-node-sort-children |
|
1300 |
(tree-buffer-get-root) |
|
1301 |
(function (lambda (l r) (string< (tree-node-get-name l) |
|
1302 |
(tree-node-get-name r)))))))) |
|
1303 |
||
1304 |
||
1305 |
(defun ecb-update-history-window (&optional filename) |
|
1306 |
"Updates the history window and highlights the item for FILENAME if given."
|
|
1307 |
(save-selected-window |
|
1308 |
(ecb-exec-in-history-window |
|
1309 |
(tree-buffer-update) |
|
1310 |
(tree-buffer-highlight-node-data filename)))) |
|
1311 |
||
1312 |
(defun ecb-set-selected-source (filename other-edit-window |
|
1313 |
no-edit-buffer-selection) |
|
1314 |
"Updates all the ECB buffers and loads the file. The file is also
|
|
1315 |
displayed unless NO-EDIT-BUFFER-SELECTION is set to non nil. In such case
|
|
1316 |
the file is only loaded invisible in the background, all semantic-parsing
|
|
1317 |
and ECB-Buffer-updating is done but the content of the main-edit window
|
|
1318 |
is not changed. For the allowed values of OTHER-EDIT-WINDOW see
|
|
1319 |
`ecb-combine-ecb-button/edit-win-nr'." |
|
1320 |
(ecb-select-source-file filename) |
|
1321 |
(if no-edit-buffer-selection |
|
1322 |
;; load the selected source in an invisible buffer, do all the
|
|
1323 |
;; updating and parsing stuff with this buffer in the background and
|
|
1324 |
;; display the methods in the METHOD-buffer. We can not go back to
|
|
1325 |
;; the edit-window because then the METHODS buffer would be
|
|
1326 |
;; immediately updated with the methods of the edit-window.
|
|
1327 |
(save-excursion |
|
1328 |
(set-buffer (find-file-noselect filename)) |
|
1329 |
(ecb-update-methods-buffer--internal 'scroll-to-begin)) |
|
1330 |
;; open the selected source in the edit-window and do all the update and
|
|
1331 |
;; parsing stuff with this buffer
|
|
1332 |
(ecb-find-file-and-display ecb-path-selected-source |
|
1333 |
other-edit-window) |
|
1334 |
(ecb-update-methods-buffer--internal 'scroll-to-begin) |
|
1335 |
(setq ecb-major-mode-selected-source major-mode) |
|
1336 |
(ecb-tag-sync 'force))) |
|
1337 |
||
1338 |
(defun ecb-clear-history () |
|
1339 |
"Clears the ECB history-buffer."
|
|
1340 |
(interactive) |
|
1341 |
(unless (or (not ecb-minor-mode) |
|
1342 |
(not (equal (selected-frame) ecb-frame))) |
|
1343 |
(save-selected-window |
|
1344 |
(ecb-exec-in-history-window |
|
1345 |
(tree-buffer-clear) |
|
1346 |
(tree-buffer-update) |
|
1347 |
(tree-buffer-highlight-node-data ecb-path-selected-source))))) |
|
1348 |
||
1349 |
||
1350 |
(defun ecb-tree-node-add-files |
|
1351 |
(node path files type include-extension old-children |
|
1352 |
&optional not-expandable) |
|
1353 |
"For every file in FILES add a child-node to NODE."
|
|
1354 |
(dolist (file files) |
|
1355 |
(let* ((filename (ecb-fix-filename path file)) |
|
1356 |
(file-1 (if include-extension |
|
1357 |
file
|
|
1358 |
(file-name-sans-extension file))) |
|
1359 |
(displayed-file file-1)) |
|
1360 |
(tree-node-add-child |
|
1361 |
node
|
|
1362 |
(ecb-new-child |
|
1363 |
old-children
|
|
1364 |
displayed-file
|
|
1365 |
type filename |
|
1366 |
(or not-expandable (= type 1)) |
|
1367 |
(if ecb-truncate-long-names 'end)))))) |
|
1368 |
||
1369 |
||
1370 |
(defun ecb-update-directory-node (node) |
|
1371 |
"Updates the directory node NODE and add all subnodes if any."
|
|
1372 |
(let ((old-children (tree-node-get-children node)) |
|
1373 |
(path (tree-node-get-data node))) |
|
1374 |
(tree-node-set-children node nil) |
|
1375 |
(if (file-accessible-directory-p path) |
|
1376 |
(let ((files-and-dirs (ecb-get-files-and-subdirs path))) |
|
1377 |
(ecb-tree-node-add-files node path (cdr files-and-dirs) |
|
1378 |
0 t old-children) |
|
1379 |
(if (ecb-show-sources-in-directories-buffer-p) |
|
1380 |
(ecb-tree-node-add-files node path (car files-and-dirs) 1 |
|
1381 |
ecb-show-source-file-extension
|
|
1382 |
old-children t)) |
|
1383 |
(tree-node-set-expandable node (or (tree-node-get-children node))) |
|
1384 |
;; if node is not expandable we set its expanded state to nil
|
|
1385 |
(tree-node-set-expanded node (if (not (tree-node-is-expandable node)) |
|
1386 |
nil
|
|
1387 |
(tree-node-is-expanded node))))))) |
|
1388 |
||
1389 |
||
1390 |
(defun ecb-get-source-paths-from-functions () |
|
1391 |
"Return a list of paths found by querying `ecb-source-path-functions'." |
|
1392 |
(let ((func ecb-source-path-functions) |
|
1393 |
(paths nil) |
|
1394 |
(rpaths nil)) |
|
1395 |
(while func |
|
1396 |
(setq paths (append paths (funcall (car ecb-source-path-functions))) |
|
1397 |
func (cdr func))) |
|
1398 |
(while paths |
|
1399 |
(setq rpaths (cons (expand-file-name (car paths)) rpaths) |
|
1400 |
paths (cdr paths))) |
|
1401 |
rpaths)) |
|
1402 |
||
1403 |
||
1404 |
(defun ecb-path-matching-any-source-path-p (path) |
|
1405 |
(let ((source-paths (append (ecb-get-source-paths-from-functions) |
|
1406 |
ecb-source-path))) |
|
1407 |
(catch 'exit |
|
1408 |
(dolist (dir source-paths) |
|
1409 |
(let ((norm-dir (ecb-fix-filename (if (listp dir) (car dir) dir) nil t))) |
|
1410 |
(save-match-data |
|
1411 |
(if (string-match (regexp-quote norm-dir) |
|
1412 |
(ecb-fix-filename (file-name-directory path))) |
|
1413 |
(throw 'exit norm-dir))) |
|
1414 |
nil))))) |
|
1415 |
||
1416 |
||
1417 |
(defun ecb-update-directories-buffer () |
|
1418 |
"Updates the ECB directories buffer."
|
|
1419 |
(interactive) |
|
1420 |
(unless (or (not ecb-minor-mode) |
|
1421 |
(not (equal (selected-frame) ecb-frame))) |
|
1422 |
(save-selected-window |
|
1423 |
(ecb-exec-in-directories-window |
|
1424 |
;; (setq tree-buffer-type-faces
|
|
1425 |
;; (list (cons 1 ecb-source-in-directories-buffer-face)))
|
|
1426 |
(let* ((node (tree-buffer-get-root)) |
|
1427 |
(old-children (tree-node-get-children node)) |
|
1428 |
(paths (append (ecb-get-source-paths-from-functions) |
|
1429 |
ecb-source-path))) |
|
1430 |
(tree-node-set-children node nil) |
|
1431 |
(dolist (dir paths) |
|
1432 |
(let* ((path (if (listp dir) (car dir) dir)) |
|
1433 |
(norm-dir (ecb-fix-filename path nil t)) |
|
1434 |
(name (if (listp dir) (cadr dir) norm-dir))) |
|
1435 |
(tree-node-add-child |
|
1436 |
node
|
|
1437 |
(ecb-new-child old-children name 2 norm-dir nil |
|
1438 |
(if ecb-truncate-long-names 'beginning))))) |
|
1439 |
;; (when (not paths)
|
|
1440 |
;; (tree-node-add-child node (tree-node-new "Welcome to ECB! Please select:"
|
|
1441 |
;; 3 '(lambda()) t))
|
|
1442 |
;; (tree-node-add-child node (tree-node-new "" 3 '(lambda()) t))
|
|
1443 |
;; (tree-node-add-child node (tree-node-new "[F2] Customize ECB" 3
|
|
1444 |
;; 'ecb-customize t))
|
|
1445 |
;; (tree-node-add-child node (tree-node-new "[F3] ECB Help" 3
|
|
1446 |
;; 'ecb-show-help t))
|
|
1447 |
;; (tree-node-add-child
|
|
1448 |
;; node (tree-node-new
|
|
1449 |
;; "[F4] Add Source Path" 3
|
|
1450 |
;; '(lambda () (call-interactively 'ecb-add-source-path)) t)))
|
|
1451 |
(tree-buffer-update)))))) |
|
1452 |
||
1453 |
||
1454 |
(defun ecb-new-child (old-children name type data &optional not-expandable shorten-name) |
|
1455 |
"Return a node with type = TYPE, data = DATA and name = NAME. Tries to find
|
|
1456 |
a node with matching TYPE and DATA in OLD-CHILDREN. If found no new node is
|
|
1457 |
created but only the fields of this node will be updated. Otherwise a new node
|
|
1458 |
is created."
|
|
1459 |
(catch 'exit |
|
1460 |
(dolist (child old-children) |
|
1461 |
(when (and (equal (tree-node-get-data child) data) |
|
1462 |
(= (tree-node-get-type child) type)) |
|
1463 |
(tree-node-set-name child name) |
|
1464 |
(if not-expandable |
|
1465 |
(tree-node-set-expandable child nil)) |
|
1466 |
(throw 'exit child))) |
|
1467 |
(let ((node (tree-node-new name type data not-expandable nil |
|
1468 |
(if ecb-truncate-long-names 'end)))) |
|
1469 |
(tree-node-set-shorten-name node shorten-name) |
|
1470 |
node))) |
|
1471 |
||
1472 |
||
1473 |
(defun ecb-add-source-path (&optional dir alias no-prompt-for-future-session) |
|
1474 |
"Add a directory to the `ecb-source-path'." |
|
1475 |
(interactive) |
|
1476 |
;; we must manually cut a filename because we must not add filenames to
|
|
1477 |
;; `ecb-source-path'!
|
|
1478 |
(let* ((use-dialog-box nil) |
|
1479 |
(my-dir (ecb-fix-filename |
|
1480 |
(or dir |
|
1481 |
(file-name-directory (read-file-name "Add source path: "))) |
|
1482 |
t)) |
|
1483 |
(my-alias (or alias |
|
1484 |
(read-string (format "Alias for \"%s\" (empty = no alias): " |
|
1485 |
my-dir))))) |
|
1486 |
(setq ecb-source-path (append ecb-source-path |
|
1487 |
(list (if (> (length my-alias) 0) |
|
1488 |
(list my-dir my-alias) my-dir)))) |
|
1489 |
(ecb-update-directories-buffer) |
|
1490 |
(if (and (not no-prompt-for-future-session) |
|
1491 |
(y-or-n-p "Add the new source-path also for future-sessions? ")) |
|
1492 |
(customize-save-variable 'ecb-source-path ecb-source-path) |
|
1493 |
(customize-set-variable 'ecb-source-path ecb-source-path)))) |
|
1494 |
||
1495 |
(tree-buffer-defpopup-command ecb-add-source-path-node |
|
1496 |
"Runs `ecb-add-source-path' from popup." |
|
1497 |
(call-interactively 'ecb-add-source-path)) |
|
1498 |
||
1499 |
||
1500 |
(tree-buffer-defpopup-command ecb-node-to-source-path |
|
1501 |
"Add this node to the source-path."
|
|
1502 |
(ecb-add-source-path (tree-node-get-data node))) |
|
1503 |
||
1504 |
||
1505 |
(defun ecb-delete-s (child children sources) |
|
1506 |
(when children |
|
1507 |
(if (eq child (car children)) |
|
1508 |
(cdr sources) |
|
1509 |
(cons (car sources) (ecb-delete-s child (cdr children) (cdr sources)))))) |
|
1510 |
||
1511 |
||
1512 |
(tree-buffer-defpopup-command ecb-delete-source-path |
|
1513 |
"Delete this source-path via popup."
|
|
1514 |
(let ((path (tree-node-get-data node))) |
|
1515 |
(when (ecb-confirm (concat "Really delete source-path " path "?")) |
|
1516 |
(setq ecb-source-path (ecb-delete-s |
|
1517 |
node (tree-node-get-children (tree-node-get-parent node)) |
|
1518 |
ecb-source-path)) |
|
1519 |
(ecb-update-directories-buffer) |
|
1520 |
(if (y-or-n-p "Delete source-path also for future-sessions? ") |
|
1521 |
(customize-save-variable 'ecb-source-path ecb-source-path) |
|
1522 |
(customize-set-variable 'ecb-source-path ecb-source-path))))) |
|
1523 |
||
1524 |
||
1525 |
(defun ecb-remove-dir-from-caches (dir) |
|
1526 |
(ecb-files-and-subdirs-cache-remove dir) |
|
1527 |
(ecb-sources-cache-remove dir)) |
|
1528 |
||
1529 |
(defun ecb-directory-update-speedbar (dir) |
|
1530 |
"Update the integrated speedbar if necessary."
|
|
1531 |
(and (ecb-speedbar-active-p) |
|
1532 |
;; depending on the value of `ecb-directory-update-speedbar' we have to
|
|
1533 |
;; check if it is senseful to update the speedbar.
|
|
1534 |
(or (equal ecb-directories-update-speedbar t) |
|
1535 |
(and (equal ecb-directories-update-speedbar 'auto) |
|
1536 |
(not (or (get-buffer-window ecb-sources-buffer-name ecb-frame) |
|
1537 |
(member ecb-layout-name |
|
1538 |
ecb-show-sources-in-directories-buffer)))) |
|
1539 |
(and (not (equal ecb-directories-update-speedbar 'auto)) |
|
1540 |
(functionp ecb-directories-update-speedbar) |
|
1541 |
(funcall ecb-directories-update-speedbar dir))) |
|
1542 |
(ecb-speedbar-update-contents))) |
|
1543 |
||
1544 |
||
1545 |
(defun ecb-directory-clicked (node ecb-button edit-window-nr shift-mode) |
|
1546 |
"Handle clicking onto NODE in the directories-buffer. ECB-BUTTON can be 1, 2
|
|
1547 |
or 3. If 3 then EDIT-WINDOW-NR contains the number of the edit-window the NODE
|
|
1548 |
should be displayed. For 1 and 2 the value of EDIT-WINDOW-NR is ignored."
|
|
1549 |
(if (= 3 (tree-node-get-type node)) |
|
1550 |
(funcall (tree-node-get-data node)) |
|
1551 |
(ecb-update-directory-node node) |
|
1552 |
(if shift-mode |
|
1553 |
(ecb-mouse-over-directory-node node nil nil 'force)) |
|
1554 |
(if (or (= 0 (tree-node-get-type node)) (= 2 (tree-node-get-type node))) |
|
1555 |
(progn |
|
1556 |
(if (= 2 ecb-button) |
|
1557 |
(when (tree-node-is-expandable node) |
|
1558 |
(tree-node-toggle-expanded node)) |
|
1559 |
||
1560 |
;; Removing the element from the sources-cache and the
|
|
1561 |
;; files-and-subdirs-cache
|
|
1562 |
(if shift-mode |
|
1563 |
(ecb-remove-dir-from-caches (tree-node-get-data node))) |
|
1564 |
||
1565 |
(ecb-set-selected-directory (tree-node-get-data node) shift-mode) |
|
1566 |
;; if we have running an integrated speedbar we must update the
|
|
1567 |
;; speedbar
|
|
1568 |
(ecb-directory-update-speedbar (tree-node-get-data node))) |
|
1569 |
||
1570 |
(ecb-exec-in-directories-window |
|
1571 |
;; Update the tree-buffer with optimized display of NODE
|
|
1572 |
(tree-buffer-update node))) |
|
1573 |
(ecb-set-selected-source (tree-node-get-data node) |
|
1574 |
(ecb-combine-ecb-button/edit-win-nr ecb-button edit-window-nr) |
|
1575 |
shift-mode)))) |
|
1576 |
||
1577 |
||
1578 |
(defun ecb-source-clicked (node ecb-button edit-window-nr shift-mode) |
|
1579 |
"Handle clicking onto NODE in the sources-buffer. ECB-BUTTON can be 1, 2 or
|
|
1580 |
3. If 3 then EDIT-WINDOW-NR contains the number of the edit-window the NODE
|
|
1581 |
should be displayed. For 1 and 2 the value of EDIT-WINDOW-NR is ignored."
|
|
1582 |
(if shift-mode |
|
1583 |
(ecb-mouse-over-source-node node nil nil 'force)) |
|
1584 |
(ecb-set-selected-source (tree-node-get-data node) |
|
1585 |
(ecb-combine-ecb-button/edit-win-nr ecb-button edit-window-nr) |
|
1586 |
shift-mode)) |
|
1587 |
||
1588 |
||
1589 |
(defun ecb-history-clicked (node ecb-button edit-window-nr shift-mode) |
|
1590 |
"Handle clicking onto NODE in the history-buffer. ECB-BUTTON can be 1, 2 or
|
|
1591 |
3. If 3 then EDIT-WINDOW-NR contains the number of the edit-window the NODE
|
|
1592 |
should be displayed. For 1 and 2 the value of EDIT-WINDOW-NR is ignored."
|
|
1593 |
(if shift-mode |
|
1594 |
(ecb-mouse-over-history-node node nil nil 'force)) |
|
1595 |
(ecb-set-selected-source (tree-node-get-data node) |
|
1596 |
(ecb-combine-ecb-button/edit-win-nr ecb-button edit-window-nr) |
|
1597 |
shift-mode)) |
|
1598 |
||
1599 |
(defun ecb-expand-directory-nodes (level) |
|
1600 |
"Set the expand level of the nodes in the ECB-directories-buffer.
|
|
1601 |
For argument LEVEL see `ecb-expand-methods-nodes'. |
|
1602 |
||
1603 |
Be aware that for deep structured paths and a lot of source-paths this command
|
|
1604 |
can last a long time - depending of machine- and disk-performance."
|
|
1605 |
(interactive "nLevel: ") |
|
1606 |
(save-selected-window |
|
1607 |
(ecb-exec-in-directories-window |
|
1608 |
(tree-buffer-expand-nodes level))) |
|
1609 |
(ecb-current-buffer-sync 'force)) |
|
1610 |
||
1611 |
||
1612 |
(defun ecb-get-file-info-text (file) |
|
1613 |
"Return a file-info string for a file in the ECB sources buffer"
|
|
1614 |
(let ((attrs (file-attributes file))) |
|
1615 |
(format "%s %8s %4d %10d %s %s" |
|
1616 |
(nth 8 attrs) |
|
1617 |
(user-login-name (nth 2 attrs)) |
|
1618 |
(nth 3 attrs) |
|
1619 |
(nth 7 attrs) |
|
1620 |
(format-time-string "%Y/%m/%d %H:%M" (nth 5 attrs)) |
|
1621 |
(if (equal (ecb-show-node-info-what ecb-sources-buffer-name) |
|
1622 |
'file-info-full) |
|
1623 |
file
|
|
1624 |
(file-name-nondirectory file))) |
|
1625 |
))
|
|
1626 |
||
1627 |
||
1628 |
(defun ecb-mouse-over-directory-node (node &optional window no-message click-force) |
|
1629 |
"Displays help text if mouse moves over a node in the directory buffer or if
|
|
1630 |
CLICK-FORCE is not nil and always with regards to the settings in
|
|
1631 |
`ecb-show-node-info-in-minibuffer'. NODE is the node for which help text |
|
1632 |
should be displayed, WINDOW is the related window, NO-MESSAGE defines if the
|
|
1633 |
help-text should be printed here."
|
|
1634 |
(if (= (tree-node-get-type node) 1) |
|
1635 |
(ecb-mouse-over-source-node node window no-message click-force) |
|
1636 |
(if (not (= (tree-node-get-type node) 3)) |
|
1637 |
(let ((str (when (or click-force |
|
1638 |
(ecb-show-minibuffer-info node window |
|
1639 |
ecb-directories-buffer-name) |
|
1640 |
(and (not (equal (ecb-show-node-info-when ecb-directories-buffer-name) |
|
1641 |
'never)) |
|
1642 |
(not (string= (tree-node-get-data node) |
|
1643 |
(tree-node-get-name node))) |
|
1644 |
(eq (tree-node-get-parent node) |
|
1645 |
(tree-buffer-get-root)))) |
|
1646 |
(if (equal (ecb-show-node-info-what ecb-directories-buffer-name) |
|
1647 |
'name) |
|
1648 |
(tree-node-get-name node) |
|
1649 |
(tree-node-get-data node))))) |
|
1650 |
(prog1 str |
|
1651 |
(unless no-message |
|
1652 |
(tree-buffer-nolog-message str))))))) |
|
1653 |
||
1654 |
||
1655 |
(defun ecb-mouse-over-source-node (node &optional window no-message click-force) |
|
1656 |
"Displays help text if mouse moves over a node in the sources buffer or if
|
|
1657 |
CLICK-FORCE is not nil and always with regards to the settings in
|
|
1658 |
`ecb-show-node-info-in-minibuffer'. NODE is the node for which help text |
|
1659 |
should be displayed, WINDOW is the related window, NO-MESSAGE defines if the
|
|
1660 |
help-text should be printed here."
|
|
1661 |
(let ((str (ignore-errors ;; For buffers that hasn't been saved yet |
|
1662 |
(when (or click-force |
|
1663 |
(ecb-show-minibuffer-info node window |
|
1664 |
ecb-sources-buffer-name)) |
|
1665 |
(if (equal (ecb-show-node-info-what ecb-sources-buffer-name) |
|
1666 |
'name) |
|
1667 |
(tree-node-get-name node) |
|
1668 |
(ecb-get-file-info-text (tree-node-get-data node))))))) |
|
1669 |
(prog1 str |
|
1670 |
(unless no-message |
|
1671 |
(tree-buffer-nolog-message str))))) |
|
1672 |
||
1673 |
||
1674 |
(defun ecb-mouse-over-history-node (node &optional window no-message click-force) |
|
1675 |
"Displays help text if mouse moves over a node in the history buffer or if
|
|
1676 |
CLICK-FORCE is not nil and always with regards to the settings in
|
|
1677 |
`ecb-show-node-info-in-minibuffer'. NODE is the node for which help text |
|
1678 |
should be displayed, WINDOW is the related window, NO-MESSAGE defines if the
|
|
1679 |
help-text should be printed here."
|
|
1680 |
(let ((str (ignore-errors ;; For buffers that hasn't been saved yet |
|
1681 |
(when (or click-force |
|
1682 |
(ecb-show-minibuffer-info node window |
|
1683 |
ecb-history-buffer-name)) |
|
1684 |
(if (equal (ecb-show-node-info-what ecb-history-buffer-name) |
|
1685 |
'name) |
|
1686 |
(tree-node-get-name node) |
|
1687 |
(tree-node-get-data node)))))) |
|
1688 |
(prog1 str |
|
1689 |
(unless no-message |
|
1690 |
(tree-buffer-nolog-message str))))) |
|
1691 |
||
1692 |
||
1693 |
;; needs methods
|
|
1694 |
(tree-buffer-defpopup-command ecb-create-source |
|
1695 |
"Creates a new sourcefile in current directory."
|
|
1696 |
(let* ((use-dialog-box nil) |
|
1697 |
(dir (ecb-fix-filename |
|
1698 |
(funcall (if (file-directory-p (tree-node-get-data node)) |
|
1699 |
'identity
|
|
1700 |
'file-name-directory) |
|
1701 |
(tree-node-get-data node)))) |
|
1702 |
(filename (file-name-nondirectory |
|
1703 |
(read-file-name "Source name: " (concat dir "/"))))) |
|
1704 |
(ecb-select-edit-window) |
|
1705 |
(if (string-match "\\.java$" filename) |
|
1706 |
(ecb-jde-gen-class-buffer dir filename) |
|
1707 |
(find-file (concat dir "/" filename))) |
|
1708 |
(when (= (point-min) (point-max)) |
|
1709 |
(set-buffer-modified-p t) |
|
1710 |
(let ((ecb-auto-update-methods-after-save nil)) |
|
1711 |
(save-buffer)) |
|
1712 |
(ecb-rebuild-methods-buffer-with-tagcache nil nil t)) |
|
1713 |
(ecb-remove-dir-from-caches dir) |
|
1714 |
(ecb-set-selected-directory dir t) |
|
1715 |
(ecb-current-buffer-sync))) |
|
1716 |
||
1717 |
||
1718 |
(defun ecb-grep-directory-internal (node find) |
|
1719 |
(ecb-select-edit-window) |
|
1720 |
(let ((default-directory (concat (ecb-fix-filename |
|
1721 |
(if (file-directory-p |
|
1722 |
(tree-node-get-data node)) |
|
1723 |
(tree-node-get-data node) |
|
1724 |
(file-name-directory |
|
1725 |
(tree-node-get-data node)))) |
|
1726 |
ecb-directory-sep-string))) |
|
1727 |
(call-interactively (if find |
|
1728 |
(or (and (fboundp ecb-grep-find-function) |
|
1729 |
ecb-grep-find-function) |
|
1730 |
'grep-find) |
|
1731 |
(or (and (fboundp ecb-grep-function) |
|
1732 |
ecb-grep-function) |
|
1733 |
'grep))))) |
|
1734 |
||
1735 |
||
1736 |
(tree-buffer-defpopup-command ecb-grep-find-directory |
|
1737 |
"Runs grep-find for current directory."
|
|
1738 |
(ecb-grep-directory-internal node t)) |
|
1739 |
||
1740 |
||
1741 |
(tree-buffer-defpopup-command ecb-grep-directory |
|
1742 |
"Runs grep for current directory."
|
|
1743 |
(ecb-grep-directory-internal node nil)) |
|
1744 |
||
1745 |
||
1746 |
(defun ecb-create-directory (parent-node) |
|
1747 |
(make-directory (concat (tree-node-get-data parent-node) "/" |
|
1748 |
(read-from-minibuffer "Directory name: "))) |
|
1749 |
(ecb-update-directory-node parent-node) |
|
1750 |
(tree-buffer-update)) |
|
1751 |
||
1752 |
||
1753 |
(tree-buffer-defpopup-command ecb-delete-directory |
|
1754 |
"Delete current directory."
|
|
1755 |
(let ((dir (tree-node-get-data node))) |
|
1756 |
(when (ecb-confirm (concat "Really delete directory" dir "? ")) |
|
1757 |
(delete-directory (tree-node-get-data node)) |
|
1758 |
(ecb-update-directory-node (tree-node-get-parent node)) |
|
1759 |
(tree-buffer-update)))) |
|
1760 |
||
1761 |
||
1762 |
(defun ecb-dired-directory-internal (node &optional other) |
|
1763 |
(ecb-select-edit-window) |
|
1764 |
(let ((dir (ecb-fix-filename |
|
1765 |
(funcall (if (file-directory-p (tree-node-get-data node)) |
|
1766 |
'identity
|
|
1767 |
'file-name-directory) |
|
1768 |
(tree-node-get-data node))))) |
|
1769 |
(ecb-with-adviced-functions |
|
1770 |
(funcall (if other |
|
1771 |
'dired-other-window
|
|
1772 |
'dired) |
|
1773 |
dir)))) |
|
1774 |
||
1775 |
||
1776 |
(tree-buffer-defpopup-command ecb-dired-directory |
|
1777 |
"Run dired for this directory."
|
|
1778 |
(ecb-dired-directory-internal node)) |
|
1779 |
||
1780 |
||
1781 |
(tree-buffer-defpopup-command ecb-dired-directory-other-window |
|
1782 |
"Run dired for this directory in the other window."
|
|
1783 |
(ecb-dired-directory-internal node 'other)) |
|
1784 |
||
1785 |
||
1786 |
(defun ecb-dir-run-cvs-op (node op op-arg-list) |
|
1787 |
(let ((dir (tree-node-get-data node))) |
|
1788 |
(funcall op dir op-arg-list))) |
|
1789 |
||
1790 |
||
1791 |
(tree-buffer-defpopup-command ecb-dir-popup-cvs-status |
|
1792 |
"Check status of directory \(and below) in pcl-cvs mode."
|
|
1793 |
(ecb-dir-run-cvs-op node 'cvs-status '("-v"))) |
|
1794 |
||
1795 |
||
1796 |
(tree-buffer-defpopup-command ecb-dir-popup-cvs-examine |
|
1797 |
"Examine directory \(and below) in pcl-cvs mode."
|
|
1798 |
(ecb-dir-run-cvs-op node 'cvs-examine '("-d" "-P"))) |
|
1799 |
||
1800 |
||
1801 |
(tree-buffer-defpopup-command ecb-dir-popup-cvs-update |
|
1802 |
"Update directory \(and below) in pcl-cvs mode."
|
|
1803 |
(ecb-dir-run-cvs-op node 'cvs-update '("-d" "-P"))) |
|
1804 |
||
1805 |
||
1806 |
(defvar ecb-common-directories-menu nil) |
|
1807 |
||
1808 |
||
1809 |
(setq ecb-common-directories-menu |
|
1810 |
'(("Grep" |
|
1811 |
(ecb-grep-directory "Grep Directory") |
|
1812 |
(ecb-grep-find-directory "Grep Directory recursive")) |
|
1813 |
;;("---")
|
|
1814 |
("Dired" |
|
1815 |
(ecb-dired-directory "Open in Dired") |
|
1816 |
(ecb-dired-directory-other-window "Open in Dired other window")) |
|
1817 |
("---") |
|
1818 |
(ecb-create-source "Create Sourcefile") |
|
1819 |
(ecb-create-directory "Create Child Directory") |
|
1820 |
(ecb-delete-directory "Delete Directory") |
|
1821 |
("---") |
|
1822 |
(ecb-add-source-path-node "Add Source Path"))) |
|
1823 |
||
1824 |
||
1825 |
(defvar ecb-directories-menu nil |
|
1826 |
"Built-in menu for the directories-buffer for directories which are not a
|
|
1827 |
source-path of `ecb-source-path'.") |
|
1828 |
(setq ecb-directories-menu |
|
1829 |
(append |
|
1830 |
ecb-common-directories-menu
|
|
1831 |
'((ecb-node-to-source-path "Make This a Source Path") |
|
1832 |
("---") |
|
1833 |
(ecb-maximize-ecb-window-menu-wrapper "Maximize window")))) |
|
1834 |
||
1835 |
||
1836 |
(defvar ecb-directories-menu-title-creator |
|
1837 |
(function (lambda (node) |
|
1838 |
(let ((node-type (tree-node-get-type node)) |
|
1839 |
(node-data (tree-node-get-name node))) |
|
1840 |
(cond ((= node-type 0) ;; directory |
|
1841 |
(format "%s (Directory)" node-data)) |
|
1842 |
((= node-type 1) ;; source-file |
|
1843 |
(format "%s (File)" node-data)) |
|
1844 |
((= node-type 2) ;; source-path |
|
1845 |
(format "%s (Source-path)" node-data)))))) |
|
1846 |
"The menu-title for the directories menu. Has to be either a string or a
|
|
1847 |
function which is called with current node and has to return a string.") |
|
1848 |
||
1849 |
||
1850 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin1 |
|
1851 |
"Open current source-file the 1. edit-window."
|
|
1852 |
;; We can use `ecb-source-clicked' for history-buffer too because shift-mode
|
|
1853 |
;; is nil.
|
|
1854 |
(ecb-source-clicked node 3 1 nil)) |
|
1855 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin2 |
|
1856 |
"Open current source-file the 2. edit-window."
|
|
1857 |
(ecb-source-clicked node 3 2 nil)) |
|
1858 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin3 |
|
1859 |
"Open current source-file the 3. edit-window."
|
|
1860 |
(ecb-source-clicked node 3 3 nil)) |
|
1861 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin4 |
|
1862 |
"Open current source-file the 4. edit-window."
|
|
1863 |
(ecb-source-clicked node 3 4 nil)) |
|
1864 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin5 |
|
1865 |
"Open current source-file the 5. edit-window."
|
|
1866 |
(ecb-source-clicked node 3 5 nil)) |
|
1867 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin6 |
|
1868 |
"Open current source-file the 6. edit-window."
|
|
1869 |
(ecb-source-clicked node 3 6 nil)) |
|
1870 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin7 |
|
1871 |
"Open current source-file the 7. edit-window."
|
|
1872 |
(ecb-source-clicked node 3 7 nil)) |
|
1873 |
(tree-buffer-defpopup-command ecb-open-source-in-editwin8 |
|
1874 |
"Open current source-file the 8. edit-window."
|
|
1875 |
(ecb-source-clicked node 3 8 nil)) |
|
1876 |
||
1877 |
(defun ecb-dir/source/hist-menu-editwin-entries () |
|
1878 |
"Generate popup-menu-entries for each edit-window if there are at least 2
|
|
1879 |
edit-windows. Otherwise return nil."
|
|
1880 |
(let ((edit-win-list (ecb-canonical-edit-windows-list)) |
|
1881 |
(result nil)) |
|
1882 |
(when (> (length edit-win-list) 1) |
|
1883 |
(dotimes (i (min 8 (length edit-win-list))) |
|
1884 |
(setq result |
|
1885 |
(append result |
|
1886 |
(list (list (intern (format "ecb-open-source-in-editwin%d" (1+ i))) |
|
1887 |
(format "edit-window %d" (1+ i))))))) |
|
1888 |
(append (list (list "---")) ;; we want a separator |
|
1889 |
(list (append (list "Open source-file in ...") |
|
1890 |
result)))))) |
|
1891 |
||
1892 |
||
1893 |
(defun ecb-directories-menu-creator (tree-buffer-name) |
|
1894 |
"Creates the popup-menus for the directories-buffer."
|
|
1895 |
(setq ecb-layout-prevent-handle-ecb-window-selection t) |
|
1896 |
(let ((dyn-user-extension |
|
1897 |
(and (functionp ecb-directories-menu-user-extension-function) |
|
1898 |
(funcall ecb-directories-menu-user-extension-function))) |
|
1899 |
(dyn-builtin-extension (ecb-dir/source/hist-menu-editwin-entries))) |
|
1900 |
(list (cons 0 (funcall (or ecb-directories-menu-sorter |
|
1901 |
'identity) |
|
1902 |
(append dyn-user-extension |
|
1903 |
ecb-directories-menu-user-extension
|
|
1904 |
ecb-directories-menu))) |
|
1905 |
(cons 1 (funcall (or ecb-sources-menu-sorter |
|
1906 |
'identity) |
|
1907 |
(append dyn-user-extension |
|
1908 |
ecb-sources-menu-user-extension
|
|
1909 |
ecb-sources-menu
|
|
1910 |
dyn-builtin-extension))) |
|
1911 |
(cons 2 (funcall (or ecb-directories-menu-sorter |
|
1912 |
'identity) |
|
1913 |
(append dyn-user-extension |
|
1914 |
ecb-directories-menu-user-extension
|
|
1915 |
ecb-source-path-menu)))))) |
|
1916 |
||
1917 |
||
1918 |
(defvar ecb-source-path-menu nil |
|
1919 |
"Built-in menu for the directories-buffer for directories which are elements of
|
|
1920 |
`ecb-source-path'.") |
|
1921 |
(setq ecb-source-path-menu |
|
1922 |
(append |
|
1923 |
ecb-common-directories-menu
|
|
1924 |
'((ecb-delete-source-path "Delete Source Path") |
|
1925 |
("---") |
|
1926 |
(ecb-maximize-ecb-window-menu-wrapper "Maximize window")))) |
|
1927 |
||
1928 |
||
1929 |
(tree-buffer-defpopup-command ecb-delete-source |
|
1930 |
"Deletes current sourcefile."
|
|
1931 |
(let* ((file (tree-node-get-data node)) |
|
1932 |
(dir (ecb-fix-filename (file-name-directory file)))) |
|
1933 |
(when (ecb-confirm (concat "Really delete " (file-name-nondirectory file) "? ")) |
|
1934 |
(when (get-file-buffer file) |
|
1935 |
(kill-buffer (get-file-buffer file))) |
|
1936 |
(ecb-delete-file file) |
|
1937 |
(ecb-remove-dir-from-caches dir) |
|
1938 |
(ecb-set-selected-directory dir t)))) |
|
1939 |
||
1940 |
||
1941 |
(tree-buffer-defpopup-command ecb-file-popup-ediff-revision |
|
1942 |
"Diff file against repository with ediff."
|
|
1943 |
(let ((file (tree-node-get-data node))) |
|
1944 |
(ediff-revision file))) |
|
1945 |
||
1946 |
||
1947 |
(tree-buffer-defpopup-command ecb-file-popup-vc-next-action |
|
1948 |
"Checkin/out file."
|
|
1949 |
(let ((file (tree-node-get-data node))) |
|
1950 |
(find-file file) |
|
1951 |
(vc-next-action nil))) |
|
1952 |
||
1953 |
||
1954 |
(tree-buffer-defpopup-command ecb-file-popup-vc-log |
|
1955 |
"Print revision history of file."
|
|
1956 |
(let ((file (tree-node-get-data node))) |
|
1957 |
(find-file file) |
|
1958 |
(vc-print-log))) |
|
1959 |
||
1960 |
||
1961 |
(tree-buffer-defpopup-command ecb-file-popup-vc-annotate |
|
1962 |
"Annotate file"
|
|
1963 |
(let ((file (tree-node-get-data node))) |
|
1964 |
(find-file file) |
|
1965 |
(vc-annotate nil))) |
|
1966 |
||
1967 |
||
1968 |
(tree-buffer-defpopup-command ecb-file-popup-vc-diff |
|
1969 |
"Diff file against last version in repository."
|
|
1970 |
(let ((file (tree-node-get-data node))) |
|
1971 |
(find-file file) |
|
1972 |
(vc-diff nil))) |
|
1973 |
||
1974 |
||
1975 |
(defvar ecb-sources-menu nil |
|
1976 |
"Built-in menu for the sources-buffer.") |
|
1977 |
||
1978 |
||
1979 |
(setq ecb-sources-menu |
|
1980 |
'(("Grep" |
|
1981 |
(ecb-grep-directory "Grep Directory") |
|
1982 |
(ecb-grep-find-directory "Grep Directory recursive")) |
|
1983 |
("Dired" |
|
1984 |
(ecb-dired-directory "Open Dir in Dired") |
|
1985 |
(ecb-dired-directory-other-window "Open Dir in Dired other window")) |
|
1986 |
("Filter" |
|
1987 |
(ecb-popup-sources-filter-by-ext "Filter by extension") |
|
1988 |
(ecb-popup-sources-filter-by-regexp "Filter by a regexp") |
|
1989 |
(ecb-popup-sources-filter-none "No filter")) |
|
1990 |
("---") |
|
1991 |
(ecb-create-source "Create Sourcefile") |
|
1992 |
(ecb-delete-source "Delete Sourcefile") |
|
1993 |
("---") |
|
1994 |
(ecb-maximize-ecb-window-menu-wrapper "Maximize window"))) |
|
1995 |
||
1996 |
||
1997 |
(defvar ecb-sources-menu-title-creator |
|
1998 |
(function (lambda (node) |
|
1999 |
(file-name-nondirectory (tree-node-get-data node)))) |
|
2000 |
"The menu-title for the sources menu. See
|
|
2001 |
`ecb-directories-menu-title-creator'.") |
|
2002 |
||
2003 |
(defun ecb-sources-menu-creator (tree-buffer-name) |
|
2004 |
"Creates the popup-menus for the sources-buffer."
|
|
2005 |
(setq ecb-layout-prevent-handle-ecb-window-selection t) |
|
2006 |
(let ((dyn-user-extension |
|
2007 |
(and (functionp ecb-sources-menu-user-extension-function) |
|
2008 |
(funcall ecb-sources-menu-user-extension-function))) |
|
2009 |
(dyn-builtin-extension (ecb-dir/source/hist-menu-editwin-entries))) |
|
2010 |
(list (cons 0 (funcall (or ecb-sources-menu-sorter |
|
2011 |
'identity) |
|
2012 |
(append dyn-user-extension |
|
2013 |
ecb-sources-menu-user-extension
|
|
2014 |
ecb-sources-menu
|
|
2015 |
dyn-builtin-extension)))))) |
|
2016 |
||
2017 |
;; history popups
|
|
2018 |
||
2019 |
(tree-buffer-defpopup-command ecb-history-kill-buffer |
|
2020 |
"Kills the buffer for current entry."
|
|
2021 |
(let ((data (tree-node-get-data node))) |
|
2022 |
(when (get-file-buffer data) |
|
2023 |
(kill-buffer (get-file-buffer data))))) |
|
2024 |
||
2025 |
(defun ecb-history-filter-by-ext (ext-str) |
|
2026 |
"Filter history entries by extension."
|
|
2027 |
(if (= (length ext-str) 0) |
|
2028 |
(setq ecb-history-filter |
|
2029 |
(cons `(lambda (filename) |
|
2030 |
(save-match-data |
|
2031 |
(string-match "^[^.]+$" filename))) |
|
2032 |
"No ext.")) |
|
2033 |
(setq ecb-history-filter |
|
2034 |
(cons `(lambda (filename) |
|
2035 |
(save-match-data |
|
2036 |
(string-match ,(format "\\.%s\\'" ext-str) |
|
2037 |
filename))) |
|
2038 |
(format "*.%s" ext-str)))) |
|
2039 |
(ecb-add-buffers-to-history)) |
|
2040 |
||
2041 |
(tree-buffer-defpopup-command ecb-popup-history-filter-by-ext |
|
2042 |
"Filter history entries by extension by popup."
|
|
2043 |
(let ((ext-str (read-string "Insert the filter-extension without leading dot: " |
|
2044 |
(and node |
|
2045 |
(file-name-extension (tree-node-get-data node)))))) |
|
2046 |
(ecb-history-filter-by-ext ext-str))) |
|
2047 |
||
2048 |
(defun ecb-history-filter-by-regexp () |
|
2049 |
"Filter history entries by regexp."
|
|
2050 |
(let ((regexp-str (read-string "Insert the filter-regexp: "))) |
|
2051 |
(if (> (length regexp-str) 0) |
|
2052 |
(setq ecb-history-filter |
|
2053 |
(cons `(lambda (filename) |
|
2054 |
(save-match-data |
|
2055 |
(string-match ,regexp-str filename))) |
|
2056 |
regexp-str)))) |
|
2057 |
(ecb-add-buffers-to-history)) |
|
2058 |
||
2059 |
(tree-buffer-defpopup-command ecb-popup-history-filter-by-regexp |
|
2060 |
"Filter history entries by regexp by popup."
|
|
2061 |
(ecb-history-filter-by-regexp)) |
|
2062 |
||
2063 |
(tree-buffer-defpopup-command ecb-popup-history-filter-all-existing |
|
2064 |
"No history filter, i.e. add all existing file-buffers to the history."
|
|
2065 |
(ecb-add-all-buffers-to-history)) |
|
2066 |
||
2067 |
||
2068 |
(defun ecb-history-filter () |
|
2069 |
"Apply a filter to the history-buffer to reduce the number of entries.
|
|
2070 |
So you get a better overlooking. There are three choices:
|
|
2071 |
- Filter by extension: Just insert the extension you want the History-buffer
|
|
2072 |
being filtered. Insert the extension without leading dot!
|
|
2073 |
- Filter by regexp: Insert the filter as regular expression.
|
|
2074 |
- No filter: This means to display an entry for all currently living
|
|
2075 |
file-buffers."
|
|
2076 |
(interactive) |
|
2077 |
(let ((choice (ecb-query-string "Filter history by:" |
|
2078 |
'("extension" "regexp" "no filter")))) |
|
2079 |
(cond ((string= choice "extension") |
|
2080 |
(ecb-history-filter-by-ext |
|
2081 |
(read-string "Insert the filter-extension without leading dot: "))) |
|
2082 |
((string= choice "regexp") |
|
2083 |
(ecb-history-filter-by-regexp)) |
|
2084 |
(t (ecb-add-all-buffers-to-history))))) |
|
2085 |
||
2086 |
(defvar ecb-history-menu nil |
|
2087 |
"Built-in menu for the history-buffer.") |
|
2088 |
||
2089 |
||
2090 |
(setq ecb-history-menu |
|
2091 |
'(("Grep" |
|
2092 |
(ecb-grep-directory "Grep Directory") |
|
2093 |
(ecb-grep-find-directory "Grep Directory recursive")) |
|
2094 |
;;("---")
|
|
2095 |
("Dired" |
|
2096 |
(ecb-dired-directory "Open Dir in Dired") |
|
2097 |
(ecb-dired-directory-other-window "Open Dir in Dired other window")) |
|
2098 |
("Filter" |
|
2099 |
(ecb-popup-history-filter-by-ext "Filter by extension") |
|
2100 |
(ecb-popup-history-filter-by-regexp "Filter by regexp") |
|
2101 |
(ecb-popup-history-filter-all-existing "No filter (all file-buffers)")) |
|
2102 |
("---") |
|
2103 |
(ecb-history-kill-buffer "Kill Buffer") |
|
2104 |
(ecb-delete-source "Delete Sourcefile") |
|
2105 |
("---") |
|
2106 |
(ecb-maximize-ecb-window-menu-wrapper "Maximize window"))) |
|
2107 |
||
2108 |
||
2109 |
(defvar ecb-history-menu-title-creator |
|
2110 |
(function (lambda (node) |
|
2111 |
(tree-node-get-name node))) |
|
2112 |
"The menu-title for the history menu. See
|
|
2113 |
`ecb-directories-menu-title-creator'.") |
|
2114 |
||
2115 |
(defun ecb-history-menu-creator (tree-buffer-name) |
|
2116 |
"Creates the popup-menus for the history-buffer."
|
|
2117 |
(setq ecb-layout-prevent-handle-ecb-window-selection t) |
|
2118 |
(let ((dyn-user-extension |
|
2119 |
(and (functionp ecb-history-menu-user-extension-function) |
|
2120 |
(funcall ecb-history-menu-user-extension-function))) |
|
2121 |
(dyn-builtin-extension (ecb-dir/source/hist-menu-editwin-entries))) |
|
2122 |
(list (cons 0 (funcall (or ecb-history-menu-sorter |
|
2123 |
'identity) |
|
2124 |
(append dyn-user-extension |
|
2125 |
ecb-history-menu-user-extension
|
|
2126 |
ecb-history-menu
|
|
2127 |
dyn-builtin-extension)))))) |
|
2128 |
||
2129 |
||
2130 |
(silentcomp-provide 'ecb-file-browser) |
|
2131 |
||
2132 |
;;; ecb-file-browser.el ends here
|