From 0e86050db8d3e20a93fada37724d9c8d59386c55 Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Thu, 26 May 2016 08:39:33 +0200 Subject: [PATCH] Fix combi mode 'bang' behaviour, improve levenshtein with combi --- include/helper.h | 2 +- include/mode-private.h | 4 ++++ include/mode.h | 1 + source/dialogs/combi.c | 50 ++++++++++++++++++++--------------------- source/dialogs/dmenu.c | 5 +++-- source/dialogs/drun.c | 9 ++++---- source/dialogs/run.c | 3 ++- source/dialogs/script.c | 1 + source/dialogs/ssh.c | 1 + source/dialogs/window.c | 11 ++++----- source/helper.c | 17 +++++++------- source/mode.c | 8 +++++++ source/textbox.c | 2 +- source/view.c | 16 ++++++++----- 14 files changed, 78 insertions(+), 52 deletions(-) diff --git a/include/helper.h b/include/helper.h index e48b6d7f..81cd330c 100644 --- a/include/helper.h +++ b/include/helper.h @@ -97,7 +97,7 @@ int find_arg ( const char * const key ); * * @returns 1 when matches, 0 otherwise */ -int token_match ( GRegex **tokens, const char *input); +int token_match ( GRegex **tokens, const char *input ); /** * @param cmd The command to execute. * diff --git a/include/mode-private.h b/include/mode-private.h index 530827e8..31e92c98 100644 --- a/include/mode-private.h +++ b/include/mode-private.h @@ -27,6 +27,8 @@ typedef void ( *__mode_destroy )( Mode *sw ); typedef ModeMode ( *_mode_result )( Mode *sw, int menu_retv, char **input, unsigned int selected_line ); +typedef char* ( *_mode_preprocess_input )( Mode *sw, const char *input ); + /** * Structure defining a switcher. * It consists of a name, callback and if enabled @@ -57,6 +59,8 @@ struct rofi_mode /** Get the 'completed' entry. */ _mode_get_completion _get_completion; + _mode_preprocess_input _preprocess_input; + /** Pointer to private data. */ void *private_data; diff --git a/include/mode.h b/include/mode.h index 672d74db..1a0d9b01 100644 --- a/include/mode.h +++ b/include/mode.h @@ -154,5 +154,6 @@ void mode_set_private_data ( Mode *mode, void *pd ); const char *mode_get_display_name ( const Mode *mode ); void mode_set_config ( Mode *mode ); +char * mode_preprocess_input ( Mode *mode, const char *input ); /*@}*/ #endif diff --git a/source/dialogs/combi.c b/source/dialogs/combi.c index 89c634b8..7cba5200 100644 --- a/source/dialogs/combi.c +++ b/source/dialogs/combi.c @@ -45,6 +45,7 @@ typedef struct // List of switchers to combine. unsigned int num_switchers; Mode **switchers; + Mode *current; } CombiModePrivateData; static void combi_mode_parse_switchers ( Mode *sw ) @@ -178,34 +179,14 @@ static ModeMode combi_mode_result ( Mode *sw, int mretv, char **input, unsigned static int combi_mode_match ( const Mode *sw, GRegex **tokens, unsigned int index ) { CombiModePrivateData *pd = mode_get_private_data ( sw ); -// if ( config.regex || config.glob ) { - // Bang support only works in text mode. - for ( unsigned i = 0; i < pd->num_switchers; i++ ) { - if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) { - return mode_token_match ( pd->switchers[i], tokens, index - pd->starts[i] ); - } + for ( unsigned i = 0; i < pd->num_switchers; i++ ) { + if ( pd->current != NULL && pd->switchers[i] != pd->current ) { + continue; } - /* @TODO fix this - } - else{ - for ( unsigned i = 0; i < pd->num_switchers; i++ ) { - if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) { - if ( tokens && tokens[0][0] == '!' ) { - if ( tokens[0][1] == mode_get_name ( pd->switchers[i] )[0] ) { - return mode_token_match ( pd->switchers[i], &tokens[1], not_ascii, case_sensitive, - index - pd->starts[i] ); - } - return 0; - } - else { - return mode_token_match ( pd->switchers[i], tokens, not_ascii, case_sensitive, - index - pd->starts[i] ); - } - } + if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) { + return mode_token_match ( pd->switchers[i], tokens, index - pd->starts[i] ); } } - */ - abort (); return 0; } static char * combi_mgrv ( const Mode *sw, unsigned int selected_line, int *state, int get_entry ) @@ -247,6 +228,24 @@ static char * combi_get_completion ( const Mode *sw, unsigned int index ) return NULL; } +static char * combi_preprocess_input ( Mode *sw, const char *input ) +{ + CombiModePrivateData *pd = mode_get_private_data ( sw ); + pd->current = NULL; + if ( input != NULL && input[0] == '!' && strlen ( input ) > 1 ) { + for ( unsigned i = 0; i < pd->num_switchers; i++ ) { + if ( input[1] == mode_get_name ( pd->switchers[i] )[0] ) { + pd->current = pd->switchers[i]; + if ( input[2] == '\0' ) { + return NULL; + } + return g_strdup ( &input[2] ); + } + } + } + return g_strdup ( input ); +} + #include "mode-private.h" Mode combi_mode = { @@ -259,6 +258,7 @@ Mode combi_mode = ._token_match = combi_mode_match, ._get_completion = combi_get_completion, ._get_display_value = combi_mgrv, + ._preprocess_input = combi_preprocess_input, .private_data = NULL, .free = NULL }; diff --git a/source/dialogs/dmenu.c b/source/dialogs/dmenu.c index 4d4cdbbc..c7b016aa 100644 --- a/source/dialogs/dmenu.c +++ b/source/dialogs/dmenu.c @@ -350,6 +350,7 @@ Mode dmenu_mode = ._token_match = dmenu_token_match, ._get_display_value = get_display_data, ._get_completion = NULL, + ._preprocess_input = NULL, .private_data = NULL, .free = NULL }; @@ -509,7 +510,7 @@ int dmenu_switcher_dialog ( void ) char *select = NULL; find_arg_str ( "-select", &select ); if ( select != NULL ) { - GRegex **tokens = tokenize ( select, config.case_sensitive ); + GRegex **tokens = tokenize ( select, config.case_sensitive ); unsigned int i = 0; for ( i = 0; i < cmd_list_length; i++ ) { if ( token_match ( tokens, cmd_list[i] ) ) { @@ -520,7 +521,7 @@ int dmenu_switcher_dialog ( void ) tokenize_free ( tokens ); } if ( find_arg ( "-dump" ) >= 0 ) { - GRegex **tokens = tokenize ( config.filter ? config.filter : "", config.case_sensitive ); + GRegex **tokens = tokenize ( config.filter ? config.filter : "", config.case_sensitive ); unsigned int i = 0; for ( i = 0; i < cmd_list_length; i++ ) { if ( token_match ( tokens, cmd_list[i] ) ) { diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c index 39fee13f..fcab4f0e 100644 --- a/source/dialogs/drun.c +++ b/source/dialogs/drun.c @@ -378,24 +378,24 @@ static char *drun_get_completion ( const Mode *sw, unsigned int index ) } } -static int drun_token_match ( const Mode *data, GRegex **tokens, unsigned int index) +static int drun_token_match ( const Mode *data, GRegex **tokens, unsigned int index ) { DRunModePrivateData *rmpd = (DRunModePrivateData *) mode_get_private_data ( data ); int match = 1; if ( tokens ) { for ( int j = 0; match && tokens != NULL && tokens[j] != NULL; j++ ) { - int test = 0; + int test = 0; GRegex *ftokens[2] = { tokens[j], NULL }; if ( !test && rmpd->entry_list[index].name && token_match ( ftokens, rmpd->entry_list[index].name ) ) { test = 1; } if ( !test && rmpd->entry_list[index].generic_name && - token_match ( ftokens, rmpd->entry_list[index].generic_name) ) { + token_match ( ftokens, rmpd->entry_list[index].generic_name ) ) { test = 1; } - if ( !test && token_match ( ftokens, rmpd->entry_list[index].exec) ) { + if ( !test && token_match ( ftokens, rmpd->entry_list[index].exec ) ) { test = 1; } if ( test == 0 ) { @@ -423,6 +423,7 @@ Mode drun_mode = ._token_match = drun_token_match, ._get_completion = drun_get_completion, ._get_display_value = _get_display_value, + ._preprocess_input = NULL, .private_data = NULL, .free = NULL }; diff --git a/source/dialogs/run.c b/source/dialogs/run.c index 51db25d9..523a0b4e 100644 --- a/source/dialogs/run.c +++ b/source/dialogs/run.c @@ -421,7 +421,7 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_ static int run_token_match ( const Mode *sw, GRegex **tokens, unsigned int index ) { const RunModePrivateData *rmpd = (const RunModePrivateData *) sw->private_data; - return token_match ( tokens, rmpd->cmd_list[index]); + return token_match ( tokens, rmpd->cmd_list[index] ); } #include "mode-private.h" @@ -436,6 +436,7 @@ Mode run_mode = ._token_match = run_token_match, ._get_display_value = _get_display_value, ._get_completion = NULL, + ._preprocess_input = NULL, .private_data = NULL, .free = NULL }; diff --git a/source/dialogs/script.c b/source/dialogs/script.c index 3abb2aba..bac6e1b8 100644 --- a/source/dialogs/script.c +++ b/source/dialogs/script.c @@ -200,6 +200,7 @@ Mode *script_switcher_parse_setup ( const char *str ) sw->_destroy = script_mode_destroy; sw->_token_match = script_token_match; sw->_get_completion = NULL, + sw->_preprocess_input = NULL, sw->_get_display_value = _get_display_value; return sw; diff --git a/source/dialogs/ssh.c b/source/dialogs/ssh.c index 3bf38f8e..331e5431 100644 --- a/source/dialogs/ssh.c +++ b/source/dialogs/ssh.c @@ -498,6 +498,7 @@ Mode ssh_mode = ._token_match = ssh_token_match, ._get_display_value = _get_display_value, ._get_completion = NULL, + ._preprocess_input = NULL, .private_data = NULL, .free = NULL }; diff --git a/source/dialogs/window.c b/source/dialogs/window.c index a2918bb7..56ff8d01 100644 --- a/source/dialogs/window.c +++ b/source/dialogs/window.c @@ -338,19 +338,19 @@ static int window_match ( const Mode *sw, GRegex **tokens, unsigned int index ) // e.g. when searching 'title element' and 'class element' GRegex *ftokens[2] = { tokens[j], NULL }; if ( !test && c->title != NULL && c->title[0] != '\0' ) { - test = token_match ( ftokens, c->title); + test = token_match ( ftokens, c->title ); } if ( !test && c->class != NULL && c->class[0] != '\0' ) { - test = token_match ( ftokens, c->class); + test = token_match ( ftokens, c->class ); } if ( !test && c->role != NULL && c->role[0] != '\0' ) { - test = token_match ( ftokens, c->role); + test = token_match ( ftokens, c->role ); } if ( !test && c->name != NULL && c->name[0] != '\0' ) { - test = token_match ( ftokens, c->name); + test = token_match ( ftokens, c->name ); } if ( test == 0 ) { @@ -653,7 +653,6 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, in return get_entry ? g_strdup ( rmpd->cmd_list[selected_line] ) : NULL; } - #include "mode-private.h" Mode window_mode = { @@ -666,6 +665,7 @@ Mode window_mode = ._token_match = window_match, ._get_display_value = _get_display_value, ._get_completion = NULL, + ._preprocess_input = NULL, .private_data = NULL, .free = NULL }; @@ -680,6 +680,7 @@ Mode window_mode_cd = ._token_match = window_match, ._get_display_value = _get_display_value, ._get_completion = NULL, + ._preprocess_input = NULL, .private_data = NULL, .free = NULL }; diff --git a/source/helper.c b/source/helper.c index 1897516f..88fed23b 100644 --- a/source/helper.c +++ b/source/helper.c @@ -196,11 +196,11 @@ static GRegex * create_regex ( const char *input, int case_sensitive ) } GRegex **tokenize ( const char *input, int case_sensitive ) { - if ( input == NULL || strlen(input) == 0 ) { + if ( input == NULL || strlen ( input ) == 0 ) { return NULL; } - char *saveptr = NULL, *token; + char *saveptr = NULL, *token; GRegex **retv = NULL; if ( !config.tokenize ) { retv = g_malloc0 ( sizeof ( GRegex* ) * 2 ); @@ -219,7 +219,7 @@ GRegex **tokenize ( const char *input, int case_sensitive ) const char * const sep = " "; for ( token = strtok_r ( str, sep, &saveptr ); token != NULL; token = strtok_r ( NULL, sep, &saveptr ) ) { retv = g_realloc ( retv, sizeof ( GRegex* ) * ( num_tokens + 2 ) ); - retv[num_tokens] = (GRegex*) create_regex ( token, case_sensitive ); + retv[num_tokens] = (GRegex *) create_regex ( token, case_sensitive ); retv[num_tokens + 1] = NULL; num_tokens++; } @@ -335,7 +335,6 @@ int find_arg_char ( const char * const key, char *val ) return FALSE; } - PangoAttrList *token_match_get_pango_attr ( GRegex **tokens, const char *input, PangoAttrList *retv ) { // Do a tokenized match. @@ -346,10 +345,12 @@ PangoAttrList *token_match_get_pango_attr ( GRegex **tokens, const char *input, while ( g_match_info_matches ( gmi ) ) { int start, end; g_match_info_fetch_pos ( gmi, 0, &start, &end ); - PangoAttribute *pa = pango_attr_underline_new ( PANGO_UNDERLINE_SINGLE ); - pa->start_index = start; - pa->end_index = end; + PangoAttribute *pa = pango_attr_underline_new ( PANGO_UNDERLINE_SINGLE ); + PangoAttribute *pa2 = pango_attr_weight_new ( PANGO_WEIGHT_BOLD ); + pa2->start_index = pa->start_index = start; + pa2->end_index = pa->end_index = end; pango_attr_list_insert ( retv, pa ); + pango_attr_list_insert ( retv, pa2 ); g_match_info_next ( gmi, NULL ); } g_match_info_free ( gmi ); @@ -358,7 +359,7 @@ PangoAttrList *token_match_get_pango_attr ( GRegex **tokens, const char *input, return retv; } -int token_match ( GRegex **tokens, const char *input) +int token_match ( GRegex **tokens, const char *input ) { int match = 1; // Do a tokenized match. diff --git a/source/mode.c b/source/mode.c index 4233f100..48cf9477 100644 --- a/source/mode.c +++ b/source/mode.c @@ -116,4 +116,12 @@ void mode_set_config ( Mode *mode ) snprintf ( mode->cfg_name_key, 128, "display-%s", mode->name ); config_parser_add_option ( xrm_String, mode->cfg_name_key, (void * *) &( mode->display_name ), "The display name of this browser" ); } + +char * mode_preprocess_input ( Mode *mode, const char *input ) +{ + if ( mode->_preprocess_input ) { + return mode->_preprocess_input ( mode, input ); + } + return g_strdup ( input ); +} /*@}*/ diff --git a/source/textbox.c b/source/textbox.c index a5f24bed..425dbf44 100644 --- a/source/textbox.c +++ b/source/textbox.c @@ -607,7 +607,7 @@ gboolean textbox_append_char ( textbox *tb, char *pad, int pad_len ) } // Filter When alt/ctrl is pressed do not accept the character. - if ( !g_unichar_iscntrl(g_utf8_get_char(pad))){ + if ( !g_unichar_iscntrl ( g_utf8_get_char ( pad ) ) ) { tb->blink = 2; textbox_insert ( tb, tb->cursor, pad, pad_len ); textbox_cursor ( tb, tb->cursor + pad_len ); diff --git a/source/view.c b/source/view.c index 8473d859..6a565aab 100644 --- a/source/view.c +++ b/source/view.c @@ -464,7 +464,7 @@ static RofiViewState * __rofi_view_state_create ( void ) typedef struct _thread_state { RofiViewState *state; - GRegex **tokens; + GRegex **tokens; unsigned int start; unsigned int stop; unsigned int count; @@ -500,7 +500,9 @@ static void filter_elements ( thread_state *t, G_GNUC_UNUSED gpointer user_data if ( config.levenshtein_sort ) { // This is inefficient, need to fix it. char * str = mode_get_completion ( t->state->sw, i ); - t->state->distance[i] = levenshtein ( t->state->text->text, str ); + char * input = mode_preprocess_input ( t->state->sw, t->state->text->text ); + t->state->distance[i] = levenshtein ( input, str ); + g_free(input); g_free ( str ); } t->count++; @@ -925,7 +927,9 @@ static void rofi_view_draw ( RofiViewState *state, cairo_t *d ) int x_offset = state->border; if ( state->rchanged ) { - GRegex **tokens = tokenize ( state->text->text, config.case_sensitive ); + char *input = mode_preprocess_input ( state->sw, state->text->text ); + GRegex **tokens = tokenize ( input, config.case_sensitive ); + g_free(input); // Move, resize visible boxes and show them. for ( i = 0; i < max_elements && ( i + offset ) < state->filtered_lines; i++ ) { unsigned int ex = ( ( i ) / state->max_rows ) * ( element_width + config.line_margin ); @@ -1248,7 +1252,9 @@ static void rofi_view_refilter ( RofiViewState *state ) TICK_N ( "Filter start" ); if ( strlen ( state->text->text ) > 0 ) { unsigned int j = 0; - GRegex **tokens = tokenize ( state->text->text, config.case_sensitive ); + gchar *input = mode_preprocess_input ( state->sw, state->text->text ); + GRegex **tokens = tokenize ( input, config.case_sensitive ); + g_free ( input ); /** * On long lists it can be beneficial to parallelize. * If number of threads is 1, no thread is spawn. @@ -1632,7 +1638,7 @@ RofiViewState *rofi_view_create ( Mode *sw, state->finalize = finalize; // Request the lines to show. - state->num_lines = mode_get_num_entries ( sw ); + state->num_lines = mode_get_num_entries ( sw ); TICK_N ( "Startup notification" );