1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2025-04-07 17:33:14 -04:00

Merge remote-tracking branch 'origin/highlight_match'

This commit is contained in:
Dave Davenport 2016-06-19 14:56:57 +02:00
commit 341f8322ed
28 changed files with 235 additions and 491 deletions

View file

@ -1,3 +1,6 @@
v1.unrelease
- Remove fuzzy option
v1.1.0
New Features
- Keys mode, showing keybindings.

View file

@ -317,8 +317,6 @@ test-x: $(bin_PROGRAMS) textbox_test
$(top_srcdir)/test/run_test.sh 215 $(top_srcdir)/test/run_regex_test.sh $(top_builddir)
echo "Test dmenu glob"
$(top_srcdir)/test/run_test.sh 216 $(top_srcdir)/test/run_glob_test.sh $(top_builddir)
echo "Test dmenu fuzzy"
$(top_srcdir)/test/run_test.sh 217 $(top_srcdir)/test/run_fuzzy_test.sh $(top_builddir)
echo "Test config dump"
$(top_srcdir)/test/run_test.sh 218 $(top_srcdir)/test/xr_config_test.sh $(top_builddir) $(top_srcdir)
echo "Test issue 333"

View file

@ -108,8 +108,6 @@ Settings config = {
.parse_known_hosts = TRUE,
/** Modi to combine into one view. */
.combi_modi = "window,run",
/** Fuzzy matching. */
.fuzzy = FALSE,
.glob = FALSE,
.tokenize = TRUE,
.regex = FALSE,

View file

@ -187,10 +187,6 @@ Start in case sensitive mode.
Cycle through the results list. Default is 'true'.
`-fuzzy`
Enable experimental fuzzy matching.
`-filter` *filter*
Filter the list by setting text in input bar to *filter*

View file

@ -274,12 +274,6 @@ Start in case sensitive mode\.
Cycle through the results list\. Default is \'true\'\.
.
.P
\fB\-fuzzy\fR
.
.P
Enable experimental fuzzy matching\.
.
.P
\fB\-filter\fR \fIfilter\fR
.
.P

View file

@ -64,8 +64,6 @@ rofi.parse-hosts: false
rofi.parse-known-hosts: true
! Set the modi to combine in combi mode
rofi.combi-modi: window,drun,run,ssh
! Do a more fuzzy matching
rofi.fuzzy: false
! Use glob matching
rofi.glob: false
! Use regex matching

View file

@ -2,6 +2,7 @@
#define ROFI_HELPER_H
#include "rofi.h"
#include <pango/pango.h>
/**
* @defgroup HELPERS Helpers
*/
@ -23,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.
@ -43,8 +32,8 @@ 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 );
GRegex **tokenize ( const char *input, int case_sensitive );
void tokenize_free ( GRegex ** tokens );
/**
* @param key The key to search for
@ -108,7 +97,7 @@ int find_arg ( const char * const key );
*
* @returns 1 when matches, 0 otherwise
*/
int token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive );
int token_match ( GRegex **tokens, const char *input );
/**
* @param cmd The command to execute.
*
@ -171,5 +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 *token_match_get_pango_attr ( GRegex **tokens, const char *input, PangoAttrList *retv );
/*@}*/
#endif // ROFI_HELPER_H

View file

