diff --git a/config/config.def.c b/config/config.def.c index 1afcd483..1bc122c0 100644 --- a/config/config.def.c +++ b/config/config.def.c @@ -110,8 +110,6 @@ Settings config = { .fixed_num_lines = FALSE, /** Do not use history */ .disable_history = FALSE, - /** Use levenshtein sorting when matching */ - .levenshtein_sort = FALSE, /** Case sensitivity of the search */ .case_sensitive = FALSE, /** Separator to use for dmenu mode */ @@ -129,7 +127,9 @@ Settings config = { /** Modi to combine into one view. */ .combi_modi = "window,run", /** Fuzzy matching. */ - .fuzzy = FALSE, + .fuzzy = FALSE, + .glob = FALSE, + .tokenize = TRUE, /** Monitor */ .monitor = -1, /** set line margin */ diff --git a/include/rofi.h b/include/rofi.h index 1aff2350..cfc6ebc8 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -210,8 +210,6 @@ typedef struct _Settings unsigned int fixed_num_lines; /** Do not use history */ unsigned int disable_history; - /** Use levenshtein sorting when matching */ - unsigned int levenshtein_sort; /** Search case sensitivity */ unsigned int case_sensitive; /** Separator to use for dmenu mode */ @@ -230,6 +228,8 @@ typedef struct _Settings char *combi_modi; /** Fuzzy match */ unsigned int fuzzy; + unsigned int glob; + unsigned int tokenize; /** Monitors */ int monitor; /** Line margin */ diff --git a/source/helper.c b/source/helper.c index 69c8f975..542e0141 100644 --- a/source/helper.c +++ b/source/helper.c @@ -181,8 +181,21 @@ char **tokenize ( const char *input, int case_sensitive ) char *saveptr = NULL, *token; char **retv = NULL; + if ( !config.tokenize ) { + retv = g_malloc0 ( sizeof ( char* ) * 2 ); + if ( config.glob ) { + token = g_strconcat ( input, "*", NULL ); + retv[0] = token_collate_key ( token, case_sensitive ); + g_free ( token ); token = NULL; + } + else{ + retv[0] = token_collate_key ( input, case_sensitive ); + } + return retv; + } + // First entry is always full (modified) stringtext. - int num_tokens = 0; + int num_tokens = 0; // Copy the string, 'strtok_r' modifies it. char *str = g_strdup ( input ); @@ -190,8 +203,15 @@ char **tokenize ( const char *input, int case_sensitive ) // Iterate over tokens. // strtok should still be valid for utf8. for ( token = strtok_r ( str, " ", &saveptr ); token != NULL; token = strtok_r ( NULL, " ", &saveptr ) ) { - retv = g_realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) ); - retv[num_tokens] = token_collate_key ( token, case_sensitive ); + retv = g_realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) ); + if ( config.glob ) { + char *t = token_collate_key ( token, case_sensitive ); + retv[num_tokens] = g_strconcat ( t, "*", NULL ); + g_free ( t ); + } + else { + retv[num_tokens] = token_collate_key ( token, case_sensitive ); + } retv[num_tokens + 1] = NULL; num_tokens++; } @@ -402,11 +422,30 @@ static int normal_token_match ( char **tokens, const char *input, int not_ascii, return match; } + +static int glob_token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive ) +{ + int match = 1; + char *compk = not_ascii ? token_collate_key ( input, case_sensitive ) : (char *) input; + + // Do a tokenized match. + if ( tokens ) { + for ( int j = 0; match && tokens[j]; j++ ) { + match = g_pattern_match_simple ( tokens[j], compk ); + } + } + if (not_ascii) g_free ( compk ); + return match; +} + int token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive, __attribute__( ( unused ) ) unsigned int index, __attribute__( ( unused ) ) Switcher *data ) { - if ( config.fuzzy ) { + if ( config.glob ) { + return glob_token_match ( tokens, input, not_ascii, case_sensitive ); + } + else if ( config.fuzzy ) { return fuzzy_token_match ( tokens, input, not_ascii, case_sensitive ); } return normal_token_match ( tokens, input, not_ascii, case_sensitive ); diff --git a/source/rofi.c b/source/rofi.c index c05579f3..34e2a5c5 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -141,59 +141,6 @@ static inline MainLoopEvent wait_for_xevent_or_timeout ( Display *display, int x * Levenshtein Sorting. */ -static int lev_sort ( const void *p1, const void *p2, void *arg ) -{ - const int *a = p1; - const int *b = p2; - int *distances = arg; - - return distances[*a] - distances[*b]; -} - -static int dist ( const char *s, const char *t, int *d, int ls, int lt, int i, int j ) -{ - if ( d[i * ( lt + 1 ) + j] >= 0 ) { - return d[i * ( lt + 1 ) + j]; - } - - int x; - if ( i == ls ) { - x = lt - j; - } - else if ( j == lt ) { - x = ls - i; - } - else if ( s[i] == t[j] ) { - x = dist ( s, t, d, ls, lt, i + 1, j + 1 ); - } - else { - x = dist ( s, t, d, ls, lt, i + 1, j + 1 ); - - int y; - if ( ( y = dist ( s, t, d, ls, lt, i, j + 1 ) ) < x ) { - x = y; - } - if ( ( y = dist ( s, t, d, ls, lt, i + 1, j ) ) < x ) { - x = y; - } - x++; - } - return d[i * ( lt + 1 ) + j] = x; -} -static int levenshtein ( const char *s, const char *t ) -{ - int ls = strlen ( s ), lt = strlen ( t ); - size_t array_length = ( ls + 1 ) * ( lt + 1 ); - - // For some reason Coverity does not get that I initialize the - // array in for loop. - int d[array_length]; - for ( size_t i = 0; i < array_length; i++ ) { - d[i] = -1; - } - - return dist ( s, t, d, ls, lt, 0, 0 ); -} // State of the menu. @@ -224,7 +171,6 @@ typedef struct MenuState textbox *case_indicator; textbox **boxes; scrollbar *scrollbar; - int *distance; unsigned int *line_map; unsigned int num_lines; @@ -307,8 +253,6 @@ static void menu_free_state ( MenuState *state ) g_free ( state->boxes ); g_free ( state->line_map ); - g_free ( state->distance ); - g_free ( state->lines_not_ascii ); } @@ -732,15 +676,9 @@ static void menu_refilter ( MenuState *state ) // If each token was matched, add it to list. if ( match ) { state->line_map[j] = i; - if ( config.levenshtein_sort ) { - state->distance[i] = levenshtein ( state->text->text, state->lines[i] ); - } j++; } } - if ( config.levenshtein_sort ) { - g_qsort_with_data ( state->line_map, j, sizeof ( int ), lev_sort, state->distance ); - } // Cleanup + bookkeeping. state->filtered_lines = j; @@ -1003,7 +941,6 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select .prev_key = 0, .last_button_press = 0, .last_offset = 0, - .distance = NULL, .quit = FALSE, .skip_absorb = FALSE, .filtered_lines = 0, @@ -1123,9 +1060,6 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select scrollbar_set_max_value ( state.scrollbar, state.num_lines ); // filtered list state.line_map = g_malloc0_n ( state.num_lines, sizeof ( unsigned int ) ); - if ( config.levenshtein_sort ) { - state.distance = (int *) g_malloc0_n ( state.num_lines, sizeof ( int ) ); - } // resize window vertically to suit // Subtract the margin of the last row. @@ -1418,7 +1352,6 @@ void error_dialog ( const char *msg, int markup ) .last_button_press = 0, .last_offset = 0, .num_lines = 0, - .distance = NULL, .quit = FALSE, .skip_absorb = FALSE, .filtered_lines = 0, diff --git a/source/textbox.c b/source/textbox.c index 8a66d87a..ff2c3edc 100644 --- a/source/textbox.c +++ b/source/textbox.c @@ -666,7 +666,6 @@ void textbox_setup ( Display *display ) void textbox_cleanup ( void ) { - printf ( "cleanup\n" ); if ( p_context ) { g_object_unref ( p_context ); p_context = NULL; diff --git a/source/xrmoptions.c b/source/xrmoptions.c index ffd05115..7e144de0 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -113,7 +113,6 @@ static XrmOption xrmOptions[] = { { xrm_String, "run-shell-command", { .str = &config.run_shell_command }, NULL }, { xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL }, - { xrm_Boolean, "levenshtein-sort", { .num = &config.levenshtein_sort }, NULL }, { xrm_Boolean, "case-sensitive", { .num = &config.case_sensitive }, NULL }, { xrm_Boolean, "sidebar-mode", { .num = &config.sidebar_mode }, NULL }, { xrm_Number, "lazy-filter-limit", { .num = &config.lazy_filter_limit }, NULL }, @@ -122,6 +121,8 @@ static XrmOption xrmOptions[] = { { xrm_Boolean, "parse-hosts", { .num = &config.parse_hosts }, NULL }, { xrm_String, "combi-modi", { .str = &config.combi_modi }, NULL }, { xrm_Boolean, "fuzzy", { .num = &config.fuzzy }, NULL }, + { xrm_Boolean, "glob", { .num = &config.glob }, NULL }, + { xrm_Boolean, "tokenize", { .num = &config.tokenize }, NULL }, { xrm_Number, "monitor", { .snum = &config.monitor }, NULL }, /* Alias for dmenu compatibility. */ { xrm_SNumber, "m", { .snum = &config.monitor }, NULL },