gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

globalff.el --- Global find file


From: spamfilteraccount
Subject: globalff.el --- Global find file
Date: 7 Mar 2006 05:43:43 -0800
User-agent: G2/0.2

One day I was drooling over the greatness of iswitchb when it occured
to me the same concept could be applied to opening files.

Not files from the current directory, but from any directory on your
computer. Why do I have to navigate directory structures, maintain
bookmarks if the file I'm looking for has a unique component in its
name? I should be able to select this file only by typing the unique
part and that's it.

So globalff was born.

Properly setup Unix-like operating systems usually have a locate
database updated every night, so why not utilize it for our advantage?



;;; globalff.el --- Global find file

;; Copyright (C) 2006  Free Software Foundation, Inc.

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; Start with M-x globallff and type in any substring of any path on
;; your system to display the matching files. The displayed list is
;; updated dynamically as you type more characters or delete some.
;;
;; Needs an up-to-date locate database for file name searching.
;;
;; Since the searching is based on locate you can use any globbing
;; characters allowed by the locate command.
;;
;; You can move up/down the list with the cursor keys (I know these
;; bindings are not very Emacsian, but I happen to like them) and
;; select a file to open with Enter.
;;
;; You can quit with C-g.
;;

;;; Code:

;;
;; User configurable variables
;;

(defvar globalff-databases nil
  "List of database files separated with colon to be used by the locate
command.
If nil then the system default database is used.")

(defvar globalff-minimum-input-length 3
  "The minimum number of characters needed to start file searching.")

(defvar globalff-search-delay 0.5
  "Idle time after last input event, before starting the search.")

(defvar globalff-map nil
  "Keymap for global find file.")

(unless globalff-map
  (setq globalff-map
        (let ((map (make-keymap)))
          (substitute-key-definition nil 'globalff-enter-input-char
map)
          (define-key map (kbd "<DEL>") 'globalff-delete-input-char)
          (define-key map (kbd "<RET>") 'globalff-select-file)
          (define-key map (kbd "<up>") 'globalff-previous-line)
          (define-key map (kbd "<down>") 'globalff-next-line)
          (define-key map (kbd "<left>") 'undefined)
          (define-key map (kbd "<right>") 'undefined)
          map)))

;;
;; End of user configurable variables
;;

(defvar globalff-idle-timer nil
  "Idle timer for monitoring typed characters.")

(defconst globalff-buffer "*globalff*"
  "Buffer used for finding files.")

(defvar globalff-input ""
  "The input substring used for searching.")

(defvar globalff-previous-input ""
  "The previous input substring used for searching.")


(defun globalff-output-filter (process string)
  "Avoid moving of point if the buffer is empty."
  (with-current-buffer globalff-buffer
    (let* ((empty (= (buffer-size) 0))
           (moving (and (not empty)
                        (= (point) (process-mark process)))))
      (save-excursion
        ;; Insert the text, advancing the process marker.
        (goto-char (process-mark process))
        (insert string)
        (set-marker (process-mark process) (point)))

      (if empty
          (globalff-mark-current-line))

      (if moving (goto-char (process-mark process))))))


(defun globalff-mark-current-line ()
  "Mark current line with a distinctive color."
  (let ((overlay (make-overlay (point-at-bol)
                               (point-at-eol))))
    (overlay-put overlay 'face 'region)))



(defun globalff-previous-line ()
  "Move mark to the previous line."
  (interactive)
  (unless (= (point-min) (line-beginning-position))
    (globalff-move-mark -1)))


(defun globalff-next-line ()
  "Move mark to the next line."
  (interactive)
  (unless (save-excursion
            (forward-line)
            (eobp))
    (globalff-move-mark +1)))


(defun globalff-move-mark (direction)
  (let ((overlays (overlays-at (point-at-bol))))
    (when overlays
      (delete-overlay (car overlays))))
  (forward-line direction)
  (globalff-mark-current-line))


(defun globalff-process-sentinel (process event)
  "Prevent printing of process status messages into the output buffer."
  )


(defun globalff-prompt-function ()
  "Display prompt."
  (concat "substring: " globalff-input))


(defun globalff-enter-input-char ()
  "Add new character to the input."
  (interactive)
  (setq globalff-input (concat globalff-input
                               (char-to-string last-command-char))))


(defun globalff-delete-input-char ()
  "Delete last character from the input."
  (interactive)
  (if (not (equal globalff-input ""))
      (setq globalff-input (substring globalff-input 0 -1))))


(defun globalff-select-file ()
  "Select current file and open it."
  (interactive)
  (throw 'exit
         (if (= (buffer-size) 0)
             ;; clear the echo area
             (progn
               (message "")
               nil)
           (buffer-substring-no-properties (line-beginning-position)
                                           (line-end-position)))))


(defun globalff-check-input ()
  "Check input string and start/stop search if necessary."
  (unless (equal globalff-input globalff-previous-input)
    (setq globalff-previous-input globalff-input)

    (globalff-kill-process)
    (erase-buffer)

    (unless (or (equal globalff-input "")
                (< (length globalff-input)
globalff-minimum-input-length))
      (let ((process (start-process "globalff-process" globalff-buffer
                                    "locate"
                                    (if globalff-databases
                                        (concat "--database="
globalff-databases)
                                      ;; -i is used as a placeholder
                                      ;; since I don't know how to
                                      ;; skip an argument
                                      "-i")
                                    "-i"
                                    globalff-input)))
        (set-process-filter process 'globalff-output-filter)
        (set-process-sentinel process 'globalff-process-sentinel)))))


(defun globalff-kill-process ()
  "Kill find process."
  (if (eq 'run (process-status globalff-buffer))
      (delete-process globalff-buffer)))


(defun globalff ()
  "Start global find file."
  (interactive)
  (let ((winconfig (current-window-configuration)))
    (pop-to-buffer globalff-buffer)
    (erase-buffer)
    (use-local-map globalff-map)
    (setq globalff-previous-input "")
    (setq globalff-input "")
    (setq globalff-idle-timer
          (run-with-idle-timer globalff-search-delay t
'globalff-check-input))

    (let ((result (catch 'exit
                    (Electric-command-loop 'exit
'globalff-prompt-function)
                    nil)))

      (globalff-kill-process)
      (cancel-timer globalff-idle-timer)
      (set-window-configuration winconfig)

      (if result
          (find-file result)))))



(provide 'globalff)
;;; globalff.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]