(org-set-tags): Keep single space after stars.
[bpt/emacs.git] / lisp / locate.el
CommitLineData
092af6d8 1;;; locate.el --- interface to the locate command
6aea3b07 2
0d30b337 3;; Copyright (C) 1996, 1998, 2001, 2002, 2003, 2004,
aaef169d 4;; 2005, 2006 Free Software Foundation, Inc.
6aea3b07 5
dc268724 6;; Author: Peter Breton <pbreton@cs.umb.edu>
f947a7fa 7;; Keywords: unix files
6aea3b07
RS
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
6aea3b07
RS
25
26;;; Commentary:
27
271a87e8 28;; Search a database of files and use dired commands on the result.
6aea3b07
RS
29;;
30;; Locate.el provides an interface to a program which searches a
31;; database of file names. By default, this program is the GNU locate
32;; command, but it could also be the BSD-style find command, or even a
33;; user specified command.
34;;
35;; To use the BSD-style "fast find", or any other shell command of the
83346ee8 36;; form
6aea3b07
RS
37;;
38;; SHELLPROGRAM Name-to-find
39;;
be8bf2d0 40;; set the variable `locate-command' in your .emacs file.
6aea3b07 41;;
83346ee8 42;; To use a more complicated expression, create a function which
be8bf2d0
RS
43;; takes a string (the name to find) as input and returns a list.
44;; The first element should be the command to be executed, the remaining
45;; elements should be the arguments (including the name to find). Then put
6aea3b07 46;;
83346ee8 47;; (setq locate-make-command-line 'my-locate-command-line)
6aea3b07
RS
48;;
49;; in your .emacs, using the name of your function in place of
be8bf2d0 50;; my-locate-command-line.
6aea3b07
RS
51;;
52;; You should make sure that whichever command you use works correctly
53;; from a shell prompt. GNU locate and BSD find expect the file databases
54;; to either be in standard places or located via environment variables.
55;; If the latter, make sure these environment variables are set in
be8bf2d0 56;; your emacs process.
6aea3b07
RS
57;;
58;; Locate-mode assumes that each line output from the locate-command
59;; consists exactly of a file name, possibly preceded or trailed by
60;; whitespace. If your file database has other information on the line (for
83346ee8 61;; example, the file size), you will need to redefine the function
be8bf2d0 62;; `locate-get-file-positions' to return a list consisting of the first
6aea3b07
RS
63;; character in the file name and the last character in the file name.
64;;
65;; To use locate-mode, simply type M-x locate and then the string
66;; you wish to find. You can use almost all of the dired commands in
67;; the resulting *Locate* buffer. It is worth noting that your commands
68;; do not, of course, affect the file database. For example, if you
69;; compress a file in the locate buffer, the actual file will be
70;; compressed, but the entry in the file database will not be
71;; affected. Consequently, the database and the filesystem will be out
be8bf2d0 72;; of sync until the next time the database is updated.
6aea3b07 73;;
be8bf2d0 74;; The command `locate-with-filter' keeps only lines matching a
6aea3b07
RS
75;; regular expression; this is often useful to constrain a big search.
76;;
77\f
271a87e8
LT
78;;;;; Building a database of files ;;;;;;;;;
79;;
80;; You can create a simple files database with a port of the Unix find command
81;; and one of the various Windows NT various scheduling utilities,
82;; for example the AT command from the NT Resource Kit, WinCron which is
83;; included with Microsoft FrontPage, or the shareware NTCron program.
84;;
85;; To set up a function which searches the files database, do something
86;; like this:
87;;
88;; (defvar locate-fcodes-file "c:/users/peter/fcodes")
89;; (defvar locate-make-command-line 'nt-locate-make-command-line)
90;;
91;; (defun nt-locate-make-command-line (arg)
92;; (list "grep" "-i" arg locate-fcodes-file))
93;;
94;;;;;;;; ADVICE For dired-make-relative: ;;;;;;;;;
95;;
96;; For certain dired commands to work right, you should also include the
97;; following in your _emacs/.emacs:
98;;
99;; (defadvice dired-make-relative (before set-no-error activate)
100;; "For locate mode and Windows, don't return errors"
101;; (if (and (eq major-mode 'locate-mode)
102;; (memq system-type (list 'windows-nt 'ms-dos)))
103;; (ad-set-arg 2 t)
104;; ))
105;;
106;; Otherwise, `dired-make-relative' will give error messages like
107;; "FILENAME: not in directory tree growing at /"
108
109\f
6aea3b07
RS
110;;; Code:
111
112(eval-when-compile
113 (require 'dired))
114
115;; Variables
6aea3b07 116
be8bf2d0
RS
117(defvar locate-current-filter nil)
118
d979dc2b
SE
119(defgroup locate nil
120 "Interface to the locate command."
121 :prefix "locate-"
122 :group 'external)
6aea3b07 123
d979dc2b 124(defcustom locate-command "locate"
18886d54
LT
125 "Executable program for searching a database of files.
126The Emacs commands `locate' and `locate-with-filter' use this.
127The value should be a program that can be called from a shell
128with one argument, SEARCH-STRING. The program determines which
129database it searches. The output of the program should consist
130of those file names in the database that match SEARCH-STRING,
131listed one per line, possibly with leading or trailing
132whitespace. If the output is in another form, you may have to
133redefine the function `locate-get-file-positions'.
134
135The program may interpret SEARCH-STRING as a literal string, a
136shell pattern or a regular expression. The exact rules of what
137constitutes a match may also depend on the program.
138
139The standard value of this variable is \"locate\".
140This program normally searches a database of all files on your
141system, or of all files that you have access to. Consult the
142documentation of that program for the details about how it determines
143which file names match SEARCH-STRING. (Those details vary highly with
144the version.)"
d979dc2b
SE
145 :type 'string
146 :group 'locate)
6aea3b07 147
d979dc2b
SE
148(defvar locate-history-list nil
149 "The history list used by the \\[locate] command.")
6aea3b07 150
83346ee8
PB
151(defvar locate-grep-history-list nil
152 "The history list used by the \\[locate-with-filter] command.")
153
d979dc2b 154(defcustom locate-make-command-line 'locate-default-make-command-line
18886d54
LT
155 "Function used to create the locate command line.
156The Emacs commands `locate' and `locate-with-filter' use this.
157This function should take one argument, a string (the name to find)
158and return a list of strings. The first element of the list should be
159the name of a command to be executed by a shell, the remaining elements
160should be the arguments to that command (including the name to find)."
d979dc2b
SE
161 :type 'function
162 :group 'locate)
163
164(defcustom locate-buffer-name "*Locate*"
18886d54 165 "Name of the buffer to show results from the \\[locate] command."
d979dc2b
SE
166 :type 'string
167 :group 'locate)
168
169(defcustom locate-fcodes-file nil
18886d54
LT
170 "File name for the database of file names used by `locate'.
171If non-nil, `locate' uses this name in the header of the `*Locate*'
172buffer. If nil, it mentions no file name in that header.
173
174Just setting this variable does not actually change the database
175that `locate' searches. The executive program that the Emacs
176function `locate' uses, as given by the variables `locate-command'
177or `locate-make-command-line', determines the database."
e0063bf6 178 :type '(choice (const :tag "None" nil) file)
d979dc2b
SE
179 :group 'locate)
180
83346ee8 181(defcustom locate-header-face nil
18886d54 182 "Face used to highlight the locate header."
e0063bf6 183 :type '(choice (const :tag "None" nil) face)
d979dc2b 184 :group 'locate)
6aea3b07 185
271a87e8
LT
186;;;###autoload
187(defcustom locate-ls-subdir-switches "-al"
188 "`ls' switches for inserting subdirectories in `*Locate*' buffers.
34bb9b0a 189This should contain the \"-l\" switch, but not the \"-F\" or \"-b\" switches."
271a87e8
LT
190 :type 'string
191 :group 'locate
bf247b6e 192 :version "22.1")
271a87e8 193
be8bf2d0 194(defcustom locate-update-command "updatedb"
18886d54 195 "The executable program used to update the locate database."
be8bf2d0
RS
196 :type 'string
197 :group 'locate)
6aea3b07 198
83346ee8 199(defcustom locate-prompt-for-command nil
18886d54 200 "If non-nil, the `locate' command prompts for a command to run.
83346ee8
PB
201Otherwise, that behavior is invoked via a prefix argument."
202 :group 'locate
203 :type 'boolean
204 )
205
6aea3b07
RS
206;; Functions
207
208(defun locate-default-make-command-line (search-string)
be8bf2d0 209 (list locate-command search-string))
6aea3b07 210
96c1776c
PB
211(defun locate-word-at-point ()
212 (let ((pt (point)))
213 (buffer-substring-no-properties
214 (save-excursion
215 (skip-chars-backward "-a-zA-Z0-9.")
216 (point))
217 (save-excursion
218 (skip-chars-forward "-a-zA-Z0-9.")
219 (skip-chars-backward "." pt)
220 (point)))))
221
1d96c2ff 222;;;###autoload
8348e1f9 223(defun locate (search-string &optional filter)
83346ee8 224 "Run the program `locate', putting results in `*Locate*' buffer.
18886d54
LT
225Pass it SEARCH-STRING as argument. Interactively, prompt for SEARCH-STRING.
226With prefix arg, prompt for the exact shell command to run instead.
227
228This program searches for those file names in a database that match
229SEARCH-STRING and normally outputs all matching absolute file names,
230one per line. The database normally consists of all files on your
231system, or of all files that you have access to. Consult the
232documentation of the program for the details about how it determines
233which file names match SEARCH-STRING. (Those details vary highly with
234the version.)
235
236You can specify another program for this command to run by customizing
237the variables `locate-command' or `locate-make-command-line'.
238
239The main use of FILTER is to implement `locate-with-filter'. See
240the docstring of that function for its meaning."
6aea3b07 241 (interactive
83346ee8 242 (list
8348e1f9
PB
243 (if (or (and current-prefix-arg
244 (not locate-prompt-for-command))
83346ee8 245 (and (not current-prefix-arg) locate-prompt-for-command))
8348e1f9
PB
246 (let ((locate-cmd (funcall locate-make-command-line "")))
247 (read-from-minibuffer
248 "Run locate (like this): "
249 (cons
250 (concat (car locate-cmd) " "
251 (mapconcat 'identity (cdr locate-cmd) " "))
252 (+ 2 (length (car locate-cmd))))
253 nil nil 'locate-history-list))
fe8c7212 254 (let* ((default (locate-word-at-point))
f1180544 255 (input
fe8c7212
RS
256 (read-from-minibuffer
257 (if (> (length default) 0)
5b76833f 258 (format "Locate (default %s): " default)
fe8c7212
RS
259 (format "Locate: "))
260 nil nil nil 'locate-history-list default t)))
261 (and (equal input "") default
262 (setq input default))
263 input))))
264 (if (equal search-string "")
c19813f3 265 (error "Please specify a filename to search for"))
be8bf2d0 266 (let* ((locate-cmd-list (funcall locate-make-command-line search-string))
6aea3b07
RS
267 (locate-cmd (car locate-cmd-list))
268 (locate-cmd-args (cdr locate-cmd-list))
83346ee8 269 (run-locate-command
8348e1f9
PB
270 (or (and current-prefix-arg (not locate-prompt-for-command))
271 (and (not current-prefix-arg) locate-prompt-for-command)))
be8bf2d0 272 )
83346ee8 273
6aea3b07 274 ;; Find the Locate buffer
be8bf2d0
RS
275 (save-window-excursion
276 (set-buffer (get-buffer-create locate-buffer-name))
277 (locate-mode)
e242b6c4
JL
278 (let ((inhibit-read-only t)
279 (buffer-undo-list t))
271a87e8 280 (erase-buffer)
83346ee8 281
271a87e8 282 (setq locate-current-filter filter)
83346ee8 283
271a87e8
LT
284 (if run-locate-command
285 (shell-command search-string locate-buffer-name)
286 (apply 'call-process locate-cmd nil t nil locate-cmd-args))
83346ee8 287
271a87e8
LT
288 (and filter
289 (locate-filter-output filter))
6aea3b07 290
271a87e8
LT
291 (locate-do-setup search-string)
292 ))
be8bf2d0
RS
293 (and (not (string-equal (buffer-name) locate-buffer-name))
294 (switch-to-buffer-other-window locate-buffer-name))
83346ee8 295
96c1776c 296 (run-hooks 'dired-mode-hook)
271a87e8 297 (dired-next-line 3) ;move to first matching file.
83346ee8 298 (run-hooks 'locate-post-command-hook)
be8bf2d0
RS
299 )
300 )
6aea3b07 301
1d96c2ff 302;;;###autoload
6aea3b07 303(defun locate-with-filter (search-string filter)
18886d54
LT
304 "Run the executable program `locate' with a filter.
305This function is similar to the function `locate', which see.
306The difference is that, when invoked interactively, the present function
307prompts for both SEARCH-STRING and FILTER. It passes SEARCH-STRING
308to the locate executable program. It produces a `*Locate*' buffer
309that lists only those lines in the output of the locate program that
310contain a match for the regular expression FILTER; this is often useful
311to constrain a big search.
312
313When called from Lisp, this function is identical with `locate',
314except that FILTER is not optional."
6aea3b07 315 (interactive
be8bf2d0
RS
316 (list (read-from-minibuffer "Locate: " nil nil
317 nil 'locate-history-list)
318 (read-from-minibuffer "Filter: " nil nil
83346ee8 319 nil 'locate-grep-history-list)))
8348e1f9 320 (locate search-string filter))
6aea3b07
RS
321
322(defun locate-filter-output (filter)
323 "Filter output from the locate command."
324 (goto-char (point-min))
18886d54 325 (keep-lines filter))
6aea3b07
RS
326
327(defvar locate-mode-map nil
328 "Local keymap for Locate mode buffers.")
329(if locate-mode-map
330 nil
331
332 (require 'dired)
333
334 (setq locate-mode-map (copy-keymap dired-mode-map))
335
336 ;; Undefine Useless Dired Menu bars
337 (define-key locate-mode-map [menu-bar Dired] 'undefined)
338 (define-key locate-mode-map [menu-bar subdir] 'undefined)
339
340 (define-key locate-mode-map [menu-bar mark executables] 'undefined)
341 (define-key locate-mode-map [menu-bar mark directory] 'undefined)
342 (define-key locate-mode-map [menu-bar mark directories] 'undefined)
343 (define-key locate-mode-map [menu-bar mark symlinks] 'undefined)
344
271a87e8 345 (define-key locate-mode-map [M-mouse-2] 'locate-mouse-view-file)
83346ee8 346 (define-key locate-mode-map "\C-c\C-t" 'locate-tags)
6aea3b07 347
271a87e8 348 (define-key locate-mode-map "l" 'locate-do-redisplay)
83346ee8
PB
349 (define-key locate-mode-map "U" 'dired-unmark-all-files)
350 (define-key locate-mode-map "V" 'locate-find-directory)
6aea3b07
RS
351)
352
353;; This variable is used to indent the lines and then to search for
354;; the file name
355(defconst locate-filename-indentation 4
be8bf2d0 356 "The amount of indentation for each file.")
6aea3b07 357
6aea3b07 358(defun locate-get-file-positions ()
18886d54
LT
359 "Return list of start and end of the file name on the current line.
360This is a list of two buffer positions.
361
362You should only call this function on lines that contain a file name
363listed by the locate program. Inside inserted subdirectories, or if
364there is no file name on the current line, the return value is
365meaningless. You can check whether the current line contains a file
366listed by the locate program, using the function
367`locate-main-listing-line-p'."
6aea3b07 368 (save-excursion
be8bf2d0
RS
369 (end-of-line)
370 (let ((eol (point)))
371 (beginning-of-line)
83346ee8 372
be8bf2d0
RS
373 ;; Assumes names end at the end of the line
374 (forward-char locate-filename-indentation)
375 (list (point) eol))))
6aea3b07
RS
376
377;; From SQL-mode
be8bf2d0 378(defun locate-current-line-number ()
6aea3b07 379 "Return the current line number, as an integer."
6aea3b07
RS
380 (+ (count-lines (point-min) (point))
381 (if (eq (current-column) 0)
382 1
383 0)))
384
18886d54
LT
385;; You should only call this function on lines that contain a file name
386;; listed by the locate program. Inside inserted subdirectories, or if
387;; there is no file name on the current line, the return value is
388;; meaningless. You can check whether the current line contains a file
389;; listed by the locate program, using the function
390;; `locate-main-listing-line-p'.
6aea3b07
RS
391(defun locate-get-filename ()
392 (let ((pos (locate-get-file-positions))
be8bf2d0 393 (lineno (locate-current-line-number)))
83346ee8
PB
394 (and (not (eq lineno 1))
395 (not (eq lineno 2))
6aea3b07
RS
396 (buffer-substring (elt pos 0) (elt pos 1)))))
397
271a87e8
LT
398(defun locate-main-listing-line-p ()
399 "Return t if current line contains a file name listed by locate.
400This function returns nil if the current line either contains no
401file name or is inside a subdirectory."
402 (save-excursion
403 (forward-line 0)
404 (looking-at (concat "."
405 (make-string (1- locate-filename-indentation) ?\ )
406 "\\(/\\|[A-Za-z]:\\)"))))
407
83346ee8 408(defun locate-mouse-view-file (event)
6aea3b07 409 "In Locate mode, view a file, using the mouse."
83346ee8 410 (interactive "@e")
6aea3b07
RS
411 (save-excursion
412 (goto-char (posn-point (event-start event)))
271a87e8
LT
413 (if (locate-main-listing-line-p)
414 (view-file (locate-get-filename))
415 (message "This command only works inside main listing."))))
6aea3b07
RS
416
417;; Define a mode for locate
418;; Default directory is set to "/" so that dired commands, which
419;; expect to be in a tree, will work properly
420(defun locate-mode ()
442c8150 421 "Major mode for the `*Locate*' buffer made by \\[locate].
271a87e8 422\\<locate-mode-map>\
442c8150
LT
423In that buffer, you can use almost all the usual dired bindings.
424\\[locate-find-directory] visits the directory of the file on the current line.
425
271a87e8
LT
426Operating on listed files works, but does not always
427automatically update the buffer as in ordinary Dired.
428This is true both for the main listing and for subdirectories.
429Reverting the buffer using \\[revert-buffer] deletes all subdirectories.
430Specific `locate-mode' commands, such as \\[locate-find-directory],
431do not work in subdirectories.
432
442c8150 433\\{locate-mode-map}"
271a87e8 434 ;; Not to be called interactively.
6aea3b07 435 (kill-all-local-variables)
271a87e8 436 ;; Avoid clobbering this variable
83346ee8 437 (make-local-variable 'dired-subdir-alist)
6aea3b07
RS
438 (use-local-map locate-mode-map)
439 (setq major-mode 'locate-mode
440 mode-name "Locate"
271a87e8
LT
441 default-directory "/"
442 buffer-read-only t
443 selective-display t)
83346ee8 444 (dired-alist-add-1 default-directory (point-min-marker))
271a87e8
LT
445 (set (make-local-variable 'dired-directory) "/")
446 (set (make-local-variable 'dired-subdir-switches) locate-ls-subdir-switches)
447 (setq dired-switches-alist nil)
9bc260cf 448 (make-local-variable 'directory-listing-before-filename-regexp)
83346ee8 449 ;; This should support both Unix and Windoze style names
9bc260cf 450 (setq directory-listing-before-filename-regexp
271a87e8 451 (concat "^."
83346ee8 452 (make-string (1- locate-filename-indentation) ?\ )
271a87e8 453 "\\(/\\|[A-Za-z]:\\)\\|"
9bc260cf 454 (default-value 'directory-listing-before-filename-regexp)))
5c6a8dfe
RS
455 (make-local-variable 'dired-actual-switches)
456 (setq dired-actual-switches "")
457 (make-local-variable 'dired-permission-flags-regexp)
83346ee8
PB
458 (setq dired-permission-flags-regexp
459 (concat "^.\\("
460 (make-string (1- locate-filename-indentation) ?\ )
271a87e8
LT
461 "\\)\\|"
462 (default-value 'dired-permission-flags-regexp)))
be8bf2d0 463 (make-local-variable 'revert-buffer-function)
83346ee8 464 (setq revert-buffer-function 'locate-update)
271a87e8 465 (set (make-local-variable 'page-delimiter) "\n\n")
9b5e13c4 466 (run-mode-hooks 'locate-mode-hook))
6aea3b07 467
8348e1f9
PB
468(defun locate-do-setup (search-string)
469 (goto-char (point-min))
470 (save-excursion
83346ee8 471
8348e1f9
PB
472 ;; Nothing returned from locate command?
473 (and (eobp)
474 (progn
475 (kill-buffer locate-buffer-name)
476 (if locate-current-filter
477 (error "Locate: no match for %s in database using filter %s"
478 search-string locate-current-filter)
479 (error "Locate: no match for %s in database" search-string))))
83346ee8 480
8348e1f9 481 (locate-insert-header search-string)
83346ee8 482
8348e1f9
PB
483 (while (not (eobp))
484 (insert-char ?\ locate-filename-indentation t)
485 (locate-set-properties)
486 (forward-line 1)))
487 (goto-char (point-min)))
6aea3b07
RS
488
489(defun locate-set-properties ()
490 (save-excursion
491 (let ((pos (locate-get-file-positions)))
83346ee8 492 (dired-insert-set-properties (elt pos 0) (elt pos 1)))))
6aea3b07
RS
493
494(defun locate-insert-header (search-string)
271a87e8
LT
495 ;; There needs to be a space before `Matches, because otherwise,
496 ;; `*!" would erase the `M'. We can not use two spaces, or the line
497 ;; would mistakenly fit `dired-subdir-regexp'.
498 (let ((locate-format-string " /:\n Matches for %s")
6aea3b07
RS
499 (locate-regexp-match
500 (concat " *Matches for \\(" (regexp-quote search-string) "\\)"))
501 (locate-format-args (list search-string))
502 )
83346ee8 503
be8bf2d0 504 (and locate-fcodes-file
6aea3b07
RS
505 (setq locate-format-string
506 (concat locate-format-string " in %s")
507 locate-regexp-match
508 (concat locate-regexp-match
509 " in \\("
510 (regexp-quote locate-fcodes-file)
511 "\\)")
512 locate-format-args
513 (append (list locate-fcodes-file) locate-format-args)))
514
be8bf2d0 515 (and locate-current-filter
6aea3b07
RS
516 (setq locate-format-string
517 (concat locate-format-string " using filter %s")
518 locate-regexp-match
519 (concat locate-regexp-match
520 " using filter "
521 "\\("
522 (regexp-quote locate-current-filter)
523 "\\)")
524 locate-format-args
525 (append (list locate-current-filter) locate-format-args)))
83346ee8 526
6aea3b07 527 (setq locate-format-string
5421b899 528 (concat locate-format-string ":\n\n")
6aea3b07 529 locate-regexp-match
5421b899 530 (concat locate-regexp-match ":\n"))
83346ee8 531
5c6a8dfe 532 (insert (apply 'format locate-format-string (reverse locate-format-args)))
83346ee8 533
6aea3b07
RS
534 (save-excursion
535 (goto-char (point-min))
271a87e8 536 (forward-line 1)
6aea3b07
RS
537 (if (not (looking-at locate-regexp-match))
538 nil
539 (add-text-properties (match-beginning 1) (match-end 1)
540 (list 'face locate-header-face))
541 (and (match-beginning 2)
542 (add-text-properties (match-beginning 2) (match-end 2)
543 (list 'face locate-header-face)))
544 (and (match-beginning 3)
545 (add-text-properties (match-beginning 3) (match-end 3)
546 (list 'face locate-header-face)))
547 ))))
548
549(defun locate-tags ()
550 "Visit a tags table in `*Locate*' mode."
551 (interactive)
271a87e8
LT
552 (if (locate-main-listing-line-p)
553 (let ((tags-table (locate-get-filename)))
554 (and (y-or-n-p (format "Visit tags table %s? " tags-table))
555 (visit-tags-table tags-table)))
556 (message "This command only works inside main listing.")))
be8bf2d0
RS
557
558;; From Stephen Eglen <stephen@cns.ed.ac.uk>
559(defun locate-update (ignore1 ignore2)
560 "Update the locate database.
561Database is updated using the shell command in `locate-update-command'."
562 (let ((str (car locate-history-list)))
563 (cond ((yes-or-no-p "Update locate database (may take a few seconds)? ")
564 (shell-command locate-update-command)
8348e1f9 565 (locate str)))))
83346ee8
PB
566
567;;; Modified three functions from `dired.el':
568;;; dired-find-directory,
569;;; dired-find-directory-other-window
570;;; dired-get-filename
571
572(defun locate-find-directory ()
573 "Visit the directory of the file mentioned on this line."
574 (interactive)
271a87e8
LT
575 (if (locate-main-listing-line-p)
576 (let ((directory-name (locate-get-dirname)))
577 (if (file-directory-p directory-name)
578 (find-file directory-name)
579 (if (file-symlink-p directory-name)
580 (error "Directory is a symlink to a nonexistent target")
581 (error "Directory no longer exists; run `updatedb' to update database"))))
582 (message "This command only works inside main listing.")))
83346ee8
PB
583
584(defun locate-find-directory-other-window ()
585 "Visit the directory of the file named on this line in other window."
586 (interactive)
18886d54
LT
587 (if (locate-main-listing-line-p)
588 (find-file-other-window (locate-get-dirname))
589 (message "This command only works inside main listing.")))
83346ee8 590
18886d54
LT
591;; You should only call this function on lines that contain a file name
592;; listed by the locate program. Inside inserted subdirectories, or if
593;; there is no file name on the current line, the return value is
594;; meaningless. You can check whether the current line contains a file
595;; listed by the locate program, using the function
596;; `locate-main-listing-line-p'.
83346ee8
PB
597(defun locate-get-dirname ()
598 "Return the directory name of the file mentioned on this line."
599 (let (file (filepos (locate-get-file-positions)))
600 (if (setq file (buffer-substring (nth 0 filepos) (nth 1 filepos)))
601 (progn
602 ;; Get rid of the mouse-face property that file names have.
603 (set-text-properties 0 (length file) nil file)
604 (setq file (file-name-directory file))
605 ;; Unquote names quoted by ls or by dired-insert-directory.
606 ;; Using read to unquote is much faster than substituting
607 ;; \007 (4 chars) -> ^G (1 char) etc. in a lisp loop.
608 (setq file
609 (read
610 (concat "\""
611 ;; some ls -b don't escape quotes, argh!
612 ;; This is not needed for GNU ls, though.
613 (or (dired-string-replace-match
614 "\\([^\\]\\|\\`\\)\"" file "\\1\\\\\"" nil t)
615 file)
616 "\"")))))
617 (and file buffer-file-coding-system
618 (not file-name-coding-system)
619 (setq file (encode-coding-string file buffer-file-coding-system)))
620 file))
621
622;; Only for GNU locate
623(defun locate-in-alternate-database (search-string database)
624 "Run the GNU locate command, using an alternate database."
625 (interactive
626 (list
627 (progn
628 ;; (require 'locate)
629 (read-from-minibuffer "Locate: " nil nil
630 nil 'locate-history-list))
631 (read-file-name "Locate using Database: " )
632 ))
633 (or (file-exists-p database)
634 (error "Database file %s does not exist" database))
635 (let ((locate-make-command-line
636 (function (lambda (string)
637 (cons locate-command
638 (list (concat "--database="
639 (expand-file-name database))
640 string))))))
8348e1f9 641 (locate search-string)))
6aea3b07 642
271a87e8
LT
643(defun locate-do-redisplay (&optional arg test-for-subdir)
644 "Like `dired-do-redisplay', but adapted for `*Locate*' buffers."
645 (interactive "P\np")
646 (if (string= (dired-current-directory) "/")
647 (message "This command only works in subdirectories.")
648 (let ((dired-actual-switches locate-ls-subdir-switches))
649 (dired-do-redisplay arg test-for-subdir))))
650
6aea3b07
RS
651(provide 'locate)
652
ab5796a9 653;;; arch-tag: 60c4d098-b5d5-4b3c-a3e0-51a2e9f43898
6aea3b07 654;;; locate.el ends here