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