1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-18 13:54:36 -05:00

Combi mode: Bang mode prefixes with len>1 (#542)

* Combi mode: Bang mode prefixes with len>1

This is required to match on modes that share a prefix.
Let 'power' and 'pass' be such modes for the following explanation:
Previously, only the first character of after the bang was compared,
so '!p' would always be matched to the 'pass' mode and there was no
way to limit selection in combi mode to the 'power' mode.
Now we can use prefixes of arbitrary length following the bang
such as '!po' (matches 'power' mode), or '!pa' (matches 'pass' mode).
Prefixes of length 1 are unchanged compared to the previous
behaviour, i.e. '!p' will still match 'pass'.

* Combi-mode prefixes should be utf-8 aware
This commit is contained in:
Moritz Maxeiner 2017-01-26 19:46:46 +01:00 committed by Dave Davenport
parent 9941efa5f4
commit 6b9dc1d081
3 changed files with 65 additions and 17 deletions

View file

@ -221,4 +221,17 @@ PangoAttrList *token_match_get_pango_attr ( ThemeHighlight th, GRegex **tokens,
*/
int rofi_scorer_fuzzy_evaluate ( const char *pattern, glong plen, const char *str, glong slen );
/*@}*/
/**
* @param a UTF-8 string to compare
* @param b UTF-8 string to compare
* @param n Maximum number of characters to compare
*
* Compares the `G_NORMALIZE_ALL_COMPOSE` forms of the two strings.
*
* @returns less than, equal to, or greater than zero if the first `n` characters (not bytes) of `a`
* are found, respectively, to be less than, to match, or be greater than the first `n`
* characters (not bytes) of `b`.
*/
int utf8_strncmp ( const char *a, const char* b, size_t n );
#endif // ROFI_HELPER_H

View file

@ -29,6 +29,7 @@
#include <stdio.h>
#include <rofi.h>
#include "settings.h"
#include "helper.h"
#include <dialogs/dialogs.h>
@ -151,18 +152,23 @@ static void combi_mode_destroy ( Mode *sw )
static ModeMode combi_mode_result ( Mode *sw, int mretv, char **input, unsigned int selected_line )
{
CombiModePrivateData *pd = mode_get_private_data ( sw );
if ( *input[0] == '!' ) {
if ( input[0][0] == '!' ) {
int switcher = -1;
for ( unsigned i = 0; switcher == -1 && i < pd->num_switchers; i++ ) {
if ( ( *input )[1] == mode_get_name ( pd->switchers[i] )[0] ) {
switcher = i;
char *eob = strchrnul ( input[0], ' ' );
ssize_t bang_len = g_utf8_pointer_to_offset ( input[0], eob ) - 1;
if ( bang_len > 0 ) {
for ( unsigned i = 0; switcher == -1 && i < pd->num_switchers; i++ ) {
const char *mode_name = mode_get_name ( pd->switchers[i] );
size_t mode_name_len = g_utf8_strlen ( mode_name, -1 );
if ( (size_t) bang_len <= mode_name_len && utf8_strncmp ( &input[0][1], mode_name, bang_len ) == 0 ) {
switcher = i;
}
}
}
if ( switcher >= 0 ) {
char *n = strchr ( *input, ' ' );
// skip whitespace
if ( n != NULL ) {
n++;
if ( switcher >= 0 ) {
if ( eob[0] == ' ' ) {
char *n = eob+1;
return mode_result ( pd->switchers[switcher], mretv, &n,
selected_line - pd->starts[switcher] );
}
@ -223,7 +229,7 @@ static char * combi_get_completion ( const Mode *sw, unsigned int index )
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) {
char *comp = mode_get_completion ( pd->switchers[i], index - pd->starts[i] );
char *mcomp = g_strdup_printf ( "!%c %s", mode_get_name ( pd->switchers[i] )[0], comp );
char *mcomp = g_strdup_printf ( "!%s %s", mode_get_name ( pd->switchers[i] ), comp );
g_free ( comp );
return mcomp;
}
@ -237,14 +243,20 @@ 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;
if ( input != NULL && input[0] == '!' ) {
char *eob = strchrnul ( input, ' ' );
ssize_t bang_len = g_utf8_pointer_to_offset ( input, eob ) - 1;
if ( bang_len > 0 ) {
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
const char *mode_name = mode_get_name ( pd->switchers[i] );
size_t mode_name_len = g_utf8_strlen ( mode_name, -1 );
if ( (size_t) bang_len <= mode_name_len && utf8_strncmp ( &input[1], mode_name, bang_len ) == 0 ) {
pd->current = pd->switchers[i];
if ( eob[0] == '\0' || eob[1] == '\0' ) {
return NULL;
}
return g_strdup ( eob+1 );
}
return g_strdup ( &input[2] );
}
}
}

View file

@ -889,3 +889,26 @@ int rofi_scorer_fuzzy_evaluate ( const char *pattern, glong plen, const char *st
g_free ( dp );
return -lefts;
}
/**
* @param a UTF-8 string to compare
* @param b UTF-8 string to compare
* @param n Maximum number of characters to compare
*
* Compares the `G_NORMALIZE_ALL_COMPOSE` forms of the two strings.
*
* @returns less than, equal to, or greater than zero if the first `n` characters (not bytes) of `a`
* are found, respectively, to be less than, to match, or be greater than the first `n`
* characters (not bytes) of `b`.
*/
int utf8_strncmp ( const char* a, const char* b, size_t n )
{
char *na = g_utf8_normalize ( a, -1, G_NORMALIZE_ALL_COMPOSE );
char *nb = g_utf8_normalize ( b, -1, G_NORMALIZE_ALL_COMPOSE );
*g_utf8_offset_to_pointer ( na, n ) = '\0';
*g_utf8_offset_to_pointer ( nb, n ) = '\0';
int r = g_utf8_collate ( na, nb );
g_free ( na );
g_free ( nb );
return r;
}