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):

;; ack.el
;; 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
;; General Public License for more details.

(require 'compile)
(require 'thingatpt)

(defvar ack-command "ack" "The command run by the ack function.")

(defvar ack-mode-font-lock-keywords
'(("^\\(Compilation\\|Ack\\) started.*"
(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))

(let (compile-command
(compilation-error-regexp-alist grep-regexp-alist)
(compilation-directory default-directory)
(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
(when ack-use-search-in-buffer-name
(function (lambda (ignore)
(regexp-quote pattern))))

(provide 'ack-emacs)

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 🙂

4 Responses to ack.el

  1. Pinault

    Hi can you let us know what is you config? ie. GNU Emacs? version? ack version? (single file?!) Many thanks in advance. Take care.

  2. kim

    Hi Pinault,

    I’m running GNU Emacs 23.1.1 on Windows XP. I’m running a single file, version 1.94 – I have ActiveState Perl installed and set up to execute .pl files, and I placed onto my path.

  3. Phil Hudson

    Please put this up on github/launchpad/… I’d like to patch it to pass multiple directories to ack, and to permit files as well as directories (both are supported).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.