*** empty log message ***
authorFrancois Fleuret <francois@fleuret.org>
Thu, 12 Mar 2009 07:10:45 +0000 (08:10 +0100)
committerFrancois Fleuret <francois@fleuret.org>
Thu, 12 Mar 2009 07:10:45 +0000 (08:10 +0100)
selector.cc

index cc25520..5b62ca8 100644 (file)
 // END_IP_HEADER                                                         //
 ///////////////////////////////////////////////////////////////////////////
 
+/*
+
+  Here is the magical shell script for a smart bash-history. Note that
+  the line remains in /tmp/selector.out, which may be a scurity concern.
+
+  ./selector -f ~/.bash_history
+  OLD_SETTINGS=`stty -g`
+  stty -echo raw
+  writevt `tty` "`cat /tmp/selector.out`"
+  stty ${OLD_SETTINGS}
+
+*/
+
 #include <stdio.h>
 #include <ncurses.h>
 #include <iostream>
@@ -31,9 +44,13 @@ using namespace std;
 
 int buffer_size = 1024;
 int nb_lines_max = 100000;
+char pattern_separator = ';';
 
-int match(char *string, char *regexp) {
-  return strstr(string, regexp) != 0;
+int match(char *string, int nb_patterns, char **patterns) {
+  for(int n = 0; n < nb_patterns; n++) {
+    if(strstr(string, patterns[n]) == 0) return 0;
+  }
+  return 1;
 }
 
 void check_opt(int argc, char **argv, int n_opt, int n, const char *help) {
@@ -43,15 +60,15 @@ void check_opt(int argc, char **argv, int n_opt, int n, const char *help) {
   }
 }
 
-int previous_visible(int current_line, int nb_lines, char **lines, char *regexp) {
+int previous_visible(int current_line, int nb_lines, char **lines, int nb_patterns, char **patterns) {
   int line = current_line - 1;
-  while(line >= 0 && !match(lines[line], regexp)) line--;
+  while(line >= 0 && !match(lines[line], nb_patterns, patterns)) line--;
   return line;
 }
 
-int next_visible(int current_line, int nb_lines, char **lines, char *regexp) {
+int next_visible(int current_line, int nb_lines, char **lines, int nb_patterns, char **patterns) {
   int line = current_line + 1;
-  while(line < nb_lines && !match(lines[line], regexp)) line++;
+  while(line < nb_lines && !match(lines[line], nb_patterns, patterns)) line++;
 
   if(line < nb_lines)
     return line;
@@ -61,10 +78,38 @@ int next_visible(int current_line, int nb_lines, char **lines, char *regexp) {
 
 void update_screen(int *current_line, int motion,
                    int nb_lines, char **lines,
-                   char *regexp, int noblink) {
+                   char *pattern_list,
+                   int noblink) {
 
   char buffer[buffer_size];
 
+  // We split the pattern list into individual patterns
+
+  int nb_patterns = 1;
+
+  for(char *s = pattern_list; *s; s++) {
+    if(*s == pattern_separator) {
+      nb_patterns++;
+    }
+  }
+
+  char splitted_patterns[strlen(pattern_list) + 1];
+  char *patterns[nb_patterns];
+
+  strcpy(splitted_patterns, pattern_list);
+
+  int n = 0;
+  char *last_pattern_start = splitted_patterns;
+  for(char *s = splitted_patterns; n < nb_patterns; s++) {
+    if(*s == pattern_separator || *s == '\0') {
+      *s = '\0';
+      patterns[n++] = last_pattern_start;
+      last_pattern_start = s + 1;
+    }
+  }
+
+  // We now take care of printing the lines per se
+
   int console_width = getmaxx(stdscr);
   int console_height = getmaxy(stdscr);
 
@@ -74,12 +119,12 @@ void update_screen(int *current_line, int motion,
   // first visible after it, or the first visible before it.
 
   int new_line;
-  if(match(lines[*current_line], regexp)) {
+  if(match(lines[*current_line], nb_patterns, patterns)) {
     new_line = *current_line;
   } else {
-    new_line = next_visible(*current_line, nb_lines, lines, regexp);
+    new_line = next_visible(*current_line, nb_lines, lines, nb_patterns, patterns);
     if(new_line < 0) {
-      new_line = previous_visible(*current_line, nb_lines, lines, regexp);
+      new_line = previous_visible(*current_line, nb_lines, lines, nb_patterns, patterns);
     }
   }
 
@@ -91,13 +136,13 @@ void update_screen(int *current_line, int motion,
 
     if(motion > 0) {
       // We want to go down, let's find the first visible line below
-      l = next_visible(new_line, nb_lines, lines, regexp);
+      l = next_visible(new_line, nb_lines, lines, nb_patterns, patterns);
       if(l >= 0) {
         new_line = l;
       }
     } else {
       // We want to go up, let's find the first visible line above
-      l = previous_visible(new_line, nb_lines, lines, regexp);
+      l = previous_visible(new_line, nb_lines, lines, nb_patterns, patterns);
       if(l >= 0) {
         new_line = l;
       }
@@ -112,47 +157,52 @@ void update_screen(int *current_line, int motion,
 
   addstr("\n");
 
-  // Here new_line is either a line number matching the regexp, or -1
+  // Here new_line is either a line number matching the patterns, or -1
 
   if(new_line >= 0) {
 
     int first_line = new_line, last_line = new_line, nb_match = 1;
 
+    // We find the first and last line to show, so that the total of
+    // visible lines between them (them include) is console_height - 1
+
     while(nb_match < console_height-1 && (first_line > 0 || last_line < nb_lines - 1)) {
 
       if(first_line > 0) {
         first_line--;
-        while(first_line > 0 && !match(lines[first_line], regexp)) {
+        while(first_line > 0 && !match(lines[first_line], nb_patterns, patterns)) {
           first_line--;
         }
-        if(match(lines[first_line], regexp)) {
+        if(match(lines[first_line], nb_patterns, patterns)) {
           nb_match++;
         }
       }
 
       if(last_line < nb_lines - 1) {
         last_line++;
-        while(last_line < nb_lines - 1 && !match(lines[last_line], regexp)) {
+        while(last_line < nb_lines - 1 && !match(lines[last_line], nb_patterns, patterns)) {
           last_line++;
         }
 
-        if(match(lines[last_line], regexp)) {
+        if(match(lines[last_line], nb_patterns, patterns)) {
           nb_match++;
         }
       }
     }
 
+    // Now we display them
+
     for(int l = first_line; l <= last_line; l++) {
-      if(match(lines[l], regexp)) {
+      if(match(lines[l], nb_patterns, patterns)) {
         int k = 0;
 
-        while(lines[l][k] && k < buffer_size - 2 && k < console_width - 1) {
+        while(lines[l][k] && k < buffer_size - 2 && k < console_width - 2) {
           buffer[k] = lines[l][k];
           k++;
         }
 
-        if(noblink) {
-          while(k < console_width - 1) {
+        if(noblink || l == new_line) {
+          while(k < console_width) {
             buffer[k++] = ' ';
           }
         }
@@ -162,10 +212,10 @@ void update_screen(int *current_line, int motion,
 
         if(l == new_line) {
           attron(COLOR_PAIR(2));
-          addstr(buffer);
+          addnstr(buffer, console_width);
           attroff(COLOR_PAIR(2));
         } else {
-          addstr(buffer);
+          addnstr(buffer, console_width);
         }
 
         last_printer_line = l;
@@ -180,33 +230,40 @@ void update_screen(int *current_line, int motion,
 
   if(noblink) { // Erase the rest of the window. That's slightly ugly.
     int k = 0;
-    while(k < console_width - 1) {
+    while(k < console_width) {
       buffer[k++] = ' ';
     }
     buffer[k++] = '\n';
     buffer[k++] = '\0';
     for(int l = nb_printed_lines; l < console_height; l++) {
-      addstr(buffer);
+      addnstr(buffer, console_width);
     }
   }
 
   // Draw the modeline
 
+  sprintf(buffer, "%d/%d pattern: %s",
+          nb_printed_lines - 1,
+          nb_lines,
+          pattern_list);
+
+  for(int k = strlen(buffer); k < console_width; k++) buffer[k] = ' ';
+  buffer[console_width] = '\0';
+
   move(0, 0);
   attron(COLOR_PAIR(1));
-  sprintf(buffer, "%d/%d pattern: %s", nb_printed_lines - 1, nb_lines, regexp);
-  for(int k = strlen(buffer); k < console_width - 1; k++) buffer[k] = ' ';
-  buffer[console_width-1] = '\0';
-  addstr(buffer);
+  addnstr(buffer, console_width);
   attroff(COLOR_PAIR(1));
 
   refresh();       // After doing something on the display, we refresh it
 }
 
+//////////////////////////////////////////////////////////////////////
+
 int main(int argc, char **argv) {
   char buffer[buffer_size];
   char *lines[nb_lines_max];
-  int noblink = 1;
+  int noblink = 0;
 
   char input_filename[buffer_size], output_filename[buffer_size];
   strcpy(input_filename, "/dev/stdin");
@@ -220,6 +277,12 @@ int main(int argc, char **argv) {
       i += 2;
     }
 
+    else if(strcmp(argv[i], "-s") == 0) {
+      check_opt(argc, argv, i, 1, "<pattern separator>");
+      pattern_separator = argv[i+1][0];
+      i += 2;
+    }
+
     else if(strcmp(argv[i], "-f") == 0) {
       check_opt(argc, argv, i, 1, "<input filename>");
       strncpy(input_filename, argv[i+1], buffer_size);
@@ -238,8 +301,12 @@ int main(int argc, char **argv) {
     }
 
     else {
-      cerr << argv[0] << " [-o <output filename>] [-b] [-l <max number of lines]" << endl;
-      exit(1);
+      cerr << argv[0] << " [-h] [-o <output filename>] [-b] [-l <max number of lines>] [-s <pattern separator>]" << endl;
+      if(strcmp(argv[i], "-h") == 0) {
+        exit(0);
+      } else {
+        exit(1);
+      }
     }
   }
 
@@ -258,10 +325,10 @@ int main(int argc, char **argv) {
     nb_lines++;
   }
 
-  char regexp[buffer_size];
-  regexp[0] = '\0';
-  int regexp_point;
-  regexp_point = 0;
+  char patterns[buffer_size];
+  patterns[0] = '\0';
+  int patterns_point;
+  patterns_point = 0;
 
   initscr();
 
@@ -283,7 +350,7 @@ int main(int argc, char **argv) {
 
   int line = 0;
 
-  update_screen(&line, 0, nb_lines, lines, regexp, noblink);
+  update_screen(&line, 0, nb_lines, lines, patterns, noblink);
 
   do {
 
@@ -292,14 +359,14 @@ int main(int argc, char **argv) {
     int motion = 0;
 
     if(key >= ' ' && key <= 'z') {
-      regexp[regexp_point++] = key;
-      regexp[regexp_point] = '\0';
+      patterns[patterns_point++] = key;
+      patterns[patterns_point] = '\0';
     }
 
     else if(key == KEY_BACKSPACE || key == KEY_DC || key == '\b') {
-      if(regexp_point > 0) {
-        regexp_point--;
-        regexp[regexp_point] = '\0';
+      if(patterns_point > 0) {
+        patterns_point--;
+        patterns[patterns_point] = '\0';
       }
     }
 
@@ -311,7 +378,7 @@ int main(int argc, char **argv) {
       motion = 1;
     }
 
-    update_screen(&line, motion, nb_lines, lines, regexp, noblink);
+    update_screen(&line, motion, nb_lines, lines, patterns, noblink);
   } while(key != '\n' && key != KEY_ENTER && key != '\a');
 
   echo();