@ -17,7 +17,7 @@ typedef char * ( *_mode_get_completion )( const Mode *sw, unsigned int selected_
*
* @returns 1 when it matches, 0 if not.
*/
typedef int ( *_mode_token_match )( const Mode *data, char **tokens, int not_ascii, int case_sensitive, unsigned int index );
typedef int ( *_mode_token_match )( const Mode *data, GRegex **tokens, unsigned int index );
typedef int ( *__mode_init )( Mode *sw );
@ -27,7 +27,7 @@ typedef void ( *__mode_destroy )( Mode *sw );
typedef ModeMode ( *_mode_result )( Mode *sw, int menu_retv, char **input, unsigned int selected_line );
typedef int ( *_mode_is_not_ascii )( const Mode *sw, unsigned int index );
typedef char* ( *_mode_preprocess_input )( Mode *sw, const char *input );
/**
* Structure defining a switcher.
@ -50,8 +50,6 @@ struct rofi_mode
__mode_destroy _destroy;
/** Get number of entries to display. (unfiltered). */
__mode_get_num_entries _get_num_entries;
/** Check if the element is ascii. */
_mode_is_not_ascii _is_not_ascii;
/** Process the result of the user selection. */
_mode_result _result;
/** Token match. */
@ -61,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;

View file

@ -96,16 +96,6 @@ char * mode_get_display_value ( const Mode *mode, unsigned int selected_line, in
*/
char * mode_get_completion ( const Mode *mode, unsigned int selected_line );
/**
* @param mode The mode to query
* @param selected_line The entry to query
*
* Check if the entry has non-ascii characters.
*
* @returns TRUE when selected line has non-ascii characters.
*/
int mode_is_not_ascii ( const Mode *mode, unsigned int selected_line );
/**
* @param mode The mode to query
* @param mretv The menu return value.
@ -121,15 +111,13 @@ ModeMode mode_result ( Mode *mode, int menu_retv, char **input, unsigned int sel
/**
* @param mode The mode to query
* @param tokens The set of tokens to match against
* @param not_ascii If the entry is pure-ascii
* @param case_sensitive If the entry should be matched case sensitive
* @param selected_line The index of the entry to match
*
* Match entry against the set of tokens.
*
* @returns TRUE if matches
*/
int mode_token_match ( const Mode *mode, char **tokens, int not_ascii, int case_sensitive, unsigned int selected_line );
int mode_token_match ( const Mode *mode, GRegex **tokens, unsigned int selected_line );
/**
* @param mode The mode to query
@ -166,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

View file

@ -106,8 +106,6 @@ typedef struct
unsigned int parse_known_hosts;
/** Combi Modes */
char *combi_modi;
/** Fuzzy match */
unsigned int fuzzy;
unsigned int glob;
unsigned int tokenize;
unsigned int regex;

View file

@ -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
@ -103,7 +103,15 @@ void textbox_text ( textbox *tb, const char *text );
void textbox_draw ( textbox *tb, cairo_t *draw );
int textbox_keybinding ( textbox *tb, KeyBindingAction action );
gboolean textbox_append ( textbox *tb, char *pad, int pad_len );
/**
* @param tb Handle to the textbox
* @param pad The text to insert
* @param pad_len the length of the text
*
* The text should be one insert from a keypress.. the first gunichar is validated to be (or not) control
* return TRUE if inserted
*/
gboolean textbox_append_char ( textbox *tb, char *pad, int pad_len );
/**
* @param tb Handle to the textbox
@ -225,6 +233,10 @@ void textbox_delete ( textbox *tb, int pos, int dlen );
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h );
int textbox_get_estimated_char_height ( void );
void textbox_set_pango_context ( PangoContext *p );
void textbox_set_pango_attributes ( textbox *tb, PangoAttrList *list );
PangoAttrList *textbox_get_pango_attributes ( textbox *tb );
const char *textbox_get_visible_text ( textbox *tb );
/*@}*/
#endif //ROFI_TEXTBOX_H

View file

@ -56,7 +56,6 @@ struct RofiViewState
// Return state
unsigned int selected_line;
MenuReturn retv;
int *lines_not_ascii;
int line_height;
unsigned int border;
workarea mon;

View file

@ -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 )
@ -175,37 +176,17 @@ static ModeMode combi_mode_result ( Mode *sw, int mretv, char **input, unsigned
}
return MODE_EXIT;
}
static int combi_mode_match ( const Mode *sw, char **tokens, int not_ascii,
int case_sensitive, unsigned int index )
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, not_ascii, case_sensitive,
index - pd->starts[i] );
}
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
if ( pd->current != NULL && pd->switchers[i] != pd->current ) {
continue;
}
if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) {
return mode_token_match ( pd->switchers[i], tokens, index - pd->starts[i] );
}
}
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] );
}
}
}
}
abort ();
return 0;
}
static char * combi_mgrv ( const Mode *sw, unsigned int selected_line, int *state, int get_entry )
@ -231,16 +212,6 @@ static char * combi_mgrv ( const Mode *sw, unsigned int selected_line, int *stat
return NULL;
}
static int combi_is_not_ascii ( const Mode *sw, unsigned int index )
{
CombiModePrivateData *pd = mode_get_private_data ( sw );
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) {
return mode_is_not_ascii ( pd->switchers[i], index - pd->starts[i] );
}
}
return FALSE;
}
static char * combi_get_completion ( const Mode *sw, unsigned int index )
{
CombiModePrivateData *pd = mode_get_private_data ( sw );
@ -257,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 =
{
@ -269,7 +258,7 @@ Mode combi_mode =
._token_match = combi_mode_match,
._get_completion = combi_get_completion,
._get_display_value = combi_mgrv,
._is_not_ascii = combi_is_not_ascii,
._preprocess_input = combi_preprocess_input,
.private_data = NULL,
.free = NULL
};

View file

@ -332,16 +332,10 @@ static int dmenu_mode_init ( Mode *sw )
return TRUE;
}
static int dmenu_token_match ( const Mode *sw, char **tokens, int not_ascii, int case_sensitive, unsigned int index )
static int dmenu_token_match ( const Mode *sw, GRegex **tokens, unsigned int index )
{
DmenuModePrivateData *rmpd = (DmenuModePrivateData *) mode_get_private_data ( sw );
return token_match ( tokens, rmpd->cmd_list[index], not_ascii, case_sensitive );
}
static int dmenu_is_not_ascii ( const Mode *sw, unsigned int index )
{
DmenuModePrivateData *rmpd = (DmenuModePrivateData *) mode_get_private_data ( sw );
return !g_str_is_ascii ( rmpd->cmd_list[index] );
return token_match ( tokens, rmpd->cmd_list[index] );
}
#include "mode-private.h"
@ -356,7 +350,7 @@ Mode dmenu_mode =
._token_match = dmenu_token_match,
._get_display_value = get_display_data,
._get_completion = NULL,
._is_not_ascii = dmenu_is_not_ascii,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
};
@ -516,25 +510,25 @@ int dmenu_switcher_dialog ( void )
char *select = NULL;
find_arg_str ( "-select", &select );
if ( select != NULL ) {
char **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], !g_str_is_ascii ( cmd_list[i] ), config.case_sensitive ) ) {
if ( token_match ( tokens, cmd_list[i] ) ) {
pd->selected_line = i;
break;
}
}
g_strfreev ( tokens );
tokenize_free ( tokens );
}
if ( find_arg ( "-dump" ) >= 0 ) {
char **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], !g_str_is_ascii ( cmd_list[i] ), config.case_sensitive ) ) {
if ( token_match ( tokens, cmd_list[i] ) ) {
dmenu_output_formatted_line ( pd->format, cmd_list[i], i, config.filter );
}
}
g_strfreev ( tokens );
tokenize_free ( tokens );
return TRUE;
}
// TODO remove

