mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
[Helper] Add -normalize-match option.
Decomposes string and remove accent characters before matching. This makes o match ö, é match e and more. It is not a perfect implementation but works. Currently disables the match highlighting. Fixes: #1119
This commit is contained in:
parent
96c7ab0fff
commit
b4bbce4af5
6 changed files with 70 additions and 3 deletions
|
@ -170,5 +170,8 @@ Settings config = {
|
||||||
.drun_reload_desktop_cache = FALSE,
|
.drun_reload_desktop_cache = FALSE,
|
||||||
|
|
||||||
/** Benchmarks */
|
/** Benchmarks */
|
||||||
.benchmark_ui = FALSE
|
.benchmark_ui = FALSE,
|
||||||
|
|
||||||
|
/** normalize match */
|
||||||
|
.normalize_match = FALSE
|
||||||
};
|
};
|
||||||
|
|
|
@ -372,6 +372,14 @@ Default: *true*
|
||||||
.fi
|
.fi
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\fC\-normalize\-match\fR
|
||||||
|
|
||||||
|
.PP
|
||||||
|
Normalize the string before matching, so o will match ö, and é matches e.
|
||||||
|
This is not a perfect implementation, but works.
|
||||||
|
For now it disabled highlighting of the matched part.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\fC\-no\-lazy\-grab\fR
|
\fB\fC\-no\-lazy\-grab\fR
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,12 @@ Show the indicator that shows what part of the string is matched.
|
||||||
|
|
||||||
Default: *true*
|
Default: *true*
|
||||||
|
|
||||||
|
`-normalize-match`
|
||||||
|
|
||||||
|
Normalize the string before matching, so o will match ö, and é matches e.
|
||||||
|
This is not a perfect implementation, but works.
|
||||||
|
For now it disabled highlighting of the matched part.
|
||||||
|
|
||||||
`-no-lazy-grab`
|
`-no-lazy-grab`
|
||||||
|
|
||||||
Disables lazy grab, this forces the keyboard being grabbed before gui is shown.
|
Disables lazy grab, this forces the keyboard being grabbed before gui is shown.
|
||||||
|
|
|
@ -203,6 +203,8 @@ typedef struct
|
||||||
|
|
||||||
/** Benchmark */
|
/** Benchmark */
|
||||||
gboolean benchmark_ui;
|
gboolean benchmark_ui;
|
||||||
|
|
||||||
|
gboolean normalize_match;
|
||||||
} Settings;
|
} Settings;
|
||||||
/** Global Settings structure. */
|
/** Global Settings structure. */
|
||||||
extern Settings config;
|
extern Settings config;
|
||||||
|
|
|
@ -180,10 +180,43 @@ static gchar *fuzzy_to_regex ( const char * input )
|
||||||
return retv;
|
return retv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *utf8_helper_simplify_string ( const char *s)
|
||||||
|
{
|
||||||
|
gunichar buf2[G_UNICHAR_MAX_DECOMPOSITION_LENGTH] = {0,};
|
||||||
|
char buf[6] = {0,};
|
||||||
|
// Compose the string in maximally composed form.
|
||||||
|
char * str = g_malloc0((g_utf8_strlen(s,0)*6+2));
|
||||||
|
char *striter = str;
|
||||||
|
for ( const char *iter = s; iter && *iter; iter = g_utf8_next_char ( iter )) {
|
||||||
|
gunichar uc = g_utf8_get_char ( iter );
|
||||||
|
int l = 0;
|
||||||
|
gsize dl = g_unichar_fully_decompose ( uc, FALSE, buf2, G_UNICHAR_MAX_DECOMPOSITION_LENGTH) ;
|
||||||
|
if ( dl ) {
|
||||||
|
l = g_unichar_to_utf8 ( buf2[0], buf);
|
||||||
|
} else {
|
||||||
|
l = g_unichar_to_utf8 ( uc, buf);
|
||||||
|
}
|
||||||
|
memcpy(striter, buf, l);
|
||||||
|
striter+=l;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
// Macro for quickly generating regex for matching.
|
// Macro for quickly generating regex for matching.
|
||||||
static inline GRegex * R ( const char *s, int case_sensitive )
|
static inline GRegex * R ( const char *s, int case_sensitive )
|
||||||
{
|
{
|
||||||
|
if ( config.normalize_match ) {
|
||||||
|
char *str = utf8_helper_simplify_string ( s );
|
||||||
|
|
||||||
|
GRegex *r = g_regex_new ( str, G_REGEX_OPTIMIZE | ( ( case_sensitive ) ? 0 : G_REGEX_CASELESS ), 0, NULL );
|
||||||
|
|
||||||
|
g_free ( str );
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
return g_regex_new ( s, G_REGEX_OPTIMIZE | ( ( case_sensitive ) ? 0 : G_REGEX_CASELESS ), 0, NULL );
|
return g_regex_new ( s, G_REGEX_OPTIMIZE | ( ( case_sensitive ) ? 0 : G_REGEX_CASELESS ), 0, NULL );
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static rofi_int_matcher * create_regex ( const char *input, int case_sensitive )
|
static rofi_int_matcher * create_regex ( const char *input, int case_sensitive )
|
||||||
|
@ -380,6 +413,10 @@ int find_arg_char ( const char * const key, char *val )
|
||||||
|
|
||||||
PangoAttrList *helper_token_match_get_pango_attr ( RofiHighlightColorStyle th, rofi_int_matcher**tokens, const char *input, PangoAttrList *retv )
|
PangoAttrList *helper_token_match_get_pango_attr ( RofiHighlightColorStyle th, rofi_int_matcher**tokens, const char *input, PangoAttrList *retv )
|
||||||
{
|
{
|
||||||
|
// Disable highlighting for normalize match, not supported atm.
|
||||||
|
if ( config.normalize_match ) {
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
// Do a tokenized match.
|
// Do a tokenized match.
|
||||||
if ( tokens ) {
|
if ( tokens ) {
|
||||||
for ( int j = 0; tokens[j]; j++ ) {
|
for ( int j = 0; tokens[j]; j++ ) {
|
||||||
|
@ -453,11 +490,20 @@ int helper_token_match ( rofi_int_matcher* const *tokens, const char *input )
|
||||||
int match = TRUE;
|
int match = TRUE;
|
||||||
// Do a tokenized match.
|
// Do a tokenized match.
|
||||||
if ( tokens ) {
|
if ( tokens ) {
|
||||||
|
if ( config.normalize_match ) {
|
||||||
|
char *r = utf8_helper_simplify_string(input);
|
||||||
|
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||||
|
match = g_regex_match ( tokens[j]->regex, r, 0, NULL );
|
||||||
|
match ^= tokens[j]->invert;
|
||||||
|
}
|
||||||
|
g_free(r);
|
||||||
|
} else {
|
||||||
for ( int j = 0; match && tokens[j]; j++ ) {
|
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||||
match = g_regex_match ( tokens[j]->regex, input, 0, NULL );
|
match = g_regex_match ( tokens[j]->regex, input, 0, NULL );
|
||||||
match ^= tokens[j]->invert;
|
match ^= tokens[j]->invert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,6 +231,8 @@ static XrmOption xrmOptions[] = {
|
||||||
"DRUN: build and use a cache with desktop file content.", CONFIG_DEFAULT },
|
"DRUN: build and use a cache with desktop file content.", CONFIG_DEFAULT },
|
||||||
{ xrm_Boolean, "drun-reload-desktop-cache", { .snum = &config.drun_reload_desktop_cache }, NULL,
|
{ xrm_Boolean, "drun-reload-desktop-cache", { .snum = &config.drun_reload_desktop_cache }, NULL,
|
||||||
"DRUN: If enabled, reload the cache with desktop file content.", CONFIG_DEFAULT },
|
"DRUN: If enabled, reload the cache with desktop file content.", CONFIG_DEFAULT },
|
||||||
|
{ xrm_Boolean, "normalize-match", { .snum = &config.normalize_match }, NULL,
|
||||||
|
"Normalize string when matching (implies -no-show-match).", CONFIG_DEFAULT },
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Dynamic array of extra options */
|
/** Dynamic array of extra options */
|
||||||
|
|
Loading…
Reference in a new issue