Fix combi mode 'bang' behaviour, improve levenshtein with combi

This commit is contained in:
Dave Davenport 2016-05-26 08:39:33 +02:00
parent 7aff2ae243
commit 0e86050db8
14 changed files with 78 additions and 52 deletions

View File

@ -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.
*

View File

@ -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;

View File

@ -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

View File

@ -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
};

View File

@ -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] ) ) {

View File

@ -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
};

View File

@ -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
};

View File

@ -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;

View File

@ -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
};

View File

@ -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
};

View File

@ -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.

View File

@ -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 );
}
/*@}*/

View File

@ -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 );

View File

@ -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" );