View file

@ -400,29 +400,24 @@ static char *drun_get_completion ( const Mode *sw, unsigned int index )
}
}
static int drun_token_match ( const Mode *data,
char **tokens,
int not_ascii,
int case_sensitive,
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;
char *ftokens[2] = { tokens[j], NULL };
int test = 0;
GRegex *ftokens[2] = { tokens[j], NULL };
if ( !test && rmpd->entry_list[index].name &&
token_match ( ftokens, rmpd->entry_list[index].name, not_ascii, case_sensitive ) ) {
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, not_ascii, case_sensitive ) ) {
token_match ( ftokens, rmpd->entry_list[index].generic_name ) ) {
test = 1;
}
if ( !test && token_match ( ftokens, rmpd->entry_list[index].exec, not_ascii, case_sensitive ) ) {
if ( !test && token_match ( ftokens, rmpd->entry_list[index].exec ) ) {
test = 1;
}
if ( test == 0 ) {
@ -438,15 +433,6 @@ static unsigned int drun_mode_get_num_entries ( const Mode *sw )
const DRunModePrivateData *pd = (const DRunModePrivateData *) mode_get_private_data ( sw );
return pd->cmd_list_length;
}
static int drun_is_not_ascii ( const Mode *sw, unsigned int index )
{
DRunModePrivateData *pd = (DRunModePrivateData *) mode_get_private_data ( sw );
if ( pd->entry_list[index].generic_name ) {
return !g_str_is_ascii ( pd->entry_list[index].name ) || !g_str_is_ascii ( pd->entry_list[index].generic_name );
}
return !g_str_is_ascii ( pd->entry_list[index].name );
}
#include "mode-private.h"
Mode drun_mode =
{
@ -459,7 +445,7 @@ Mode drun_mode =
._token_match = drun_token_match,
._get_completion = drun_get_completion,
._get_display_value = _get_display_value,
._is_not_ascii = drun_is_not_ascii,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
};

View file

@ -103,14 +103,12 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, in
return g_strdup ( pd->messages[selected_line] );
}
static int help_keys_token_match ( const Mode *data,
char **tokens,
int not_ascii,
int case_sensitive,
GRegex **tokens,
unsigned int index
)
{
KeysHelpModePrivateData *rmpd = (KeysHelpModePrivateData *) mode_get_private_data ( data );
return token_match ( tokens, rmpd->messages[index], not_ascii, case_sensitive );
return token_match ( tokens, rmpd->messages[index] );
}
static unsigned int help_keys_mode_get_num_entries ( const Mode *sw )
@ -118,11 +116,6 @@ static unsigned int help_keys_mode_get_num_entries ( const Mode *sw )
const KeysHelpModePrivateData *pd = (const KeysHelpModePrivateData *) mode_get_private_data ( sw );
return pd->messages_length;
}
static int help_keys_is_not_ascii ( const Mode *sw, unsigned int index )
{
const KeysHelpModePrivateData *pd = (const KeysHelpModePrivateData *) mode_get_private_data ( sw );
return !g_str_is_ascii ( pd->messages[index] );
}
#include "mode-private.h"
Mode help_keys_mode =
@ -136,7 +129,6 @@ Mode help_keys_mode =
._token_match = help_keys_token_match,
._get_completion = NULL,
._get_display_value = _get_display_value,
._is_not_ascii = help_keys_is_not_ascii,
.private_data = NULL,
.free = NULL
};

