commit 6c4c42e07c3ebc32f3ea82173f6936b9f522733a from: Stefan Sperling date: Mon Jun 24 20:28:11 2019 UTC implement search for 'tog blame' commit - 5e070240dfc4a9ff80bb9789bc54b22b77db6306 commit + 6c4c42e07c3ebc32f3ea82173f6936b9f522733a blob - 6baad612e9f1ecbad710071e93668cb9e6da2c5b blob + 4f5a750057ad8008dfbb50f5e971a7e9988205a6 --- include/got_object.h +++ include/got_object.h @@ -202,11 +202,12 @@ const struct got_error *got_object_blob_read_block(siz /* * Read the entire content of a blob and write it to the specified file. * Flush and rewind the file as well. Indicate the amount of bytes - * written in the size_t output argument, and the number of lines in - * the file in int argument (NULL can be passed for either output argument). + * written in the size_t output argument, and the number of lines in the + * file in the int argument, and line offsets in the the off_t argument + * (NULL can be passed for any output argument). */ const struct got_error *got_object_blob_dump_to_file(size_t *, int *, - FILE *, struct got_blob_object *); + off_t **, FILE *, struct got_blob_object *); /* * Attempt to open a tag object in a repository. blob - b4f8b83d691aa50dc051471e60fc030370cb8298 blob + eda1af09420ccb027636f66eca0fbf48834c4c5a --- lib/blame.c +++ lib/blame.c @@ -40,6 +40,7 @@ struct got_blame_line { int annotated; struct got_object_id id; + off_t offset; }; struct got_blame_diff_offsets { @@ -52,9 +53,11 @@ SLIST_HEAD(got_blame_diff_offsets_list, got_blame_diff struct got_blame { FILE *f; + size_t filesize; int nlines; int nannotated; struct got_blame_line *lines; /* one per line */ + off_t *line_offsets; /* one per line */ int ncommits; struct got_blame_diff_offsets_list diff_offsets_list; }; @@ -329,8 +332,8 @@ blame_open(struct got_blame **blamep, const char *path err = got_error_from_errno("got_opentemp"); goto done; } - err = got_object_blob_dump_to_file(NULL, &blame->nlines, blame->f, - blob); + err = got_object_blob_dump_to_file(&blame->filesize, &blame->nlines, + &blame->line_offsets, blame->f, blob); if (err) goto done; blob - 4da542a630e60a18a9b1066bc987ff7453340987 blob + 449f4a66c5e45ada327bc786016b0b7788668394 --- lib/diff.c +++ lib/diff.c @@ -71,7 +71,8 @@ diff_blobs(struct got_blob_object *blob1, struct got_b size1 = 0; if (blob1) { idstr1 = got_object_blob_id_str(blob1, hex1, sizeof(hex1)); - err = got_object_blob_dump_to_file(&size1, NULL, f1, blob1); + err = got_object_blob_dump_to_file(&size1, NULL, NULL, f1, + blob1); if (err) goto done; } else @@ -80,7 +81,8 @@ diff_blobs(struct got_blob_object *blob1, struct got_b size2 = 0; if (blob2) { idstr2 = got_object_blob_id_str(blob2, hex2, sizeof(hex2)); - err = got_object_blob_dump_to_file(&size2, NULL, f2, blob2); + err = got_object_blob_dump_to_file(&size2, NULL, NULL, f2, + blob2); if (err) goto done; } else @@ -157,7 +159,8 @@ got_diff_blob_file(struct got_blob_object *blob1, FILE if (f1 == NULL) return got_error_from_errno("got_opentemp"); idstr1 = got_object_blob_id_str(blob1, hex1, sizeof(hex1)); - err = got_object_blob_dump_to_file(&size1, NULL, f1, blob1); + err = got_object_blob_dump_to_file(&size1, NULL, NULL, f1, + blob1); if (err) goto done; } else { blob - 1c9eb57ad51151c9e4e3a1f258c9a1cd977fa114 blob + 1a425faf447bc2565598eab69be83532393fee3a --- lib/object.c +++ lib/object.c @@ -1136,13 +1136,17 @@ got_object_blob_read_block(size_t *outlenp, struct got const struct got_error * got_object_blob_dump_to_file(size_t *total_len, int *nlines, - FILE *outfile, struct got_blob_object *blob) + off_t **line_offsets, FILE *outfile, struct got_blob_object *blob) { const struct got_error *err = NULL; size_t n, len, hdrlen; const uint8_t *buf; int i; + size_t noffsets = 0; + off_t off = 0; + if (line_offsets) + *line_offsets = NULL; if (total_len) *total_len = 0; if (nlines) @@ -1155,15 +1159,31 @@ got_object_blob_dump_to_file(size_t *total_len, int *n return err; if (len == 0) break; - if (total_len) - *total_len += len; buf = got_object_blob_get_read_buf(blob); - if (nlines) { - for (i = 0; i < len; i++) { - if (buf[i] == '\n') - (*nlines)++; + for (i = 0; i < len; i++) { + if (buf[i] != '\n') + continue; + if (nlines) + (*nlines)++; + if (line_offsets && nlines && noffsets < *nlines) { + off_t *o = recallocarray(*line_offsets, + noffsets, *nlines, sizeof(**line_offsets)); + if (o == NULL) { + free(*line_offsets); + *line_offsets = NULL; + return got_error_from_errno( + "recallocarray"); + } + *line_offsets = o; + noffsets = *nlines; } + if (line_offsets && nlines && total_len) { + (*line_offsets)[*nlines - 1] = off; + off = *total_len + i + 1; + } } + if (total_len) + *total_len += len; /* Skip blob object header first time around. */ n = fwrite(buf + hdrlen, 1, len - hdrlen, outfile); if (n != len - hdrlen) blob - b0e00b1694127e0786c2ba99bebc3d6873e007a3 blob + 4fbd3aaabfde3b33052fdb193f6bfbe62e442d57 --- lib/worktree.c +++ lib/worktree.c @@ -761,7 +761,8 @@ merge_blob(int *local_changes_subsumed, struct got_wor err = got_opentemp_named(&blob_deriv_path, &f_deriv, base_path); if (err) goto done; - err = got_object_blob_dump_to_file(NULL, NULL, f_deriv, blob_deriv); + err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv, + blob_deriv); if (err) goto done; @@ -776,7 +777,7 @@ merge_blob(int *local_changes_subsumed, struct got_wor if (err) goto done; if (blob_orig) { - err = got_object_blob_dump_to_file(NULL, NULL, f_orig, + err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_orig, blob_orig); if (err) goto done; blob - 5f0b98dc25c59a1d20742b1f3ca97eb62e7ec46c blob + 55b3318255e7f5de44835c303f5370b76ebc849d --- tog/tog.1 +++ tog/tog.1 @@ -193,6 +193,15 @@ currently selected line's commit. Reload the .Cm blame view with the previously blamed commit. +.It Cm / +Prompt for a search pattern and start searching for matching line. +The search pattern is an extended regular expression. +Regular expression syntax is documented in +.Xr re_format 7 . +.It Cm n +Find the next line which matches the current search pattern. +.It Cm N +Find the previous line which matches the current search pattern. .El .Pp The options for blob - 5aed76e3488a03cbbd52d854c272deb3cd5308e6 blob + 1795147c016f75f29a1af18260aecb5f3fe91128 --- tog/tog.c +++ tog/tog.c @@ -178,6 +178,7 @@ struct tog_blame { size_t filesize; struct tog_blame_line *lines; int nlines; + off_t *line_offsets; pthread_t thread; struct tog_blame_thread_args thread_args; struct tog_blame_cb_args cb_args; @@ -198,6 +199,7 @@ struct tog_blame_view_state { struct got_reflist_head *refs; struct got_object_id *commit_id; struct tog_blame blame; + int matched_line; }; struct tog_parent_tree { @@ -303,6 +305,8 @@ static const struct got_error *show_blame_view(struct static const struct got_error *input_blame_view(struct tog_view **, struct tog_view **, struct tog_view **, struct tog_view *, int); static const struct got_error *close_blame_view(struct tog_view *); +static const struct got_error *search_start_blame_view(struct tog_view *); +static const struct got_error *search_next_blame_view(struct tog_view *); static const struct got_error *open_tree_view(struct tog_view *, struct got_tree_object *, struct got_object_id *, @@ -3122,7 +3126,7 @@ run_blame(struct tog_blame *blame, struct tog_view *vi goto done; } err = got_object_blob_dump_to_file(&blame->filesize, &blame->nlines, - blame->f, blob); + &blame->line_offsets, blame->f, blob); if (err) goto done; @@ -3191,6 +3195,8 @@ open_blame_view(struct tog_view *view, char *path, view->show = show_blame_view; view->input = input_blame_view; view->close = close_blame_view; + view->search_start = search_start_blame_view; + view->search_next = search_next_blame_view; return run_blame(&s->blame, view, &s->blame_complete, &s->first_displayed_line, &s->last_displayed_line, @@ -3220,6 +3226,109 @@ close_blame_view(struct tog_view *view) } static const struct got_error * +search_start_blame_view(struct tog_view *view) +{ + struct tog_blame_view_state *s = &view->state.blame; + + s->matched_line = 0; + return NULL; +} + +static int +match_line(const char *line, regex_t *regex) +{ + regmatch_t regmatch; + + return regexec(regex, line, 1, ®match, 0) == 0; +} + + +static const struct got_error * +search_next_blame_view(struct tog_view *view) +{ + const struct got_error *err = NULL; + struct tog_blame_view_state *s = &view->state.blame; + int lineno; + + if (!view->searching) { + view->search_next_done = 1; + return NULL; + } + + if (s->matched_line) { + if (view->searching == TOG_SEARCH_FORWARD) + lineno = s->first_displayed_line - 1 + s->selected_line + 1; + else + lineno = s->first_displayed_line - 1 + s->selected_line - 1; + } else { + if (view->searching == TOG_SEARCH_FORWARD) + lineno = 1; + else + lineno = s->blame.nlines; + } + + while (1) { + char *line = NULL; + off_t offset; + size_t len; + + if (lineno <= 0 || lineno > s->blame.nlines) { + if (s->matched_line == 0) { + view->search_next_done = 1; + free(line); + break; + } + if (view->searching == TOG_SEARCH_FORWARD) + lineno = 1; + else + lineno = s->blame.nlines; + } + + offset = s->blame.line_offsets[lineno - 1]; + if (fseeko(s->blame.f, offset, SEEK_SET) != 0) { + free(line); + return got_error_from_errno("fseeko"); + } + free(line); + line = parse_next_line(s->blame.f, &len); + if (line == NULL) + break; + if (match_line(line, &view->regex)) { + view->search_next_done = 1; + s->matched_line = lineno; + free(line); + break; + } + free(line); + line = NULL; + if (view->searching == TOG_SEARCH_FORWARD) + lineno++; + else + lineno--; + } + + if (s->matched_line) { + int cur = s->first_displayed_line - 1 + s->selected_line; + while (cur < s->matched_line) { + err = input_blame_view(NULL, NULL, NULL, view, KEY_DOWN); + if (err) + return err; + cur++; + } + while (cur > s->matched_line) { + err = input_blame_view(NULL, NULL, NULL, view, KEY_UP); + if (err) + return err; + cur--; + } + s->first_displayed_line = s->matched_line; + s->selected_line = 1; + } + + return NULL; +} + +static const struct got_error * show_blame_view(struct tog_view *view) { const struct got_error *err = NULL;