@ 201216.1

161125.4.2 · 08b7b0aa3e6b72e9c8e9d62777cacf6cf3f8507a

Fix #347 - Keep enough context around to print in stream mode

reading declarations

src/print.c

@@ -61,6 +61,41 @@ void print_cleanup_context(void) {     print_context.context_prev_lines = NULL; } +void print_context_append(const char *line, size_t len) {+    if (opts.before == 0) {+        return;+    }+    if (print_context.context_prev_lines[print_context.last_prev_line] != NULL) {+        free(print_context.context_prev_lines[print_context.last_prev_line]);+    }+    print_context.context_prev_lines[print_context.last_prev_line] = ag_strndup(line, len);+    print_context.last_prev_line = (print_context.last_prev_line + 1) % opts.before;+}++void print_trailing_context(const char *path, const char *buf, size_t n) {+    char sep = '-';++    if (opts.ackmate || opts.vimgrep) {+        sep = ':';+    }++    if (print_context.lines_since_last_match != 0 &&+        print_context.lines_since_last_match <= opts.after) {+        if (opts.print_path == PATH_PRINT_EACH_LINE) {+            print_path(path, ':');+        }+        print_line_number(print_context.line, sep);++        fwrite(buf, 1, n, out_fd);+        fputc('\n', out_fd);+    }++    print_context.line++;+    if (!print_context.in_a_match && print_context.lines_since_last_match < INT_MAX) {+        print_context.lines_since_last_match++;+    }+}+ void print_path(const char *path, const char sep) {     if (opts.print_path == PATH_PRINT_NOTHING && !opts.vimgrep) {         return;@@ -172,12 +207,8 @@ void print_file_matches(const char *path, const char *buf, const size_t buf_len,          /* We found the end of a line. */         if ((i == buf_len || buf[i] == '\n') && opts.before > 0) {-            if (print_context.context_prev_lines[print_context.last_prev_line] != NULL) {-                free(print_context.context_prev_lines[print_context.last_prev_line]);-            }             /* We don't want to strcpy the \n */-            print_context.context_prev_lines[print_context.last_prev_line] = ag_strndup(&buf[print_context.prev_line_offset], i - print_context.prev_line_offset);-            print_context.last_prev_line = (print_context.last_prev_line + 1) % opts.before;+            print_context_append(&buf[print_context.prev_line_offset], i - print_context.prev_line_offset);         }          if (i == buf_len || buf[i] == '\n') {@@ -272,24 +303,17 @@ void print_file_matches(const char *path, const char *buf, const size_t buf_len,                         fprintf(out_fd, "%s", color_reset);                     }                 }-            } else if (print_context.lines_since_last_match <= opts.after) {-                /* print context after matching line */-                if (opts.print_path == PATH_PRINT_EACH_LINE) {-                    print_path(path, ':');-                }-                print_line_number(print_context.line, sep);+            } -                for (j = print_context.prev_line_offset; j < i; j++) {-                    fputc(buf[j], out_fd);-                }-                fputc('\n', out_fd);+            if (opts.search_stream) {+                break;             } +            /* print context after matching line */+            print_trailing_context(path, &buf[print_context.prev_line_offset], i - print_context.prev_line_offset);+             print_context.prev_line_offset = i + 1; /* skip the newline */-            print_context.line++;-            if (!print_context.in_a_match && print_context.lines_since_last_match < INT_MAX) {-                print_context.lines_since_last_match++;-            }+             /* File doesn't end with a newline. Print one so the output is pretty. */             if (i == buf_len && buf[i - 1] != '\n' && !opts.search_stream) {                 fputc('\n', out_fd);@@ -302,9 +326,6 @@ void print_line_number(size_t line, const char sep) {     if (!opts.print_line_numbers) {         return;     }-    if (opts.search_stream && opts.stream_line_num) {-        line = opts.stream_line_num;-    }     if (opts.color) {         fprintf(out_fd, "%s%lu%s%c", opts.color_line_number, (unsigned long)line, color_reset, sep);     } else {

src/print.h

@@ -5,6 +5,8 @@  void print_init_context(void); void print_cleanup_context(void);+void print_context_append(const char *line, size_t len);+void print_trailing_context(const char *path, const char *buf, size_t n); void print_path(const char *path, const char sep); void print_path_count(const char *path, const char sep, const size_t count); void print_line(const char *buf, size_t buf_pos, size_t prev_line_offset);

src/search.c

@@ -197,6 +197,10 @@ multiline_done:         log_debug("No match in %s", dir_full_path);     } +    if (matches_len == 0 && opts.search_stream) {+        print_context_append(buf, buf_len - 1);+    }+     if (matches_size > 0) {         free(matches);     }@@ -214,6 +218,10 @@ void search_stream(FILE *stream, const char *path) {     for (i = 1; (line_len = getline(&line, &line_cap, stream)) > 0; i++) {         opts.stream_line_num = i;         search_buf(line, line_len, path);+        if (line[line_len - 1] == '\n') {+            line_len--;+        }+        print_trailing_context(path, line, line_len);     }      free(line);

tests/pipecontext.t

new file mode 100644@@ -0,0 +1,29 @@+Setup:++  $ . $TESTDIR/setup.sh+  $ mkdir pipecontext_dir+  $ printf "a\nb\nc\n" > pipecontext_test.txt+  $ cd pipecontext_dir++Do not use parallel flag, which disables stream input:++  $ unalias ag+  $ alias ag="$TESTDIR/../ag --nocolor --workers=1"++B flag on pipe:++  $ cat ../pipecontext_test.txt | ag --numbers -B1 b+  1-a+  2:b++C flag on pipe:++  $ cat ../pipecontext_test.txt | ag --numbers -C1 b+  1-a+  2:b+  3-c++Just match last line:++  $ cat ../pipecontext_test.txt | ag --numbers c+  3:c