diff options
| author | Jari Vetoniemi <mailroxas@gmail.com> | 2014-04-10 23:05:13 +0300 | 
|---|---|---|
| committer | Jari Vetoniemi <mailroxas@gmail.com> | 2014-04-10 23:05:13 +0300 | 
| commit | 71beb7583f6cba2eb8070d5a05dcdf05b54f52bf (patch) | |
| tree | b10e0c65d9cabd1e36d4798ba094f84c5ef99df1 /lib | |
| parent | 45e21171593050aedc92b1da44d0441e4a734a1b (diff) | |
| download | bemenu-71beb7583f6cba2eb8070d5a05dcdf05b54f52bf.tar.gz bemenu-71beb7583f6cba2eb8070d5a05dcdf05b54f52bf.tar.bz2 bemenu-71beb7583f6cba2eb8070d5a05dcdf05b54f52bf.zip | |
Make it possible filter manually, and optimized filtering.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/bemenu.h | 11 | ||||
| -rw-r--r-- | lib/filter.c | 27 | ||||
| -rw-r--r-- | lib/internal.h | 9 | ||||
| -rw-r--r-- | lib/menu.c | 103 | 
4 files changed, 96 insertions, 54 deletions
| diff --git a/lib/bemenu.h b/lib/bemenu.h index 4534966..6348693 100644 --- a/lib/bemenu.h +++ b/lib/bemenu.h @@ -319,6 +319,17 @@ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb);  void bmMenuRender(const bmMenu *menu);  /** + * Trigger filtering of menu manually. + * This is useful when adding new items and want to dynamically see them filtered. + * + * Do note that filtering might be heavy, so you should only call it after batch manipulation of items. + * Not after manipulation of each single item. + * + * @param menu bmMenu instance which to filter. + */ +void bmMenuFilter(bmMenu *menu); + +/**   * Poll key and unicode from underlying UI toolkit.   *   * This function will block on @link ::bmDrawMode BM_DRAW_MODE_CURSES @endlink draw mode. diff --git a/lib/filter.c b/lib/filter.c index 7e87b11..c8cbfff 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -76,12 +76,13 @@ fail:   * Dmenu filterer that accepts substring function.   *   * @param menu bmMenu instance to filter. + * @param addition This will be 1, if filter is same as previous filter with something appended.   * @param fstrstr Substring function used to match items.   * @param outNmemb unsigned int reference to filtered items outNmemb.   * @param outHighlighted unsigned int reference to new outHighlighted item index.   * @return Pointer to array of bmItem pointers.   */ -bmItem** _bmFilterDmenuFun(bmMenu *menu, char* (*fstrstr)(const char *a, const char *b), unsigned int *outNmemb, unsigned int *outHighlighted) +bmItem** _bmFilterDmenuFun(bmMenu *menu, char addition, char* (*fstrstr)(const char *a, const char *b), unsigned int *outNmemb, unsigned int *outHighlighted)  {      assert(menu);      assert(outNmemb); @@ -89,7 +90,13 @@ bmItem** _bmFilterDmenuFun(bmMenu *menu, char* (*fstrstr)(const char *a, const c      *outNmemb = *outHighlighted = 0;      unsigned int itemsCount; -    bmItem **items = bmMenuGetItems(menu, &itemsCount); +    bmItem **items; + +    if (addition) { +        items = bmMenuGetFilteredItems(menu, &itemsCount); +    } else { +        items = bmMenuGetItems(menu, &itemsCount); +    }      bmItem **filtered = calloc(itemsCount, sizeof(bmItem*));      if (!filtered) @@ -99,6 +106,7 @@ bmItem** _bmFilterDmenuFun(bmMenu *menu, char* (*fstrstr)(const char *a, const c      unsigned int tokc;      char *buffer = _bmFilterTokenize(menu, &tokv, &tokc); +    char found = 0;      unsigned int i, f;      for (f = i = 0; i < itemsCount; ++i) {          bmItem *item = items[i]; @@ -112,8 +120,11 @@ bmItem** _bmFilterDmenuFun(bmMenu *menu, char* (*fstrstr)(const char *a, const c                  continue;          } -        if (f == 0 || item == bmMenuGetHighlightedItem(menu)) +        if (!found && item == bmMenuGetHighlightedItem(menu)) {              *outHighlighted = f; +            found = 1; +        } +          filtered[f++] = item;      } @@ -130,26 +141,28 @@ bmItem** _bmFilterDmenuFun(bmMenu *menu, char* (*fstrstr)(const char *a, const c   * Filter that mimics the vanilla dmenu filtering.   *   * @param menu bmMenu instance to filter. + * @param addition This will be 1, if filter is same as previous filter with something appended.   * @param outNmemb unsigned int reference to filtered items outNmemb.   * @param outHighlighted unsigned int reference to new outHighlighted item index.   * @return Pointer to array of bmItem pointers.   */ -bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) +bmItem** _bmFilterDmenu(bmMenu *menu, char addition, unsigned int *outNmemb, unsigned int *outHighlighted)  { -    return _bmFilterDmenuFun(menu, strstr, outNmemb, outHighlighted); +    return _bmFilterDmenuFun(menu, addition, strstr, outNmemb, outHighlighted);  }  /**   * Filter that mimics the vanilla case-insensitive dmenu filtering.   *   * @param menu bmMenu instance to filter. + * @param addition This will be 1, if filter is same as previous filter with something appended.   * @param outNmemb unsigned int reference to filtered items outNmemb.   * @param outHighlighted unsigned int reference to new outHighlighted item index.   * @return Pointer to array of bmItem pointers.   */ -bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) +bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, char addition, unsigned int *outNmemb, unsigned int *outHighlighted)  { -    return _bmFilterDmenuFun(menu, _bmStrupstr, outNmemb, outHighlighted); +    return _bmFilterDmenuFun(menu, addition, _bmStrupstr, outNmemb, outHighlighted);  }  /* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/lib/internal.h b/lib/internal.h index 043c906..985d366 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -103,6 +103,11 @@ struct _bmMenu {      char filter[1024];      /** +     * Used as optimization. +     */ +    char *oldFilter; + +    /**       * Current byte offset on filter text.       */      unsigned int cursor; @@ -136,8 +141,8 @@ int _bmDrawCursesInit(struct _bmRenderApi *api);  int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item);  /* filter.c */ -bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted); -bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted); +bmItem** _bmFilterDmenu(bmMenu *menu, char addition, unsigned int *outNmemb, unsigned int *outHighlighted); +bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, char addition, unsigned int *outNmemb, unsigned int *outHighlighted);  /* list.c */  void _bmItemListFreeList(struct _bmItemList *list); @@ -7,27 +7,11 @@  /**   * Filter function map.   */ -static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) = { +static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, char addition, unsigned int *outNmemb, unsigned int *outHighlighted) = {      _bmFilterDmenu, /* BM_FILTER_DMENU */      _bmFilterDmenuCaseInsensitive /* BM_FILTER_DMENU_CASE_INSENSITIVE */  }; -static void _bmMenuFilter(bmMenu *menu) -{ -    assert(menu); - -    if (!strlen(menu->filter) || !menu->items.list || menu->items.count <= 0) { -        _bmItemListFreeList(&menu->filtered); -        return; -    } - -    unsigned int count, selected; -    bmItem **filtered = filterFunc[menu->filterMode](menu, &count, &selected); - -    _bmItemListSetItemsNoCopy(&menu->filtered, filtered, count); -    menu->index = selected; -} -  int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item)  {      assert(menu); @@ -87,6 +71,9 @@ void bmMenuFree(bmMenu *menu)      if (menu->title)          free(menu->title); +    if (menu->oldFilter) +        free(menu->oldFilter); +      bmMenuFreeItems(menu);      free(menu);  } @@ -138,12 +125,7 @@ void* bmMenuGetUserdata(bmMenu *menu)  void bmMenuSetFilterMode(bmMenu *menu, bmFilterMode mode)  {      assert(menu); - -    bmFilterMode oldMode = mode;      menu->filterMode = (mode >= BM_FILTER_MODE_LAST ? BM_FILTER_MODE_DMENU : mode); - -    if (oldMode != mode) -        _bmMenuFilter(menu);  }  /** @@ -202,13 +184,7 @@ const char* bmMenuGetTitle(const bmMenu *menu)  int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index)  {      assert(menu); - -    int ret = _bmItemListAddItemAt(&menu->items, item, index); - -    if (ret) -        _bmMenuFilter(menu); - -    return ret; +    return _bmItemListAddItemAt(&menu->items, item, index);  }  /** @@ -220,12 +196,7 @@ int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index)   */  int bmMenuAddItem(bmMenu *menu, bmItem *item)  { -    int ret = _bmItemListAddItem(&menu->items, item); - -    if (ret) -        _bmMenuFilter(menu); - -    return ret; +    return _bmItemListAddItem(&menu->items, item);  }  /** @@ -250,7 +221,6 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index)      if (ret) {          _bmItemListRemoveItem(&menu->selection, item);          _bmItemListRemoveItem(&menu->filtered, item); -        _bmMenuFilter(menu);      }      return ret; @@ -274,7 +244,6 @@ int bmMenuRemoveItem(bmMenu *menu, bmItem *item)      if (ret) {          _bmItemListRemoveItem(&menu->selection, item);          _bmItemListRemoveItem(&menu->filtered, item); -        _bmMenuFilter(menu);      }      return ret; @@ -393,7 +362,6 @@ int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb)      if (ret) {          _bmItemListFreeList(&menu->selection);          _bmItemListFreeList(&menu->filtered); -        _bmMenuFilter(menu);      }      return ret; @@ -448,6 +416,57 @@ void bmMenuRender(const bmMenu *menu)  }  /** + * Trigger filtering of menu manually. + * This is useful when adding new items and want to dynamically see them filtered. + * + * Do note that filtering might be heavy, so you should only call it after batch manipulation of items. + * Not after manipulation of each single item. + * + * @param menu bmMenu instance which to filter. + */ +void bmMenuFilter(bmMenu *menu) +{ +    assert(menu); + +    char addition = 0; +    size_t len = strlen(menu->filter); + +    if (!len || !menu->items.list || menu->items.count <= 0) { +        _bmItemListFreeList(&menu->filtered); + +        if (menu->oldFilter) +            free(menu->oldFilter); + +        menu->oldFilter = NULL; +        return; +    } + +    if (menu->oldFilter) { +        size_t oldLen = strlen(menu->oldFilter); +        addition = (oldLen < len && !memcmp(menu->oldFilter, menu->filter, oldLen)); +    } + +    if (menu->oldFilter && addition && menu->filtered.count <= 0) +        return; + +    if (menu->oldFilter && !strcmp(menu->filter, menu->oldFilter)) +        return; + +    unsigned int count, selected; +    bmItem **filtered = filterFunc[menu->filterMode](menu, addition, &count, &selected); + +    _bmItemListSetItemsNoCopy(&menu->filtered, filtered, count); +    menu->index = selected; + +    if (count) { +        if (menu->oldFilter) +            free(menu->oldFilter); + +        menu->oldFilter = _bmStrdup(menu->filter); +    } +} + +/**   * Poll key and unicode from underlying UI toolkit.   *   * This function will block on @link ::bmDrawMode BM_DRAW_MODE_CURSES @endlink draw mode. @@ -485,8 +504,6 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)      unsigned int itemsCount;      bmMenuGetFilteredItems(menu, &itemsCount); -    char *oldFilter = _bmStrdup(menu->filter); -      switch (key) {          case BM_KEY_LEFT:              { @@ -619,11 +636,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)          default: break;      } -    if (oldFilter && strcmp(oldFilter, menu->filter)) -        _bmMenuFilter(menu); - -    if (oldFilter) -        free(oldFilter); +    bmMenuFilter(menu);      switch (key) {          case BM_KEY_RETURN: return BM_RUN_RESULT_SELECTED; | 