View file

@ -418,16 +418,10 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_
const RunModePrivateData *rmpd = (const RunModePrivateData *) sw->private_data;
return get_entry ? g_strdup ( rmpd->cmd_list[selected_line] ) : NULL;
}
static int run_token_match ( const Mode *sw, char **tokens, int not_ascii, int case_sensitive, unsigned int index )
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], not_ascii, case_sensitive );
}
static int run_is_not_ascii ( const Mode *sw, unsigned int index )
{
const RunModePrivateData *rmpd = (const RunModePrivateData *) sw->private_data;
return !g_str_is_ascii ( rmpd->cmd_list[index] );
return token_match ( tokens, rmpd->cmd_list[index] );
}
#include "mode-private.h"
@ -442,7 +436,7 @@ Mode run_mode =
._token_match = run_token_match,
._get_display_value = _get_display_value,
._get_completion = NULL,
._is_not_ascii = run_is_not_ascii,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
};

View file

@ -168,16 +168,10 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_
return get_entry ? g_strdup ( rmpd->cmd_list[selected_line] ) : NULL;
}
static int script_token_match ( const Mode *sw, char **tokens, int not_ascii, int case_sensitive, unsigned int index )
static int script_token_match ( const Mode *sw, GRegex **tokens, unsigned int index )
{
ScriptModePrivateData *rmpd = sw->private_data;
return token_match ( tokens, rmpd->cmd_list[index], not_ascii, case_sensitive );
}
static int script_is_not_ascii ( const Mode *sw, unsigned int index )
{
ScriptModePrivateData *rmpd = sw->private_data;
return !g_str_is_ascii ( rmpd->cmd_list[index] );
return token_match ( tokens, rmpd->cmd_list[index] );
}
#include "mode-private.h"
@ -206,8 +200,8 @@ 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;
sw->_is_not_ascii = script_is_not_ascii;
return sw;
}

View file

