'everything' module: added evry_fuzzy_match to replace e_util_glob_match

which also gives a weight fo the results. now the items in 'All' list are 
nicely sorted.


SVN revision: 41764
This commit is contained in:
Hannes Janetzek 2009-08-14 14:44:18 +00:00
parent 30bb106ec8
commit fbb36478cc
9 changed files with 235 additions and 196 deletions

View File

@ -32,22 +32,27 @@ struct _Plugin_Config
struct _Evry_Item
{
Evry_Plugin *plugin;
/* label to show for this item */
const char *label;
const char *uri;
const char *mime;
/* item can be browsed, e.g. folders */
Eina_Bool browseable;
/* these are only for internally use by plugins */
/* used e.g. as pointer for item data (Efreet_Desktop) or */
/* for internal stuff, like priority hints for sorting, etc */
/* used e.g. as pointer for item data (Efreet_Desktop) */
void *data[4];
/* priority hints for sorting */
int priority;
/* not to be set by plugin! */
/* store value of fuzzy match with input */
int fuzzy_match;
/* do not set by plugin! */
Evry_Plugin *plugin;
Evas_Object *o_icon;
Evas_Object *o_bg;
int ref;
@ -153,3 +158,6 @@ void evry_item_free(Evry_Item *it);
void evry_plugin_async_update(Evry_Plugin *plugin, int state);
void evry_clear_input(void);
int evry_icon_theme_set(Evas_Object *obj, const char *icon);
int evry_fuzzy_match(const char *str, const char *match);

View File

@ -10,6 +10,7 @@
*/
#define INPUTLEN 40
#define MATCH_LAG 0.33
#define MAX_FUZZ 200
typedef struct _Evry_State Evry_State;
@ -419,7 +420,7 @@ evry_plugin_async_update(Evry_Plugin *p, int action)
/* update aggregator */
if (eina_list_count(s->cur_plugins) > 1)
{
agg->fetch(agg, NULL);
agg->fetch(agg, s->input);
/* add aggregator */
if (!(s->cur_plugins->data == agg))
@ -451,6 +452,53 @@ evry_plugin_async_update(Evry_Plugin *p, int action)
}
}
int
evry_fuzzy_match(const char *str, const char *match)
{
const char *p, *m;
char mc;
unsigned int cnt = 1;
unsigned int pos = 0;
unsigned int last = 0;
if (!match || !match[0] || !str || !str[0]) return 0;
for (m = match; *m != 0; m++)
{
mc = tolower(*m);
for (p = str; *p != 0 && *m != 0; p++)
{
if (tolower(*p) == mc)
{
cnt += cnt * (pos - last);
last = pos;
m++;
mc = tolower(*m);
}
else pos++;
if (cnt > MAX_FUZZ) return 0;
if (isspace(mc) && strchr(p, ' '))
break;
}
/* search next word */
if (isspace(mc))
{
pos = last = 0;
/* add some weight */
cnt += pos;
}
else break;
}
if (*m == 0)
return cnt;
else
return 0;
}
/* local subsystem functions */
@ -1016,7 +1064,7 @@ _evry_browse_back(Evry_Selector *sel)
_evry_list_clear_list(s);
_evry_state_pop(sel);
sel->aggregator->fetch(sel->aggregator, NULL);
sel->aggregator->fetch(sel->aggregator, sel->state->input);
_evry_selector_update(sel);
_evry_list_update(sel->state);
_evry_update_text_label(sel->state);
@ -1491,7 +1539,7 @@ _evry_matches_update(Evry_Selector *sel)
if (eina_list_count(s->cur_plugins) > 1)
{
sel->aggregator->fetch(sel->aggregator, NULL);
sel->aggregator->fetch(sel->aggregator, s->input);
s->cur_plugins = eina_list_prepend(s->cur_plugins, sel->aggregator);
}
else
@ -1933,6 +1981,26 @@ _evry_list_tab_show(Evry_State *s, Evry_Plugin *p)
p->tab = o;
}
static int
_evry_fuzzy_sort_cb(const void *data1, const void *data2)
{
const Evry_Item *it1 = data1;
const Evry_Item *it2 = data2;
if (it1->fuzzy_match && !it2->fuzzy_match)
return -1;
if (!it1->fuzzy_match && it2->fuzzy_match)
return 1;
if (it1->fuzzy_match - it2->fuzzy_match)
return (it1->fuzzy_match - it2->fuzzy_match);
if (it1->plugin->config->priority - it2->plugin->config->priority)
return (it1->plugin->config->priority - it2->plugin->config->priority);
return (it1->priority - it2->priority);
}
/* action selector plugin: provides list of actions registered for
candidate types provided by current plugin */
@ -2005,40 +2073,28 @@ _evry_plug_actions_fetch(Evry_Plugin *p, const char *input)
Eina_List *l;
Evry_Item *it;
Evry_Selector *sel = selectors[1];
char match1[128];
char match2[128];
int prio;
int fuzz = 0;
if (p->items)
{
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
}
snprintf(match1, sizeof(match1), "%s*", input);
snprintf(match2, sizeof(match2), "*%s*", input);
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
EINA_LIST_FOREACH(sel->actions, l, act)
{
if (input)
{
if (e_util_glob_case_match(act->name, match1))
prio = 1;
else if (e_util_glob_case_match(act->name, match2))
prio = 2;
else prio = 0;
}
fuzz = evry_fuzzy_match(act->name, input);
if (!input || prio)
if (!input || fuzz)
{
it = evry_item_new(p, act->name, NULL);
it->priority = prio;
it->fuzzy_match = fuzz;
it->data[0] = act;
p->items = eina_list_append(p->items, it);
}
}
if (input)
p->items = eina_list_sort(p->items, eina_list_count(p->items), _evry_fuzzy_sort_cb);
if (p->items) return 1;
return 0;
@ -2106,8 +2162,9 @@ _evry_plug_aggregator_free(Evry_Plugin *p)
E_FREE(p);
}
static int
_evry_plug_aggregator_fetch(Evry_Plugin *p, const char *input __UNUSED__)
_evry_plug_aggregator_fetch(Evry_Plugin *p, const char *input)
{
Evry_Selector *selector = p->private;
Evry_State *s = selector->state;
@ -2115,6 +2172,8 @@ _evry_plug_aggregator_fetch(Evry_Plugin *p, const char *input __UNUSED__)
Evry_Plugin *plugin;
Evry_Item *it;
int cnt = 0;
int fuzzy;
Eina_List *items = NULL;
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
@ -2122,30 +2181,48 @@ _evry_plug_aggregator_fetch(Evry_Plugin *p, const char *input __UNUSED__)
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
cnt += eina_list_count(plugin->items);
if (cnt <= 100)
if (input[0])
{
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
{
EINA_LIST_FOREACH(plugin->items, ll, it)
{
_evry_item_ref(it);
p->items = eina_list_append(p->items, it);
if (!it->fuzzy_match)
it->fuzzy_match = evry_fuzzy_match(it->label, input);
if (it->fuzzy_match)
{
_evry_item_ref(it);
items = eina_list_append(items, it);
p->items = eina_list_append(p->items, it);
}
}
}
}
else
if (!input[0] || eina_list_count(items) < 20)
{
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
{
for (cnt = 0, ll = plugin->items; ll && cnt < 15; ll = ll->next, cnt++)
{
it = ll->data;
_evry_item_ref(it);
p->items = eina_list_append(p->items, it);
}
}
{
for (cnt = 0, ll = plugin->items; ll && cnt < 15; ll = ll->next, cnt++)
{
if (!items || !eina_list_data_find_list(items, ll->data))
{
it = ll->data;
_evry_item_ref(it);
it->fuzzy_match = 0;
p->items = eina_list_append(p->items, it);
}
}
}
}
eina_list_free(items);
if (input[0])
p->items = eina_list_sort(p->items, eina_list_count(p->items), _evry_fuzzy_sort_cb);
return 1;
}

