"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
tog search highlighting
To:
gameoftrees@openbsd.org
Date:
Wed, 11 Nov 2020 04:04:20 +0100

Download raw body.

Thread
  • Stefan Sperling:

    tog search highlighting

This adds visual highlighting of search terms in tog's diff and blame views.

The other views are not changed, because:

In the tree view we already highlight matching tree entries.

In the commit view we already highlight the commit's corresponding line, and
the text which was matched is only displayed if it is in the initial part of
the log message. Handling this seems to be more trouble than it's worth.

OK?


diff 135a2da0c5bd18fcf65ac142fa604ec03ad1aa2d /home/stsp/src/got
blob - 7b48924a0835e067b5b49dc74d78a60a76d928d4
file + tog/tog.c
--- tog/tog.c
+++ tog/tog.c
@@ -441,6 +441,7 @@ struct tog_view {
 #define TOG_SEARCH_NO_MORE	2
 #define TOG_SEARCH_HAVE_NONE	3
 	regex_t regex;
+	regmatch_t regmatch;
 };
 
 static const struct got_error *open_diff_view(struct tog_view *,
@@ -727,8 +728,7 @@ view_search_start(struct tog_view *view)
 		view->searching = 0;
 	}
 
-	if (regcomp(&view->regex, pattern,
-	    REG_EXTENDED | REG_NOSUB | REG_NEWLINE) == 0) {
+	if (regcomp(&view->regex, pattern, REG_EXTENDED | REG_NEWLINE) == 0) {
 		err = view->search_start(view);
 		if (err) {
 			regfree(&view->regex);
@@ -2774,11 +2774,10 @@ parse_next_line(FILE *f, size_t *len)
 }
 
 static int
-match_line(const char *line, regex_t *regex)
+match_line(const char *line, regex_t *regex, size_t nmatch,
+    regmatch_t *regmatch)
 {
-	regmatch_t regmatch;
-
-	return regexec(regex, line, 1, &regmatch, 0) == 0;
+	return regexec(regex, line, nmatch, regmatch, 0) == 0;
 }
 
 struct tog_color *
@@ -2787,8 +2786,69 @@ match_color(struct tog_colors *colors, const char *lin
 	struct tog_color *tc = NULL;
 
 	SIMPLEQ_FOREACH(tc, colors, entry) {
-		if (match_line(line, &tc->regex))
+		if (match_line(line, &tc->regex, 0, NULL))
 			return tc;
+	}
+
+	return NULL;
+}
+
+static const struct got_error *
+add_matched_line(int *wtotal, const char *line, int wlimit, int col_tab_align,
+    WINDOW *window, regmatch_t *regmatch)
+{
+	const struct got_error *err = NULL;
+	wchar_t *wline;
+	int width;
+	char *s;
+
+	*wtotal = 0;
+
+	s = strndup(line, regmatch->rm_so);
+	if (s == NULL)
+		return got_error_from_errno("strndup");
+
+	err = format_line(&wline, &width, s, wlimit, col_tab_align);
+	if (err) {
+		free(s);
+		return err;
+	}
+	waddwstr(window, wline);
+	free(wline);
+	free(s);
+	wlimit -= width;
+	*wtotal += width;
+
+	if (wlimit > 0) {
+		s = strndup(line + regmatch->rm_so,
+		    regmatch->rm_eo - regmatch->rm_so);
+		if (s == NULL) {
+			err = got_error_from_errno("strndup");
+			free(s);
+			return err;
+		}
+		err = format_line(&wline, &width, s, wlimit, col_tab_align);
+		if (err) {
+			free(s);
+			return err;
+		}
+		wattr_on(window, A_STANDOUT, NULL);
+		waddwstr(window, wline);
+		wattr_off(window, A_STANDOUT, NULL);
+		free(wline);
+		free(s);
+		wlimit -= width;
+		*wtotal += width;
+	}
+
+	if (wlimit > 0 && strlen(line) > regmatch->rm_eo) {
+		err = format_line(&wline, &width,
+		     line + regmatch->rm_eo, wlimit, col_tab_align);
+		if (err)
+			return err;
+		waddwstr(window, wline);
+		free(wline);
+		*wtotal += width;
 	}
 
 	return NULL;
@@ -2797,7 +2857,8 @@ match_color(struct tog_colors *colors, const char *lin
 static const struct got_error *
 draw_file(struct tog_view *view, FILE *f, int first_displayed_line, int nlines,
     off_t *line_offsets, int selected_line, int max_lines,
-    int *last_displayed_line, int *eof, char *header, struct tog_colors *colors)
+    int *last_displayed_line, int *eof, char *header,
+    struct tog_colors *colors, int matched_line, regmatch_t *regmatch)
 {
 	const struct got_error *err;
 	int nprinted = 0;
@@ -2846,17 +2907,29 @@ draw_file(struct tog_view *view, FILE *f, int first_di
 			*eof = 1;
 			break;
 		}
-		err = format_line(&wline, &width, line, view->ncols, 0);
-		if (err) {
-			free(line);
-			return err;
-		}
 
 		tc = match_color(colors, line);
 		if (tc)
 			wattr_on(view->window,
 			    COLOR_PAIR(tc->colorpair), NULL);
-		waddwstr(view->window, wline);
+		if (first_displayed_line + nprinted == matched_line &&
+		    regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) {
+			err = add_matched_line(&width, line, view->ncols, 0,
+			    view->window, regmatch);
+			if (err) {
+				free(line);
+				return err;
+			}
+		} else {
+			err = format_line(&wline, &width, line, view->ncols, 0);
+			if (err) {
+				free(line);
+				return err;
+			}
+			waddwstr(view->window, wline);
+			free(wline);
+			wline = NULL;
+		}
 		if (tc)
 			wattr_off(view->window,
 			    COLOR_PAIR(tc->colorpair), NULL);
@@ -2864,8 +2937,6 @@ draw_file(struct tog_view *view, FILE *f, int first_di
 			waddch(view->window, '\n');
 		nprinted++;
 		free(line);
-		free(wline);
-		wline = NULL;
 	}
 	if (nprinted >= 1)
 		*last_displayed_line = first_displayed_line + (nprinted - 1);
@@ -3259,7 +3330,8 @@ search_next_diff_view(struct tog_view *view)
 		}
 		free(line);
 		line = parse_next_line(s->f, &len);
-		if (line && match_line(line, &view->regex)) {
+		if (line &&
+		    match_line(line, &view->regex, 1, &view->regmatch)) {
 			view->search_next_done = TOG_SEARCH_HAVE_MORE;
 			s->matched_line = lineno;
 			free(line);
@@ -3448,7 +3520,8 @@ show_diff_view(struct tog_view *view)
 
 	return draw_file(view, s->f, s->first_displayed_line, s->nlines,
 	    s->line_offsets, s->selected_line, view->nlines,
-	    &s->last_displayed_line, &s->eof, header, &s->colors);
+	    &s->last_displayed_line, &s->eof, header, &s->colors,
+	    s->matched_line, &view->regmatch);
 }
 
 static const struct got_error *
@@ -3730,7 +3803,7 @@ draw_blame(struct tog_view *view, struct got_object_id
     const char *path, struct tog_blame_line *lines, int nlines,
     int blame_complete, int selected_line, int *first_displayed_line,
     int *last_displayed_line, int *eof, int max_lines,
-    struct tog_colors *colors)
+    struct tog_colors *colors, int matched_line, regmatch_t *regmatch)
 {
 	const struct got_error *err;
 	int lineno = 0, nprinted = 0;
@@ -3808,70 +3881,77 @@ draw_blame(struct tog_view *view, struct got_object_id
 			continue;
 		}
 
+		if (view->focussed && nprinted == selected_line - 1)
+			wstandout(view->window);
+
+		if (nlines > 0) {
+			blame_line = &lines[lineno - 1];
+			if (blame_line->annotated && prev_id &&
+			    got_object_id_cmp(prev_id, blame_line->id) == 0 &&
+			    !(view->focussed &&
+			    nprinted == selected_line - 1)) {
+				waddstr(view->window, "        ");
+			} else if (blame_line->annotated) {
+				char *id_str;
+				err = got_object_id_str(&id_str, blame_line->id);
+				if (err) {
+					free(line);
+					return err;
+				}
+				tc = get_color(colors, TOG_COLOR_COMMIT);
+				if (tc)
+					wattr_on(view->window,
+					    COLOR_PAIR(tc->colorpair), NULL);
+				wprintw(view->window, "%.8s", id_str);
+				if (tc)
+					wattr_off(view->window,
+					    COLOR_PAIR(tc->colorpair), NULL);
+				free(id_str);
+				prev_id = blame_line->id;
+			} else {
+				waddstr(view->window, "........");
+				prev_id = NULL;
+			}
+		} else {
+			waddstr(view->window, "........");
+			prev_id = NULL;
+		}
+
+		if (view->focussed && nprinted == selected_line - 1)
+			wstandend(view->window);
+		waddstr(view->window, " ");
+
 		if (view->ncols <= 9) {
 			width = 9;
 			wline = wcsdup(L"");
-			if (wline == NULL)
+			if (wline == NULL) {
 				err = got_error_from_errno("wcsdup");
+				free(line);
+				return err;
+			}
+		} else if (*first_displayed_line + nprinted == matched_line &&
+		    regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) {
+			err = add_matched_line(&width, line, view->ncols - 9, 9,
+			    view->window, regmatch);
+			if (err) {
+				free(line);
+				return err;
+			}
+			width += 9;
 		} else {
 			err = format_line(&wline, &width, line,
 			    view->ncols - 9, 9);
+			waddwstr(view->window, wline);
+			free(wline);
+			wline = NULL;
 			width += 9;
 		}
-		if (err) {
-			free(line);
-			return err;
-		}
 
-		if (view->focussed && nprinted == selected_line - 1)
-			wstandout(view->window);
-
-		if (nlines > 0) {
-			blame_line = &lines[lineno - 1];
-			if (blame_line->annotated && prev_id &&
-			    got_object_id_cmp(prev_id, blame_line->id) == 0 &&
-			    !(view->focussed &&
-			    nprinted == selected_line - 1)) {
-				waddstr(view->window, "        ");
-			} else if (blame_line->annotated) {
-				char *id_str;
-				err = got_object_id_str(&id_str, blame_line->id);
-				if (err) {
-					free(line);
-					free(wline);
-					return err;
-				}
-				tc = get_color(colors, TOG_COLOR_COMMIT);
-				if (tc)
-					wattr_on(view->window,
-					    COLOR_PAIR(tc->colorpair), NULL);
-				wprintw(view->window, "%.8s", id_str);
-				if (tc)
-					wattr_off(view->window,
-					    COLOR_PAIR(tc->colorpair), NULL);
-				free(id_str);
-				prev_id = blame_line->id;
-			} else {
-				waddstr(view->window, "........");
-				prev_id = NULL;
-			}
-		} else {
-			waddstr(view->window, "........");
-			prev_id = NULL;
-		}
-
-		if (view->focussed && nprinted == selected_line - 1)
-			wstandend(view->window);
-		waddstr(view->window, " ");
-
-		waddwstr(view->window, wline);
 		if (width <= view->ncols - 1)
 			waddch(view->window, '\n');
 		if (++nprinted == 1)
 			*first_displayed_line = lineno;
 		free(line);
-		free(wline);
-		wline = NULL;
 	}
 	*last_displayed_line = lineno;
 
@@ -4245,7 +4325,8 @@ search_next_blame_view(struct tog_view *view)
 		}
 		free(line);
 		line = parse_next_line(s->blame.f, &len);
-		if (line && match_line(line, &view->regex)) {
+		if (line &&
+		    match_line(line, &view->regex, 1, &view->regmatch)) {
 			view->search_next_done = TOG_SEARCH_HAVE_MORE;
 			s->matched_line = lineno;
 			free(line);
@@ -4288,7 +4369,8 @@ show_blame_view(struct tog_view *view)
 	err = draw_blame(view, s->blamed_commit->id, s->blame.f,
 	    s->path, s->blame.lines, s->blame.nlines, s->blame_complete,
 	    s->selected_line, &s->first_displayed_line,
-	    &s->last_displayed_line, &s->eof, view->nlines, &s->colors);
+	    &s->last_displayed_line, &s->eof, view->nlines, &s->colors,
+	    s->matched_line, &view->regmatch);
 
 	view_vborder(view);
 	return err;