cl-grep

Simple implementation of grep
Log | Files | Refs

commit ac0bd2240ead610276e1f8bb31d047ffb9f32f34
parent 2af733c0cc3db8db1ebdacbfaedcd92791d6ce9c
Author: ChanderG <[email protected]>
Date:   Thu,  4 Dec 2025 15:45:00 +0530

match and highlight all targets on each line

we now explicitly search for more matches on each line
store positions of each match
highlight all matches in red in the output

Diffstat:
Mgrep.lisp | 36++++++++++++++++++++++++++++++++----
1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/grep.lisp b/grep.lisp @@ -16,6 +16,8 @@ (format nil "~c[35m~a~c[0m" #\ESC str #\ESC)) (defun color-green (str) (format nil "~c[32m~a~c[0m" #\ESC str #\ESC)) +(defun color-red (str) + (format nil "~c[91m~a~c[0m" #\ESC str #\ESC)) (defstruct file-result name entries) @@ -24,7 +26,20 @@ (defun format-file-result (fr stream) (format stream "~a: ~%" (color-magenta (file-result-name fr))) (loop for e in (file-result-entries fr) do - (format stream "~a: ~a~%" (color-green (car e)) (cadr e))) + ;; print the file name + (format stream "~a: " (color-green (car e))) + ;; now print the line with color coding of matching portions + (let ((line (cadr e)) + (locs (caddr e)) + (lm (length *match*))) + (loop with s = 0 + for n from 0 below (length locs) do + (let ((m (nth n locs))) + (write-string (subseq line s m) stream) + (write-string (color-red (subseq line m (+ m lm))) stream) + (setf s (+ m lm))) + finally + (format stream "~a~%" (subseq line s (- (length line) 1)))))) (format stream "~%")) ;; ;; alternative grep like format to easily test parity @@ -32,17 +47,30 @@ ;; (loop for e in (file-result-entries fr) do ;; (write-string (format nil "~a: ~a~%" (file-result-name fr) e) stream))) +;; Search a line for all matches of our target +;; returns a list of positions in the line +(defun search-line (line match-idx fmatch) + (loop with res = (list fmatch) + with curr = (+ fmatch (length *match*)) + while (setf curr (sm:search-bmh8 match-idx line :start2 curr)) + do + (setf res (append res (list curr))) + (incf curr (length *match*)) + finally (return res))) + (defun grep-file (file match-idx) (lo "Grepping file: ~a" file) (handler-case (with-open-file (stream file) (let ((results (loop for line = (read-line stream nil :eof) - with i = 0 + with i = 0 with fmatch = nil until (eq line :eof) do (incf i) - if (sm:search-bmh8 match-idx line) - collect (list i line)))) + ;; search for location of first match + if (setf fmatch (sm:search-bmh8 match-idx line)) + ;; now run the rest of the matches + collect (list i line (search-line line match-idx fmatch))))) (when results (lq:push-queue (make-file-result :name file :entries results) *print-queue*))))