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:
commit
341f8322ed
28 changed files with 235 additions and 491 deletions
|
@ -1,3 +1,6 @@
|
|||
v1.unrelease
|
||||
- Remove fuzzy option
|
||||
|
||||
v1.1.0
|
||||
New Features
|
||||
- Keys mode, showing keybindings.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
211
source/helper.c
211
source/helper.c
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
/*@}*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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}
|
Loading…
Add table
Reference in a new issue