1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-25 13:55:34 -05: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:
QC 2014-08-07 21:42:16 +02:00
parent 2d87f12c44
commit 280c3d7f7f
4 changed files with 71 additions and 64 deletions

View file

@ -2,21 +2,12 @@
#define __SIMPLESWITCHER_H__ #define __SIMPLESWITCHER_H__
#include <config.h> #include <config.h>
#include <X11/X.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 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 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 ) ) ) #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; extern const char *cache_dir;

View file

@ -139,15 +139,18 @@ int token_match ( char **tokens, const char *input,
__attribute__( ( unused ) ) int index, __attribute__( ( unused ) ) int index,
__attribute__( ( unused ) ) void *data ) __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. // Do a tokenized match.
if ( tokens ) { if ( tokens ) {
for ( int j = 1; match && tokens[j]; j++ ) { for ( int j = 0; match && tokens[j]; j++ ) {
match = ( strcasestr ( input, tokens[j] ) != NULL ); match = ( strstr ( compk, tokens[j] ) != NULL );
} }
} }
g_free ( lowerc );
g_free ( compk );
return match; return match;
} }
@ -161,27 +164,28 @@ static char **tokenize ( const char *input )
char *saveptr = NULL, *token; char *saveptr = NULL, *token;
char **retv = NULL; char **retv = NULL;
// First entry is always full (modified) stringtext. // First entry is always full (modified) stringtext.
int num_tokens = 1; int num_tokens = 0;
//First entry is string that is modified. // Copy the string, 'strtok_r' modifies it.
retv = malloc ( 2 * sizeof ( char* ) ); char *str = strdup ( input );
retv[0] = strdup ( input );
retv[1] = NULL;
// Iterate over tokens. // Iterate over tokens.
// strtok should still be valid for utf8. // strtok should still be valid for utf8.
for ( token = strtok_r ( retv[0], " ", &saveptr ); for ( token = strtok_r ( str, " ", &saveptr );
token != NULL; token != NULL;
token = strtok_r ( NULL, " ", &saveptr ) ) { token = strtok_r ( NULL, " ", &saveptr ) ) {
char **tr = realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) ); char **tr = realloc ( retv, sizeof ( char* ) * ( num_tokens + 2 ) );
if ( tr != NULL ) { if ( tr != NULL ) {
char *tmp = g_utf8_casefold ( token, -1 );
retv = tr; retv = tr;
retv[num_tokens + 1] = NULL; retv[num_tokens + 1] = NULL;
retv[num_tokens] = token; retv[num_tokens] = g_utf8_collate_key ( tmp, -1 );
num_tokens++; num_tokens++;
g_free ( tmp );
} }
} }
// Free str.
free ( str );
return retv; return retv;
} }
@ -191,7 +195,10 @@ static inline void tokenize_free ( char **ip )
return; return;
} }
free ( ip[0] ); // Free with g_free.
for ( int i = 0; ip[i] != NULL; i++ ) {
g_free ( ip[i] );
}
free ( ip ); free ( ip );
} }
@ -785,7 +792,8 @@ void menu_draw ( textbox **boxes,
// selected row is always visible. // selected row is always visible.
// If selected is visible do not scroll. // 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; offset = *last_offset;
} }
else{ else{
@ -883,25 +891,38 @@ int window_match ( char **tokens, __attribute__( ( unused ) ) const char *input,
winlist *ids = ( winlist * ) data; winlist *ids = ( winlist * ) data;
client *c = window_client ( ids->array[index] ); client *c = window_client ( ids->array[index] );
if ( tokens ) { if ( tokens ) {
for ( int j = 1; match && tokens[j]; j++ ) { for ( int j = 0; match && tokens[j]; j++ ) {
int test = 0; 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' ) { 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' ) { 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' ) { 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' ) { 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 ) { if ( test == 0 ) {
match = 0; match = 0;
@ -1739,7 +1760,7 @@ static void run_switcher ( int do_fork, SwitcherMode mode )
// strangeness... // strangeness...
if ( do_fork == TRUE ) { if ( do_fork == TRUE ) {
if ( fork () ) { if ( fork () ) {
return ; return;
} }
display = XOpenDisplay ( 0 ); display = XOpenDisplay ( 0 );
@ -2231,9 +2252,9 @@ int main ( int argc, char *argv[] )
} }
else if ( find_arg ( argc, argv, "-dmenu" ) >= 0 ) { else if ( find_arg ( argc, argv, "-dmenu" ) >= 0 ) {
find_arg_str ( argc, argv, "-p", &dmenu_prompt ); find_arg_str ( argc, argv, "-p", &dmenu_prompt );
int retv = run_dmenu(); int retv = run_dmenu ();
// User cancelled the operation. // User cancelled the operation.
if(retv == FALSE) { if ( retv == FALSE ) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }

View file

@ -120,7 +120,7 @@ static int sort_func ( const void *a, const void *b )
{ {
const char *astr = *( const char * const * ) a; const char *astr = *( const char * const * ) a;
const char *bstr = *( const char * const * ) b; const char *bstr = *( const char * const * ) b;
return strcasecmp ( astr, bstr ); return g_utf8_collate ( astr, bstr );
} }
static char ** get_ssh ( unsigned int *length ) static char ** get_ssh ( unsigned int *length )
{ {

View file

@ -40,6 +40,7 @@
#include "rofi.h" #include "rofi.h"
#include "textbox.h" #include "textbox.h"
#include <glib.h>
#define SIDE_MARGIN 2 #define SIDE_MARGIN 2
@ -132,8 +133,12 @@ void textbox_text ( textbox *tb, char *text )
if ( tb->text ) { if ( tb->text ) {
free ( tb->text ); free ( tb->text );
} }
if ( g_utf8_validate ( text, -1, NULL ) ) {
tb->text = strdup ( text ); tb->text = strdup ( text );
}
else {
tb->text = strdup ( "Invalid UTF-8 string." );
}
pango_layout_set_text ( tb->layout, tb->text, strlen ( tb->text ) ); pango_layout_set_text ( tb->layout, tb->text, strlen ( tb->text ) );
tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( text ), tb->cursor ) ); tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( text ), tb->cursor ) );
@ -206,7 +211,7 @@ void textbox_free ( textbox *tb )
if ( tb->text ) { if ( tb->text ) {
free ( tb->text ); free ( tb->text );
} }
if ( tb->layout == NULL ) { if ( tb->layout != NULL ) {
g_object_unref ( tb->layout ); g_object_unref ( tb->layout );
} }
@ -272,17 +277,6 @@ void textbox_draw ( textbox *tb )
XFreePixmap ( display, canvas ); 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 // cursor handling for edit mode
void textbox_cursor ( textbox *tb, int pos ) void textbox_cursor ( textbox *tb, int pos )
{ {
@ -292,16 +286,17 @@ void textbox_cursor ( textbox *tb, int pos )
// move right // move right
void textbox_cursor_inc ( textbox *tb ) 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 // move left
void textbox_cursor_dec ( textbox *tb ) 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 // end of line
void textbox_cursor_end ( textbox *tb ) void textbox_cursor_end ( textbox *tb )
{ {
@ -337,8 +332,8 @@ void textbox_delete ( textbox *tb, int pos, int dlen )
// delete on character // delete on character
void textbox_cursor_del ( textbox *tb ) void textbox_cursor_del ( textbox *tb )
{ {
int del_r = nextrune ( tb, 1 ); int index = g_utf8_next_char ( &( tb->text[tb->cursor] ) ) - tb->text;
textbox_delete ( tb, tb->cursor, del_r - tb->cursor ); textbox_delete ( tb, tb->cursor, index - tb->cursor );
} }
// back up and delete one character // back up and delete one character
@ -370,46 +365,46 @@ int textbox_keypress ( textbox *tb, XEvent *ev )
// Left or Ctrl-b // Left or Ctrl-b
if ( key == XK_Left || if ( key == XK_Left ||
(( ev->xkey.state&ControlMask) && key == XK_b) ) { ( ( ev->xkey.state & ControlMask ) && key == XK_b ) ) {
textbox_cursor_dec ( tb ); textbox_cursor_dec ( tb );
return 1; return 1;
} }
// Right or Ctrl-F // Right or Ctrl-F
else if ( key == XK_Right || else if ( key == XK_Right ||
(( ev->xkey.state&ControlMask) && key == XK_f) ) { ( ( ev->xkey.state & ControlMask ) && key == XK_f ) ) {
textbox_cursor_inc ( tb ); textbox_cursor_inc ( tb );
return 1; return 1;
} }
// Delete or Ctrl-D // Delete or Ctrl-D
else if ( key == XK_Delete || else if ( key == XK_Delete ||
(( ev->xkey.state&ControlMask) && key == XK_d) ) { ( ( ev->xkey.state & ControlMask ) && key == XK_d ) ) {
textbox_cursor_del ( tb ); textbox_cursor_del ( tb );
return 1; return 1;
} }
// Ctrl-U: Kill from the beginning to the end of the line. // Ctrl-U: Kill from the beginning to the end of the line.
else if ( ( ev->xkey.state&ControlMask) && key == XK_u) { else if ( ( ev->xkey.state & ControlMask ) && key == XK_u ) {
textbox_text( tb, ""); textbox_text ( tb, "" );
return 1; return 1;
} }
// Ctrl-A // Ctrl-A
else if ( ( ev->xkey.state&ControlMask) && key == XK_a) { else if ( ( ev->xkey.state & ControlMask ) && key == XK_a ) {
textbox_cursor ( tb, 0 ); textbox_cursor ( tb, 0 );
return 1; return 1;
} }
// Ctrl-E // Ctrl-E
else if ( ( ev->xkey.state&ControlMask) && key == XK_e) { else if ( ( ev->xkey.state & ControlMask ) && key == XK_e ) {
textbox_cursor_end ( tb ); textbox_cursor_end ( tb );
return 1; return 1;
} }
// BackSpace, Ctrl-h // BackSpace, Ctrl-h
else if ( key == XK_BackSpace || else if ( key == XK_BackSpace ||
(( ev->xkey.state&ControlMask) && key == XK_h) ) { ( ( ev->xkey.state & ControlMask ) && key == XK_h ) ) {
textbox_cursor_bkspc ( tb ); textbox_cursor_bkspc ( tb );
return 1; return 1;
} }
else if ( key == XK_Return || key == XK_KP_Enter || else if ( key == XK_Return || key == XK_KP_Enter ||
((ev->xkey.state&ControlMask) && key == XK_j) || ( ( ev->xkey.state & ControlMask ) && key == XK_j ) ||
((ev->xkey.state&ControlMask) && key == XK_m)) { ( ( ev->xkey.state & ControlMask ) && key == XK_m ) ) {
return -1; return -1;
} }
else if ( !iscntrl ( *pad ) ) { else if ( !iscntrl ( *pad ) ) {