View File

@ -177,37 +177,21 @@ _item_add(Evry_Plugin *p, Efreet_Desktop *desktop, char *file, int prio)
}
static void
_add_desktop_list(Evry_Plugin *p, Eina_List *apps, char *m1, char *m2)
_add_desktop_list(Evry_Plugin *p, Eina_List *apps, const char *input)
{
Efreet_Desktop *desktop;
Eina_List *l;
int fuzz;
EINA_LIST_FOREACH(apps, l, desktop)
{
if (eina_list_count(p->items) > 99) continue;
if (eina_list_count(p->items) > 199) continue;
if (!desktop || !desktop->name || !desktop->exec) continue;
if (e_util_glob_case_match(desktop->exec, m1))
_item_add(p, desktop, NULL, 1);
else if (e_util_glob_case_match(desktop->name, m1))
_item_add(p, desktop, NULL, 1);
}
EINA_LIST_FOREACH(apps, l, desktop)
{
if (eina_list_count(p->items) > 99) continue;
if (!desktop || !desktop->name || !desktop->exec) continue;
if (e_util_glob_case_match(desktop->exec, m2))
_item_add(p, desktop, NULL, 2);
else if (e_util_glob_case_match(desktop->name, m2))
_item_add(p, desktop, NULL, 2);
/* else if (desktop->comment)
* {
* if (e_util_glob_case_match(desktop->comment, m1))
* _item_add(p, desktop, NULL, 3);
* else if (e_util_glob_case_match(desktop->comment, m2))
* _item_add(p, desktop, NULL, 4);
* } */
if (fuzz = evry_fuzzy_match(desktop->exec, input))
_item_add(p, desktop, NULL, fuzz);
else if (fuzz = evry_fuzzy_match(desktop->name, input))
_item_add(p, desktop, NULL, fuzz);
}
}
@ -264,37 +248,47 @@ _fetch(Evry_Plugin *p, const char *input)
_list_free(p);
if (input)
{
snprintf(match1, sizeof(match1), "%s*", input);
snprintf(match2, sizeof(match2), "*%s*", input);
}
/* add apps for a given mimetype */
if (p->type == type_action)
{
if (input)
{
_add_desktop_list(p, inst->apps_mime, match1, match2);
_add_desktop_list(p, inst->apps_mime, input);
}
else
{
EINA_LIST_FOREACH(inst->apps_mime, l, desktop)
_item_add(p, desktop, NULL, 1);
}
if (input)
EINA_LIST_FOREACH(p->items, l, it)
it->priority += 2;
}
/* add apps matching input */
if (input)
{
if (!inst->apps_all)
inst->apps_all = efreet_util_desktop_name_glob_list("*");
{
Eina_List *apps = NULL;
Eina_List *stuff;
Eina_List *l, *ll;
_add_desktop_list(p, inst->apps_all, match1, match2);
apps = efreet_util_desktop_name_glob_list("*");
stuff = efreet_util_desktop_category_list("Screensaver");
EINA_LIST_FOREACH(stuff, l, desktop)
{
ll = eina_list_data_find_list(apps, desktop);
if (ll)
{
efreet_desktop_free(desktop);
apps = eina_list_remove_list(apps, ll);
}
/* efreet_desktop_free(desktop); */
}
inst->apps_all = apps;
}
_add_desktop_list(p, inst->apps_all, input);
}
/* add exe history items */
else if (!p->items)
@ -362,7 +356,11 @@ _fetch(Evry_Plugin *p, const char *input)
if (p->items)
{
int prio;
p->items = eina_list_sort(p->items, eina_list_count(p->items), _cb_sort);
EINA_LIST_FOREACH(p->items, l, it)
it->priority = prio++;
return 1;
}

