summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2022-06-02 22:22:58 -0400
committerJune McEnroe <june@causal.agency>2022-06-02 22:40:41 -0400
commit3e6c29a0d0e43587289e46f38f2a2e18dc5778e4 (patch)
tree1a5504af8556547b2ef8e9695a55764165a7505b
parentClean up parsing a little (diff)
downloadsrc-3e6c29a0d0e43587289e46f38f2a2e18dc5778e4.tar.gz
src-3e6c29a0d0e43587289e46f38f2a2e18dc5778e4.zip
Do basic match highlighting
-rw-r--r--bin/man1/qf.117
-rw-r--r--bin/qf.c49
2 files changed, 61 insertions, 5 deletions
diff --git a/bin/man1/qf.1 b/bin/man1/qf.1
index 06676087..8828d723 100644
--- a/bin/man1/qf.1
+++ b/bin/man1/qf.1
@@ -7,7 +7,7 @@
 .Nd grep pager
 .
 .Sh SYNOPSIS
-.Nm
+.Nm Op Ar pattern
 .
 .Sh DESCRIPTION
 .Nm
@@ -31,6 +31,19 @@ It otherwise operates similar to
 .Xr less 1 .
 .
 .Pp
+If
+.Ar pattern
+is given,
+the first match on each line
+will be highlighted.
+The
+.Ar pattern
+is interpreted as
+an extended regular expression
+and is matched case-insensitively
+unless it contains an uppercase letter.
+.
+.Pp
 The keys are as follows:
 .Bl -tag -width Ds
 .It Ic Enter
@@ -49,6 +62,8 @@ Move to next or previous line.
 Jump to next or previous match line.
 .It Ic q
 Exit.
+.It Ic r
+Refresh the display.
 .El
 .
 .Sh EXAMPLES
diff --git a/bin/qf.c b/bin/qf.c
index 0a79307e..f2979d4f 100644
--- a/bin/qf.c
+++ b/bin/qf.c
@@ -14,10 +14,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <ctype.h>
 #include <curses.h>
 #include <err.h>
 #include <fcntl.h>
 #include <poll.h>
+#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -37,6 +39,7 @@ struct Line {
 	char *path;
 	unsigned nr;
 	char *text;
+	regmatch_t match;
 };
 
 static struct {
@@ -53,6 +56,9 @@ static void push(struct Line line) {
 	lines.ptr[lines.len++] = line;
 }
 
+static const char *pattern;
+static regex_t regex;
+
 static void parse(struct Line line) {
 	line.path = strsep(&line.text, ":");
 	if (!line.text) {
@@ -80,6 +86,9 @@ static void parse(struct Line line) {
 	} else {
 		line.type = Text;
 	}
+	if (line.type == Match && pattern) {
+		regexec(&regex, line.text, 1, &line.match, 0);
+	}
 	push(line);
 }
 
@@ -99,7 +108,7 @@ static void curse(void) {
 	use_default_colors();
 	init_pair(Path, COLOR_GREEN, -1);
 	init_pair(Number, COLOR_YELLOW, -1);
-	init_pair(Highlight, COLOR_BLACK, COLOR_YELLOW);
+	init_pair(Highlight, COLOR_MAGENTA, -1);
 }
 
 static size_t top;
@@ -124,11 +133,29 @@ static void draw(void) {
 				addstr(line.path);
 				color_set(0, NULL);
 			}
-			break; case Match: case Context: {
+			break; case Match: {
+				color_set(Number, NULL);
+				printw("%u", line.nr);
+				color_set(0, NULL);
+				addch(':');
+				if (line.match.rm_so == line.match.rm_eo) {
+					addstr(line.text);
+					break;
+				}
+				addnstr(line.text, line.match.rm_so);
+				color_set(Highlight, NULL);
+				addnstr(
+					&line.text[line.match.rm_so],
+					line.match.rm_eo - line.match.rm_so
+				);
+				color_set(0, NULL);
+				addstr(&line.text[line.match.rm_eo]);
+			}
+			break; case Context: {
 				color_set(Number, NULL);
 				printw("%u", line.nr);
 				color_set(0, NULL);
-				addch(line.type == Match ? ':' : '-');
+				addch('-');
 				addstr(line.text);
 			}
 			break; case Text: addstr(line.text);
@@ -198,13 +225,27 @@ static void input(void) {
 				endwin();
 				exit(EX_OK);
 			}
+			break; case 'r': clearok(stdscr, true);
 		}
 	}
 	if (cur < top) top = cur;
 	if (cur >= top + LINES) top = cur - LINES + 1;
 }
 
-int main(void) {
+int main(int argc, char *argv[]) {
+	if (isatty(STDIN_FILENO)) errx(EX_USAGE, "no input");
+	if (argc > 1) {
+		pattern = argv[1];
+		int flags = REG_EXTENDED | REG_ICASE;
+		for (const char *ch = pattern; *ch; ++ch) {
+			if (isupper(*ch)) {
+				flags &= ~REG_ICASE;
+				break;
+			}
+		}
+		int error = regcomp(&regex, pattern, flags);
+		if (error) errx(EX_USAGE, "invalid pattern");
+	}
 	curse();
 	struct pollfd fds[2] = {
 		{ .fd = STDIN_FILENO, .events = POLLIN },