1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-25 13:55:34 -05:00

Merge pull request #103 from EdwinPujols/master

Fix #102 - Add case sensitivity.
This commit is contained in:
Dave Davenport 2015-01-13 11:47:13 +01:00
commit 08485c0cfc
10 changed files with 116 additions and 53 deletions

View file

@ -101,6 +101,8 @@ Settings config = {
.disable_history = FALSE,
/** Use levenshtein sorting when matching */
.levenshtein_sort = FALSE,
/** Case sensitivity of the search */
.case_sensitive = FALSE,
/** Separator to use for dmenu mode */
.separator = '\n',
/** Height of an element in #chars */

View file

@ -12,9 +12,9 @@ rofi - A window switcher, run dialog and dmenu replacement
-fixed-num-lines ] [ -padding *padding* ] [ -opacity *opacity%* ] [ -display *display* ] [ -bc
*color* ] [ -bw *width* ] [ -dmenu [ -p *prompt* ] ] [ -ssh-client *client* ] [ -ssh-command
*command* ] [ -now ] [ -rnow ] [ -snow ] [ -version ] [ -help] [ -dump-xresources ] [
-disable-history ] [ -levenshtein-sort ] [ -show *mode* ] [ -switcher *mode1,mode2* ] [ -e
*message*] [ -sep *separator* ] [ -eh *element height* ] [ -l *selected line* ] [ -run-list-command
*cmd* ]
-disable-history ] [ -levenshtein-sort ] [ -case-sensitive ] [ -show *mode* ] [ -switcher *mode1,
mode2* ] [ -e *message*] [ -sep *separator* ] [ -eh *element height* ] [ -l *selected line* ] [
-run-list-command *cmd* ]
## DESCRIPTION
@ -120,6 +120,9 @@ The default key combinations are:
rofi -switchers "window,run,ssh,Workspaces:i3_switch_workspaces.sh" -show Workspaces
`-case-sensitive`
Start in case sensitive mode.
### Theming
@ -262,7 +265,6 @@ The default key combinations are:
Override the used ssh client. Default is `ssh`.
### SSH settings
`-ssh-set-title` *true|false*
@ -391,6 +393,7 @@ Rofi supports the following keybindings:
* `ctrl-/`: Switch to the previous modi. The list can be customized with the `-switchers` argument.
* `Ctrl-space`: Set selected item as input text.
* `Shift-Del`: Delete entry from history.
* `grave`: Toggle case sensitivity.
## FAQ

View file

