Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ugrep for openSUSE:Factory checked in at 2023-04-03 00:52:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ugrep (Old) and /work/SRC/openSUSE:Factory/.ugrep.new.9019 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ugrep" Mon Apr 3 00:52:01 2023 rev:40 rq:1076764 version:3.11.1 Changes: -------- --- /work/SRC/openSUSE:Factory/ugrep/ugrep.changes 2023-03-19 16:17:05.127470017 +0100 +++ /work/SRC/openSUSE:Factory/.ugrep.new.9019/ugrep.changes 2023-04-03 00:52:01.766378443 +0200 @@ -1,0 +2,7 @@ +Sun Apr 2 18:28:20 UTC 2023 - Andreas Stieger <andreas.stie...@gmx.de> + +- update to 3.11.1: + * Smarter interactive navigation in the TUI when option --tree is + used with option -l or -c + +------------------------------------------------------------------- Old: ---- ugrep-3.11.0.tar.gz New: ---- ugrep-3.11.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ugrep.spec ++++++ --- /var/tmp/diff_new_pack.qp4Y7z/_old 2023-04-03 00:52:02.270381008 +0200 +++ /var/tmp/diff_new_pack.qp4Y7z/_new 2023-04-03 00:52:02.274381029 +0200 @@ -17,7 +17,7 @@ Name: ugrep -Version: 3.11.0 +Version: 3.11.1 Release: 0 Summary: Universal grep: a feature-rich grep implementation with focus on speed License: BSD-3-Clause ++++++ ugrep-3.11.0.tar.gz -> ugrep-3.11.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/.github/workflows/c-cpp.yml new/ugrep-3.11.1/.github/workflows/c-cpp.yml --- old/ugrep-3.11.0/.github/workflows/c-cpp.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/ugrep-3.11.1/.github/workflows/c-cpp.yml 2023-04-02 15:59:38.000000000 +0200 @@ -0,0 +1,21 @@ +name: C/C++ CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: configure + run: ./configure + - name: make + run: make + - name: make test + run: make test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/README.md new/ugrep-3.11.1/README.md --- old/ugrep-3.11.0/README.md 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/README.md 2023-04-02 15:59:38.000000000 +0200 @@ -1,4 +1,4 @@ -[![build status][travis-image]][travis-url] [![license][bsd-3-image]][bsd-3-url] +[![build status][ci-image]][ci-url] [![license][bsd-3-image]][bsd-3-url] **ugrep v3.11 is now available: more features & even faster than before** @@ -1886,17 +1886,17 @@ Output NUM lines of trailing context after matching lines. Places a --group-separator between contiguous groups of matches. If -o is specified, output the match with context to fit NUM columns after - the match or shortening the match. See also options -B, -C and -y. + the match or shortens the match. See also options -B, -C and -y. -B NUM, --before-context=NUM Output NUM lines of leading context before matching lines. Places a --group-separator between contiguous groups of matches. If -o is specified, output the match with context to fit NUM columns before - the match or shortening the match. See also options -A, -C and -y. + the match or shortens the match. See also options -A, -C and -y. -C NUM, --context=NUM Output NUM lines of leading and trailing context surrounding each matching line. Places a --group-separator between contiguous groups of matches. If -o is specified, output the match with - context to fit NUM columns before and after the match or shortening + context to fit NUM columns before and after the match or shortens the match. See also options -A, -B and -y. -y, --any-line Any line is output (passthru). Non-matching lines are output as @@ -3916,7 +3916,7 @@ Output NUM lines of trailing context after matching lines. Places a --group-separator between contiguous groups of matches. If -o is specified, output the match with context to fit NUM columns - after the match or shortening the match. See also options -B, -C + after the match or shortens the match. See also options -B, -C and -y. -a, --text @@ -3942,7 +3942,7 @@ Output NUM lines of leading context before matching lines. Places a --group-separator between contiguous groups of matches. If -o is specified, output the match with context to fit NUM columns - before the match or shortening the match. See also options -A, -C + before the match or shortens the match. See also options -A, -C and -y. -b, --byte-offset @@ -3998,8 +3998,8 @@ Output NUM lines of leading and trailing context surrounding each matching line. Places a --group-separator between contiguous groups of matches. If -o is specified, output the match with - context to fit NUM columns before and after the match or - shortening the match. See also options -A, -B and -y. + context to fit NUM columns before and after the match or shortens + the match. See also options -A, -B and -y. -c, --count Only a count of selected lines is written to standard output. If @@ -4515,7 +4515,8 @@ --separator[=SEP] Use SEP as field separator between file name, line number, column number, byte offset and the matched line. The default is a colon - (`:'). + (`:'), a plus (`+') for additional matches on the same line, and a + bar (`|') for multi-line pattern matches. --sort[=KEY] Displays matching files in the order specified by KEY in recursive @@ -5258,7 +5259,7 @@ - ugrep 3.11.0 March 18, 2023 UGREP(1) + ugrep 3.11.1 April 2, 2023 UGREP(1) ð [Back to table of contents](#toc) @@ -5530,7 +5531,7 @@ [report an issue](https://github.com/Genivia/ugrep/issues) on GitHub. Bug reports are quickly addressed. -[travis-image]: https://travis-ci.com/Genivia/ugrep.svg?branch=master -[travis-url]: https://app.travis-ci.com/github/Genivia/ugrep +[ci-image]: https://github.com/Genivia/ugrep/actions/workflows/c-cpp.yml/badge.svg +[ci-url]: https://github.com/Genivia/ugrep/actions/workflows/c-cpp.yml [bsd-3-image]: https://img.shields.io/badge/license-BSD%203--Clause-blue.svg [bsd-3-url]: https://opensource.org/licenses/BSD-3-Clause Binary files old/ugrep-3.11.0/bin/win32/ugrep.exe and new/ugrep-3.11.1/bin/win32/ugrep.exe differ Binary files old/ugrep-3.11.0/bin/win64/ugrep.exe and new/ugrep-3.11.1/bin/win64/ugrep.exe differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/man/ugrep.1 new/ugrep-3.11.1/man/ugrep.1 --- old/ugrep-3.11.0/man/ugrep.1 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/man/ugrep.1 2023-04-02 15:59:38.000000000 +0200 @@ -1,4 +1,4 @@ -.TH UGREP "1" "March 18, 2023" "ugrep 3.11.0" "User Commands" +.TH UGREP "1" "April 02, 2023" "ugrep 3.11.1" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS @@ -58,7 +58,7 @@ Output NUM lines of trailing context after matching lines. Places a \fB\-\-group\-separator\fR between contiguous groups of matches. If \fB\-o\fR is specified, output the match with context to fit NUM columns after -the match or shortening the match. See also options \fB\-B\fR, \fB\-C\fR and \fB\-y\fR. +the match or shortens the match. See also options \fB\-B\fR, \fB\-C\fR and \fB\-y\fR. .TP \fB\-a\fR, \fB\-\-text\fR Process a binary file as if it were text. This is equivalent to @@ -83,7 +83,7 @@ Output NUM lines of leading context before matching lines. Places a \fB\-\-group\-separator\fR between contiguous groups of matches. If \fB\-o\fR is specified, output the match with context to fit NUM columns before -the match or shortening the match. See also options \fB\-A\fR, \fB\-C\fR and \fB\-y\fR. +the match or shortens the match. See also options \fB\-A\fR, \fB\-C\fR and \fB\-y\fR. .TP \fB\-b\fR, \fB\-\-byte\-offset\fR The offset in bytes of a matched line is displayed in front of the @@ -136,7 +136,7 @@ Output NUM lines of leading and trailing context surrounding each matching line. Places a \fB\-\-group\-separator\fR between contiguous groups of matches. If \fB\-o\fR is specified, output the match with -context to fit NUM columns before and after the match or shortening +context to fit NUM columns before and after the match or shortens the match. See also options \fB\-A\fR, \fB\-B\fR and \fB\-y\fR. .TP \fB\-c\fR, \fB\-\-count\fR @@ -643,7 +643,8 @@ \fB\-\-separator\fR[=\fISEP\fR] Use SEP as field separator between file name, line number, column number, byte offset and the matched line. The default is a colon -(`:'). +(`:'), a plus (`+') for additional matches on the same line, and a +bar (`|') for multi\-line pattern matches. .TP \fB\-\-sort\fR[=\fIKEY\fR] Displays matching files in the order specified by KEY in recursive diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/flag.hpp new/ugrep-3.11.1/src/flag.hpp --- old/ugrep-3.11.0/src/flag.hpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/flag.hpp 2023-04-02 15:59:38.000000000 +0200 @@ -175,6 +175,9 @@ extern const char *flag_replace; extern const char *flag_save_config; extern const char *flag_separator; +extern const char *flag_separator_dash; +extern const char *flag_separator_plus; +extern const char *flag_separator_bar; extern const char *flag_sort; extern const char *flag_stats; extern const char *flag_tag; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/output.cpp new/ugrep-3.11.1/src/output.cpp --- old/ugrep-3.11.0/src/output.cpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/output.cpp 2023-04-02 15:59:38.000000000 +0200 @@ -30,7 +30,7 @@ @file output.cpp @brief Output management @author Robert van Engelen - enge...@genivia.com -@copyright (c) 2019-2022, Robert van Engelen, Genivia Inc. All rights reserved. +@copyright (c) 2019-2023, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ @@ -224,7 +224,7 @@ dump.done(); bool sep = false; // when a separator is needed - bool nul = false; // -Q: mark pathname with three NUL bytes unless -a + bool nul = false; // -Q: mark pathname with three \0 markers unless -a if (flag_with_filename && pathname != NULL) { @@ -360,10 +360,10 @@ } } -// output the pathname header for --files_with_matches and --count +// output the short pathname header for --files_with_matches and --count void Output::header(const char *pathname, const std::string& partname) { - bool nul = flag_query > 0; // -Q: mark pathname with three NUL bytes + bool nul = flag_query > 0; // -Q: mark pathname with three \0 markers for quick navigation if (flag_tree) { @@ -377,6 +377,7 @@ Tree::path.pop_back(); size_t len = Tree::path.rfind(PATHSEPCHR); + if (len == std::string::npos) Tree::path.clear(); else @@ -390,25 +391,39 @@ { for (int i = 0; i < Tree::depth; ++i) str(Tree::bar); - while (--up > 0) + for (int i = 1; i < up; ++i) str(Tree::end); nl(); + + // make sure to add a break between trees with terminated leafs + if (up > 1 && *Tree::end != '\0' && Tree::depth == 0) + nl(); + } + else if (Tree::path.empty() && strchr(pathname, PATHSEPCHR) != NULL) + { + // add a break between the list of filenames without path and filenames with paths + nl(); } const char *sep; while ((sep = strchr(pathname + Tree::path.size(), PATHSEPCHR)) != NULL) { + if (nul) + chr('\0'); + for (int i = 1; i < Tree::depth; ++i) str(Tree::bar); + if (Tree::depth > 0) str(Tree::ptr); - else if (nul) - str("\0\0", 2); + + if (nul) + chr('\0'); str(pathname + Tree::path.size(), sep - (pathname + Tree::path.size()) + 1); - if (nul && Tree::depth == 0) + if (nul) chr('\0'); nl(); @@ -416,12 +431,14 @@ ++Tree::depth; } + if (nul) + chr('\0'); + for (int i = 1; i < Tree::depth; ++i) str(Tree::bar); + if (Tree::depth > 0) str(Tree::ptr); - else if (nul) - chr('\0'); str(color_fn); @@ -433,12 +450,12 @@ str(color_st); } - if (nul && Tree::depth == 0) + if (nul) chr('\0'); str(pathname + Tree::path.size()); - if (nul && Tree::depth == 0) + if (nul) chr('\0'); } @@ -488,9 +505,11 @@ { if ((mode_ & BINARY) != 0) return; + str(color_off); str("Binary file"); str(color_fn); + if (pathname != NULL) { chr(' '); @@ -508,6 +527,7 @@ str(color_st); } } + if (!partname.empty()) { if (pathname == NULL) @@ -516,9 +536,11 @@ str(partname); chr('}'); } + str(color_off); str(" matches"); nl(); + mode_ |= BINARY; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/output.hpp new/ugrep-3.11.1/src/output.hpp --- old/ugrep-3.11.0/src/output.hpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/output.hpp 2023-04-02 15:59:38.000000000 +0200 @@ -30,7 +30,7 @@ @file output.hpp @brief Output management @author Robert van Engelen - enge...@genivia.com -@copyright (c) 2019-2022, Robert van Engelen, Genivia Inc. All rights reserved. +@copyright (c) 2019-2023, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/query.cpp new/ugrep-3.11.1/src/query.cpp --- old/ugrep-3.11.0/src/query.cpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/query.cpp 2023-04-02 15:59:38.000000000 +0200 @@ -30,7 +30,7 @@ @file query.cpp @brief Query engine and UI @author Robert van Engelen - enge...@genivia.com -@copyright (c) 2019-2022, Robert van Engelen, Genivia Inc. All rights reserved. +@copyright (c) 2019-2023, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ @@ -1357,7 +1357,7 @@ row_ = 0; rows_ = 0; skip_ = 0; - dots_ = 6; // to clear screen after 300ms + dots_ = 6; // to clear screen after 300 ms error_ = -1; arg_pattern = globbing_ ? temp_ : line_; @@ -1434,8 +1434,8 @@ Screen::put(rows_ - row_ + 1, 0, eof_ ? "(END)" : searching_); Screen::normal(); - // when still searching, don't immediately clear the rest of the screen but clear after 300ms (init dots_ = 6 and three iters) - if (dots_ == 0) + // when still searching, don't immediately clear the rest of the screen to avoid screen flicker, clear after 300 ms (init dots_ = 6 and three iters) + if (eof_ || dots_ == 0) Screen::end(); } @@ -1647,10 +1647,10 @@ } } -// execute the search in a new thread -void Query::execute(int fd) +// execute the search in a new thread and send results to a pipe +void Query::execute(int pipe_fd) { - output = fdopen(fd, "wb"); + output = fdopen(pipe_fd, "wb"); if (output != NULL) { @@ -1871,40 +1871,44 @@ // compare the directory part for options -l and -c to move between directories bool compare_dir = flag_files_with_matches || flag_count; - std::string filename; - bool found = false; + // scroll current row_ or select_ selection + int& ref = select_ == -1 ? row_ : select_; - if (select_ == -1) - { - if (row_ == 0) - return; + if (ref == 0) + return; - --row_; + --ref; - // get the current filename to compare when present - is_filename(view_[row_], filename); + if (compare_dir && flag_tree) + { + if (ref == 0) + return; - while (row_ > 0 && !(found = is_filename(view_[row_], filename, compare_dir))) - --row_; + --ref; - if (found && !flag_heading) - ++row_; + while (ref > 0 && view_[ref].size() > 1) + --ref; } else { - if (select_ == 0) - return; + std::string filename; - --select_; + // get the current filename to compare against, when present + find_filename(ref, filename); - // get the current filename to compare when present - is_filename(view_[select_], filename); + bool found = false; + + while (ref > 0 && !(found = find_filename(ref, filename, compare_dir))) + --ref; - while (select_ > 0 && !(found = is_filename(view_[select_], filename, compare_dir))) - --select_; + if (found && (compare_dir || !flag_heading)) + { + ++ref; - if (found && !flag_heading) - ++select_; + // --tree: skip over directory tree spacing + if (compare_dir && flag_tree && (view_[ref].empty() || view_[ref].front() != '\0')) + ++ref; + } } redraw(); @@ -1924,30 +1928,25 @@ // compare the directory part for options -l and -c to move between directories bool compare_dir = flag_files_with_matches || flag_count; - std::string filename; + // scroll current row_ or select_ selection + int& ref = select_ == -1 ? row_ : select_; - if (select_ == -1) + if (compare_dir && flag_tree) { - if (row_ < rows_) - { - // get the current filename to compare when present - is_filename(view_[row_], filename); - } - - ++row_; + ++ref; while (true) { bool found = false; - while (row_ + 1 < rows_ && !(found = is_filename(view_[row_], filename, compare_dir))) - ++row_; - - if (found || (eof_ && buflen_ == 0)) - break; + while (ref + 1 < rows_ && !(found = view_[ref].size() <= 1)) + ++ref; redraw(); + if (found || (eof_ && buflen_ == 0)) + return; + // fetch more search results when available if (update()) { @@ -1965,26 +1964,27 @@ } else { - if (select_ < rows_) - { - // get the current filename to compare when present - is_filename(view_[select_], filename); - } + std::string filename; - ++select_; + // get the current filename to compare when present + if (ref < rows_) + find_filename(ref, filename); + + ++ref; while (true) { bool found = false; - while (select_ + 1 < rows_ && !(found = is_filename(view_[select_], filename, compare_dir))) - ++select_; - - if (found || (eof_ && buflen_ == 0)) - break; + // seach forward for different filename or different directory + while (ref + 1 < rows_ && !(found = find_filename(ref, filename, compare_dir))) + ++ref; redraw(); + if (found || (eof_ && buflen_ == 0)) + return; + // fetch more search results when available if (update()) { @@ -2000,8 +2000,6 @@ } } } - - redraw(); } // jump to the specified row @@ -2010,87 +2008,45 @@ if (row < 0) row = 0; - if (select_ == -1) - { - if (row <= row_) - { - row_ = row; - - if (row_ >= rows_) - row_ = rows_ - 1; - } - else if (row < rows_) - { - row_ = row; - } - else - { - while (true) - { - while (row_ < row && row_ + 1 < rows_) - ++row_; - - // exit if at the desired row or if the desired row is beyond the end of the search results - if (row_ == row || (eof_ && buflen_ == 0)) - break; + // scroll current row_ or select_ selection + int& ref = select_ == -1 ? row_ : select_; - redraw(); + if (row <= ref) + { + ref = row; - // fetch more search results when available - if (update()) - { - // poll keys without timeout and stop if a key was pressed - if (VKey::poll(0)) - return; - } - else - { - // poll keys with 100 ms timeout and stop if a key was pressed - if (VKey::poll(100)) - return; - } - } - } + if (ref >= rows_) + ref = rows_ - 1; + } + else if (row < rows_) + { + ref = row; } else { - if (row <= select_) - { - select_ = row; - - if (select_ >= rows_) - select_ = rows_ - 1; - } - else if (row < rows_) - { - select_ = row; - } - else + while (true) { - while (true) - { - while (select_ < row && select_ + 1 < rows_) - ++select_; + while (ref < row && ref + 1 < rows_) + ++ref; - // exit if at the desired row or if the desired row is beyond the end of the search results - if (select_ == row || (eof_ && buflen_ == 0)) - break; + // exit if at the desired row or if the desired row is beyond the end of the search results + if (ref == row || (eof_ && buflen_ == 0)) + break; - redraw(); + redraw(); - // fetch more search results when available - if (update()) - { - // poll keys without timeout and stop if a key was pressed - if (VKey::poll(0)) - return; - } - else - { - // poll keys with 100 ms timeout and stop if a key was pressed - if (VKey::poll(100)) - return; - } + // fetch more search results when available + if (update()) + { + // poll keys without timeout and stop if a key was pressed + if (VKey::poll(0)) + return; + } + else + { + // poll keys with 100 ms timeout and stop if a key was pressed + if (VKey::poll(100)) + return; } } } @@ -2111,11 +2067,13 @@ if (flag_stdin) { message("cannot view or edit standard input"); + return; } const char *pager = flag_view; + // if --view is empty and not --no-view, then try the PAGER or EDITOR environment variable as viewer or default viewer if (pager != NULL && *pager == '\0') { pager = getenv("PAGER"); @@ -2127,6 +2085,7 @@ pager = DEFAULT_VIEW_COMMAND; } + // if no viewer, then give up if (pager == NULL || *pager == '\0') { Screen::alert(); @@ -2134,12 +2093,21 @@ return; } + int row = select_ >= 0 ? select_ : row_; + + // --tree: move down over non-filename lines to reach a filename + if (flag_tree && (flag_files_with_matches || flag_count)) + { + while (row + 1 < rows_ && (view_[row].empty() || view_[row].front() != '\0')) + ++row; + } + std::string filename; bool found = false; - int row; - for (row = row_; row >= 0 && !(found = is_filename(view_[row], filename)); --row) - continue; + // move up until a filename header is found + while (row >= 0 && !(found = find_filename(row, filename))) + --row; if (!found && arg_files.size() == 1) { @@ -2174,6 +2142,17 @@ if (system(command.c_str()) == 0) { +#ifdef OS_WIN + if (pager == "more") + { + Screen::setpos(Screen::rows - 1, 0); + Screen::put("(END) press a key"); + Screen::alert(); + VKey::flush(); + VKey::get(); + } +#endif + Screen::clear(); bool changed; @@ -2207,14 +2186,15 @@ } else { - Screen::put(0, 0, command.c_str()); Screen::alert(); + redraw(); + message(std::string("failed: ").append(command)); } } } if (!found) - message(std::string("cannot edit file ").append(filename)); + message(std::string("cannot view or edit ").append(filename)); } // chdir one level down into the directory of the file located under the cursor or just above the screen @@ -2234,11 +2214,21 @@ return; } + int row = select_ >= 0 ? select_ : row_; + + // --tree: move down over non-filename lines to reach a filename + if (flag_tree && (flag_files_with_matches || flag_count)) + { + while (row + 1 < rows_ && (view_[row].empty() || view_[row].front() != '\0')) + ++row; + } + std::string pathname; bool found = false; - for (int i = select_ >= 0 ? select_ : row_; i >= 0 && !(found = is_filename(view_[i], pathname)); --i) - continue; + // move up until a filename header is found + while (row >= 0 && !(found = find_filename(row, pathname))) + --row; if (found) { @@ -3117,7 +3107,7 @@ const char *text = line.c_str(); const char *end = text + line.size(); - // how many nulls to ignore, part of filename marking? + // how many NULs to ignore that are part of the pathname marking in headers? int nulls = *text == '\0' && !flag_text ? 2 : 0; if (nulls > 0) @@ -3510,9 +3500,10 @@ return nwritten; } -// true if line starts with a valid filename/filepath identified by three \0 markers and differs from the given filename, then assigns filename -bool Query::is_filename(const std::string& line, std::string& filename, bool compare_dir) +// true if view_[ref] starts with a valid filename/filepath identified by three \0 markers and differs from the given filename, then assigns filename +bool Query::find_filename(int ref, std::string& filename, bool compare_dir) { + const std::string& line = view_[ref]; size_t end = line.size(); if (end < 4 || line.front() != '\0') @@ -3534,26 +3525,72 @@ if (pos == start || pos >= end) return false; + // extract the new filename + std::string new_filename = line.substr(start, pos - start); + + // --tree: the new filename is the basename, we should reconstruct the new pathname from the tree in view_[] + if (flag_tree && (flag_files_with_matches || flag_count)) + { + size_t last_start = start; + + // while the top directory was not found (works since no colors are used for directory names) + while (start > 2 && --ref >= 0) + { + const std::string& scanline = view_[ref]; + + end = scanline.size(); + + if (end <= 1) + break; + + if (end < 4 || scanline.front() != '\0') + continue; + + pos = 1; + + while (pos < end && scanline.at(pos) != '\0') + ++pos; + + if (++pos >= end) + continue; + + start = pos; + + while (pos < end && scanline.at(pos) != '\0') + ++pos; + + if (pos == start || pos >= end) + continue; + + // if line scanned represents a parent directory, then prepend the directory to the new filename + if (start < last_start && scanline.at(pos - 1) == PATHSEPCHR) + { + new_filename.insert(0, scanline, start, pos - start); + last_start = start; + } + } + } + if (compare_dir) { + // the new filename must not be in the same directory as the old filename size_t skip = 0; #ifdef OS_WIN if (filename.size() >= 3 && filename.at(1) == ':' && filename.at(2) == PATHSEPCHR) skip = 3; #endif - size_t pos1 = line.find(PATHSEPCHR, start + skip); + size_t pos1 = new_filename.find(PATHSEPCHR, skip); size_t pos2 = filename.find(PATHSEPCHR, skip); - if (pos1 != std::string::npos) - pos1 -= start; - if (pos1 == pos2 && (pos1 == std::string::npos || line.compare(start, skip + pos1, filename, 0, skip + pos2) == 0)) - return false; // the extracted filename is the same or in the same directory as the previous + + if (pos1 == pos2 && (pos1 == std::string::npos || new_filename.compare(0, pos1, filename, 0, pos2) == 0)) + return false; // the extracted filename is the same or is in the same directory as the old filename } - else if (line.compare(start, pos - start, filename) == 0) + else if (new_filename.compare(filename) == 0) { - return false; // the extracted filename is the same as the previous + return false; // the new filename is the same as the old filename } - filename = line.substr(start, pos - start); + filename.swap(new_filename); return true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/query.hpp new/ugrep-3.11.1/src/query.hpp --- old/ugrep-3.11.0/src/query.hpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/query.hpp 2023-04-02 15:59:38.000000000 +0200 @@ -30,7 +30,7 @@ @file query.hpp @brief Query engine and UI @author Robert van Engelen - enge...@genivia.com -@copyright (c) 2019-2022, Robert van Engelen, Genivia Inc. All rights reserved. +@copyright (c) 2019-2023, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ @@ -266,7 +266,7 @@ static ssize_t stdin_sender(int fd); - static bool is_filename(const std::string& line, std::string& filename, bool compare_dir = false); + static bool find_filename(int ref, std::string& filename, bool compare_dir = false); static Mode mode_; static bool updated_; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/ugrep.cpp new/ugrep-3.11.1/src/ugrep.cpp --- old/ugrep-3.11.0/src/ugrep.cpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/ugrep.cpp 2023-04-02 15:59:38.000000000 +0200 @@ -30,7 +30,7 @@ @file ugrep.cpp @brief a pattern search utility written in C++11 @author Robert van Engelen - enge...@genivia.com -@copyright (c) 2019-2022, Robert van Engelen, Genivia Inc. All rights reserved. +@copyright (c) 2019-2023, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt For download and installation instructions: @@ -415,7 +415,10 @@ const char *flag_pager = DEFAULT_PAGER; const char *flag_replace = NULL; const char *flag_save_config = NULL; -const char *flag_separator = ":"; +const char *flag_separator = NULL; +const char *flag_separator_dash = "-"; +const char *flag_separator_plus = "+"; +const char *flag_separator_bar = "|"; const char *flag_sort = NULL; const char *flag_stats = NULL; const char *flag_tag = NULL; @@ -2160,7 +2163,7 @@ // context colors with or without -v short v_hex_context_line = flag_invert_match ? Output::Dump::HEX_LINE : Output::Dump::HEX_CONTEXT_LINE; const char *v_color_cx = flag_invert_match ? color_sl : color_cx; - const char *separator = flag_invert_match ? flag_separator : "-"; + const char *separator = flag_invert_match ? flag_separator : flag_separator_dash; while (ptr != NULL) { @@ -2304,7 +2307,7 @@ grep.out.dump.done(); if (!flag_no_header) - grep.out.header(pathname, grep.partname, before_lineno + i, NULL, state.before_offset[j], "-", state.before_binary[j]); + grep.out.header(pathname, grep.partname, before_lineno + i, NULL, state.before_offset[j], flag_separator_dash, state.before_binary[j]); hex = state.before_binary[j]; @@ -2429,7 +2432,7 @@ grep.out.dump.done(); if (!flag_no_header) - grep.out.header(pathname, grep.partname, lineno, NULL, offset, "-", binary); + grep.out.header(pathname, grep.partname, lineno, NULL, offset, flag_separator_dash, binary); hex = binary; @@ -2559,7 +2562,7 @@ grep.out.dump.done(); if (!flag_no_header) - grep.out.header(pathname, grep.partname, before_lineno + i, NULL, offset, "-", state.before_binary[j]); + grep.out.header(pathname, grep.partname, before_lineno + i, NULL, offset, flag_separator_dash, state.before_binary[j]); hex = state.before_binary[j]; @@ -4220,7 +4223,7 @@ fprintf(file, "# Enable/disable color\n%s\n\n", flag_color != NULL ? "color" : "no-color"); fprintf(file, "# Enable/disable query UI confirmation prompts, default: confirm\n%s\n\n", flag_confirm ? "confirm" : "no-confirm"); - fprintf(file, "# Enable/disable query UI file viewing command with CTRL-Y, default: view\n"); + fprintf(file, "# Enable/disable query UI file viewing command with CTRL-Y or F2, default: view\n"); if (flag_view != NULL && *flag_view == '\0') fprintf(file, "view\n\n"); else if (flag_view != NULL) @@ -4298,6 +4301,12 @@ fprintf(file, "# Enable/disable binary files, default: no-ignore-binary\n%s\n\n", strcmp(flag_binary_files, "without-match") == 0 ? "ignore-binary" : "no-ignore-binary"); fprintf(file, "# Enable/disable decompression and archive search, default: no-decompress\n%s\n\n", flag_decompress ? "decompress" : "no-decompress"); fprintf(file, "# Maximum decompression and de-archiving nesting levels, default: 1\nzmax=%zu\n\n", flag_zmax); + if (flag_dereference) + fprintf(file, "# Dereference symlinks, default: no-dereference\ndereference\n\n"); + if (flag_devices != NULL) + fprintf(file, "# Search devices, default: devices=skip\ndevices=%s\n\n", flag_devices); + if (flag_max_depth > 0) + fprintf(file, "# Recursively search directories up to %zu levels deep\nmax-depth=%zu\n\n", flag_max_depth, flag_max_depth); if (flag_ignore_files.empty()) { fprintf(file, "# Enable/disable ignore files, default: no-ignore-files\nno-ignore-files\n\n"); @@ -4323,6 +4332,9 @@ fprintf(file, "### OUTPUT ###\n\n"); + if (flag_separator != NULL) + fprintf(file, "# Separator, default: none specified to output a `:', a `+', and a `|'\nseparator=%s\n\n", flag_separator); + fprintf(file, "# Enable/disable sorted output, default: no-sort\n"); if (flag_sort != NULL) fprintf(file, "sort=%s\n\n", flag_sort); @@ -4813,7 +4825,7 @@ else if (strncmp(arg, "save-config=", 12) == 0) flag_save_config = arg + 12; else if (strcmp(arg, "separator") == 0) - flag_separator = ":"; + flag_separator = NULL; else if (strncmp(arg, "separator=", 10) == 0) flag_separator = arg + 10; else if (strcmp(arg, "silent") == 0) @@ -5620,6 +5632,12 @@ exit(EXIT_ERROR); } + // --separator: override :, + and |, otherwise use default separators :, +, and | + if (flag_separator == NULL || *flag_separator == '\0') + flag_separator = ":"; + else + flag_separator_bar = flag_separator_plus = flag_separator; + #ifdef OS_WIN // save_config() and help() assume text mode, so switch to // binary after we're no longer going to call them. @@ -9073,7 +9091,7 @@ if (!flag_no_header) { - const char *separator = lineno != current_lineno ? flag_separator : "+"; + const char *separator = lineno != current_lineno ? flag_separator : flag_separator_plus; out.header(pathname, partname, current_lineno, matcher, matcher->first(), separator, binary); } @@ -9238,7 +9256,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, ++lineno, NULL, matcher->first() + (to - begin) + 1, "|", false); + out.header(pathname, partname, ++lineno, NULL, matcher->first() + (to - begin) + 1, flag_separator_bar, false); from = to + 1; } @@ -9427,7 +9445,7 @@ if (!flag_no_header) { - const char *separator = lineno != current_lineno ? flag_separator : "+"; + const char *separator = lineno != current_lineno ? flag_separator : flag_separator_plus; out.header(pathname, partname, current_lineno, matcher, first, separator, binary); } @@ -9499,7 +9517,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, ++lineno, NULL, first + (to - begin) + 1, "|", false); + out.header(pathname, partname, ++lineno, NULL, first + (to - begin) + 1, flag_separator_bar, false); from = to + 1; } @@ -9580,7 +9598,7 @@ if (left < first - restline_last) { if (!flag_no_header) - out.header(pathname, partname, current_lineno, matcher, first, "+", binary); + out.header(pathname, partname, current_lineno, matcher, first, flag_separator_plus, binary); left = first - restline_last - left; @@ -9624,7 +9642,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, "|", false); + out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, flag_separator_bar, false); from = to + 1; ++num; @@ -10010,7 +10028,7 @@ if (!flag_no_header) { - const char *separator = lineno != current_lineno ? flag_invert_match ? "-" : flag_separator : "+"; + const char *separator = lineno != current_lineno ? flag_invert_match ? flag_separator_dash : flag_separator : flag_separator_plus; out.header(pathname, partname, current_lineno, matcher, first, separator, binary); } @@ -10065,7 +10083,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, ++lineno, NULL, first + (to - begin) + 1, "|", false); + out.header(pathname, partname, ++lineno, NULL, first + (to - begin) + 1, flag_separator_bar, false); from = to + 1; } @@ -10163,7 +10181,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, "|", false); + out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, flag_separator_bar, false); from = to + 1; ++num; @@ -10456,7 +10474,7 @@ if (!flag_no_header) { - const char *separator = lineno != current_lineno ? flag_invert_match ? "-" : flag_separator : "+"; + const char *separator = lineno != current_lineno ? flag_invert_match ? flag_separator_dash : flag_separator : flag_separator_plus; out.header(pathname, partname, current_lineno, matcher, first, separator, binary); } @@ -10521,7 +10539,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, ++lineno, NULL, first + (to - begin) + 1, "|", false); + out.header(pathname, partname, ++lineno, NULL, first + (to - begin) + 1, flag_separator_bar, false); from = to + 1; } @@ -10619,7 +10637,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, "|", false); + out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, flag_separator_bar, false); from = to + 1; ++num; @@ -10918,7 +10936,7 @@ out.dump.done(); if (!flag_no_header) - out.header(pathname, partname, lineno, matcher, first, "-", binary); + out.header(pathname, partname, lineno, matcher, first, flag_separator_dash, binary); hex = binary; @@ -10965,7 +10983,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, "-", false); + out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, flag_separator_dash, false); from = to + 1; ++num; @@ -11099,7 +11117,7 @@ out.str(match_off); out.chr('\n'); - out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, "-", false); + out.header(pathname, partname, lineno + num, NULL, first + (to - begin) + 1, flag_separator_dash, false); from = to + 1; ++num; @@ -11134,7 +11152,7 @@ out.nl(); if (hex != binary && !flag_no_header) - out.header(pathname, partname, lineno + lines - 1, matcher, last, "-", binary); + out.header(pathname, partname, lineno + lines - 1, matcher, last, flag_separator_dash, binary); hex = binary; @@ -11695,7 +11713,7 @@ Output NUM lines of trailing context after matching lines. Places\n\ a --group-separator between contiguous groups of matches. If -o is\n\ specified, output the match with context to fit NUM columns after\n\ - the match or shortening the match. See also options -B, -C and -y.\n\ + the match or shortens the match. See also options -B, -C and -y.\n\ -a, --text\n\ Process a binary file as if it were text. This is equivalent to\n\ the --binary-files=text option. This option might output binary\n\ @@ -11716,7 +11734,7 @@ Output NUM lines of leading context before matching lines. Places\n\ a --group-separator between contiguous groups of matches. If -o is\n\ specified, output the match with context to fit NUM columns before\n\ - the match or shortening the match. See also options -A, -C and -y.\n\ + the match or shortens the match. See also options -A, -C and -y.\n\ -b, --byte-offset\n\ The offset in bytes of a matched line is displayed in front of the\n\ respective matched line. If -u is specified, displays the offset\n\ @@ -11764,7 +11782,7 @@ Output NUM lines of leading and trailing context surrounding each\n\ matching line. Places a --group-separator between contiguous\n\ groups of matches. If -o is specified, output the match with\n\ - context to fit NUM columns before and after the match or shortening\n\ + context to fit NUM columns before and after the match or shortens\n\ the match. See also options -A, -B and -y.\n\ -c, --count\n\ Only a count of selected lines is written to standard output.\n\ @@ -12231,7 +12249,8 @@ --separator[=SEP]\n\ Use SEP as field separator between file name, line number, column\n\ number, byte offset and the matched line. The default is a colon\n\ - (`:').\n\ + (`:'), a plus (`+') for additional matches on the same line, and a\n\ + bar (`|') for multi-line pattern matches.\n\ --sort[=KEY]\n\ Displays matching files in the order specified by KEY in recursive\n\ searches. Normally the ug command sorts by name whereas the ugrep\n\ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ugrep-3.11.0/src/ugrep.hpp new/ugrep-3.11.1/src/ugrep.hpp --- old/ugrep-3.11.0/src/ugrep.hpp 2023-03-19 02:07:00.000000000 +0100 +++ new/ugrep-3.11.1/src/ugrep.hpp 2023-04-02 15:59:38.000000000 +0200 @@ -30,7 +30,7 @@ @file ugrep.hpp @brief a pattern search utility written in C++11 @author Robert van Engelen - enge...@genivia.com -@copyright (c) 2019-2022, Robert van Engelen, Genivia Inc. All rights reserved. +@copyright (c) 2019-2023, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt */ @@ -38,7 +38,7 @@ #define UGREP_HPP // ugrep version -#define UGREP_VERSION "3.11.0" +#define UGREP_VERSION "3.11.1" // disable mmap because mmap is almost always slower than the file reading speed improvements since 3.0.0 #define WITH_NO_MMAP @@ -348,7 +348,7 @@ // the default -Q UI view command when --view is used and PAGER or EDITOR are not set #ifndef DEFAULT_VIEW_COMMAND # ifdef OS_WIN -# define DEFAULT_VIEW_COMMAND "ugrep" +# define DEFAULT_VIEW_COMMAND "more" # else # define DEFAULT_VIEW_COMMAND "less" # endif