commit - 5e070240dfc4a9ff80bb9789bc54b22b77db6306
commit + 6c4c42e07c3ebc32f3ea82173f6936b9f522733a
blob - 6baad612e9f1ecbad710071e93668cb9e6da2c5b
blob + 4f5a750057ad8008dfbb50f5e971a7e9988205a6
--- include/got_object.h
+++ include/got_object.h
/*
* 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
struct got_blame_line {
int annotated;
struct got_object_id id;
+ off_t offset;
};
struct got_blame_diff_offsets {
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;
};
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
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
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
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
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)
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
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;
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
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
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;
struct got_reflist_head *refs;
struct got_object_id *commit_id;
struct tog_blame blame;
+ int matched_line;
};
struct tog_parent_tree {
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 *,
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;
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,
}
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;