@ -198,7 +198,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
// Reading one line per time.
while ( getline ( &buffer, &buffer_length, fd ) > 0 ) {
// Evaluate one line.
unsigned int index = 0, ti = 0;
unsigned int index = 0, ti = 0;
char *token = buffer;
// Tokenize it.
@ -481,26 +481,11 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_
*
* @returns TRUE if matches
*/
static int ssh_token_match ( const Mode *sw, char **tokens, int not_ascii, int case_sensitive, unsigned int index )
static int ssh_token_match ( const Mode *sw, GRegex **tokens, unsigned int index )
{
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
return token_match ( tokens, rmpd->hosts_list[index], not_ascii, case_sensitive );
return token_match ( tokens, rmpd->hosts_list[index] );
}
/**
* @param sw Object handle to the SSH Mode object
* @param index The index of the entry to match
*
* Check if the selected entry contains non-ascii symbols.
*
* @returns TRUE if string contains non-ascii symbols
*/
static int ssh_is_not_ascii ( const Mode *sw, unsigned int index )
{
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
return !g_str_is_ascii ( rmpd->hosts_list[index] );
}
#include "mode-private.h"
Mode ssh_mode =
{
@ -513,7 +498,7 @@ Mode ssh_mode =
._token_match = ssh_token_match,
._get_display_value = _get_display_value,
._get_completion = NULL,
._is_not_ascii = ssh_is_not_ascii,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
};

View file

@ -319,9 +319,7 @@ typedef struct
char *cache;
} ModeModePrivateData;
static int window_match ( const Mode *sw, char **tokens,
__attribute__( ( unused ) ) int not_ascii,
int case_sensitive, unsigned int index )
static int window_match ( const Mode *sw, GRegex **tokens, unsigned int index )
{
ModeModePrivateData *rmpd = (ModeModePrivateData *) mode_get_private_data ( sw );
int match = 1;
@ -338,21 +336,21 @@ static int window_match ( const Mode *sw, char **tokens,
// Now we want it to match only one item at the time.
// If hack not in place it would not match queries spanning multiple fields.
// e.g. when searching 'title element' and 'class element'
char *ftokens[2] = { tokens[j], NULL };
GRegex *ftokens[2] = { tokens[j], NULL };
if ( !test && c->title != NULL && c->title[0] != '\0' ) {
test = token_match ( ftokens, c->title, not_ascii, case_sensitive );
test = token_match ( ftokens, c->title );
}
if ( !test && c->class != NULL && c->class[0] != '\0' ) {
test = token_match ( ftokens, c->class, not_ascii, case_sensitive );
test = token_match ( ftokens, c->class );
}
if ( !test && c->role != NULL && c->role[0] != '\0' ) {
test = token_match ( ftokens, c->role, not_ascii, case_sensitive );
test = token_match ( ftokens, c->role );
}
if ( !test && c->name != NULL && c->name[0] != '\0' ) {
test = token_match ( ftokens, c->name, not_ascii, case_sensitive );
test = token_match ( ftokens, c->name );
}
if ( test == 0 ) {
@ -685,26 +683,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;
}
static int window_is_not_ascii ( const Mode *sw, unsigned int index )
{
const ModeModePrivateData *rmpd = mode_get_private_data ( sw );
const winlist *ids = ( winlist * ) rmpd->ids;
// Want to pull directly out of cache, X calls are not thread safe.
int idx = winlist_find ( cache_client, ids->array[index] );
g_assert ( idx >= 0 );
client *c = cache_client->data[idx];
if ( c->role && !g_str_is_ascii ( c->role ) ) {
return TRUE;
}
if ( c->class && !g_str_is_ascii ( c->class ) ) {
return TRUE;
}
if ( c->title && !g_str_is_ascii ( c->title ) ) {
return TRUE;
}
return FALSE;
}
#include "mode-private.h"
Mode window_mode =
{
@ -717,7 +695,7 @@ Mode window_mode =
._token_match = window_match,
._get_display_value = _get_display_value,
._get_completion = NULL,
._is_not_ascii = window_is_not_ascii,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
};
@ -732,7 +710,7 @@ Mode window_mode_cd =
._token_match = window_match,
._get_display_value = _get_display_value,
._get_completion = NULL,
._is_not_ascii = window_is_not_ascii,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
};

View file

@ -136,71 +136,71 @@ int helper_parse_setup ( char * string, char ***output, int *length, ... )
return FALSE;
}
char *token_collate_key ( const char *token, int case_sensitive )
void tokenize_free ( GRegex ** tokens )
{
char *tmp, *compk;
if ( case_sensitive ) {
tmp = g_strdup ( token );
for ( size_t i = 0; tokens && tokens[i]; i++ ) {
g_regex_unref ( (GRegex *) tokens[i] );
}
else {
tmp = g_utf8_casefold ( token, -1 );
}
compk = g_utf8_normalize ( tmp, -1, G_NORMALIZE_ALL );
g_free ( tmp );
return compk;
g_free ( tokens );
}
void tokenize_free ( char ** tokens )
static gchar *glob_to_regex ( const char *input )
{
if ( config.glob ) {
for ( size_t i = 0; tokens && tokens[i]; i++ ) {
g_pattern_spec_free ( (GPatternSpec *) tokens[i] );
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 ), 0, 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++ ) {
if ( tokens[i] != NULL ) {
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{
// 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 )
GRegex **tokenize ( const char *input, int case_sensitive )
{
if ( input == NULL ) {
return NULL;
}
size_t len = strlen ( input );
if ( len == 0 ) {
return NULL;
}
char *saveptr = NULL, *token;
char **retv = NULL;
char *saveptr = NULL, *token;
GRegex **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 );
}
retv[0] = (char *) reg;
}
else{
retv[0] = token_collate_key ( input, case_sensitive );
}
retv = g_malloc0 ( sizeof ( GRegex* ) * 2 );
retv[0] = (GRegex *) create_regex ( input, case_sensitive );
return retv;
}
@ -214,25 +214,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 ( GRegex* ) * ( num_tokens + 2 ) );
retv[num_tokens] = (GRegex *) create_regex ( token, case_sensitive );
retv[num_tokens + 1] = NULL;
num_tokens++;
}
@ -348,98 +331,42 @@ 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 )
PangoAttrList *token_match_get_pango_attr ( GRegex **tokens, const char *input, PangoAttrList *retv )
{
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 );
for ( int j = 0; tokens[j]; j++ ) {
GMatchInfo *gmi = NULL;
g_regex_match ( (GRegex *) tokens[j], input, G_REGEX_MATCH_PARTIAL, &gmi );
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 );
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 );
}
match = !( *token );
g_match_info_free ( gmi );
}
g_free ( compk );
}
return match;
return retv;
}
static int normal_token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive )
int token_match ( GRegex **tokens, const char *input )
{
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;
// 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 );
match = g_regex_match ( (GRegex *) tokens[j], input, 0, NULL );
}
}
return match;
}
static int glob_token_match ( char **tokens, const char *input, int not_ascii, int case_sensitive )
{
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;
}
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 );
}
int execute_generator ( const char * cmd )
{
char **args = NULL;

View file

@ -57,12 +57,6 @@ char * mode_get_completion ( const Mode *mode, unsigned int selected_line )
}
}
int mode_is_not_ascii ( const Mode *mode, unsigned int selected_line )
{
g_assert ( mode != NULL );
g_assert ( mode->_is_not_ascii != NULL );
return mode->_is_not_ascii ( mode, selected_line );
}
ModeMode mode_result ( Mode *mode, int menu_retv, char **input, unsigned int selected_line )
{
g_assert ( mode != NULL );
@ -71,11 +65,11 @@ ModeMode mode_result ( Mode *mode, int menu_retv, char **input, unsigned int sel
return mode->_result ( mode, menu_retv, input, selected_line );
}
int mode_token_match ( const Mode *mode, char **tokens, int not_ascii, int case_sensitive, unsigned int selected_line )
int mode_token_match ( const Mode *mode, GRegex **tokens, unsigned int selected_line )
{
g_assert ( mode != NULL );
g_assert ( mode->_token_match != NULL );
return mode->_token_match ( mode, tokens, not_ascii, case_sensitive, selected_line );
return mode->_token_match ( mode, tokens, selected_line );
}
const char *mode_get_name ( const Mode *mode )
@ -122,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 );
}
/*@}*/

