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__
#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;

View file

@ -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;
}
}

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 *bstr = *( const char * const * ) b;
return strcasecmp ( astr, bstr );
return g_utf8_collate ( astr, bstr );
}
static char ** get_ssh ( unsigned int *length )
{

View file

@ -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 ) ) {