@ 260915.5

260421.1 · ba4c5b611448acdbb4c6295fb30dfef4dc9a401d

TUI stdin pipe following #540

fix a TUI stdin buffering issue to support #540

reading declarations

src/output.cpp

@@ -256,7 +256,7 @@ void Output::header(const char *pathname, const std::string& partname, bool& hea   size_t columno = flag_column_number && matcher != NULL ? matcher->columno() + 1 : 1;    // -Q: mark pathname with three \0 markers in headings, unless -a-  bool nul = heading && flag_query && !flag_text;+  bool nul = flag_query && heading && !flag_text;    if (nul)     chr('\0');

src/query.cpp

@@ -851,13 +851,9 @@ void Query::query() #else    signal(SIGINT, sigint);-   signal(SIGQUIT, sigint);-   signal(SIGTERM, sigint);-   signal(SIGPIPE, SIG_IGN);-   signal(SIGWINCH, sigwinch);  #endif@@ -890,7 +886,7 @@ void Query::query()   VKey::cleanup();   Screen::cleanup(); -  // check TTY again for color support, this time without --query+  // check TTY a final time for color support to print results, if any, this time without --query   flag_query = false;   terminal(); @@ -909,10 +905,7 @@ void Query::query()    // close the stdin pipe   if (flag_stdin && Static::source != stdin && Static::source != NULL)-  {-    fclose(Static::source);-    Static::source = NULL;-  }+    fclose(Static::source); // close source but don't reset to NULL, source is used by the search thread    // join the search thread   if (search_thread_.joinable())@@ -1671,13 +1664,13 @@ bool Query::update()   // fetch viewable portion plus one up to two screenfuls more   fetch(row_ - (row_ % Screen::rows) + 2 * Screen::rows); +  int end = rows_ + append_;+   // display the viewable portion when updated-  if (rows_ + append_ > begin && begin < row_ + append_ + maxrows_ - 2)+  if (end > begin && begin < row_ + maxrows_ - 2)   {     Screen::normal(); -    int end = rows_ + append_;-     if (begin + maxrows_ - 2 > end)       begin = end - maxrows_ + 2;     if (begin < 0)@@ -1685,17 +1678,12 @@ bool Query::update()     if (begin < row_)       begin = row_; -    if (end > row_ + maxrows_ - 2)-      end = row_ + maxrows_ - 2;--    for (int i = begin; i < end; ++i)+    for (int i = begin; i < std::min(end, row_ + maxrows_ - 2); ++i)       disp(i);   }    if (error_ == -1)   {-    int end = rows_ + append_;-     if (tick_ < 8 && end < row_ + maxrows_ - 2)     {       int row = end - row_ + 1;@@ -1919,7 +1907,8 @@ bool Query::fetch(int row)       if (!incomplete)       {         // added another row-        ++rows_;+        if (++rows_ < static_cast<int>(view_.size()))+          view_[rows_].clear();          // skip \n         if (nlptr < buffer_ + buflen_)@@ -1929,9 +1918,8 @@ bool Query::fetch(int row)       // append the next chunk of text from the buffer       append_ = incomplete; +      // shift the buffer to make room       buflen_ -= nlptr - buffer_;--      // shift the buffer       memmove(buffer_, nlptr, buflen_);     }   }@@ -4118,10 +4106,11 @@ void Query::set_prompt()  void Query::get_stdin() {-  // if standard input is searched, then buffer all its text+  // if standard input is searched, then dynamically buffer the input to search   if (flag_stdin)   { #ifndef OS_WIN+    // make stdin non-blocking to read and buffer dynamically     fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK); #endif @@ -4162,7 +4151,7 @@ void Query::stop_stdin()   {     // close the stdin pipe when open     if (Static::source != stdin && Static::source != NULL)-      fclose(Static::source);+      fclose(Static::source); // close source but don't reset to NULL, source is used by the search thread      // join the stdin_sender     stdin_stop = true;@@ -4174,15 +4163,21 @@ void Query::stop_stdin() // push standard input down the specified pipe fd void Query::stdin_sender(int fd) {-  // write the stdin data all at once, we can ignore the return value+  // write the stdin data all at once to the search pipe+  char buf[QUERY_BUFFER_SIZE];   ssize_t len = stdin_buffer_.size(), nwritten = write(fd, stdin_buffer_.c_str(), len); -#ifndef OS_WIN+  // when more stdin input arrives, buffer it and write it to the search pipe   while (!stdin_stop && !feof(stdin) && nwritten == len)   {-    len = stdin_input_.file_get(buffer_, QUERY_BUFFER_SIZE);+    len = stdin_input_.file_get(buf, QUERY_BUFFER_SIZE);+     if (len == 0)     {+      if (feof(stdin))+        break;++#ifndef OS_WIN       struct timeval tv;       fd_set rfds, efds;       FD_ZERO(&rfds);@@ -4194,15 +4189,16 @@ void Query::stdin_sender(int fd)       clearerr(stdin);       if (::select(0 + 1, &rfds, NULL, &efds, &tv) >= 0 && FD_ISSET(0, &efds) != 0)         break;+#endif+       nwritten = 0;     }     else     {-      stdin_buffer_.append(buffer_, len);-      nwritten = write(fd, buffer_, len);+      stdin_buffer_.append(buf, len);+      nwritten = write(fd, buf, len);     }   }-#endif    close(fd); }@@ -4453,7 +4449,7 @@ reflex::Input              Query::stdin_input_; std::string                Query::stdin_buffer_; int                        Query::stdin_pipe_[2]; std::thread                Query::stdin_thread_;-volatile bool              Query::stdin_stop           = false;+std::atomic_bool           Query::stdin_stop; size_t                     Query::searched_            = 0; size_t                     Query::found_               = 0; int                        Query::tick_                = 0;

src/query.hpp

@@ -320,7 +320,7 @@ class Query {   static std::string              stdin_buffer_;   static int                      stdin_pipe_[2];   static std::thread              stdin_thread_;-  static volatile bool            stdin_stop;+  static std::atomic_bool         stdin_stop;   static size_t                   searched_;    // last update number of files searched   static size_t                   found_;       // last update number of files found   static int                      tick_;        // 100ms tick 0 to 7 or steady 8

src/stats.cpp

@@ -43,6 +43,10 @@ void Stats::report(FILE *output) {   size_t sf = searched_files();   size_t sd = searched_dirs();+  size_t si = searched_indexed();+  size_t ss = searched_skipped();+  size_t sc = searched_changed();+  size_t sa = searched_added();   size_t sl = searched_lines();   size_t ff = found_files();   size_t fp = found_parts();@@ -71,17 +75,17 @@ void Stats::report(FILE *output)    if (flag_index && indexed > 0)   {-    fprintf(output, "Skipped %zu file%s of %zu (%.4g%%) not matching %zu indexes\n", skipped, (skipped == 1 ? "" : "s"), sf - ff, 100.0 * skipped / (sf - ff), indexed);-    if (changed > 0 || added > 0)+    fprintf(output, "Skipped %zu file%s of %zu (%.4g%%) not matching %zu indexes\n", ss, (ss == 1 ? "" : "s"), sf - ff, 100.0 * ss / (sf - ff), si);+    if (sc > 0 || sa > 0)     {       fprintf(output, "Detected outdated or missing index files, run ugrep-indexer to re-index:\n");-      if (changed > 1)-        fprintf(output, "  searched %zu changed files\n", changed);-      else if (changed == 1)+      if (sc > 1)+        fprintf(output, "  searched %zu changed files\n", sc);+      else if (sc == 1)         fprintf(output, "  searched 1 changed file\n");-      if (added > 1)-        fprintf(output, "  searched %zu new files\n", added);-      else if (added == 1)+      if (sa > 1)+        fprintf(output, "  searched %zu new files\n", sa);+      else if (sa == 1)         fprintf(output, "  searched 1 new file\n");     }   }@@ -200,12 +204,12 @@ void Stats::report(FILE *output) }  reflex::timer_type       Stats::timer;-size_t                   Stats::files   = 0;-size_t                   Stats::dirs    = 0;-size_t                   Stats::indexed = 0;-size_t                   Stats::skipped = 0;-size_t                   Stats::changed = 0;-size_t                   Stats::added   = 0;+std::atomic_size_t       Stats::files;+std::atomic_size_t       Stats::dirs;+std::atomic_size_t       Stats::indexed;+std::atomic_size_t       Stats::skipped;+std::atomic_size_t       Stats::changed;+std::atomic_size_t       Stats::added; std::atomic_size_t       Stats::fileno; std::atomic_size_t       Stats::partno; std::atomic_size_t       Stats::matchno;

src/stats.hpp

@@ -126,6 +126,30 @@ class Stats {     return dirs;   } +  // number of indexed files visited+  static size_t searched_indexed()+  {+    return indexed;+  }++  // numbder of indexed files skipped from search+  static size_t searched_skipped()+  {+    return skipped;+  }++  // number of indexed files changed and searched (stale index file)+  static size_t searched_changed()+  {+    return changed;+  }++  // number of non-indexed files added and searched (stale index file)+  static size_t searched_added()+  {+    return added;+  }+   // number of lines searched   static size_t searched_lines()   {@@ -190,12 +214,12 @@ class Stats {  protected:    static reflex::timer_type       timer;   // elapsed wall-clock time in milli seconds (ms)-  static size_t                   files;   // number of files searched, excluding files in archives-  static size_t                   dirs;    // number of directories searched-  static size_t                   indexed; // number of files found to be indexed-  static size_t                   skipped; // number of files found to be indexed that were skipped as not matching-  static size_t                   changed; // number of files found to be indexed but changed (stale index file)-  static size_t                   added;   // number of files found to be added (stale index file)+  static std::atomic_size_t       files;   // number of files searched, excluding files in archives+  static std::atomic_size_t       dirs;    // number of directories searched+  static std::atomic_size_t       indexed; // number of files found to be indexed+  static std::atomic_size_t       skipped; // number of files found to be indexed that were skipped as not matching+  static std::atomic_size_t       changed; // number of files found to be indexed but changed (stale index file)+  static std::atomic_size_t       added;   // number of files found to be added (stale index file)   static std::atomic_size_t       fileno;  // number of matching files, excluding files in archives, atomic for GrepWorker::search() update   static std::atomic_size_t       partno;  // number of matching files, including files in archives, atomic for GrepWorker::search() update   static std::atomic_size_t       lineno;  // number of lines searched cummulatively