mirror of
https://github.com/lbonn/rofi
synced 2024-11-15 08:37:17 +00:00
Using Glib's utf8 functions to do string collating.
* casefold and use utf-8 collating. * use g_utf8_next/prev for moving cursor.
This commit is contained in:
parent
2d87f12c44
commit
280c3d7f7f
4 changed files with 71 additions and 64 deletions
|
@ -2,21 +2,12 @@
|
|||
#define __SIMPLESWITCHER_H__
|
||||
#include <config.h>
|
||||
#include <X11/X.h>
|
||||
#include <glib.h>
|
||||
|
||||
#define MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
|
||||
#define MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
|
||||
#define NEAR( a, o, b ) ( ( b ) > ( a ) - ( o ) && ( b ) < ( a ) + ( o ) )
|
||||
#define OVERLAP( a, b, c, d ) ( ( ( a ) == ( c ) && ( b ) == ( d ) ) || MIN ( ( a ) + ( b ), ( c ) + ( d ) ) - MAX ( ( a ), ( c ) ) > 0 )
|
||||
#define INTERSECT( x, y, w, h, x1, y1, w1, h1 ) ( OVERLAP ( ( x ), ( w ), ( x1 ), ( w1 ) ) && OVERLAP ( ( y ), ( h ), ( y1 ), ( h1 ) ) )
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
extern const char *cache_dir;
|
||||
|
||||
|
||||
|
|
|
@ -139,15 +139,18 @@ int token_match ( char **tokens, const char *input,
|
|||
__attribute__( ( unused ) ) int index,
|
||||
__attribute__( ( unused ) ) void *data )
|
||||
{
|
||||
int match = 1;
|
||||
int match = 1;
|
||||
|
||||
char *lowerc = g_utf8_casefold ( input, -1 );
|
||||
char *compk = g_utf8_collate_key ( lowerc, -1 );
|
||||
// Do a tokenized match.
|
||||
if ( tokens ) {
|
||||
for ( int j = 1; match && tokens[j]; j++ ) {
|
||||
match = ( strcasestr ( input, tokens[j] ) != NULL );
|
||||
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||
match = ( strstr ( compk, tokens[j] ) != NULL );
|
||||
}
|
||||
}
|
||||
|
||||
g_free ( lowerc );
|
||||
g_free ( compk );
|
||||
return match;
|
||||
}
|
||||
|
||||
|
@ -161,27 +164,28 @@ static char **tokenize ( const char *input )
|
|||
char *saveptr = NULL, *token;
|
||||
char **retv = NULL;
|
||||
// First entry is always full (modified) stringtext.
|
||||
int num_tokens = 1;
|
||||
int num_tokens = 0;
|
||||
|
||||
//First entry is string that is modified.
|
||||
retv = malloc ( 2 * sizeof ( char* ) );
|
||||
retv[0] = strdup ( input );
|
||||
retv[1] = NULL;
|
||||
// Copy the string, 'strtok_r' modifies it.
|
||||
char *str = strdup ( input );
|
||||
|
||||
// Iterate over tokens.
|
||||
// strtok should still be valid for utf8.
|
||||
for ( token = strtok_r ( retv[0], " ", &saveptr );
|
||||
for ( token = strtok_r ( str, " ", &saveptr );
|
||||
token != NULL;
|
||||
token = strtok_r ( NULL, " ", &saveptr ) ) {
|
||||
char **tr = realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) );
|
||||
if ( tr != NULL ) {
|
||||
char *tmp = g_utf8_casefold ( token, -1 );
|
||||
retv = tr;
|
||||
retv[num_tokens + 1] = NULL;
|
||||
retv[num_tokens] = token;
|
||||
retv[num_tokens] = g_utf8_collate_key ( tmp, -1 );
|
||||
num_tokens++;
|
||||
g_free ( tmp );
|
||||
}
|
||||
}
|
||||
|
||||
// Free str.
|
||||
free ( str );
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
@ -191,7 +195,10 @@ static inline void tokenize_free ( char **ip )
|
|||
return;
|
||||
}
|
||||
|
||||
free ( ip[0] );
|
||||
// Free with g_free.
|
||||
for ( int i = 0; ip[i] != NULL; i++ ) {
|
||||
g_free ( ip[i] );
|
||||
}
|
||||
free ( ip );
|
||||
}
|
||||
|
||||
|
@ -785,7 +792,8 @@ void menu_draw ( textbox **boxes,
|
|||
|
||||
// selected row is always visible.
|
||||
// If selected is visible do not scroll.
|
||||
if ( ( selected - ( *last_offset ) ) < ( max_elements ) && ( selected - ( *last_offset ) ) >= 0 ) {
|
||||
if ( ( ( selected - ( *last_offset ) ) < ( max_elements ) )
|
||||
&& ( ( selected - ( *last_offset ) ) >= 0 ) ) {
|
||||
offset = *last_offset;
|
||||
}
|
||||
else{
|
||||
|
@ -883,25 +891,38 @@ int window_match ( char **tokens, __attribute__( ( unused ) ) const char *input,
|
|||
winlist *ids = ( winlist * ) data;
|
||||
client *c = window_client ( ids->array[index] );
|
||||
|
||||
|
||||
if ( tokens ) {
|
||||
for ( int j = 1; match && tokens[j]; j++ ) {
|
||||
int test = 0;
|
||||
for ( int j = 0; match && tokens[j]; j++ ) {
|
||||
int test = 0;
|
||||
|
||||
char *sml = g_utf8_casefold ( c->title, -1 );
|
||||
char *key = g_utf8_collate_key ( sml, -1 );
|
||||
if ( !test && c->title[0] != '\0' ) {
|
||||
test = ( strcasestr ( c->title, tokens[j] ) != NULL );
|
||||
test = ( strstr ( key, tokens[j] ) != NULL );
|
||||
}
|
||||
g_free ( sml ); g_free ( key );
|
||||
|
||||
sml = g_utf8_casefold ( c->class, -1 );
|
||||
key = g_utf8_collate_key ( sml, -1 );
|
||||
if ( !test && c->class[0] != '\0' ) {
|
||||
test = ( strcasestr ( c->class, tokens[j] ) != NULL );
|
||||
test = ( strstr ( key, tokens[j] ) != NULL );
|
||||
}
|
||||
g_free ( sml ); g_free ( key );
|
||||
|
||||
sml = g_utf8_casefold ( c->role, -1 );
|
||||
key = g_utf8_collate_key ( sml, -1 );
|
||||
if ( !test && c->role[0] != '\0' ) {
|
||||
test = ( strcasestr ( c->role, tokens[j] ) != NULL );
|
||||
test = ( strstr ( key, tokens[j] ) != NULL );
|
||||
}
|
||||
g_free ( sml ); g_free ( key );
|
||||
|
||||
sml = g_utf8_casefold ( c->name, -1 );
|
||||
key = g_utf8_collate_key ( sml, -1 );
|
||||
if ( !test && c->name[0] != '\0' ) {
|
||||
test = ( strcasestr ( c->name, tokens[j] ) != NULL );
|
||||
test = ( strstr ( key, tokens[j] ) != NULL );
|
||||
}
|
||||
g_free ( sml ); g_free ( key );
|
||||
|
||||
if ( test == 0 ) {
|
||||
match = 0;
|
||||
|
@ -1739,7 +1760,7 @@ static void run_switcher ( int do_fork, SwitcherMode mode )
|
|||
// strangeness...
|
||||
if ( do_fork == TRUE ) {
|
||||
if ( fork () ) {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
display = XOpenDisplay ( 0 );
|
||||
|
@ -2231,9 +2252,9 @@ int main ( int argc, char *argv[] )
|
|||
}
|
||||
else if ( find_arg ( argc, argv, "-dmenu" ) >= 0 ) {
|
||||
find_arg_str ( argc, argv, "-p", &dmenu_prompt );
|
||||
int retv = run_dmenu();
|
||||
int retv = run_dmenu ();
|
||||
// User cancelled the operation.
|
||||
if(retv == FALSE) {
|
||||
if ( retv == FALSE ) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ static int sort_func ( const void *a, const void *b )
|
|||
{
|
||||
const char *astr = *( const char * const * ) a;
|
||||
const char *bstr = *( const char * const * ) b;
|
||||
return strcasecmp ( astr, bstr );
|
||||
return g_utf8_collate ( astr, bstr );
|
||||
}
|
||||
static char ** get_ssh ( unsigned int *length )
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "rofi.h"
|
||||
#include "textbox.h"
|
||||
#include <glib.h>
|
||||
#define SIDE_MARGIN 2
|
||||
|
||||
|
||||
|
@ -132,8 +133,12 @@ void textbox_text ( textbox *tb, char *text )
|
|||
if ( tb->text ) {
|
||||
free ( tb->text );
|
||||
}
|
||||
|
||||
tb->text = strdup ( text );
|
||||
if ( g_utf8_validate ( text, -1, NULL ) ) {
|
||||
tb->text = strdup ( text );
|
||||
}
|
||||
else {
|
||||
tb->text = strdup ( "Invalid UTF-8 string." );
|
||||
}
|
||||
pango_layout_set_text ( tb->layout, tb->text, strlen ( tb->text ) );
|
||||
|
||||
tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( text ), tb->cursor ) );
|
||||
|
@ -206,7 +211,7 @@ void textbox_free ( textbox *tb )
|
|||
if ( tb->text ) {
|
||||
free ( tb->text );
|
||||
}
|
||||
if ( tb->layout == NULL ) {
|
||||
if ( tb->layout != NULL ) {
|
||||
g_object_unref ( tb->layout );
|
||||
}
|
||||
|
||||
|
@ -272,17 +277,6 @@ void textbox_draw ( textbox *tb )
|
|||
XFreePixmap ( display, canvas );
|
||||
}
|
||||
|
||||
|
||||
static size_t nextrune ( textbox *tb, int inc )
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
/* return location of next utf8 rune in the given direction (+1 or -1) */
|
||||
for ( n = tb->cursor + inc; n + inc >= 0 && ( tb->text[n] & 0xc0 ) == 0x80; n += inc ) {
|
||||
;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
// cursor handling for edit mode
|
||||
void textbox_cursor ( textbox *tb, int pos )
|
||||
{
|
||||
|
@ -292,16 +286,17 @@ void textbox_cursor ( textbox *tb, int pos )
|
|||
// move right
|
||||
void textbox_cursor_inc ( textbox *tb )
|
||||
{
|
||||
textbox_cursor ( tb, nextrune ( tb, 1 ) );
|
||||
int index = g_utf8_next_char ( &( tb->text[tb->cursor] ) ) - tb->text;
|
||||
textbox_cursor ( tb, index );
|
||||
}
|
||||
|
||||
// move left
|
||||
void textbox_cursor_dec ( textbox *tb )
|
||||
{
|
||||
textbox_cursor ( tb, nextrune ( tb, -1 ) );
|
||||
int index = g_utf8_prev_char ( &( tb->text[tb->cursor] ) ) - tb->text;
|
||||
textbox_cursor ( tb, index );
|
||||
}
|
||||
|
||||
|
||||
// end of line
|
||||
void textbox_cursor_end ( textbox *tb )
|
||||
{
|
||||
|
@ -337,8 +332,8 @@ void textbox_delete ( textbox *tb, int pos, int dlen )
|
|||
// delete on character
|
||||
void textbox_cursor_del ( textbox *tb )
|
||||
{
|
||||
int del_r = nextrune ( tb, 1 );
|
||||
textbox_delete ( tb, tb->cursor, del_r - tb->cursor );
|
||||
int index = g_utf8_next_char ( &( tb->text[tb->cursor] ) ) - tb->text;
|
||||
textbox_delete ( tb, tb->cursor, index - tb->cursor );
|
||||
}
|
||||
|
||||
// back up and delete one character
|
||||
|
@ -370,46 +365,46 @@ int textbox_keypress ( textbox *tb, XEvent *ev )
|
|||
|
||||
// Left or Ctrl-b
|
||||
if ( key == XK_Left ||
|
||||
(( ev->xkey.state&ControlMask) && key == XK_b) ) {
|
||||
textbox_cursor_dec ( tb );
|
||||
( ( ev->xkey.state & ControlMask ) && key == XK_b ) ) {
|
||||
textbox_cursor_dec ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Right or Ctrl-F
|
||||
else if ( key == XK_Right ||
|
||||
(( ev->xkey.state&ControlMask) && key == XK_f) ) {
|
||||
( ( ev->xkey.state & ControlMask ) && key == XK_f ) ) {
|
||||
textbox_cursor_inc ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Delete or Ctrl-D
|
||||
else if ( key == XK_Delete ||
|
||||
(( ev->xkey.state&ControlMask) && key == XK_d) ) {
|
||||
( ( ev->xkey.state & ControlMask ) && key == XK_d ) ) {
|
||||
textbox_cursor_del ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-U: Kill from the beginning to the end of the line.
|
||||
else if ( ( ev->xkey.state&ControlMask) && key == XK_u) {
|
||||
textbox_text( tb, "");
|
||||
else if ( ( ev->xkey.state & ControlMask ) && key == XK_u ) {
|
||||
textbox_text ( tb, "" );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-A
|
||||
else if ( ( ev->xkey.state&ControlMask) && key == XK_a) {
|
||||
else if ( ( ev->xkey.state & ControlMask ) && key == XK_a ) {
|
||||
textbox_cursor ( tb, 0 );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-E
|
||||
else if ( ( ev->xkey.state&ControlMask) && key == XK_e) {
|
||||
else if ( ( ev->xkey.state & ControlMask ) && key == XK_e ) {
|
||||
textbox_cursor_end ( tb );
|
||||
return 1;
|
||||
}
|
||||
// BackSpace, Ctrl-h
|
||||
else if ( key == XK_BackSpace ||
|
||||
(( ev->xkey.state&ControlMask) && key == XK_h) ) {
|
||||
( ( ev->xkey.state & ControlMask ) && key == XK_h ) ) {
|
||||
textbox_cursor_bkspc ( tb );
|
||||
return 1;
|
||||
}
|
||||
else if ( key == XK_Return || key == XK_KP_Enter ||
|
||||
((ev->xkey.state&ControlMask) && key == XK_j) ||
|
||||
((ev->xkey.state&ControlMask) && key == XK_m)) {
|
||||
( ( ev->xkey.state & ControlMask ) && key == XK_j ) ||
|
||||
( ( ev->xkey.state & ControlMask ) && key == XK_m ) ) {
|
||||
return -1;
|
||||
}
|
||||
else if ( !iscntrl ( *pad ) ) {
|
||||
|
|
Loading…
Reference in a new issue