View file

@ -74,9 +74,9 @@ struct xkb_stuff xkb = {
.keymap = NULL,
.state = NULL,
.compose = {
.table = NULL,
.state = NULL
}
.table = NULL,
.state = NULL
}
};
char *config_path = NULL;
// Array of modi.
@ -441,22 +441,22 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN
xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id );
break;
case XCB_XKB_STATE_NOTIFY:
{
xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
guint modmask;
xkb_state_update_mask ( xkb.state,
ksne->baseMods,
ksne->latchedMods,
ksne->lockedMods,
ksne->baseGroup,
ksne->latchedGroup,
ksne->lockedGroup );
modmask = x11_get_current_mask ( &xkb );
if ( modmask == 0 ) {
abe_trigger_release ( );
}
break;
{
xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
guint modmask;
xkb_state_update_mask ( xkb.state,
ksne->baseMods,
ksne->latchedMods,
ksne->lockedMods,
ksne->baseGroup,
ksne->latchedGroup,
ksne->lockedGroup );
modmask = x11_get_current_mask ( &xkb );
if ( modmask == 0 ) {
abe_trigger_release ( );
}
break;
}
}
return G_SOURCE_CONTINUE;
}

View file

@ -162,6 +162,18 @@ static void __textbox_update_pango_text ( textbox *tb )
pango_layout_set_text ( tb->layout, tb->text, -1 );
}
}
const char *textbox_get_visible_text ( textbox *tb )
{
return pango_layout_get_text ( tb->layout );
}
PangoAttrList *textbox_get_pango_attributes ( textbox *tb )
{
return pango_layout_get_attributes ( tb->layout );
}
void textbox_set_pango_attributes ( textbox *tb, PangoAttrList *list )
{
pango_layout_set_attributes ( tb->layout, list );
}
// set the default text to display
void textbox_text ( textbox *tb, const char *text )
@ -588,22 +600,19 @@ int textbox_keybinding ( textbox *tb, KeyBindingAction action )
g_return_val_if_reached ( 0 );
}
gboolean textbox_append ( textbox *tb, char *pad, int pad_len )
gboolean textbox_append_char ( textbox *tb, char *pad, int pad_len )
{
if ( !( tb->flags & TB_EDITABLE ) ) {
return FALSE;
}
int old_blink = tb->blink;
tb->blink = 2;
// Filter When alt/ctrl is pressed do not accept the character.
if ( !g_ascii_iscntrl ( *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 );
return TRUE;
}
tb->blink = old_blink;
return FALSE;
}

