Download
(defgroup everything nil
"Bridge to the Windows desktop search-engine everything. See http://www.voidtools.com."
:group 'external
:prefix "everything-")
(defcustom everything-host "127.0.0.1" "Ftp server address of Everything. Defaults to 127.0.0.1."
:group 'everything
:type 'string)
(defcustom everything-port 21 "Everythings ftp server port. Defaults to 21."
:group 'everything
:type 'integer)
(defcustom everything-user "anonymous" "Login name."
:group 'everything
:type 'string)
(defcustom everything-pass nil "Password."
:group 'everything
:type 'string)
(defcustom everything-query-limit #xfff "Maximum number of filenames returned. The maximum supported is #xfffffff."
:group 'everything
:type 'integer)
(defcustom everything-ffap-integration t "Integrate everything into ffap."
:group 'everything
:type 'boolean)
(defcustom everything-cmd "c:/Programme/Everything/es.exe" "Path to es.exe."
:group 'everything
:type 'string)
(defcustom everything-use-ftp nil "Use ftp interface instead of es.exe"
:group 'everything
:type 'boolean)
(defvar everything-matchcase nil "Tells everything to use case sensitve searching.")
(defvar everything-matchwholeword nil "Tells everything to match only whole words.")
(defvar everything-matchpath nil "Tells everything to include matching the file's path.")
(defvar everything-wait 100 "Time in milliseconds to wait for responses.")
(defvar everything-post-process-hook nil "Functions that post-process the buffer `everything-result-buffer'
after the server finished sending the query result.")
(defvar everything-response-counter 0)
(defvar everything-response-handler nil "Function to handle server responses.")
(defvar everything-response-finished nil "Indicates if a response is finished, so emacs can stop waiting for responses.
Must be set by `everything-response-handler'.")
(defvar everything-response-status 0 "The status code returned by the server.")
(defvar everything-response-numlines 0 "The number of files/paths returned from the server.
This is the sum of `everything-response-numfolders' and `everything-response-numfiles'")
(defvar everything-response-numfolders 0 "The number of folders returned.")
(defvar everything-response-numfiles 0 "The number of files returned.")
(defvar everything-result-buffer "*everything*" "Name of buffer to write the query response to.
After successfully fetching the matching filenames, this buffer holds one filename per line.
See `everything-post-process-hook' to post-process this buffer.")
(defvar everything-log-buffer "*everything-log*" "Name of buffer to write log messages to.")
(defvar everything-log nil "Switch to enable log buffer.")
(require 'cl)
(defalias 'everything 'everything-find-file)
(defun everything-find-file ()
"Prompt for a search string, let the user choose one of the returned files and
open it."
(interactive)
(find-file (everything-find-prompt)))
(defun everything-find-prompt ()
"Prompt for a query and return the chosen filename.
If the current major mode is dired or (e)shell-mode limit the search to
the current directory and its sub-directories."
(let ((query (read-from-minibuffer (everything-create-query-prompt)
(when (or (eq major-mode 'shell-mode)
(eq major-mode 'eshell-mode)
(eq major-mode 'dired-mode))
(format "\"%s\" " (expand-file-name default-directory))))))
(unless (string= query "")
(everything-select query))))
(defun everything-toggle-case ()
(interactive)
(setq everything-matchcase (not everything-matchcase)))
(defun everything-toggle-wholeword ()
(interactive)
(setq everything-matchwholeword (not everything-matchwholeword)))
(defun everything-toggle-path ()
(interactive)
(setq everything-matchpath (not everything-matchpath)))
(defun everything-set-passwd ()
(setq everything-pass (read-passwd "Password: " nil)))
(defun everything-create-query-prompt ()
(format "Query everything [%s%s%s]: "
(if everything-matchcase "C" "c")
(if everything-matchpath "P" "p")
(if everything-matchwholeword "W" "w")))
(defun everything-select (query)
"Run the query query and return the chosen file.
If query is already an existing file, return it without running a query."
(if (file-exists-p query)
query
(let ((files (everything-locate query)))
(cond ((eq (length files) 0)
(progn (message "No matches.")
nil))
((eq (length files) 1)
(car files))
(t
(completing-read (format "Select from query '%s' (%s matches): " query (length files))
files nil nil (when (eq (length files) 1)
(car files))))))))
(defun everything-locate (query)
"Run a query via Everything and return a list of files, nil
otherwise."
(if everything-use-ftp
(everything-ftp-query query
everything-host
everything-port
everything-user
everything-query-limit
everything-matchcase
everything-matchwholeword
everything-matchpath)
(everything-cmd-query query
everything-query-limit
everything-matchcase
everything-matchwholeword
everything-matchpath))
(save-excursion
(set-buffer (get-buffer-create everything-result-buffer))
(goto-char (point-min))
(while (search-forward "\\" nil t)
(replace-match "/" nil t))
(run-hooks 'everything-post-process-hook)
(split-string
(buffer-substring-no-properties (point-min) (point-max)) "\n" t)))
(defun everything-cmd-query (query maxfiles matchcase matchwholeword matchpath)
(when (not (file-exists-p everything-cmd)) (error (concat everything-cmd " not found")))
(let ((args nil))
(when matchcase (add-to-list 'args "-i" t))
(when matchwholeword (add-to-list 'args "-w" t))
(when matchpath (add-to-list 'args "-p" t))
(add-to-list 'args "-n" t)
(add-to-list 'args (number-to-string maxfiles) t)
(add-to-list 'args "-r" t)
(add-to-list 'args query t)
(when (get-buffer everything-result-buffer)
(kill-buffer everything-result-buffer))
(apply #'call-process everything-cmd nil (get-buffer-create everything-result-buffer) nil args)))
(defun everything-is-running ()
"Check if Everything is running."
(find "Everything.exe"
(mapcar (lambda (p) (cdr (assoc 'comm (process-attributes p))))
(list-system-processes))
:test 'string=))
(defun everything-filter-fnc (proc response)
"Filter function "
(setq everything-response-counter (1+ everything-response-counter))
(setq everything-response-status (string-to-number response))
(if everything-response-handler
(funcall everything-response-handler response everything-response-counter)))
(defun everything-ftp-send-request (proc request responsehandler)
"Send the request request to the network process proc."
(setq everything-response-handler responsehandler)
(setq everything-response-finished nil)
(setq everything-response-counter 0)
(everything-log (concat request "\n"))
(unless (equal (process-status proc) 'open)
(error "Connection closed unexpectedly"))
(process-send-string proc (concat request "\n"))
(while (not everything-response-finished)
(sleep-for 0 everything-wait))
(cond ((= everything-response-status 331)
(let ((pwd (if everything-pass
everything-pass
(everything-set-passwd))))
(everything-ftp-send-request proc (concat "PASS " pwd) 'generic-response-handler)))
((= everything-response-status 530)
(error "Login or password incorrect. Try setting everything-user and everything-pass."))))
(defun files-response-handler (response responsecounter)
(when (= responsecounter 1)
(let* ((sep (search "\n" response))
(statusline (substring response 0 sep)))
(everything-log (concat statusline "\n"))
(everything-savenumfiles statusline)
(setq response (substring response (1+ (search "\n" response))))))
(let ((numlines (save-excursion
(set-buffer (get-buffer-create everything-result-buffer))
(insert response)
(count-lines (point-min) (point-max)))))
(when (>= numlines everything-response-numlines)
(setq everything-response-finished t))))
(defun generic-response-handler (response responsecounter)
(everything-log response)
(setq everything-response-finished t))
(defun everything-savenumfiles (statusline)
(let ((lst (split-string statusline " ")))
(setq everything-response-numlines (string-to-number (elt lst 2)))
(setq everything-response-numfolders (string-to-number (elt lst 3)))
(setq everything-response-numfiles (string-to-number (elt lst 4)))))
(defun everything-log (message)
(when everything-log
(save-excursion
(set-buffer (get-buffer-create everything-log-buffer))
(goto-char (point-max))
(insert message))))
(defun everything-ftp-query (query host service user maxfiles matchcase matchwholeword matchpath)
(unless (everything-is-running)
(error "Everything is not running."))
(setq everything-response-handler nil)
(when (get-buffer everything-result-buffer)
(kill-buffer everything-result-buffer))
(let ((proc nil))
(condition-case ex
(setq proc (make-network-process :name "everythingftp"
:host host
:service service
:filter 'everything-filter-fnc))
('error (error (format "Failed to connect to Everything's ftp server at %s:%i. Is the server running?" host service))))
(sleep-for 0 everything-wait)
(unwind-protect
(condition-case ex
(progn (everything-ftp-send-request proc (concat "USER " user) 'generic-response-handler)
(everything-ftp-send-request proc (format "QUERY 0 %i %i %i %i %s"
maxfiles
(if matchcase 1 0)
(if matchwholeword 1 0)
(if matchpath 1 0)
query)
'files-response-handler)
(everything-ftp-send-request proc "QUIT" 'generic-response-handler)
(delete-process proc))
('error (progn
(when proc
(everything-ftp-send-request proc "QUIT" 'generic-response-handler)
(delete-process proc))
(error (cadr ex))))))))
(defun everything-ffap-guesser (file)
(let* ((match nil)
(file (replace-regexp-in-string "\\\\" "/" file))
(file (replace-regexp-in-string "//" "/" file))
(file (replace-regexp-in-string "\\.\\./" "" file))
(file (replace-regexp-in-string "\\./" "" file))
(file (replace-regexp-in-string "^/" "" file))
(query (if (eq (length (split-string file "/" t)) 1)
file
(concat "\\" file))))
(setq match (everything-select query))
(while (not match)
(setq query (read-from-minibuffer "Nothing found. Try again: " query))
(setq match (everything-select query)))
match))
(when everything-ffap-integration
(when (require 'ffap nil t)
(setf (cdr (last ffap-alist)) '(("\\.*\\'" . everything-ffap-guesser)))))
(provide 'everything)