~ubuntu-branches/debian/lenny/ecb/lenny

« back to all changes in this revision

Viewing changes to ecb-file-browser.el

  • Committer: Bazaar Package Importer
  • Author(s): Joerg Jaspert
  • Date: 2004-02-16 23:16:24 UTC
  • Revision ID: james.westby@ubuntu.com-20040216231624-brlrnyp41twx033r
Tags: upstream-2.21
ImportĀ upstreamĀ versionĀ 2.21

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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