View file

@ -298,7 +298,6 @@ void rofi_view_free ( RofiViewState *state )
g_free ( state->boxes );
g_free ( state->line_map );
g_free ( state->distance );
g_free ( state->lines_not_ascii );
// Free the switcher boxes.
// When state is free'ed we should no longer need these.
if ( config.sidebar_mode == TRUE ) {
@ -462,7 +461,7 @@ static RofiViewState * __rofi_view_state_create ( void )
typedef struct _thread_state
{
RofiViewState *state;
char **tokens;
GRegex **tokens;
unsigned int start;
unsigned int stop;
unsigned int count;
@ -491,27 +490,22 @@ static void filter_elements ( thread_state *t, G_GNUC_UNUSED gpointer user_data
{
// input changed
for ( unsigned int i = t->start; i < t->stop; i++ ) {
int match = mode_token_match ( t->state->sw, t->tokens, t->state->lines_not_ascii[i],
config.case_sensitive, i );
int match = mode_token_match ( t->state->sw, t->tokens, i );
// If each token was matched, add it to list.
if ( match ) {
t->state->line_map[t->start + t->count] = i;
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 * str = mode_get_completion ( t->state->sw, i );
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++;
}
}
}
static void check_is_ascii ( thread_state *t, G_GNUC_UNUSED gpointer user_data )
{
for ( unsigned int i = t->start; i < t->stop; i++ ) {
t->state->lines_not_ascii[i] = mode_is_not_ascii ( t->state->sw, i );
}
}
static void rofi_view_setup_fake_transparency ( void )
{
@ -932,6 +926,9 @@ static void rofi_view_draw ( RofiViewState *state, cairo_t *d )
int x_offset = state->border;
if ( state->rchanged ) {
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 );
@ -945,10 +942,20 @@ static void rofi_view_draw ( RofiViewState *state, cairo_t *d )
TextBoxFontType tbft = fstate | ( ( i + offset ) == state->selected ? HIGHLIGHT : type );
textbox_font ( state->boxes[i], tbft );
textbox_text ( state->boxes[i], text );
PangoAttrList *list = textbox_get_pango_attributes ( state->boxes[i] );
if ( list != NULL ) {
pango_attr_list_ref ( 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 );
}
textbox_draw ( state->boxes[i], d );
}
tokenize_free ( tokens );
state->rchanged = FALSE;
}
else{
@ -1243,7 +1250,9 @@ static void rofi_view_refilter ( RofiViewState *state )
TICK_N ( "Filter start" );
if ( strlen ( state->text->text ) > 0 ) {
unsigned int j = 0;
char **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.
@ -1530,7 +1539,7 @@ static void rofi_view_handle_keypress ( RofiViewState *state, xkb_stuff *xkb, xc
}
}
if ( ( len > 0 ) && ( textbox_append ( state->text, pad, len ) ) ) {
if ( ( len > 0 ) && ( textbox_append_char ( state->text, pad, len ) ) ) {
state->refilter = TRUE;
state->update = TRUE;
return;
@ -1627,46 +1636,8 @@ RofiViewState *rofi_view_create ( Mode *sw,
state->finalize = finalize;
// Request the lines to show.
state->num_lines = mode_get_num_entries ( sw );
state->lines_not_ascii = g_malloc0_n ( state->num_lines, sizeof ( int ) );
state->num_lines = mode_get_num_entries ( sw );
// find out which lines contain non-ascii codepoints, so we can be faster in some cases.
if ( state->num_lines > 0 ) {
TICK_N ( "Is ASCII start" );
unsigned int nt = MAX ( 1, state->num_lines / 5000 );
thread_state states[nt];
unsigned int steps = ( state->num_lines + nt ) / nt;
unsigned int count = nt;
GCond cond;
GMutex mutex;
g_mutex_init ( &mutex );
g_cond_init ( &cond );
for ( unsigned int i = 0; i < nt; i++ ) {
states[i].state = state;
states[i].start = i * steps;
states[i].stop = MIN ( ( i + 1 ) * steps, state->num_lines );
states[i].acount = &count;
states[i].mutex = &mutex;
states[i].cond = &cond;
states[i].callback = check_is_ascii;
if ( i > 0 ) {
g_thread_pool_push ( tpool, &( states[i] ), NULL );
}
}
// Run one in this thread.
rofi_view_call_thread ( &( states[0] ), NULL );
// No need to do this with only one thread.
if ( nt > 1 ) {
g_mutex_lock ( &mutex );
while ( count > 0 ) {
g_cond_wait ( &cond, &mutex );
}
g_mutex_unlock ( &mutex );
}
g_cond_clear ( &cond );
g_mutex_clear ( &mutex );
TICK_N ( "Is ASCII stop" );
}
TICK_N ( "Startup notification" );
// Try to grab the keyboard as early as possible.

View file

@ -139,8 +139,6 @@ static XrmOption xrmOptions[] = {
"Parse known_hosts file for ssh mode" },
{ 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,

View file

@ -50,20 +50,6 @@ int main ( int argc, char ** argv )
return EXIT_FAILURE;
}
/**
* Collating.
*/
char *res = token_collate_key ( "€ Sign", FALSE );
TASSERT ( strcmp ( res, "€ sign" ) == 0 );
g_free ( res );
res = token_collate_key ( "éÉêèë Sign", FALSE );
TASSERT ( strcmp ( res, "ééêèë sign" ) == 0 );
g_free ( res );
res = token_collate_key ( "éÉêèë³ Sign", TRUE );
TASSERT ( strcmp ( res, "éÉêèë3 Sign" ) == 0 );
g_free ( res );
/**
* Char function
*/
@ -83,20 +69,6 @@ int main ( int argc, char ** argv )
/**
* tokenize
*/
config.regex = FALSE;
config.glob = FALSE;
char ** retv = tokenize ( "aAp nOoT MieS 12", FALSE );
TASSERT ( retv[0] && strcmp ( retv[0], "aap" ) == 0 );
TASSERT ( retv[1] && strcmp ( retv[1], "noot" ) == 0 );
TASSERT ( retv[2] && strcmp ( retv[2], "mies" ) == 0 );
TASSERT ( retv[3] && strcmp ( retv[3], "12" ) == 0 );
tokenize_free ( retv );
retv = tokenize ( "blub³ bOb bEp bEE", TRUE );
TASSERT ( retv[0] && strcmp ( retv[0], "blub3" ) == 0 );
TASSERT ( retv[1] && strcmp ( retv[1], "bOb" ) == 0 );
TASSERT ( retv[2] && strcmp ( retv[2], "bEp" ) == 0 );
TASSERT ( retv[3] && strcmp ( retv[3], "bEE" ) == 0 );
tokenize_free ( retv );
TASSERT ( levenshtein ( "aap", "aap" ) == 0 );
TASSERT ( levenshtein ( "aap", "aap " ) == 1 );

View file

@ -1,22 +0,0 @@
#!/usr/bin/env bash
echo -en "nooty\naap\nnoot\nmies" | rofi -fuzzy -no-regex -dmenu > output.txt &
RPID=$!
# send enter.
sleep 5;
xdotool type 'nty'
sleep 0.4
xdotool key Return
# Get result, kill xvfb
wait ${RPID}
RETV=$?
OUTPUT=$(cat output.txt)
if [ "${OUTPUT}" != 'nooty' ]
then
echo "Got: '${OUTPUT}' expected 'nooty'"
exit 1
fi
exit ${RETV}