From b5301bfe1c4b110dad8788ea822acbd785e9ef7a Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 14:38:00 +0100 Subject: [PATCH 01/16] Fixed the odd number of lines bug. --- selector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selector.cc b/selector.cc index de06b45..af8ef84 100644 --- a/selector.cc +++ b/selector.cc @@ -214,7 +214,7 @@ void update_screen(int *current_line, int *temporary_line, int motion, } } - if(last_line < nb_lines - 1) { + if(nb_match < console_height - 1 && last_line < nb_lines - 1) { last_line++; while(last_line < nb_lines - 1 && !match(lines[last_line], nb_patterns, patterns)) { last_line++; -- 2.20.1 From c597e11ab02854d2552c8966d376523902ad6d25 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 18:57:58 +0100 Subject: [PATCH 02/16] Changed the -r option to removing of all duplicates, wherever they are. Needed a hash-table to do it kind of properly. Seems to work so far. Wonder if the hash_table_size being ten times the maximum number of lines makes sense. --- selector.cc | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/selector.cc b/selector.cc index af8ef84..fbcd67a 100644 --- a/selector.cc +++ b/selector.cc @@ -65,13 +65,13 @@ void inject_into_tty_buffer(char *line) { tcgetattr(STDIN_FILENO,&oldtio); memset(&newtio, 0, sizeof(newtio)); // Set input mode (non-canonical, *no echo*,...) - tcsetattr(STDIN_FILENO,TCSANOW, &newtio); + tcsetattr(STDIN_FILENO, TCSANOW, &newtio); // Put the selected line in the tty input buffer for(char *k = line; *k; k++) { ioctl(STDIN_FILENO, TIOCSTI, k); } // Restore the old settings - tcsetattr(STDIN_FILENO,TCSANOW, &oldtio); + tcsetattr(STDIN_FILENO, TCSANOW, &oldtio); } ////////////////////////////////////////////////////////////////////// @@ -306,6 +306,38 @@ void update_screen(int *current_line, int *temporary_line, int motion, refresh(); } +////////////////////////////////////////////////////////////////////// +// A quick and dirty hash table + +int *new_hash_table(int hash_table_size) { + int *result; + result = new int[hash_table_size]; + for(int k = 0; k < hash_table_size; k++) { + result[k] = -1; + } + return result; +} + +int test_and_add(char *new_string, int new_index, + char **strings, int *hash_table, int hash_table_size) { + unsigned int code = 0; + + for(int k = 0; new_string[k]; k++) { + code += int(new_string[k]) << (8 * k%4); + } + + code = code % hash_table_size; + + while(hash_table[code] >= 0) { + if(strcmp(new_string, strings[hash_table[code]]) == 0) return 1; + code = (code + 1) % hash_table_size; + } + + hash_table[code] = new_index; + + return 0; +} + ////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { @@ -433,10 +465,18 @@ int main(int argc, char **argv) { return 1; } + int hash_table_size = nb_lines_max * 10; + int *hash_table = 0; + + if(remove_duplicates) { + hash_table = new_hash_table(hash_table_size); + } + while(nb_lines < nb_lines_max && !file.eof()) { file.getline(buffer, buffer_size); if(strcmp(buffer, "") != 0) { char *s = buffer; + if(zsh_history && *s == ':') { while(*s && *s != ';') s++; if(*s == ';') s++; @@ -446,7 +486,7 @@ int main(int argc, char **argv) { while(*s == ' ' || (*s >= '0' && *s <= '9')) s++; } - if(!remove_duplicates || nb_lines == 0 || strcmp(lines[nb_lines - 1], s)) { + if(!hash_table || !test_and_add(s, nb_lines, lines, hash_table, hash_table_size)) { lines[nb_lines] = new char[strlen(s) + 1]; strcpy(lines[nb_lines], s); nb_lines++; @@ -454,6 +494,8 @@ int main(int argc, char **argv) { } } + delete[] hash_table; + if(inverse_order) { for(int i = 0; i < nb_lines/2; i++) { char *s = lines[nb_lines - 1 - i]; -- 2.20.1 From 58c7fdbb05978456149eab289490b6779aa23874 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 18:58:51 +0100 Subject: [PATCH 03/16] Cosmetics. Moved the hash-table routines. --- selector.cc | 64 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/selector.cc b/selector.cc index fbcd67a..668323e 100644 --- a/selector.cc +++ b/selector.cc @@ -95,6 +95,38 @@ void check_opt(int argc, char **argv, int n_opt, int n, const char *help) { } } +////////////////////////////////////////////////////////////////////// +// A quick and dirty hash table + +int *new_hash_table(int hash_table_size) { + int *result; + result = new int[hash_table_size]; + for(int k = 0; k < hash_table_size; k++) { + result[k] = -1; + } + return result; +} + +int test_and_add(char *new_string, int new_index, + char **strings, int *hash_table, int hash_table_size) { + unsigned int code = 0; + + for(int k = 0; new_string[k]; k++) { + code += int(new_string[k]) << (8 * k%4); + } + + code = code % hash_table_size; + + while(hash_table[code] >= 0) { + if(strcmp(new_string, strings[hash_table[code]]) == 0) return 1; + code = (code + 1) % hash_table_size; + } + + hash_table[code] = new_index; + + return 0; +} + ////////////////////////////////////////////////////////////////////// int previous_visible(int current_line, int nb_lines, char **lines, int nb_patterns, char **patterns) { @@ -306,38 +338,6 @@ void update_screen(int *current_line, int *temporary_line, int motion, refresh(); } -////////////////////////////////////////////////////////////////////// -// A quick and dirty hash table - -int *new_hash_table(int hash_table_size) { - int *result; - result = new int[hash_table_size]; - for(int k = 0; k < hash_table_size; k++) { - result[k] = -1; - } - return result; -} - -int test_and_add(char *new_string, int new_index, - char **strings, int *hash_table, int hash_table_size) { - unsigned int code = 0; - - for(int k = 0; new_string[k]; k++) { - code += int(new_string[k]) << (8 * k%4); - } - - code = code % hash_table_size; - - while(hash_table[code] >= 0) { - if(strcmp(new_string, strings[hash_table[code]]) == 0) return 1; - code = (code + 1) % hash_table_size; - } - - hash_table[code] = new_index; - - return 0; -} - ////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { -- 2.20.1 From 4ddeef0bd7aa9434029aa6f2167d2d858e932f26 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 19:03:10 +0100 Subject: [PATCH 04/16] Changed the option to remove duplicates from -r to -d. --- selector.1 | 4 ++-- selector.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selector.1 b/selector.1 index c1762c1..f3fadcd 100644 --- a/selector.1 +++ b/selector.1 @@ -40,7 +40,7 @@ inverse the order of the lines remove the numeric prefix from bash history .IP "\fB-z\fP" 10 remove the time prefix from zsh history -.IP "\fB-r\fP" 10 +.IP "\fB-d\fP" 10 remove duplicated lines .IP "\fB-c \fP" 10 select the modline and highlight color numbers @@ -57,7 +57,7 @@ specify the file to search into To use selector to search into your bash history, you can use -.B selector -r -i -b -v -f <(history) +.B selector -d -i -b -v -f <(history) .SH "BUGS" diff --git a/selector.cc b/selector.cc index 668323e..1518120 100644 --- a/selector.cc +++ b/selector.cc @@ -403,7 +403,7 @@ int main(int argc, char **argv) { i++; } - else if(strcmp(argv[i], "-r") == 0) { + else if(strcmp(argv[i], "-d") == 0) { remove_duplicates = 1; i++; } @@ -432,7 +432,7 @@ int main(int argc, char **argv) { << " [-h]" << " [-v]" << " [-m]" - << " [-r]" + << " [-d]" << " [-z]" << " [-i]" << " [-c ]" -- 2.20.1 From 3a810d0b9e8b805698ee9de88ff34c2c1d13a891 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 21:27:30 +0100 Subject: [PATCH 05/16] Added the option to use a standard regexp. You can either activate it with the -e option, or switch it on/off with ^R. --- selector.1 | 10 +- selector.cc | 307 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 187 insertions(+), 130 deletions(-) diff --git a/selector.1 b/selector.1 index f3fadcd..81c4aa4 100644 --- a/selector.1 +++ b/selector.1 @@ -7,8 +7,12 @@ selector - A simple command line for dynamic pattern selection .SH "DESCRIPTION" .PP \fBselector\fP is a command line dynamic string selection. As you type -a list of strings separated by ';', the display is updated in real -time to show only the lines containing all the said strings. +a list of strings separated by ';' or a regexp, the display is updated +in real time to show only the lines containing all the said strings, +or matching the regexp. + +The ^R key switches between the standard multi-substring mode and the +regexp mode. The main usage of selector is as an efficient search in the shell command history. With the correct option, it will inject the selected @@ -42,6 +46,8 @@ remove the numeric prefix from bash history remove the time prefix from zsh history .IP "\fB-d\fP" 10 remove duplicated lines +.IP "\fB-e\fP" 10 +start with the regexp mode activated .IP "\fB-c \fP" 10 select the modline and highlight color numbers .IP "\fB-o \fP" 10 diff --git a/selector.cc b/selector.cc index 1518120..e21025f 100644 --- a/selector.cc +++ b/selector.cc @@ -39,6 +39,7 @@ #include #include #include +#include using namespace std; @@ -55,6 +56,7 @@ int with_colors = 1; int zsh_history = 0, bash_history = 0; int inverse_order = 0; int remove_duplicates = 0; +int use_regexp = 0; ////////////////////////////////////////////////////////////////////// @@ -76,15 +78,6 @@ void inject_into_tty_buffer(char *line) { ////////////////////////////////////////////////////////////////////// -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) { if(n_opt + n >= argc) { cerr << "Missing argument for " << argv[n_opt] << "." @@ -127,17 +120,79 @@ int test_and_add(char *new_string, int new_index, return 0; } +////////////////////////////////////////////////////////////////////// +// A matcher matches either with a collection of substrings, or with a +// regexp + +struct matcher_t { + regex_t preg; + int regexp_error; + int nb_patterns; + char *splitted_patterns, **patterns; +}; + +int match(char *string, matcher_t *matcher) { + if(matcher->nb_patterns >= 0) { + for(int n = 0; n < matcher->nb_patterns; n++) { + if(strstr(string, matcher->patterns[n]) == 0) return 0; + } + return 1; + } else { + return regexec(&matcher->preg, string, 0, 0, 0) == 0; + } +} + +void free_matcher(matcher_t *matcher) { + if(matcher->nb_patterns >= 0) { + delete[] matcher->splitted_patterns; + delete[] matcher->patterns; + } else { + if(!matcher->regexp_error) regfree(&matcher->preg); + } +} + +void initialize_matcher(int use_regexp, matcher_t *matcher, const char *pattern) { + if(use_regexp) { + matcher->nb_patterns = -1; + matcher->regexp_error = regcomp(&matcher->preg, pattern, REG_ICASE); + } else { + matcher->regexp_error = 0; + matcher->nb_patterns = 1; + + for(const char *s = pattern; *s; s++) { + if(*s == pattern_separator) { + matcher->nb_patterns++; + } + } + + matcher->splitted_patterns = new char[strlen(pattern) + 1]; + matcher->patterns = new char*[matcher->nb_patterns]; + + strcpy(matcher->splitted_patterns, pattern); + + int n = 0; + char *last_pattern_start = matcher->splitted_patterns; + for(char *s = matcher->splitted_patterns; n < matcher->nb_patterns; s++) { + if(*s == pattern_separator || *s == '\0') { + *s = '\0'; + matcher->patterns[n++] = last_pattern_start; + last_pattern_start = s + 1; + } + } + } +} + ////////////////////////////////////////////////////////////////////// -int previous_visible(int current_line, int nb_lines, char **lines, int nb_patterns, char **patterns) { +int previous_visible(int current_line, int nb_lines, char **lines, matcher_t *matcher) { int line = current_line - 1; - while(line >= 0 && !match(lines[line], nb_patterns, patterns)) line--; + while(line >= 0 && !match(lines[line], matcher)) line--; return line; } -int next_visible(int current_line, int nb_lines, char **lines, int nb_patterns, char **patterns) { +int next_visible(int current_line, int nb_lines, char **lines, matcher_t *matcher) { int line = current_line + 1; - while(line < nb_lines && !match(lines[line], nb_patterns, patterns)) line++; + while(line < nb_lines && !match(lines[line], matcher)) line++; if(line < nb_lines) return line; @@ -145,36 +200,16 @@ int next_visible(int current_line, int nb_lines, char **lines, int nb_patterns, return -1; } +////////////////////////////////////////////////////////////////////// + void update_screen(int *current_line, int *temporary_line, int motion, int nb_lines, char **lines, char *pattern_list) { char buffer[buffer_size]; + matcher_t matcher; - // 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; - } - } + initialize_matcher(use_regexp, &matcher, pattern_list); // We now take care of printing the lines per se @@ -184,140 +219,144 @@ void update_screen(int *current_line, int *temporary_line, int motion, // First, we find a visible line. In priority: The current, or the // first visible after it, or the first visible before it. - int new_line; - if(match(lines[*current_line], nb_patterns, patterns)) { - new_line = *current_line; + int nb_printed_lines = 0; + + clear(); + use_default_colors(); + addstr("\n"); + + if(matcher.regexp_error) { + addstr("[regexp error]"); } else { - 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, nb_patterns, patterns); + + int new_line; + if(match(lines[*current_line], &matcher)) { + new_line = *current_line; + } else { + new_line = next_visible(*current_line, nb_lines, lines, &matcher); + if(new_line < 0) { + new_line = previous_visible(*current_line, nb_lines, lines, &matcher); + } } - } - // If we found a visible line and we should move, let's move + // If we found a visible line and we should move, let's move - if(new_line >= 0 && motion != 0) { - int l = new_line; - if(motion > 0) { - // We want to go down, let's find the first visible line below - for(int m = 0; l >= 0 && m < motion; m++) { - l = next_visible(l, nb_lines, lines, nb_patterns, patterns); - if(l >= 0) { - new_line = l; + if(new_line >= 0 && motion != 0) { + int l = new_line; + if(motion > 0) { + // We want to go down, let's find the first visible line below + for(int m = 0; l >= 0 && m < motion; m++) { + l = next_visible(l, nb_lines, lines, &matcher); + if(l >= 0) { + new_line = l; + } } - } - } else { - // We want to go up, let's find the first visible line above - for(int m = 0; l >= 0 && m < -motion; m++) { - l = previous_visible(l, 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 + for(int m = 0; l >= 0 && m < -motion; m++) { + l = previous_visible(l, nb_lines, lines, &matcher); + if(l >= 0) { + new_line = l; + } } } } - } - clear(); + // Here new_line is either a line number matching the patterns, or -1 - use_default_colors(); - - addstr("\n"); - - int nb_printed_lines = 0; - - // Here new_line is either a line number matching the patterns, or -1 + if(new_line >= 0) { - if(new_line >= 0) { + int first_line = new_line, last_line = new_line, nb_match = 1; - 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 - // 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)) { - 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], nb_patterns, patterns)) { + if(first_line > 0) { first_line--; + while(first_line > 0 && !match(lines[first_line], &matcher)) { + first_line--; + } + if(match(lines[first_line], &matcher)) { + nb_match++; + } } - if(match(lines[first_line], nb_patterns, patterns)) { - nb_match++; - } - } - if(nb_match < console_height - 1 && last_line < nb_lines - 1) { - last_line++; - while(last_line < nb_lines - 1 && !match(lines[last_line], nb_patterns, patterns)) { + if(nb_match < console_height - 1 && last_line < nb_lines - 1) { last_line++; - } + while(last_line < nb_lines - 1 && !match(lines[last_line], &matcher)) { + last_line++; + } - if(match(lines[last_line], nb_patterns, patterns)) { - nb_match++; + if(match(lines[last_line], &matcher)) { + nb_match++; + } } } - } - - // Now we display them - - for(int l = first_line; l <= last_line; l++) { - if(match(lines[l], nb_patterns, patterns)) { - int k = 0; - while(lines[l][k] && k < buffer_size - 2 && k < console_width - 2) { - buffer[k] = lines[l][k]; - k++; - } + // Now we display them - // We fill the rest of the line with blanks if either we did - // not clear() or if this is the highlighted line + for(int l = first_line; l <= last_line; l++) { + if(match(lines[l], &matcher)) { + int k = 0; - if(l == new_line) { - while(k < console_width) { - buffer[k++] = ' '; + while(lines[l][k] && k < buffer_size - 2 && k < console_width - 2) { + buffer[k] = lines[l][k]; + k++; } - } - buffer[k++] = '\n'; - buffer[k++] = '\0'; + // We fill the rest of the line with blanks if either we did + // not clear() or if this is the highlighted line - // Highlight the highlighted line ... + if(l == new_line) { + while(k < console_width) { + buffer[k++] = ' '; + } + } - if(l == new_line) { - if(with_colors) { - attron(COLOR_PAIR(2)); - addnstr(buffer, console_width); - attroff(COLOR_PAIR(2)); + buffer[k++] = '\n'; + buffer[k++] = '\0'; + + // Highlight the highlighted line ... + + if(l == new_line) { + if(with_colors) { + attron(COLOR_PAIR(2)); + addnstr(buffer, console_width); + attroff(COLOR_PAIR(2)); + } else { + attron(A_STANDOUT); + addnstr(buffer, console_width); + attroff(A_STANDOUT); + } } else { - attron(A_STANDOUT); addnstr(buffer, console_width); - attroff(A_STANDOUT); } - } else { - addnstr(buffer, console_width); - } - nb_printed_lines++; + nb_printed_lines++; + } } - } - if(motion != 0) { - *current_line = new_line; + if(motion != 0) { + *current_line = new_line; + } } - } - *temporary_line = new_line; + *temporary_line = new_line; - if(nb_printed_lines == 0) { - addnstr("[no selection]\n", console_width); + if(nb_printed_lines == 0) { + addnstr("[no selection]\n", console_width); + } } // Draw the modeline - sprintf(buffer, "%d/%d pattern: %s", + sprintf(buffer, "%d/%d pattern: %s%s", nb_printed_lines, nb_lines, - pattern_list); + pattern_list, + use_regexp ? " [regexp]" : ""); for(int k = strlen(buffer); k < console_width; k++) buffer[k] = ' '; buffer[console_width] = '\0'; @@ -336,6 +375,7 @@ void update_screen(int *current_line, int *temporary_line, int motion, // We are done refresh(); + free_matcher(&matcher); } ////////////////////////////////////////////////////////////////////// @@ -408,6 +448,11 @@ int main(int argc, char **argv) { i++; } + else if(strcmp(argv[i], "-e") == 0) { + use_regexp = 1; + i++; + } + else if(strcmp(argv[i], "-l") == 0) { check_opt(argc, argv, i, 1, ""); nb_lines_max = atoi(argv[i+1]); @@ -433,6 +478,7 @@ int main(int argc, char **argv) { << " [-v]" << " [-m]" << " [-d]" + << " [-e]" << " [-z]" << " [-i]" << " [-c ]" @@ -579,6 +625,10 @@ int main(int argc, char **argv) { motion = -1; } + else if(key == '') { + use_regexp = !use_regexp; + } + else if(key == KEY_DOWN || key == '') { motion = 1; } @@ -620,6 +670,7 @@ int main(int argc, char **argv) { for(int l = 0; l < nb_lines; l++) { delete[] lines[l]; } + delete[] lines; exit(0); -- 2.20.1 From 50710a40445f3a2b25bfbc5b484abb7c5a0ee893 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 21:38:45 +0100 Subject: [PATCH 06/16] Added the ^U key to erase the pattern. --- selector.1 | 4 ++-- selector.cc | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/selector.1 b/selector.1 index 81c4aa4..a4a436f 100644 --- a/selector.1 +++ b/selector.1 @@ -28,8 +28,8 @@ PageUp and PageDown move by ten lines. The Home and End key move to the top and the bottom of the list respectively. The return key selects the current line and exits. -You can cancel the selection either by interrupting the command with -^C or by typing ^G. +The ^U key erases the current pattern, and you can cancel the +selection by either interrupting the command with ^C or by typing ^G. .SH "OPTIONS" .IP "\fB-h\fP" 10 diff --git a/selector.cc b/selector.cc index e21025f..c6cf64c 100644 --- a/selector.cc +++ b/selector.cc @@ -629,6 +629,11 @@ int main(int argc, char **argv) { use_regexp = !use_regexp; } + else if(key == '') { + patterns_point = 0; + patterns[patterns_point] = '\0'; + } + else if(key == KEY_DOWN || key == '') { motion = 1; } -- 2.20.1 From 8b0d331c335d51f61c1a56b98e05f91bd53a1441 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Mon, 16 Mar 2009 22:20:36 +0100 Subject: [PATCH 07/16] Changed the documentation of the debian package. --- mkdeb.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mkdeb.sh b/mkdeb.sh index fa3a029..04baa3a 100755 --- a/mkdeb.sh +++ b/mkdeb.sh @@ -27,7 +27,7 @@ # Depends: ${shlibs:Depends} -VERSION=1.0 +VERSION=1.0-R`git log|grep ^commit|wc -l` PACKAGE=/tmp/selector_${VERSION}_i386.deb make -k @@ -49,8 +49,8 @@ Architecture: i386 Depends: libncurses5, libstdc++6, libc6, libgcc1 Description: A command line for dynamic string-matching. This is a command line for dynamic string selection. As you type a - list of strings separated by ';', the display is updated in real time - to show only the lines containing all the said strings. The main + list of strings separated by ';' or a regexp, the display is updated + in real time to show only the lines with matching content. The main usage of selector is as an efficient search in the shell command history. With the correct option, it will inject the selected line into the virtual tty input buffer, hence allowing the user to edit -- 2.20.1 From 919a7e0c12d771d722d87cbc00d991e406f30a30 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 07:59:18 +0100 Subject: [PATCH 08/16] Changed the hash formula. If I was not that lazy I would look at a standard string hashing technique instead of making my own. --- selector.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/selector.cc b/selector.cc index c6cf64c..e9b4f64 100644 --- a/selector.cc +++ b/selector.cc @@ -104,8 +104,11 @@ int test_and_add(char *new_string, int new_index, char **strings, int *hash_table, int hash_table_size) { unsigned int code = 0; + // This is my recipe. I checked, it seems to work (as long as + // hash_table_size is not a multiple of 387433 that should be okay) + for(int k = 0; new_string[k]; k++) { - code += int(new_string[k]) << (8 * k%4); + code = code * 387433 + (unsigned int) (new_string[k]); } code = code % hash_table_size; @@ -469,7 +472,7 @@ int main(int argc, char **argv) { } else { - cerr << "Selector version " << VERSION + cerr << "Selector version " << VERSION << "-R" << REVISION_NUMBER << endl << "Written by Francois Fleuret " << endl -- 2.20.1 From 10836361b425af2fd602d4fe6adb12c8037f99d9 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 08:02:53 +0100 Subject: [PATCH 09/16] Changed the handling of the argument errors and short help printing. --- selector.cc | 57 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/selector.cc b/selector.cc index e9b4f64..d36c836 100644 --- a/selector.cc +++ b/selector.cc @@ -401,7 +401,9 @@ int main(int argc, char **argv) { strcpy(output_filename, ""); int i = 1; - while(i < argc) { + int error = 0, show_help = 0; + + while(!error && !show_help && i < argc) { if(strcmp(argv[i], "-o") == 0) { check_opt(argc, argv, i, 1, ""); @@ -471,33 +473,40 @@ int main(int argc, char **argv) { i += 5; } + else if(strcmp(argv[i], "-h") == 0) { + show_help = 1; + i++; + } + else { - cerr << "Selector version " << VERSION << "-R" << REVISION_NUMBER - << endl - << "Written by Francois Fleuret " - << endl - << argv[0] - << " [-h]" - << " [-v]" - << " [-m]" - << " [-d]" - << " [-e]" - << " [-z]" - << " [-i]" - << " [-c ]" - << " [-o ]" - << " [-s ]" - << " [-l ]" - << " -f " - << endl; - if(strcmp(argv[i], "-h") == 0) { - exit(0); - } else { - exit(1); - } + cerr << "Unknown argument " << argv[i] << "." << endl; + error = 1; } } + if(show_help || error) { + cerr << "Selector version " << VERSION << "-R" << REVISION_NUMBER + << endl + << "Written by Francois Fleuret " + << endl + << argv[0] + << " [-h]" + << " [-v]" + << " [-m]" + << " [-d]" + << " [-e]" + << " [-z]" + << " [-i]" + << " [-c ]" + << " [-o ]" + << " [-s ]" + << " [-l ]" + << " -f " + << endl; + + exit(error); + } + char **lines = new char *[nb_lines_max]; if(!input_filename[0]) { -- 2.20.1 From c7ba212093be8da9d393ad74eeaac47e11370db4 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 08:05:19 +0100 Subject: [PATCH 10/16] Added an automatic computation of the revision number (which is defined as being the number of "commits" in the git log). --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b723ea1..9838c51 100644 --- a/Makefile +++ b/Makefile @@ -23,13 +23,15 @@ LDFLAGS=-lcurses +REVISION_NUMBER=$(shell git log | grep ^commit | wc -l) + ifeq ($(DEBUG),yes) OPTIMIZE_FLAG = -ggdb3 -DDEBUG else OPTIMIZE_FLAG = -ggdb3 -O3 endif -CXXFLAGS = -Wall $(OPTIMIZE_FLAG) +CXXFLAGS = -DREVISION_NUMBER=$(REVISION_NUMBER) -Wall $(OPTIMIZE_FLAG) all: selector -- 2.20.1 From e8ef89ff14e0d0729c8cbfb292267a01fca4be98 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 08:10:54 +0100 Subject: [PATCH 11/16] Cosmetics. --- selector.1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selector.1 b/selector.1 index a4a436f..0af244d 100644 --- a/selector.1 +++ b/selector.1 @@ -34,8 +34,6 @@ selection by either interrupting the command with ^C or by typing ^G. .SH "OPTIONS" .IP "\fB-h\fP" 10 display help and exits -.IP "\fB-v\fP" 10 -inject the selected line into the tty input buffer .IP "\fB-m\fP" 10 force the monochrome mode .IP "\fB-i\fP" 10 @@ -49,13 +47,15 @@ remove duplicated lines .IP "\fB-e\fP" 10 start with the regexp mode activated .IP "\fB-c \fP" 10 -select the modline and highlight color numbers +select the modeline and highlight color numbers +.IP "\fB-v\fP" 10 +inject the selected line into the tty input buffer .IP "\fB-o \fP" 10 write the selected line into the specified file .IP "\fB-s \fP" 10 specify the symbol to separate the substrings in the search pattern .IP "\fB-l \fP" 10 -specify the maximum number of lines to consider +specify the maximum number of lines to take into account .IP "\fB-f \fP" 10 specify the file to search into -- 2.20.1 From 55f0e8ae89c54546a16a308c1a2080d16a89b811 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 08:20:19 +0100 Subject: [PATCH 12/16] Fixed a comment. --- selector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selector.cc b/selector.cc index d36c836..0278589 100644 --- a/selector.cc +++ b/selector.cc @@ -24,7 +24,7 @@ // To use it as a super-history-search for bash: // -// alias h='./selector -i -b -v -f <(history)' +// alias h='selector -d -i -b -v -f <(history)' // This software is highly Linux-specific, but I would be glad to get // patches to make it work on other OS -- 2.20.1 From f5a9d933f1272364e11c93589903e711b05bcbe5 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 09:27:21 +0100 Subject: [PATCH 13/16] Cosmectics. --- selector.cc | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/selector.cc b/selector.cc index 0278589..ebbd021 100644 --- a/selector.cc +++ b/selector.cc @@ -207,12 +207,12 @@ int next_visible(int current_line, int nb_lines, char **lines, matcher_t *matche void update_screen(int *current_line, int *temporary_line, int motion, int nb_lines, char **lines, - char *pattern_list) { + char *pattern) { char buffer[buffer_size]; matcher_t matcher; - initialize_matcher(use_regexp, &matcher, pattern_list); + initialize_matcher(use_regexp, &matcher, pattern); // We now take care of printing the lines per se @@ -358,7 +358,7 @@ void update_screen(int *current_line, int *temporary_line, int motion, sprintf(buffer, "%d/%d pattern: %s%s", nb_printed_lines, nb_lines, - pattern_list, + pattern, use_regexp ? " [regexp]" : ""); for(int k = strlen(buffer); k < console_width; k++) buffer[k] = ' '; @@ -487,7 +487,8 @@ int main(int argc, char **argv) { if(show_help || error) { cerr << "Selector version " << VERSION << "-R" << REVISION_NUMBER << endl - << "Written by Francois Fleuret " + << "Written by Francois Fleuret ." + << endl << endl << argv[0] << " [-h]" @@ -562,10 +563,10 @@ int main(int argc, char **argv) { } } - char patterns[buffer_size]; - patterns[0] = '\0'; - int patterns_point; - patterns_point = 0; + char pattern[buffer_size]; + pattern[0] = '\0'; + int pattern_point; + pattern_point = 0; initscr(); @@ -596,7 +597,7 @@ int main(int argc, char **argv) { int key; int current_line = 0, temporary_line = 0; - update_screen(¤t_line, &temporary_line, 0, nb_lines, lines, patterns); + update_screen(¤t_line, &temporary_line, 0, nb_lines, lines, pattern); do { @@ -605,15 +606,15 @@ int main(int argc, char **argv) { int motion = 0; if(key >= ' ' && key <= '~') { - patterns[patterns_point++] = key; - patterns[patterns_point] = '\0'; + pattern[pattern_point++] = key; + pattern[pattern_point] = '\0'; } else if(key == KEY_BACKSPACE || key == '' || key == '' || key == KEY_DC || key == '') { - if(patterns_point > 0) { - patterns_point--; - patterns[patterns_point] = '\0'; + if(pattern_point > 0) { + pattern_point--; + pattern[pattern_point] = '\0'; } } @@ -633,6 +634,10 @@ int main(int argc, char **argv) { motion = -10; } + else if(key == KEY_DOWN || key == '') { + motion = 1; + } + else if(key == KEY_UP || key == '') { motion = -1; } @@ -642,16 +647,12 @@ int main(int argc, char **argv) { } else if(key == '') { - patterns_point = 0; - patterns[patterns_point] = '\0'; - } - - else if(key == KEY_DOWN || key == '') { - motion = 1; + pattern_point = 0; + pattern[pattern_point] = '\0'; } update_screen(¤t_line, &temporary_line, motion, - nb_lines, lines, patterns); + nb_lines, lines, pattern); } while(key != '\n' && key != KEY_ENTER && key != ''); -- 2.20.1 From 0a66c657ac6a8c10207164fbd0444ca09db6684c Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 09:27:21 +0100 Subject: [PATCH 14/16] Cosmetics. --- selector.cc | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/selector.cc b/selector.cc index 0278589..ebbd021 100644 --- a/selector.cc +++ b/selector.cc @@ -207,12 +207,12 @@ int next_visible(int current_line, int nb_lines, char **lines, matcher_t *matche void update_screen(int *current_line, int *temporary_line, int motion, int nb_lines, char **lines, - char *pattern_list) { + char *pattern) { char buffer[buffer_size]; matcher_t matcher; - initialize_matcher(use_regexp, &matcher, pattern_list); + initialize_matcher(use_regexp, &matcher, pattern); // We now take care of printing the lines per se @@ -358,7 +358,7 @@ void update_screen(int *current_line, int *temporary_line, int motion, sprintf(buffer, "%d/%d pattern: %s%s", nb_printed_lines, nb_lines, - pattern_list, + pattern, use_regexp ? " [regexp]" : ""); for(int k = strlen(buffer); k < console_width; k++) buffer[k] = ' '; @@ -487,7 +487,8 @@ int main(int argc, char **argv) { if(show_help || error) { cerr << "Selector version " << VERSION << "-R" << REVISION_NUMBER << endl - << "Written by Francois Fleuret " + << "Written by Francois Fleuret ." + << endl << endl << argv[0] << " [-h]" @@ -562,10 +563,10 @@ int main(int argc, char **argv) { } } - char patterns[buffer_size]; - patterns[0] = '\0'; - int patterns_point; - patterns_point = 0; + char pattern[buffer_size]; + pattern[0] = '\0'; + int pattern_point; + pattern_point = 0; initscr(); @@ -596,7 +597,7 @@ int main(int argc, char **argv) { int key; int current_line = 0, temporary_line = 0; - update_screen(¤t_line, &temporary_line, 0, nb_lines, lines, patterns); + update_screen(¤t_line, &temporary_line, 0, nb_lines, lines, pattern); do { @@ -605,15 +606,15 @@ int main(int argc, char **argv) { int motion = 0; if(key >= ' ' && key <= '~') { - patterns[patterns_point++] = key; - patterns[patterns_point] = '\0'; + pattern[pattern_point++] = key; + pattern[pattern_point] = '\0'; } else if(key == KEY_BACKSPACE || key == '' || key == '' || key == KEY_DC || key == '') { - if(patterns_point > 0) { - patterns_point--; - patterns[patterns_point] = '\0'; + if(pattern_point > 0) { + pattern_point--; + pattern[pattern_point] = '\0'; } } @@ -633,6 +634,10 @@ int main(int argc, char **argv) { motion = -10; } + else if(key == KEY_DOWN || key == '') { + motion = 1; + } + else if(key == KEY_UP || key == '') { motion = -1; } @@ -642,16 +647,12 @@ int main(int argc, char **argv) { } else if(key == '') { - patterns_point = 0; - patterns[patterns_point] = '\0'; - } - - else if(key == KEY_DOWN || key == '') { - motion = 1; + pattern_point = 0; + pattern[pattern_point] = '\0'; } update_screen(¤t_line, &temporary_line, motion, - nb_lines, lines, patterns); + nb_lines, lines, pattern); } while(key != '\n' && key != KEY_ENTER && key != ''); -- 2.20.1 From 06d791c1683465286307455c17b44f8002bbf216 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 16:07:59 +0100 Subject: [PATCH 15/16] Added back the -b option in the short help. Cosmetics. --- selector.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/selector.cc b/selector.cc index ebbd021..2725c2b 100644 --- a/selector.cc +++ b/selector.cc @@ -438,13 +438,13 @@ int main(int argc, char **argv) { i++; } - else if(strcmp(argv[i], "-z") == 0) { - zsh_history = 1; + else if(strcmp(argv[i], "-b") == 0) { + bash_history = 1; i++; } - else if(strcmp(argv[i], "-b") == 0) { - bash_history = 1; + else if(strcmp(argv[i], "-z") == 0) { + zsh_history = 1; i++; } @@ -496,6 +496,7 @@ int main(int argc, char **argv) { << " [-m]" << " [-d]" << " [-e]" + << " [-b]" << " [-z]" << " [-i]" << " [-c ]" -- 2.20.1 From e4ebdbec894a0edf237c76737218a309db967794 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Tue, 17 Mar 2009 17:26:37 +0100 Subject: [PATCH 16/16] Changed the removal of duplicates so that the most recent one is kept instead of the older one. --- selector.cc | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/selector.cc b/selector.cc index 2725c2b..7422fd6 100644 --- a/selector.cc +++ b/selector.cc @@ -114,13 +114,17 @@ int test_and_add(char *new_string, int new_index, code = code % hash_table_size; while(hash_table[code] >= 0) { - if(strcmp(new_string, strings[hash_table[code]]) == 0) return 1; + if(strcmp(new_string, strings[hash_table[code]]) == 0) { + int result = hash_table[code]; + hash_table[code] = new_index; + return result; + } code = (code + 1) % hash_table_size; } hash_table[code] = new_index; - return 0; + return -1; } ////////////////////////////////////////////////////////////////////// @@ -546,16 +550,36 @@ int main(int argc, char **argv) { while(*s == ' ' || (*s >= '0' && *s <= '9')) s++; } - if(!hash_table || !test_and_add(s, nb_lines, lines, hash_table, hash_table_size)) { + int dup; + + if(hash_table) { + dup = test_and_add(s, nb_lines, lines, hash_table, hash_table_size); + } else { + dup = -1; + } + + if(dup < 0) { lines[nb_lines] = new char[strlen(s) + 1]; strcpy(lines[nb_lines], s); - nb_lines++; + } else { + lines[nb_lines] = lines[dup]; + lines[dup] = 0; } + + nb_lines++; } } delete[] hash_table; + int n = 0; + for(int k = 0; k < nb_lines; k++) { + if(lines[k]) { + lines[n++] = lines[k]; + } + } + nb_lines = n; + if(inverse_order) { for(int i = 0; i < nb_lines/2; i++) { char *s = lines[nb_lines - 1 - i]; -- 2.20.1