locate.el 26 KB

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