mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
Fix combi mode 'bang' behaviour, improve levenshtein with combi
This commit is contained in:
parent
7aff2ae243
commit
0e86050db8
14 changed files with 78 additions and 52 deletions
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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] ) ) {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
/*@}*/
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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" );
|
||||
|
||||
|
|
Loading…
Reference in a new issue