View File

@ -20,7 +20,7 @@ _item_free(Evry_Item *it)
}
static void
_item_add(Evry_Plugin *p, E_Border *bd, int prio)
_item_add(Evry_Plugin *p, E_Border *bd, int fuzz, int *prio)
{
Evry_Item *it;
@ -28,7 +28,10 @@ _item_add(Evry_Plugin *p, E_Border *bd, int prio)
e_object_ref(E_OBJECT(bd));
it->data[0] = bd;
it->priority = prio;
it->fuzzy_match = fuzz;
it->priority = *prio;
*prio = *prio - 1;
p->items = eina_list_append(p->items, it);
}
@ -37,10 +40,11 @@ _item_add(Evry_Plugin *p, E_Border *bd, int prio)
static int
_cb_sort(const void *data1, const void *data2)
{
const Evry_Item *it1, *it2;
const Evry_Item *it1 = data1;
const Evry_Item *it2 = data2;
it1 = data1;
it2 = data2;
if (it1->fuzzy_match - it2->fuzzy_match)
return (it1->fuzzy_match - it2->fuzzy_match);
return (it1->priority - it2->priority);
}
@ -50,54 +54,41 @@ _fetch(Evry_Plugin *p, const char *input)
{
E_Manager *man;
E_Zone *zone;
char m1[128];
char m2[128];
E_Border *bd;
E_Border_List *bl;
int fuzz;
int prio = 0;
_cleanup(p);
man = e_manager_current_get();
zone = e_util_zone_current_get(man);
if (input)
{
snprintf(m1, sizeof(m1), "%s*", input);
snprintf(m2, sizeof(m2), "*%s*", input);
}
bl = e_container_border_list_first(e_container_current_get(man));
while ((bd = e_container_border_list_next(bl)))
{
if (zone == bd->zone)
{
if (!input)
_item_add(p, bd, 1);
else if (bd->client.icccm.name &&
e_util_glob_case_match(bd->client.icccm.name, m1))
_item_add(p, bd, 1);
else if (e_util_glob_case_match(e_border_name_get(bd), m1))
_item_add(p, bd, 1);
else if (bd->client.icccm.name &&
e_util_glob_case_match(bd->client.icccm.name, m2))
_item_add(p, bd, 2);
else if (e_util_glob_case_match(e_border_name_get(bd), m2))
_item_add(p, bd, 2);
_item_add(p, bd, 0, &prio);
else if ((bd->client.icccm.name) &&
(fuzz = evry_fuzzy_match(bd->client.icccm.name, input)))
_item_add(p, bd, fuzz, &prio);
else if ((fuzz = evry_fuzzy_match(e_border_name_get(bd), input)))
_item_add(p, bd, fuzz, &prio);
else if (bd->desktop)
{
if (e_util_glob_case_match(bd->desktop->name, m1))
_item_add(p, bd, 1);
else if (e_util_glob_case_match(bd->desktop->name, m2))
_item_add(p, bd, 2);
if ((fuzz = evry_fuzzy_match(bd->desktop->name, input)))
_item_add(p, bd, fuzz, &prio);
}
}
}
e_container_border_list_free(bl);
if (eina_list_count(p->items) > 0)
if (p->items)
{
p->items = eina_list_sort(p->items, eina_list_count(p->items), _cb_sort);
return 1;
}

View File

@ -76,12 +76,10 @@ _begin(Evry_Plugin *p __UNUSED__, const Evry_Item *item)
static int
_cb_sort(const void *data1, const void *data2)
{
const Evry_Item *it1, *it2;
const Evry_Item *it1 = data1;
const Evry_Item *it2 = data2;
it1 = data1;
it2 = data2;
return (it1->priority - it2->priority);
return (it1->fuzzy_match - it2->fuzzy_match);
}
static void
@ -91,27 +89,20 @@ _item_free(Evry_Item *it)
}
static void
_item_add(Evry_Plugin *p, const char *label, void (*action_cb) (E_Border *bd), const char *icon, char *m1, char *m2)
_item_add(Evry_Plugin *p, const char *label, void (*action_cb) (E_Border *bd), const char *icon, const char *input)
{
Evry_Item *it;
int prio = 1;
int fuzz = 1;
if (m1[0] && m2[0])
{
if (e_util_glob_case_match(label, m1))
prio = 1;
else if (e_util_glob_case_match(label, m2))
prio = 2;
else
prio = 0;
}
if (input)
fuzz = evry_fuzzy_match(label, input);
if (!prio) return;
if (!fuzz) return;
it = evry_item_new(p, label, &_item_free);
it->data[0] = action_cb;
it->data[1] = (void *) eina_stringshare_add(icon);
it->priority = prio;
it->fuzzy_match = fuzz;
p->items = eina_list_prepend(p->items, it);
}
@ -126,37 +117,23 @@ _cleanup(Evry_Plugin *p)
}
static int
_fetch(Evry_Plugin *p, const char *input __UNUSED__)
_fetch(Evry_Plugin *p, const char *input)
{
char m1[128];
char m2[128];
_cleanup(p);
if (input)
{
snprintf(m1, sizeof(m1), "%s*", input);
snprintf(m2, sizeof(m2), "*%s*", input);
}
else
{
m1[0] = 0;
m2[0] = 0;
}
_item_add(p, _("Switch To"), _act_cb_border_switch_to, "go-next", m1, m2);
_item_add(p, _("Switch To"), _act_cb_border_switch_to, "go-next", input);
if (inst->border->iconic)
_item_add(p, _("Uniconify"), _act_cb_border_unminimize, "window-minimize", m1, m2);
_item_add(p, _("Uniconify"), _act_cb_border_unminimize, "window-minimize", input);
else
_item_add(p, _("Iconify"), _act_cb_border_minimize, "window-minimize", m1, m2);
_item_add(p, _("Iconify"), _act_cb_border_minimize, "window-minimize", input);
if (!inst->border->fullscreen)
_item_add(p, _("Fullscreen"), _act_cb_border_fullscreen, "view-fullscreen", m1, m2);
_item_add(p, _("Fullscreen"), _act_cb_border_fullscreen, "view-fullscreen", input);
else
_item_add(p, _("Unfullscreen"), _act_cb_border_fullscreen, "view-restore", m1, m2);
_item_add(p, _("Unfullscreen"), _act_cb_border_fullscreen, "view-restore", input);
_item_add(p, _("Close"), _act_cb_border_close, "window-close", m1, m2);
_item_add(p, _("Close"), _act_cb_border_close, "window-close", input);
if (eina_list_count(p->items) > 0)
{

View File

@ -56,6 +56,12 @@ _cleanup(Evry_Plugin *p)
Evry_Item *it;
int items = 10;
if (p->items)
{
evry_item_free(p->items->data);
p->items = eina_list_remove_list(p->items, p->items);
}
EINA_LIST_FREE(p->items, it)
{
if (items-- > 0)

View File

@ -14,13 +14,14 @@ _cleanup(Evry_Plugin *p)
}
static void
_item_add(Evry_Plugin *p, E_Configure_It *eci, int prio)
_item_add(Evry_Plugin *p, E_Configure_It *eci, int fuzz, int prio)
{
Evry_Item *it;
it = evry_item_new(p, eci->label, NULL);
it->data[0] = eci;
it->priority = prio;
it->fuzzy_match = fuzz;
p->items = eina_list_append(p->items, it);
}
@ -28,46 +29,38 @@ _item_add(Evry_Plugin *p, E_Configure_It *eci, int prio)
static int
_cb_sort(const void *data1, const void *data2)
{
const Evry_Item *it1, *it2;
const Evry_Item *it1 = data1;
const Evry_Item *it2 = data2;
it1 = data1;
it2 = data2;
if (it1->fuzzy_match - it2->fuzzy_match)
return (it1->fuzzy_match - it2->fuzzy_match);
/* TODO sort by name? */
return (it1->priority - it2->priority);
}
static int
_fetch(Evry_Plugin *p, const char *input)
{
char match1[128];
char match2[128];
Eina_List *l, *ll;
E_Configure_Cat *ecat;
E_Configure_It *eci;
int fuzz;
_cleanup(p);
snprintf(match1, sizeof(match1), "%s*", input);
snprintf(match2, sizeof(match2), "*%s*", input);
EINA_LIST_FOREACH(e_configure_registry, l, ecat)
{
if ((ecat->pri < 0) || (!ecat->items)) continue;
if (!strcmp(ecat->cat, "system")) continue;
EINA_LIST_FOREACH(ecat->items, ll, eci)
{
if (eci->pri >= 0)
{
if (e_util_glob_case_match(eci->label, match1))
_item_add(p, eci, 1);
else if (e_util_glob_case_match(eci->label, match2))
_item_add(p, eci, 2);
else if (e_util_glob_case_match(ecat->label, match1))
_item_add(p, eci, 3);
else if (e_util_glob_case_match(ecat->label, match2))
_item_add(p, eci, 4);
if (fuzz = evry_fuzzy_match(eci->label, input))
_item_add(p, eci, fuzz, 0);
else if (fuzz = evry_fuzzy_match(ecat->label, input))
_item_add(p, eci, fuzz, 1);
}
}
}
@ -116,7 +109,7 @@ _action(Evry_Action *act, const Evry_Item *it, const Evry_Item *it2 __UNUSED__,
EINA_LIST_FOREACH(e_configure_registry, l, ecat)
{
if (found) break;
EINA_LIST_FOREACH(ecat->items, ll, eci2)
{
if (eci == eci2)

View File

@ -77,15 +77,19 @@ _item_fill(Evry_Item *it)
static int
_cb_sort(const void *data1, const void *data2)
{
const Evry_Item *it1, *it2;
const Evry_Item *it1 = data1;
const Evry_Item *it2 = data2;
it1 = data1;
it2 = data2;
if (it1->browseable && !it2->browseable)
return -1;
if (it2->priority - it1->priority)
return (it2->priority - it1->priority);
else
return strcasecmp(it1->label, it2->label);
if (!it1->browseable && it2->browseable)
return 1;
if (it1->fuzzy_match - it2->fuzzy_match)
return (it1->fuzzy_match - it2->fuzzy_match);
return strcasecmp(it1->label, it2->label);
}
static int
@ -111,8 +115,6 @@ _dirbrowse_idler(void *data)
if (!s->command)
{
/* evry_plugin_async_update(p, EVRY_ASYNC_UPDATE_CLEAR); */
if (eina_list_count(p->items) > 0)
{
p->items = eina_list_sort(p->items, eina_list_count(p->items), _cb_sort);
@ -240,8 +242,6 @@ _fetch(Evry_Plugin *p, const char *input)
{
Evry_Item *it;
Eina_List *l;
char match1[4096];
char match2[4096];
int cnt = 0;
State *s = ((Eina_List *)p->private)->data;
@ -316,21 +316,15 @@ _fetch(Evry_Plugin *p, const char *input)
s->command = EINA_FALSE;
}
if (input)
{
snprintf(match1, sizeof(match1), "%s*", input);
snprintf(match2, sizeof(match2), "*%s*", input);
}
EINA_LIST_FOREACH(s->items, l, it)
{
if (input)
{
if (e_util_glob_case_match(it->label, match1))
it->priority = 1 + (it->browseable ? 1 : 0);
else if (e_util_glob_case_match(it->label, match2))
it->priority = (it->browseable ? 1 : 0);
else it = NULL;
int fuzz;
if ((fuzz = evry_fuzzy_match(it->label, input)))
it->priority = fuzz;
else
it = NULL;
}
if (it)

View File

@ -96,6 +96,7 @@ _item_add(Evry_Plugin *p, char *file, char *mime, int prio)
{
it->browseable = EINA_TRUE;
it->mime = eina_stringshare_add("x-directory/normal");
it->priority = 1;
}
else
it->mime = eina_stringshare_add(mime);
@ -205,8 +206,6 @@ _dbus_cb_reply(void *data, DBusMessage *msg, DBusError *error)
}
else if (inst->items && inst->input)
{
char input[128];
char *pos = input;
int len_matched = strlen(inst->matched);
int len_input = strlen(inst->input);
Eina_List *l;
@ -215,12 +214,8 @@ _dbus_cb_reply(void *data, DBusMessage *msg, DBusError *error)
{
p->items = NULL;
snprintf(input, 128, "*%s*", inst->input + len_matched);
for (; *pos != '\0'; pos++)
if (isspace(*pos)) *pos = '*';
EINA_LIST_FOREACH(inst->items, l, it)
if (e_util_glob_case_match(it->label, input))
if (evry_fuzzy_match(it->label, (inst->input + len_matched)))
p->items = eina_list_append(p->items, it);
if (inst->matched)