Since I’m unfortunately required to use Windows at work, I’ve become quite a fan of ack to search for items within my code (or otherwise). It’s convenient to execute the ack search from within emacs, and treat it as a compile, so that the results can be located using the compile mode’s capacity for viewing each error or event of interest – Voyager figured that stuff out, and I was most grateful.
Interfacing with ack to make it do this from within emacs can be a trifle tedious though, since ack wants to know what to look for (the pattern) and where to look. This can all be provided on a command line, but that’s irritating, since directory autocompletion doesn’t work. I hacked together the following code (borrowed liberally from Voyager’s efforts and the w32-find-dired.el file):
;; With credit to w32-find-dired.el
;; Copyright (C) 2008 Kim van Wyk and Johan Kohler
;; This file is not currently part of GNU Emacs.
;; This program 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 program 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.
(defvar ack-command "ack" "The command run by the ack function.")
(0 '(face nil message nil help-echo nil mouse-face nil) t))))
(defvar ack-use-search-in-buffer-name t
"If non-nil, use the search string in the ack buffer's name.")
(define-compilation-mode ack-mode "Ack"
"Specialization of compilation-mode for use with ack."
(defun ack (dir pattern args)
"Run ack, with user-specified ARGS, and collect output in a buffer.
While ack runs asynchronously, you can use the \\[next-error] command to
find the text that ack hits refer to. The command actually run is
defined by the ack-command variable."
(interactive (list (read-file-name "Run ack in directory: " nil "" t)
(read-string "Search for: " (thing-at-point 'symbol))
(read-string "Ack arguments: " "-i" nil "-i" nil)
; Get dir into an the right state, incase a file name was used
(setq dir (abbreviate-file-name
(file-name-as-directory (expand-file-name dir))))
;; Check that it's really a directory.
(or (file-directory-p dir)
(error "ack needs a directory: %s" dir))
(ack-full-buffer-name (concat "*ack-" pattern "*")))
;; (save-some-buffers (not compilation-ask-about-save) nil)
;; lambda defined here since compilation-start expects to call a function to get the buffer name
(compilation-start (concat ack-command " " args " " pattern " " dir) 'ack-mode
(function (lambda (ignore)
Placing this code somewhere in your emacs path should allow you to call the “ack” function, which will prompt for where to search (with a history of previous entries), what to search for (again with a history) and what arguments to give to ack (with a default “-i” for case-insensitivity) and display the output in a compilation buffer.
It’s hardly challenging or mind-bending elisp, but it’s the first elisp I’ve ever made work, so I’m kinda proud of it 🙂