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

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