(require 'cl) (require 'htmlize) (defun egrep-1 (result-buffer regexp predicate args) (let ((file-name (buffer-file-name))) (save-excursion (goto-char (point-min)) (while (re-search-forward regexp nil t) (if (or (not predicate) (save-excursion (goto-char (match-beginning 0)) (apply predicate args))) (let ((line (count-lines (point-min) (point))) (column (current-column)) (text (buffer-substring (save-excursion (beginning-of-line) (point)) (save-excursion (end-of-line) (point))))) (with-current-buffer result-buffer (let ((inhibit-read-only t)) (insert (format "%s:%d:%d: %s\n" (dired-make-relative file-name default-directory) line column text)))) ; only one match / line (forward-line 1))))))) (defun egrep-prepare-result-buffer () (let ((result-buffer (get-buffer-create "*egrep*"))) (with-current-buffer result-buffer (let ((inhibit-read-only t)) (grep-mode) (erase-buffer) (insert (format "; Searching for '%s' ...\n" regexp)) (pop-to-buffer result-buffer))) result-buffer)) (defun egrep-finalize-result-buffer (result-buffer) (goto-char (point-min))) (defun egrep (regexp &optional predicate &rest args) (interactive "sRegexp: ") (let ((result-buffer (egrep-prepare-result-buffer))) (egrep-1 result-buffer regexp predicate args) (egrep-finalize-result-buffer result-buffer))) (defun egrep-font-face-predicate (face-symbol) (loop for point from (match-beginning 0) to (1- (match-end 0)) if (not (eq (get-text-property point 'face) face-symbol)) return nil finally return t)) (defun egrep-with-face (regexp face-symbol) (interactive (list (read-string "Regexp: ") (intern (completing-read "Face symbol: " (mapcar (lambda (face) (symbol-name face)) (face-list)) nil t)))) (egrep regexp 'egrep-font-face-predicate face-symbol)) (defun egrep-dired-marked-files (regexp &optional prepare predicate &rest args) (interactive "sRegexp: ") (let ((result-buffer (egrep-prepare-result-buffer))) (loop for file-name in (dired-get-marked-files nil current-prefix-arg) do (let ((buffer (find-file-noselect file-name))) (with-current-buffer buffer (message (format "Searching %s ..." (file-name-nondirectory file-name))) (sit-for .1) (if prepare (funcall prepare)) (egrep-1 result-buffer regexp predicate args)))) (egrep-finalize-result-buffer result-buffer) (message "Search complete."))) (defun egrep-string-startswith (string start) (and (> (length string) (length start)) (string= (substring string 0 (length start)) start))) (defun egrep-grep-list (func list) (let (r) (while list (if (funcall func (car list)) (setq r (cons (car list) r))) (setq list (cdr list))) (nreverse r))) (defun egrep-read-font-lock-face (prompt &optional predicate initial hist default inherit-input-method) (intern (completing-read prompt (egrep-grep-list (lambda (font) (egrep-string-startswith font "font-lock-")) (mapcar (lambda (face) (symbol-name face)) (face-list))) predicate t (or initial "font-lock-") hist default inherit-input-method))) (defun egrep-with-face-dired-marked-files (regexp face-symbol) (interactive (list (read-string "Regexp: ") (egrep-read-font-lock-face "Font symbol: "))) (egrep-dired-marked-files regexp (lambda () (font-lock-fontify-buffer) (htmlize-ensure-fontified)) 'egrep-font-face-predicate face-symbol)) (provide 'egrep)