From aeaceb154a773247a4709a66c27df34669f6c1ad Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Tue, 17 Nov 2015 16:10:14 +0100 Subject: [PATCH] Add experimental regex support --- config/config.def.c | 1 + include/helper.h | 1 + include/rofi.h | 1 + include/textbox.h | 16 +++++------ source/helper.c | 66 ++++++++++++++++++++++++++++++++++++++++----- source/rofi.c | 2 +- source/xrmoptions.c | 1 + 7 files changed, 73 insertions(+), 15 deletions(-) diff --git a/config/config.def.c b/config/config.def.c index 87a371e0..4b4139bd 100644 --- a/config/config.def.c +++ b/config/config.def.c @@ -134,6 +134,7 @@ Settings config = { .fuzzy = FALSE, .glob = FALSE, .tokenize = TRUE, + .regex = FALSE, /** Monitor */ .monitor = -1, /** set line margin */ diff --git a/include/helper.h b/include/helper.h index 01d42d4b..305e6d61 100644 --- a/include/helper.h +++ b/include/helper.h @@ -39,6 +39,7 @@ char *token_collate_key ( const char *token, int case_sensitive ); * @returns a newly allocated 2 dimensional array of strings. */ char **tokenize ( const char *input, int case_sensitive ); +void tokenize_free ( char ** tokens ); /** * @param key The key to search for diff --git a/include/rofi.h b/include/rofi.h index 4b3ae5ef..05883004 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -235,6 +235,7 @@ typedef struct _Settings unsigned int fuzzy; unsigned int glob; unsigned int tokenize; + unsigned int regex; /** Monitors */ int monitor; /** Line margin */ diff --git a/include/textbox.h b/include/textbox.h index 9b0c4090..fb03234e 100644 --- a/include/textbox.h +++ b/include/textbox.h @@ -33,14 +33,14 @@ typedef struct typedef enum { - TB_AUTOHEIGHT = 1 << 0, - TB_AUTOWIDTH = 1 << 1, - TB_LEFT = 1 << 16, - TB_RIGHT = 1 << 17, - TB_CENTER = 1 << 18, - TB_EDITABLE = 1 << 19, - TB_MARKUP = 1 << 20, - TB_WRAP = 1 << 21, + TB_AUTOHEIGHT = 1 << 0, + TB_AUTOWIDTH = 1 << 1, + TB_LEFT = 1 << 16, + TB_RIGHT = 1 << 17, + TB_CENTER = 1 << 18, + TB_EDITABLE = 1 << 19, + TB_MARKUP = 1 << 20, + TB_WRAP = 1 << 21, } TextboxFlags; typedef enum diff --git a/source/helper.c b/source/helper.c index 7e7c88d1..1553dd89 100644 --- a/source/helper.c +++ b/source/helper.c @@ -147,7 +147,24 @@ char *token_collate_key ( const char *token, int case_sensitive ) return compk; } - +void tokenize_free ( char ** tokens ) +{ + if ( config.glob ) { + for ( size_t i = 0; tokens && tokens[i]; i++ ) { + g_pattern_spec_free ( (GPatternSpec *) tokens[i] ); + } + g_free ( tokens ); + } + else if ( config.regex ) { + for ( size_t i = 0; tokens && tokens[i]; i++ ) { + g_regex_unref ( (GRegex *) tokens[i] ); + } + g_free ( tokens ); + } + else { + g_strfreev ( tokens ); + } +} char **tokenize ( const char *input, int case_sensitive ) { if ( input == NULL ) { @@ -159,9 +176,19 @@ char **tokenize ( const char *input, int case_sensitive ) 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 ); + token = g_strdup_printf ( "*%s*", input ); + char *str = token_collate_key ( token, case_sensitive ); + retv[0] = (char *) g_pattern_spec_new ( str ); g_free ( token ); token = NULL; + g_free ( str ); + } + else if ( config.regex ) { + GRegex *reg = g_regex_new ( input, ( case_sensitive ) ? 0 : G_REGEX_CASELESS, G_REGEX_MATCH_PARTIAL, NULL ); + if ( reg == NULL ) { + g_free ( retv ); + return NULL; + } + retv[0] = (char *) reg; } else{ retv[0] = token_collate_key ( input, case_sensitive ); @@ -180,9 +207,20 @@ char **tokenize ( const char *input, int case_sensitive ) for ( token = strtok_r ( str, " ", &saveptr ); token != NULL; token = strtok_r ( NULL, " ", &saveptr ) ) { 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 ); + char *t = token_collate_key ( token, case_sensitive ); + char *str = g_strdup_printf ( "*%s*", input ); + retv[num_tokens] = (char *) g_pattern_spec_new ( str ); g_free ( t ); + g_free ( str ); + } + else if ( config.regex ) { + GError *error = NULL; + retv[num_tokens] = (char *) g_regex_new ( token, case_sensitive ? 0 : G_REGEX_CASELESS, 0, &error ); + if ( retv[num_tokens] == NULL ) { + fprintf ( stderr, "Failed to parse: '%s'\n", error->message ); + g_error_free ( error ); + num_tokens--; + } } else { retv[num_tokens] = token_collate_key ( token, case_sensitive ); @@ -405,6 +443,19 @@ static int normal_token_match ( char **tokens, const char *input, int not_ascii, return match; } +static int regex_token_match ( char **tokens, const char *input, G_GNUC_UNUSED int not_ascii, G_GNUC_UNUSED int case_sensitive ) +{ + int match = 1; + + // Do a tokenized match. + if ( tokens ) { + for ( int j = 0; match && tokens[j]; j++ ) { + match = g_regex_match ( (GRegex *) tokens[j], input, G_REGEX_MATCH_PARTIAL, NULL ); + } + } + return match; +} + static int glob_token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive ) { int match = 1; @@ -413,7 +464,7 @@ static int glob_token_match ( char **tokens, const char *input, int not_ascii, i // Do a tokenized match. if ( tokens ) { for ( int j = 0; match && tokens[j]; j++ ) { - match = g_pattern_match_simple ( tokens[j], compk ); + match = g_pattern_match_string ( (GPatternSpec *) tokens[j], compk ); } } if ( not_ascii ) { @@ -429,6 +480,9 @@ int token_match ( char **tokens, const char *input, int not_ascii, int case_sens if ( config.glob ) { return glob_token_match ( tokens, input, not_ascii, case_sensitive ); } + else if ( config.regex ) { + return regex_token_match ( tokens, input, not_ascii, case_sensitive ); + } else if ( config.fuzzy ) { return fuzzy_token_match ( tokens, input, not_ascii, case_sensitive ); } diff --git a/source/rofi.c b/source/rofi.c index 12fdf59f..02a5dd25 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -822,7 +822,7 @@ static void menu_refilter ( MenuState *state ) // Cleanup + bookkeeping. state->filtered_lines = j; - g_strfreev ( tokens ); + tokenize_free ( tokens ); } else{ for ( unsigned int i = 0; i < state->num_lines; i++ ) { diff --git a/source/xrmoptions.c b/source/xrmoptions.c index b119d9ec..70779e27 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -125,6 +125,7 @@ static XrmOption xrmOptions[] = { { xrm_String, "combi-modi", { .str = &config.combi_modi }, NULL, "Set the modi to combine in combi mode" }, { xrm_Boolean, "fuzzy", { .num = &config.fuzzy }, NULL, "Do a more fuzzy matching" }, { xrm_Boolean, "glob", { .num = &config.glob }, NULL, "Use glob matching" }, + { xrm_Boolean, "regex", { .num = &config.regex }, NULL, "Use regex matching" }, { xrm_Boolean, "tokenize", { .num = &config.tokenize }, NULL, "Tokenize input string" }, { xrm_Number, "monitor", { .snum = &config.monitor }, NULL, "" }, /* Alias for dmenu compatibility. */