mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-18 13:54:36 -05:00
Go Regex Go
This commit is contained in:
parent
2a20821ddd
commit
8091558ed8
6 changed files with 74 additions and 168 deletions
|
@ -67,7 +67,7 @@ Settings config = {
|
|||
/** Command executed when running application in terminal */
|
||||
.run_shell_command = "{terminal} -e {cmd}",
|
||||
/** Command executed on accep-entry-custom for window modus */
|
||||
.window_command = "xkill -id {window}",
|
||||
.window_command = "xkill -id {window}",
|
||||
/**
|
||||
* Location of the window.
|
||||
* Enumeration indicating location or gravity of window.
|
||||
|
|
|
@ -24,18 +24,6 @@
|
|||
*/
|
||||
int helper_parse_setup ( char * string, char ***output, int *length, ... );
|
||||
|
||||
/**
|
||||
* @param token The string for which we want a collation key.
|
||||
* @param case_sensitive Whether case is significant.
|
||||
*
|
||||
* Get a collation key for @p token. @p token must be a null-terminated string.
|
||||
* This collation key can be used for matching the user input against the list
|
||||
* of commands, windows, or ssh commands.
|
||||
*
|
||||
* @returns A newly allocated string containing the collation key.
|
||||
*/
|
||||
char *token_collate_key ( const char *token, int case_sensitive );
|
||||
|
||||
/**
|
||||
* @param input The input string.
|
||||
* @param case_sensitive Whether case is significant.
|
||||
|
@ -172,6 +160,6 @@ unsigned int levenshtein ( const char *needle, const char *haystack );
|
|||
*/
|
||||
char * rofi_force_utf8 ( gchar *data );
|
||||
char * rofi_latin_to_utf8_strdup ( const char *input, gssize length );
|
||||
PangoAttrList *regex_token_match_get_pango_attr ( char **tokens, const char *input, PangoAttrList *retv );
|
||||
PangoAttrList *token_match_get_pango_attr ( char **tokens, const char *input, PangoAttrList *retv );
|
||||
/*@}*/
|
||||
#endif // ROFI_HELPER_H
|
||||
|
|
|
@ -39,15 +39,15 @@ 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_PASSWORD = 1 << 22,
|
||||
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_PASSWORD = 1 << 22,
|
||||
} TextboxFlags;
|
||||
|
||||
typedef enum
|
||||
|
|
|
@ -534,7 +534,7 @@ static inline int act_on_window ( xcb_window_t window )
|
|||
int argc = 0;
|
||||
char window_str[100]; /* We are probably safe here */
|
||||
|
||||
g_snprintf(window_str, sizeof window_str, "%d", window);
|
||||
g_snprintf ( window_str, sizeof window_str, "%d", window );
|
||||
|
||||
helper_parse_setup ( config.window_command, &args, &argc, "{window}", window_str, NULL );
|
||||
|
||||
|
|
199
source/helper.c
199
source/helper.c
|
@ -136,70 +136,75 @@ int helper_parse_setup ( char * string, char ***output, int *length, ... )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
char *token_collate_key ( const char *token, int case_sensitive )
|
||||
{
|
||||
char *tmp, *compk;
|
||||
|
||||
if ( case_sensitive ) {
|
||||
tmp = g_strdup ( token );
|
||||
}
|
||||
else {
|
||||
tmp = g_utf8_casefold ( token, -1 );
|
||||
}
|
||||
|
||||
compk = g_utf8_normalize ( tmp, -1, G_NORMALIZE_ALL );
|
||||
g_free ( tmp );
|
||||
|
||||
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] );
|
||||
for ( size_t i = 0; tokens && tokens[i]; i++ ) {
|
||||
g_regex_unref ( (GRegex *) tokens[i] );
|
||||
}
|
||||
g_free ( tokens );
|
||||
}
|
||||
|
||||
static gchar *glob_to_regex ( const char *input )
|
||||
{
|
||||
gchar *r = g_regex_escape_string ( input, -1 );
|
||||
size_t str_l = strlen ( r );
|
||||
for ( size_t i = 0; i < str_l; i++ ) {
|
||||
if ( r[i] == '\\' ) {
|
||||
if ( r[i + 1] == '*' ) {
|
||||
r[i] = '.';
|
||||
}
|
||||
else if ( r[i + 1] == '?' ) {
|
||||
r[i + 1] = 'S';
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_free ( tokens );
|
||||
}
|
||||
return r;
|
||||
}
|
||||
static GRegex * create_regex ( const char *input, int case_sensitive )
|
||||
{
|
||||
#define R( s ) g_regex_new ( s, G_REGEX_OPTIMIZE | ( ( case_sensitive ) ? 0 : G_REGEX_CASELESS ), G_REGEX_MATCH_PARTIAL, NULL )
|
||||
GRegex *retv = NULL;
|
||||
if ( config.glob ) {
|
||||
gchar *r = glob_to_regex ( input );
|
||||
retv = R ( r );
|
||||
g_free ( r );
|
||||
}
|
||||
else if ( config.regex ) {
|
||||
for ( size_t i = 0; tokens && tokens[i]; i++ ) {
|
||||
g_regex_unref ( (GRegex *) tokens[i] );
|
||||
retv = R ( input );
|
||||
if ( retv == NULL ) {
|
||||
gchar *r = g_regex_escape_string ( input, -1 );
|
||||
retv = R ( r );
|
||||
g_free ( r );
|
||||
}
|
||||
g_free ( tokens );
|
||||
}
|
||||
else {
|
||||
g_strfreev ( tokens );
|
||||
else if ( config.fuzzy ) {
|
||||
gchar *r = g_regex_escape_string ( input, -1 );
|
||||
// TODO either strip fuzzy, or fix this pattern.
|
||||
gchar *str = g_strdup_printf ( "[%s]+", r );
|
||||
retv = R ( str );
|
||||
g_free ( r );
|
||||
g_free ( str );
|
||||
}
|
||||
else{
|
||||
// TODO; regex should be default?
|
||||
gchar *r = g_regex_escape_string ( input, -1 );
|
||||
retv = R ( r );
|
||||
g_free ( r );
|
||||
}
|
||||
return retv;
|
||||
}
|
||||
char **tokenize ( const char *input, int case_sensitive )
|
||||
{
|
||||
if ( input == NULL ) {
|
||||
if ( input == NULL || strlen(input) == 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *saveptr = NULL, *token;
|
||||
char **retv = NULL;
|
||||
if ( !config.tokenize ) {
|
||||
retv = g_malloc0 ( sizeof ( char* ) * 2 );
|
||||
if ( config.glob ) {
|
||||
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 ) {
|
||||
gchar *r = g_regex_escape_string ( input, -1 );
|
||||
reg = g_regex_new ( r, ( case_sensitive ) ? 0 : G_REGEX_CASELESS, G_REGEX_MATCH_PARTIAL, NULL );
|
||||
g_free ( r );
|
||||
g_free ( retv );
|
||||
}
|
||||
retv[0] = (char *) reg;
|
||||
}
|
||||
else{
|
||||
retv[0] = token_collate_key ( input, case_sensitive );
|
||||
}
|
||||
retv = g_malloc0 ( sizeof ( char* ) * 2 );
|
||||
retv[0] = (char *) create_regex ( input, case_sensitive );
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
@ -213,25 +218,8 @@ char **tokenize ( const char *input, int case_sensitive )
|
|||
// strtok should still be valid for utf8.
|
||||
const char * const sep = " ";
|
||||
for ( token = strtok_r ( str, sep, &saveptr ); token != NULL; token = strtok_r ( NULL, sep, &saveptr ) ) {
|
||||
retv = g_realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) );
|
||||
if ( config.glob ) {
|
||||
char *str = g_strdup_printf ( "*%s*", token );
|
||||
char *t = token_collate_key ( str, case_sensitive );
|
||||
retv[num_tokens] = (char *) g_pattern_spec_new ( t );
|
||||
g_free ( t );
|
||||
g_free ( str );
|
||||
}
|
||||
else if ( config.regex ) {
|
||||
retv[num_tokens] = (char *) g_regex_new ( token, case_sensitive ? 0 : G_REGEX_CASELESS, 0, NULL );
|
||||
if ( retv[num_tokens] == NULL ) {
|
||||
gchar *r = g_regex_escape_string ( input, -1 );
|
||||
retv[num_tokens] = (char *) g_regex_new ( r, ( case_sensitive ) ? 0 : G_REGEX_CASELESS, G_REGEX_MATCH_PARTIAL, NULL );
|
||||
g_free ( r );
|
||||
}
|
||||
}
|
||||
else {
|
||||
retv[num_tokens] = token_collate_key ( token, case_sensitive );
|
||||
}
|
||||
retv = g_realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) );
|
||||
retv[num_tokens] = (char *) create_regex ( token, case_sensitive );
|
||||
retv[num_tokens + 1] = NULL;
|
||||
num_tokens++;
|
||||
}
|
||||
|
@ -347,56 +335,6 @@ int find_arg_char ( const char * const key, char *val )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared 'token_match' function.
|
||||
* Matches tokenized.
|
||||
*/
|
||||
static int fuzzy_token_match ( char **tokens, const char *input, __attribute__( ( unused ) ) int not_ascii, int case_sensitive )
|
||||
{
|
||||
int match = 1;
|
||||
|
||||
// Do a tokenized match.
|
||||
|
||||
if ( tokens ) {
|
||||
char *compk = not_ascii ? token_collate_key ( input, case_sensitive ) : (char *) g_ascii_strdown ( input, -1 );
|
||||
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||
char *t = compk;
|
||||
char *token = tokens[j];
|
||||
|
||||
while ( *t && *token ) {
|
||||
if ( ( g_utf8_get_char ( t ) == g_utf8_get_char ( token ) ) ) {
|
||||
token = g_utf8_next_char ( token );
|
||||
}
|
||||
t = g_utf8_next_char ( t );
|
||||
}
|
||||
match = !( *token );
|
||||
}
|
||||
g_free ( compk );
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
static int normal_token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive )
|
||||
{
|
||||
int match = 1;
|
||||
|
||||
// Do a tokenized match.
|
||||
|
||||
if ( tokens ) {
|
||||
char *compk = not_ascii ? token_collate_key ( input, case_sensitive ) : (char *) input;
|
||||
char *( *comparison )( const char *, const char * );
|
||||
comparison = ( case_sensitive || not_ascii ) ? strstr : strcasestr;
|
||||
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||
match = ( comparison ( compk, tokens[j] ) != NULL );
|
||||
}
|
||||
if ( not_ascii ) {
|
||||
g_free ( compk );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -410,9 +348,8 @@ static int regex_token_match ( char **tokens, const char *input, G_GNUC_UNUSED i
|
|||
return match;
|
||||
}
|
||||
|
||||
PangoAttrList *regex_token_match_get_pango_attr ( char **tokens, const char *input, PangoAttrList *retv )
|
||||
static PangoAttrList *regex_token_match_get_pango_attr ( char **tokens, const char *input, PangoAttrList *retv )
|
||||
{
|
||||
if ( config.regex == FALSE ) return retv;
|
||||
// Do a tokenized match.
|
||||
if ( tokens ) {
|
||||
for ( int j = 0; tokens[j]; j++ ) {
|
||||
|
@ -432,34 +369,14 @@ PangoAttrList *regex_token_match_get_pango_attr ( char **tokens, const char *inp
|
|||
}
|
||||
return retv;
|
||||
}
|
||||
|
||||
static int glob_token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive )
|
||||
PangoAttrList *token_match_get_pango_attr ( char **tokens, const char *input, PangoAttrList *retv )
|
||||
{
|
||||
int match = 1;
|
||||
char *compk = not_ascii ? token_collate_key ( input, case_sensitive ) : g_ascii_strdown ( input, -1 );
|
||||
|
||||
// Do a tokenized match.
|
||||
if ( tokens ) {
|
||||
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||
match = g_pattern_match_string ( (GPatternSpec *) tokens[j], compk );
|
||||
}
|
||||
}
|
||||
g_free ( compk );
|
||||
return match;
|
||||
return regex_token_match_get_pango_attr ( tokens, input, retv );
|
||||
}
|
||||
|
||||
int token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
return normal_token_match ( tokens, input, not_ascii, case_sensitive );
|
||||
return regex_token_match ( tokens, input, not_ascii, case_sensitive );
|
||||
}
|
||||
|
||||
int execute_generator ( const char * cmd )
|
||||
|
|
|
@ -949,10 +949,11 @@ static void rofi_view_draw ( RofiViewState *state, cairo_t *d )
|
|||
textbox_text ( state->boxes[i], text );
|
||||
|
||||
PangoAttrList *list = textbox_get_pango_attributes ( state->boxes[i] );
|
||||
if ( list != NULL )
|
||||
if ( list != NULL ) {
|
||||
pango_attr_list_ref ( list );
|
||||
else list = pango_attr_list_new ();
|
||||
regex_token_match_get_pango_attr ( tokens, textbox_get_visible_text ( state->boxes[i] ), list );
|
||||
}
|
||||
else{ list = pango_attr_list_new (); }
|
||||
token_match_get_pango_attr ( tokens, textbox_get_visible_text ( state->boxes[i] ), list );
|
||||
textbox_set_pango_attributes ( state->boxes[i], list );
|
||||
pango_attr_list_unref ( list );
|
||||
g_free ( text );
|
||||
|
|
Loading…
Reference in a new issue