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