@ -10,9 +10,9 @@ rofi \- A window switcher, run dialog and dmenu replacement
\-fixed\-num\-lines ] [ \-padding \fIpadding\fP ] [ \-opacity \fIopacity%\fP ] [ \-display \fIdisplay\fP ] [ \-bc
\fIcolor\fP ] [ \-bw \fIwidth\fP ] [ \-dmenu [ \-p \fIprompt\fP ] ] [ \-ssh\-client \fIclient\fP ] [ \-ssh\-command
\fIcommand\fP ] [ \-now ] [ \-rnow ] [ \-snow ] [ \-version ] [ \-help] [ \-dump\-xresources ] [
\-disable\-history ] [ \-levenshtein\-sort ] [ \-show \fImode\fP ] [ \-switcher \fImode1,mode2\fP ] [ \-e
\fImessage\fP] [ \-sep \fIseparator\fP ] [ \-eh \fIelement height\fP ] [ \-l \fIselected line\fP ] [ \-run\-list\-command
\fIcmd\fP ]
\-disable\-history ] [ \-levenshtein\-sort ] [ \-case\-sensitive ] [ \-show \fImode\fP ] [ \-switcher \fImode1,
mode2\fP ] [ \-e \fImessage\fP] [ \-sep \fIseparator\fP ] [ \-eh \fIelement height\fP ] [ \-l \fIselected line\fP ] [
\-run\-list\-command \fIcmd\fP ]
.SH DESCRIPTION
.PP
\fBrofi\fP is an X11 popup window switcher. A list is displayed center\-screen showing open window titles, WM_CLASS, and desktop number.
@ -141,6 +141,10 @@ So to have a mode 'Workspaces' using the \fB\fCi3_switch_workspace.sh\fR script
rofi \-switchers "window,run,ssh,Workspaces:i3_switch_workspaces.sh" \-show Workspaces
.fi
.RE
.PP
\fB\fC\-case\-sensitive\fR
.IP
Start in case sensitive mode.
.SS Theming
.PP
\fB\fC\-bg\fR
@ -512,6 +516,8 @@ Rofi supports the following keybindings:
\fB\fCCtrl\-space\fR: Set selected item as input text.
.IP \(bu 2
\fB\fCShift\-Del\fR: Delete entry from history.
.IP \(bu 2
\fB\fCgrave\fR: Toggle case sensitivity.
.RE
.SH FAQ
.PP
@ -533,18 +539,14 @@ Check quotes used on the commandline: e.g. used “ instead of ".
.SH WEBSITE
.PP
\fBrofi\fP website can be found at here
.UR https://davedavenport.github.io/rofi/
.UE
\[la]https://davedavenport.github.io/rofi/\[ra]
.PP
\fBrofi\fP bugtracker can be found here
.UR https://github.com/DaveDavenport/rofi/issues
.UE
\[la]https://github.com/DaveDavenport/rofi/issues\[ra]
.SH AUTHOR
.PP
Qball Cow
.MT qball@gmpclient.org
.ME
\[la]qball@gmpclient.org\[ra]
.PP
Original code based on work by: Sean Pringle
.MT sean.pringle@gmail.com
.ME
\[la]sean.pringle@gmail.com\[ra]

View file

@ -18,14 +18,27 @@ int helper_parse_setup ( char * string, char ***output, int *length, ... );
*/
char* fgets_s ( char* s, int n, FILE *iop, char sep );
/**
* @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.
*
* Tokenize the string on spaces.
*
* @returns a newly allocated 2 dimensional array of strings.
*/
char **tokenize ( const char *input );
char **tokenize ( const char *input, int case_sensitive );
/**
* @param argc Number of arguments.
@ -92,6 +105,7 @@ int find_arg ( const int argc, char * const argv[], const char * const key );
* @params tokens
* @param tokens List of (input) tokens to match.
* @param input The entry to match against.
* @param case_sensitive Whether case is significant.
* @param index The current selected index.
* @param data User data.
*
@ -99,7 +113,7 @@ int find_arg ( const int argc, char * const argv[], const char * const key );
*
* @returns 1 when matches, 0 otherwise
*/
int token_match ( char **tokens, const char *input,
int token_match ( char **tokens, const char *input, int case_sensitive,
__attribute__( ( unused ) ) int index,
__attribute__( ( unused ) ) void *data );

View file

@ -62,6 +62,7 @@ typedef enum
/**
* @param tokens List of (input) tokens to match.
* @param input The entry to match against.
* @param case_sensitive Whether case is significant.
* @param index The current selected index.
* @param data User data.
*
@ -69,7 +70,7 @@ typedef enum
*
* @returns 1 when it matches, 0 if not.
*/
typedef int ( *menu_match_cb )( char **tokens, const char *input, int index, void *data );
typedef int ( *menu_match_cb )( char **tokens, const char *input, int case_sensitive, int index, void *data );
/**
* @param lines An array of strings to display.
@ -196,6 +197,8 @@ typedef struct _Settings
unsigned int disable_history;
/** Use levenshtein sorting when matching */
unsigned int levenshtein_sort;
/** Search case sensitivity */
unsigned int case_sensitive;
/** Separator to use for dmenu mode */
char separator;
/** Height of an element in #chars */

View file

@ -118,7 +118,23 @@ int helper_parse_setup ( char * string, char ***output, int *length, ... )
return FALSE;
}
char **tokenize ( const char *input )
char *token_collate_key ( const char *token, int case_sensitive )
{
char *tmp, *compk;
if ( case_sensitive ) {
tmp = g_strdup ( token );
} else {
tmp = g_utf8_casefold ( token, -1 );
}
compk = g_utf8_collate_key ( tmp, -1 );
g_free ( tmp );
return compk;
}
char **tokenize ( const char *input, int case_sensitive )
{
if ( input == NULL ) {
return NULL;
@ -137,15 +153,10 @@ char **tokenize ( const char *input )
for ( token = strtok_r ( str, " ", &saveptr );
token != NULL;
token = strtok_r ( NULL, " ", &saveptr ) ) {
// Get case insensitive version of the string.
char *tmp = g_utf8_casefold ( token, -1 );
retv = g_realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) );
retv[num_tokens] = token_collate_key ( token, case_sensitive );
retv[num_tokens + 1] = NULL;
// Create compare key from the case insensitive version.
retv[num_tokens] = g_utf8_collate_key ( tmp, -1 );
num_tokens++;
g_free ( tmp );
}
// Free str.
g_free ( str );
@ -258,21 +269,19 @@ int find_arg_char ( const int argc, char * const argv[], const char * const key,
* Shared 'token_match' function.
* Matches tokenized.
*/
int token_match ( char **tokens, const char *input,
int token_match ( char **tokens, const char *input, int case_sensitive,
__attribute__( ( unused ) ) int index,
__attribute__( ( unused ) ) void *data )
{
int match = 1;
char *compk = token_collate_key ( input, case_sensitive );
char *lowerc = g_utf8_casefold ( input, -1 );
char *compk = g_utf8_collate_key ( lowerc, -1 );
// Do a tokenized match.
if ( tokens ) {
for ( int j = 0; match && tokens[j]; j++ ) {
match = ( strstr ( compk, tokens[j] ) != NULL );
}
}
g_free ( lowerc );
g_free ( compk );
return match;
}

View file

@ -690,43 +690,39 @@ static void menu_set_arrow_text ( int filtered_lines, int selected, int max_elem
}
static int window_match ( char **tokens, __attribute__( ( unused ) ) const char *input, int index, void *data )
static int window_match ( char **tokens, __attribute__( ( unused ) ) const char *input,
int case_sensitive, int index, void *data )
{
int match = 1;
winlist *ids = ( winlist * ) data;
client *c = window_client ( ids->array[index] );
if ( tokens ) {
for ( int j = 0; match && tokens[j]; j++ ) {
int test = 0;
if ( !test && c->title[0] != '\0' ) {
char *sml = g_utf8_casefold ( c->title, -1 );
char *key = g_utf8_collate_key ( sml, -1 );
char *key = token_collate_key ( c->title, case_sensitive );
test = ( strstr ( key, tokens[j] ) != NULL );
g_free ( sml ); g_free ( key );
g_free ( key );
}
if ( !test && c->class[0] != '\0' ) {
char *sml = g_utf8_casefold ( c->class, -1 );
char *key = g_utf8_collate_key ( sml, -1 );
char *key = token_collate_key ( c->title, case_sensitive );
test = ( strstr ( key, tokens[j] ) != NULL );
g_free ( sml ); g_free ( key );
g_free ( key );
}
if ( !test && c->role[0] != '\0' ) {
char *sml = g_utf8_casefold ( c->role, -1 );
char *key = g_utf8_collate_key ( sml, -1 );
char *key = token_collate_key ( c->title, case_sensitive );
test = ( strstr ( key, tokens[j] ) != NULL );
g_free ( sml ); g_free ( key );
g_free ( key );
}
if ( !test && c->name[0] != '\0' ) {
char *sml = g_utf8_casefold ( c->name, -1 );
char *key = g_utf8_collate_key ( sml, -1 );
char *key = token_collate_key ( c->title, case_sensitive );
test = ( strstr ( key, tokens[j] ) != NULL );
g_free ( sml ); g_free ( key );
g_free ( key );
}
if ( test == 0 ) {
@ -852,6 +848,7 @@ typedef struct MenuState
// Entries
textbox *text;
textbox *prompt_tb;
textbox *case_indicator;
textbox *arrowbox_top;
textbox *arrowbox_bottom;
textbox **boxes;
@ -887,6 +884,7 @@ static void menu_free_state ( MenuState *state )
{
textbox_free ( state->text );
textbox_free ( state->prompt_tb );
textbox_free ( state->case_indicator );
textbox_free ( state->arrowbox_bottom );
textbox_free ( state->arrowbox_top );
@ -1201,15 +1199,16 @@ static void menu_mouse_navigation ( MenuState *state, XButtonEvent *xbe )
}
}
static void menu_refilter ( MenuState *state, char **lines, menu_match_cb mmc, void *mmc_data, int sorting )
static void menu_refilter ( MenuState *state, char **lines, menu_match_cb mmc, void *mmc_data,
int sorting, int case_sensitive )
{
unsigned int i, j = 0;
if ( strlen ( state->text->text ) > 0 ) {
char **tokens = tokenize ( state->text->text );
char **tokens = tokenize ( state->text->text, case_sensitive );
// input changed
for ( i = 0; i < state->num_lines; i++ ) {
int match = mmc ( tokens, lines[i], i, mmc_data );
int match = mmc ( tokens, lines[i], case_sensitive, i, mmc_data );
// If each token was matched, add it to list.
if ( match ) {
@ -1297,8 +1296,9 @@ static void menu_update ( MenuState *state )
menu_hide_arrow_text ( state->filtered_lines, state->selected,
state->max_elements, state->arrowbox_top,
state->arrowbox_bottom );
textbox_draw ( state->text );
textbox_draw ( state->case_indicator );
textbox_draw ( state->prompt_tb );
textbox_draw ( state->text );
menu_draw ( state );
menu_set_arrow_text ( state->filtered_lines, state->selected,
state->max_elements, state->arrowbox_top,
@ -1413,16 +1413,24 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
// search text input
// we need this at this point so we can get height.
state.prompt_tb = textbox_create ( main_window, TB_AUTOHEIGHT | TB_AUTOWIDTH,
state.case_indicator = textbox_create ( main_window, TB_AUTOHEIGHT | TB_AUTOWIDTH,
( config.padding ), ( config.padding ),
0, 0,
NORMAL, "*" );
state.prompt_tb = textbox_create ( main_window, TB_AUTOHEIGHT | TB_AUTOWIDTH,
( config.padding ) + textbox_get_width ( state.case_indicator ),
( config.padding ),
0, 0, NORMAL, prompt );
state.text = textbox_create ( main_window, TB_AUTOHEIGHT | TB_EDITABLE,
( config.padding ) + textbox_get_width ( state.prompt_tb ),
( config.padding ) + textbox_get_width ( state.prompt_tb )
+ textbox_get_width ( state.case_indicator ),
( config.padding ),
( ( config.hmode == TRUE ) ?
state.element_width : ( state.w - ( 2 * ( config.padding ) ) ) )
- textbox_get_width ( state.prompt_tb ), 1,
- textbox_get_width ( state.prompt_tb )
- textbox_get_width ( state.case_indicator ), 1,
NORMAL,
( input != NULL ) ? *input : "" );
@ -1430,6 +1438,10 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
textbox_show ( state.text );
textbox_show ( state.prompt_tb );
if ( config.case_sensitive ) {
textbox_show ( state.case_indicator );
}
// Height of a row.
int line_height = textbox_get_height ( state.text );
if ( config.menu_lines == 0 ) {
@ -1552,7 +1564,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
while ( !state.quit ) {
// If something changed, refilter the list. (paste or text entered)
if ( state.refilter ) {
menu_refilter ( &state, lines, mmc, mmc_data, sorting );
menu_refilter ( &state, lines, mmc, mmc_data, sorting, config.case_sensitive );
}
// Update if requested.
if ( state.update ) {
@ -1621,6 +1633,18 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
state.quit = TRUE;
break;
}
// Toggle case sensitivity.
else if ( key == XK_grave ) {
config.case_sensitive = !config.case_sensitive;
*( state.selected_line ) = 0;
state.refilter = TRUE;
state.update = TRUE;
if ( config.case_sensitive ) {
textbox_show ( state.case_indicator );
} else {
textbox_hide ( state.case_indicator );
}
}
// Switcher short-cut
else if ( ( ( ev.xkey.state & Mod1Mask ) == Mod1Mask ) &&
key >= XK_1 && key <= XK_9 ) {
@ -2211,6 +2235,9 @@ static void parse_cmd_options ( int argc, char ** argv )
if ( find_arg ( argc, argv, "-levenshtein-sort" ) >= 0 ) {
config.levenshtein_sort = TRUE;
}
if ( find_arg ( argc, argv, "-case-sensitive" ) >= 0 ) {
config.case_sensitive = TRUE;
}
// Parse commandline arguments about behavior
find_arg_str ( argc, argv, "-terminal", &( config.terminal_emulator ) );

View file

@ -311,7 +311,8 @@ SwitcherMode run_switcher_dialog ( char **input, G_GNUC_UNUSED void *data )
}
int mretv = menu ( cmd_list, cmd_list_length, input, "run:",
NULL, &shift, token_match, NULL, &selected_line, config.levenshtein_sort );
NULL, &shift, token_match, NULL, &selected_line,
config.levenshtein_sort );
if ( mretv == MENU_NEXT ) {
retv = NEXT_DIALOG;

View file

@ -225,7 +225,8 @@ SwitcherMode ssh_switcher_dialog ( char **input, G_GNUC_UNUSED void *data )
int shift = 0;
int selected_line = 0;
int mretv = menu ( cmd_list, cmd_list_length, input, "ssh:",
NULL, &shift, token_match, NULL, &selected_line, config.levenshtein_sort );
NULL, &shift, token_match, NULL, &selected_line,
config.levenshtein_sort );
if ( mretv == MENU_NEXT ) {
retv = NEXT_DIALOG;

View file

@ -108,6 +108,7 @@ static XrmOption xrmOptions[] = {
{ xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL },
{ xrm_Boolean, "levenshtein-sort", { .num = &config.levenshtein_sort }, NULL },
{ xrm_Boolean, "case-sensitive", { .num = &config.case_sensitive }, NULL },
/* Key bindings */
{ xrm_String, "key", { .str = &config.window_key }, NULL },
{ xrm_String, "rkey", { .str = &config.run_key }, NULL },