Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package bemenu for openSUSE:Factory checked in at 2022-12-16 17:52:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/bemenu (Old) and /work/SRC/openSUSE:Factory/.bemenu.new.1835 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "bemenu" Fri Dec 16 17:52:14 2022 rev:18 rq:1043312 version:0.6.14 Changes: -------- --- /work/SRC/openSUSE:Factory/bemenu/bemenu.changes 2022-10-11 18:04:55.106023567 +0200 +++ /work/SRC/openSUSE:Factory/.bemenu.new.1835/bemenu.changes 2022-12-16 17:52:19.492239968 +0100 @@ -1,0 +2,9 @@ +Fri Dec 16 10:12:42 UTC 2022 - Michael Vetter <[email protected]> + +- Update to 0.6.14: + * Add basic vim bindings #314 + * Make pkg-config configurable #316 + * improve exit code docs #320 + * Fix --filter #322 + +------------------------------------------------------------------- Old: ---- bemenu-0.6.13.tar.gz New: ---- bemenu-0.6.14.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ bemenu.spec ++++++ --- /var/tmp/diff_new_pack.sFzp31/_old 2022-12-16 17:52:19.928242368 +0100 +++ /var/tmp/diff_new_pack.sFzp31/_new 2022-12-16 17:52:19.936242411 +0100 @@ -18,7 +18,7 @@ %define bcond_with curses Name: bemenu -Version: 0.6.13 +Version: 0.6.14 Release: 0 Summary: Dynamic menu library and client program inspired by dmenu License: MIT ++++++ bemenu-0.6.13.tar.gz -> bemenu-0.6.14.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/GNUmakefile new/bemenu-0.6.14/GNUmakefile --- old/bemenu-0.6.13/GNUmakefile 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/GNUmakefile 2022-12-16 01:15:13.000000000 +0100 @@ -4,6 +4,7 @@ bindir ?= /bin libdir ?= /lib mandir ?= /share/man/man1 +PKG_CONFIG ?= pkg-config GIT_SHA1 = $(shell git rev-parse HEAD 2>/dev/null || printf 'nogit') GIT_TAG = $(shell git tag --points-at HEAD 2>/dev/null || cat VERSION) @@ -64,18 +65,18 @@ util.a: lib/util.c lib/internal.h libbemenu.so: private override LDLIBS += -ldl -libbemenu.so: lib/bemenu.h lib/internal.h lib/filter.c lib/item.c lib/library.c lib/list.c lib/menu.c util.a cdl.a +libbemenu.so: lib/bemenu.h lib/internal.h lib/filter.c lib/item.c lib/library.c lib/list.c lib/menu.c lib/vim.c util.a cdl.a -bemenu-renderer-curses.so: private override LDLIBS += $(shell pkg-config --libs ncursesw) -lm -bemenu-renderer-curses.so: private override CPPFLAGS += $(shell pkg-config --cflags-only-I ncursesw) +bemenu-renderer-curses.so: private override LDLIBS += $(shell $(PKG_CONFIG) --libs ncursesw) -lm +bemenu-renderer-curses.so: private override CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I ncursesw) bemenu-renderer-curses.so: lib/renderers/curses/curses.c util.a -bemenu-renderer-x11.so: private override LDLIBS += $(shell pkg-config --libs x11 xinerama cairo pango pangocairo) -bemenu-renderer-x11.so: private override CPPFLAGS += $(shell pkg-config --cflags-only-I x11 xinerama cairo pango pangocairo) +bemenu-renderer-x11.so: private override LDLIBS += $(shell $(PKG_CONFIG) --libs x11 xinerama cairo pango pangocairo) +bemenu-renderer-x11.so: private override CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I x11 xinerama cairo pango pangocairo) bemenu-renderer-x11.so: lib/renderers/cairo_renderer.h lib/renderers/x11/x11.c lib/renderers/x11/x11.h lib/renderers/x11/window.c lib/renderers/x11/xkb_unicode.c lib/renderers/x11/xkb_unicode.h util.a lib/renderers/wayland/xdg-shell.c: - wayland-scanner private-code < "$$(pkg-config --variable=pkgdatadir wayland-protocols)/stable/xdg-shell/xdg-shell.xml" > $@ + wayland-scanner private-code < "$$($(PKG_CONFIG) --variable=pkgdatadir wayland-protocols)/stable/xdg-shell/xdg-shell.xml" > $@ lib/renderers/wayland/wlr-layer-shell-unstable-v1.h: lib/renderers/wayland/wlr-layer-shell-unstable-v1.xml wayland-scanner client-header < $^ > $@ @@ -90,16 +91,16 @@ wayland-scanner private-code < $^ > $@ xdg-shell.a: private override LDFLAGS += -fPIC -xdg-shell.a: private override CPPFLAGS += $(shell pkg-config --cflags-only-I wayland-client) +xdg-shell.a: private override CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I wayland-client) xdg-shell.a: lib/renderers/wayland/xdg-shell.c wlr-layer-shell.a: private override LDFLAGS += -fPIC -wlr-layer-shell.a: private override CPPFLAGS += $(shell pkg-config --cflags-only-I wayland-client) +wlr-layer-shell.a: private override CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I wayland-client) wlr-layer-shell.a: lib/renderers/wayland/wlr-layer-shell-unstable-v1.c lib/renderers/wayland/wlr-layer-shell-unstable-v1.h xdg-output.a: private override LDFLAGS += -fPIC -xdg-output.a: private override CPPFLAGS += $(shell pkg-config --cflags-only-I wayland-client) +xdg-output.a: private override CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I wayland-client) xdg-output.a: lib/renderers/wayland/xdg-output-unstable-v1.c lib/renderers/wayland/xdg-output-unstable-v1.h -bemenu-renderer-wayland.so: private override LDLIBS += $(shell pkg-config --libs wayland-client cairo pango pangocairo xkbcommon) -bemenu-renderer-wayland.so: private override CPPFLAGS += $(shell pkg-config --cflags-only-I wayland-client cairo pango pangocairo xkbcommon) +bemenu-renderer-wayland.so: private override LDLIBS += $(shell $(PKG_CONFIG) --libs wayland-client cairo pango pangocairo xkbcommon) +bemenu-renderer-wayland.so: private override CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I wayland-client cairo pango pangocairo xkbcommon) bemenu-renderer-wayland.so: lib/renderers/cairo_renderer.h lib/renderers/wayland/wayland.c lib/renderers/wayland/wayland.h lib/renderers/wayland/registry.c lib/renderers/wayland/window.c xdg-shell.a wlr-layer-shell.a xdg-output.a util.a common.a: client/common/common.c client/common/common.h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/README.md new/bemenu-0.6.14/README.md --- old/bemenu-0.6.13/README.md 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/README.md 2022-12-16 01:15:13.000000000 +0100 @@ -112,7 +112,7 @@ ## Keybindings - +### Default Bindings | Key | Binding | |---------------------|----------------------------------------------------------------| | Left Arrow | Move cursor left | @@ -159,6 +159,51 @@ | Ctrl + m | Execute selected item | | Ctrl + y | Paste clipboard | +### Vim Bindings +Vim bindings can be activated via the `--binding vim` option. All bindings are in vim +`normal` mode. When bemenu is started with vim bindings it will be in `insert` mode. By +pressing `escape`, `normal` mode can be activated. + +**Note**: The default bindings can still be used for actions that do not have a separate +vim binding such as launching a program or pasting. + +| Key | Binding | +|-------|-----------------------------------------------| +| j/n | Goto next item | +| k/p | Goto previous item | +| h | Move cursor left | +| l | Move cursor right | +| q | Quit bemenu | +| v | Toggle item selection | +| i | Enter insert mode | +| I | Move to line start and enter insert mode | +| a | Move to the right and enter insert mode | +| A | Move to line end and enter insert mode | +| w | Move a word | +| b | Move a word backwards | +| e | Move to end of word | +| x | Delete a character | +| X | Delete a character before the cursor | +| 0 | Move to line start | +| $ | Move to line end | +| gg | Goto first item | +| G | Goto last item | +| H | Goto first item in view | +| M | Goto middle item in view | +| L | Goto last item in view | +| F | Scroll one page of items down | +| B | Scroll one page of items up | +| dd | Delete the whole line | +| dw | Delete a word | +| db | Delete a word backwards | +| d0 | Delete to start of line | +| d$ | Delete to end of line | +| cc | Change the whole line | +| cw | Change a word | +| cb | Change a word backwards | +| c0 | Change to start of line | +| c$ | Change to end of line | + ## Projects using bemenu * [pinentry-bemenu](https://github.com/t-8ch/pinentry-bemenu) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/VERSION new/bemenu-0.6.14/VERSION --- old/bemenu-0.6.13/VERSION 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/VERSION 2022-12-16 01:15:13.000000000 +0100 @@ -1 +1 @@ -0.6.13 +0.6.14 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/client/common/common.c new/bemenu-0.6.14/client/common/common.c --- old/bemenu-0.6.13/client/common/common.c 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/client/common/common.c 2022-12-16 01:15:13.000000000 +0100 @@ -181,6 +181,7 @@ " -C, --no-cursor ignore cursor events.\n" " -T, --no-touch ignore touch events.\n" " -K, --no-keyboard ignore keyboard events.\n" + " --binding use alternative key bindings. Available options: vim\n" " --scrollbar display scrollbar. (none (default), always, autohide)\n" " --accept-single immediately return if there is only one item.\n" " --ifne only display menu if there are items.\n" @@ -308,6 +309,7 @@ { "scb", required_argument, 0, 0x114 }, { "scf", required_argument, 0, 0x115 }, { "bdr", required_argument, 0, 0x121 }, + { "binding", required_argument, 0, 0x128 }, { "disco", no_argument, 0, 0x116 }, { 0, 0, 0, 0 } @@ -320,7 +322,7 @@ for (optind = 0;;) { int32_t opt; - if ((opt = getopt_long(*argc, *argv, "hviwxcl:I:p:P:I:bfm:H:M:W:B:nsCTK", opts, NULL)) < 0) + if ((opt = getopt_long(*argc, *argv, "hviwxcl:I:p:P:I:bfF:m:H:M:W:B:nsCTK", opts, NULL)) < 0) break; switch (opt) { @@ -479,6 +481,13 @@ case 0x121: client->colors[BM_COLOR_BORDER] = optarg; break; + case 0x128: + if(strcmp(optarg, "vim") == 0){ + client->key_binding = BM_KEY_BINDING_VIM; + } else { + client->key_binding = BM_KEY_BINDING_DEFAULT; + } + break; case 0x116: disco(); @@ -534,6 +543,7 @@ bm_menu_set_password(menu, client->password); bm_menu_set_width(menu, client->hmargin_size, client->width_factor); bm_menu_set_border_size(menu, client->border_size); + bm_menu_set_key_binding(menu, client->key_binding); if (client->center) { bm_menu_set_align(menu, BM_ALIGN_CENTER); @@ -559,6 +569,10 @@ enum bm_run_result run_menu(const struct client *client, struct bm_menu *menu, void (*item_cb)(const struct client *client, struct bm_item *item)) { + bm_menu_set_highlighted_index(menu, client->selected); + bm_menu_grab_keyboard(menu, true); + bm_menu_set_filter(menu, client->initial_filter); + { uint32_t total_item_count; struct bm_item **items = bm_menu_get_items(menu, &total_item_count); @@ -574,10 +588,6 @@ } - bm_menu_set_highlighted_index(menu, client->selected); - bm_menu_grab_keyboard(menu, true); - bm_menu_set_filter(menu, client->initial_filter); - uint32_t unicode; enum bm_key key = BM_KEY_NONE; struct bm_pointer pointer; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/client/common/common.h new/bemenu-0.6.14/client/common/common.h --- old/bemenu-0.6.13/client/common/common.h 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/client/common/common.h 2022-12-16 01:15:13.000000000 +0100 @@ -36,6 +36,7 @@ bool force_fork, fork; bool no_exec; bool password; + enum bm_key_binding key_binding; char *monitor_name; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/lib/bemenu.h new/bemenu-0.6.14/lib/bemenu.h --- old/bemenu-0.6.13/lib/bemenu.h 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/lib/bemenu.h 2022-12-16 01:15:13.000000000 +0100 @@ -353,6 +353,16 @@ BM_COLOR_LAST }; + +/** + * Key bindings + */ +enum bm_key_binding { + BM_KEY_BINDING_DEFAULT, + BM_KEY_BINDING_VIM, +}; + + /** * @name Menu Memory * @{ */ @@ -788,6 +798,15 @@ BM_PUBLIC bool bm_menu_get_password(struct bm_menu *menu); +/** + * Specify the key bindings that should be used. + * + * @param menu bm_menu instance to set the key binding on. + * @param key_binding binding that should be used. + */ +BM_PUBLIC void bm_menu_set_key_binding(struct bm_menu *menu, enum bm_key_binding); + + /** @} Properties */ /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/lib/internal.h new/bemenu-0.6.14/lib/internal.h --- old/bemenu-0.6.13/lib/internal.h 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/lib/internal.h 2022-12-16 01:15:13.000000000 +0100 @@ -411,6 +411,17 @@ * Is the menu needing a redraw ? */ bool dirty; + + /** + * Key binding that should be used. + */ + enum bm_key_binding key_binding; + + /** + * Vim binding specific variables. + */ + char vim_mode; + uint32_t vim_last_key; }; /* library.c */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/lib/menu.c new/bemenu-0.6.14/lib/menu.c --- old/bemenu-0.6.13/lib/menu.c 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/lib/menu.c 2022-12-16 01:15:13.000000000 +0100 @@ -6,6 +6,8 @@ #include <unistd.h> #include <assert.h> +#include "vim.h" + /** * Default font. */ @@ -53,6 +55,10 @@ menu->dirty = true; + menu->key_binding = BM_KEY_BINDING_DEFAULT; + menu->vim_mode = 'i'; + menu->vim_last_key = 0; + uint32_t count; const struct bm_renderer **renderers = bm_get_renderers(&count); @@ -683,6 +689,11 @@ return list_set_items_no_copy(&menu->selection, new_items, nmemb); } +void +bm_menu_set_key_binding(struct bm_menu *menu, enum bm_key_binding key_binding){ + menu->key_binding = key_binding; +} + struct bm_item** bm_menu_get_selected_items(const struct bm_menu *menu, uint32_t *out_nmemb) { @@ -939,6 +950,20 @@ if (key != BM_KEY_NONE) menu->dirty = true; + if(menu->key_binding == BM_KEY_BINDING_VIM){ + enum bm_vim_code code = bm_vim_key_press(menu, key, unicode, count, displayed); + + switch(code){ + case BM_VIM_CONSUME: + return BM_RUN_RESULT_RUNNING; + case BM_VIM_EXIT: + list_free_list(&menu->selection); + return BM_RUN_RESULT_CANCEL; + case BM_VIM_IGNORE: + break; + } + } + switch (key) { case BM_KEY_LEFT: if (menu->filter) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/lib/renderers/wayland/wayland.c new/bemenu-0.6.14/lib/renderers/wayland/wayland.c --- old/bemenu-0.6.13/lib/renderers/wayland/wayland.c 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/lib/renderers/wayland/wayland.c 2022-12-16 01:15:13.000000000 +0100 @@ -54,7 +54,8 @@ // be(re)created. We need to do the render ASAP (not schedule it) because otherwise, // since we lack a window, we may not receive further events and will get deadlocked render_windows_if_pending(menu, wayland); - } else if (menu->dirty) { + } + if (menu->dirty) { bm_wl_window_schedule_render(window); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/lib/vim.c new/bemenu-0.6.14/lib/vim.c --- old/bemenu-0.6.13/lib/vim.c 1970-01-01 01:00:00.000000000 +0100 +++ new/bemenu-0.6.14/lib/vim.c 2022-12-16 01:15:13.000000000 +0100 @@ -0,0 +1,368 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <assert.h> + +#include "vim.h" + + +static enum bm_vim_code vim_on_first_key(struct bm_menu *menu, uint32_t unicode, uint32_t item_count, uint32_t items_displayed); +static enum bm_vim_code vim_on_second_key(struct bm_menu *menu, uint32_t unicode, uint32_t item_count, uint32_t items_displayed); + + +static void move_left(struct bm_menu *menu){ + if(menu->filter && menu->cursor > 0){ + uint32_t old_cursor = menu->cursor; + menu->cursor -= bm_utf8_rune_prev(menu->filter, menu->cursor); + menu->curses_cursor -= bm_utf8_rune_width(menu->filter + menu->cursor, old_cursor - menu->cursor); + } +} + +static void move_right(struct bm_menu *menu, size_t filter_length){ + if(menu->cursor < filter_length){ + uint32_t old_cursor = menu->cursor; + menu->cursor += bm_utf8_rune_next(menu->filter, menu->cursor); + menu->curses_cursor += bm_utf8_rune_width(menu->filter + old_cursor, menu->cursor - old_cursor); + } +} + +static void move_line_start(struct bm_menu *menu){ + menu->cursor = 0; + menu->curses_cursor = 0; +} + +static void move_line_end(struct bm_menu *menu){ + menu->cursor = (menu->filter ? strlen(menu->filter) : 0); + menu->curses_cursor = (menu->filter ? bm_utf8_string_screen_width(menu->filter) : 0); +} + +static void menu_next(struct bm_menu *menu, uint32_t count, bool wrap){ + if (menu->index < count - 1) { + bm_menu_set_highlighted_index(menu, menu->index + 1); + } else if (wrap) { + bm_menu_set_highlighted_index(menu, 0); + } +} + +static void menu_prev(struct bm_menu *menu, uint32_t count, bool wrap){ + if (menu->index > 0) { + bm_menu_set_highlighted_index(menu, menu->index - 1); + } else if (wrap) { + bm_menu_set_highlighted_index(menu, count - 1); + } +} + +static void menu_first(struct bm_menu *menu, uint32_t count){ + if(count > 0){ + bm_menu_set_highlighted_index(menu, 0); + } +} + +static void menu_last(struct bm_menu *menu, uint32_t count){ + if(count > 0){ + bm_menu_set_highlighted_index(menu, count - 1); + } +} + +static void menu_view_high(struct bm_menu *menu, uint32_t count){ + if(count > 0){ + uint32_t nth_view_item = menu->index % menu->lines; + bm_menu_set_highlighted_index(menu, menu->index - nth_view_item); + } +} + +static void menu_view_mid(struct bm_menu *menu, uint32_t count, uint32_t displayed){ + if(count > 0){ + uint32_t nth_view_item = menu->index % menu->lines; + uint32_t half_view_height = (displayed - 1) / 2; + bm_menu_set_highlighted_index(menu, menu->index - nth_view_item + half_view_height); + } +} + +static void menu_view_low(struct bm_menu *menu, uint32_t count, uint32_t displayed){ + if(count > 0){ + uint32_t nth_view_item = menu->index % menu->lines; + uint32_t view_bottom_offset = (displayed - 2) - nth_view_item; + bm_menu_set_highlighted_index(menu, menu->index + view_bottom_offset); + } +} + +static void menu_page_down(struct bm_menu *menu, uint32_t count, uint32_t displayed){ + bm_menu_set_highlighted_index(menu, (menu->index + displayed >= count ? count - 1 : menu->index + (displayed - 1))); +} + +static void menu_page_up(struct bm_menu *menu, uint32_t displayed){ + bm_menu_set_highlighted_index(menu, (menu->index < displayed ? 0 : menu->index - (displayed - 1))); +} + +static void move_word(struct bm_menu *menu){ + if(!menu->filter) return; + + size_t filter_length = strlen(menu->filter); + while (menu->cursor < filter_length && !isspace(menu->filter[menu->cursor])) move_right(menu, filter_length); + while (menu->cursor < filter_length && isspace(menu->filter[menu->cursor])) move_right(menu, filter_length); +} + +static void move_word_back(struct bm_menu *menu){ + while (menu->cursor > 0 && isspace(menu->filter[menu->cursor - 1])) move_left(menu); + while (menu->cursor > 0 && !isspace(menu->filter[menu->cursor - 1])) move_left(menu); +} + +static void move_word_end(struct bm_menu *menu){ + if(!menu->filter) return; + + size_t filter_length = strlen(menu->filter); + size_t old_cursor = menu->cursor; + size_t old_curses_cursor = menu->curses_cursor; + + while (menu->cursor < filter_length && isspace(menu->filter[menu->cursor + 1])) move_right(menu, filter_length); + while (menu->cursor < filter_length && !isspace(menu->filter[menu->cursor + 1])) move_right(menu, filter_length); + + if(menu->cursor == filter_length){ + menu->cursor = old_cursor; + menu->curses_cursor = old_curses_cursor; + } +} + +static void delete_char(struct bm_menu *menu){ + if(menu->filter){ + if(menu->cursor < strlen(menu->filter)){ + size_t width; + bm_utf8_rune_remove(menu->filter, menu->cursor + 1, &width); + } + } +} + +static void delete_char_back(struct bm_menu *menu){ + if(menu->filter){ + if(menu->cursor > 0){ + size_t width; + bm_utf8_rune_remove(menu->filter, menu->cursor, &width); + move_left(menu); + } + } +} + +static void delete_word(struct bm_menu *menu){ + if(!menu->filter) return; + + size_t filter_length = strlen(menu->filter); + while (menu->cursor < filter_length && !isspace(menu->filter[menu->cursor])) delete_char(menu); + while (menu->cursor < filter_length && isspace(menu->filter[menu->cursor])) delete_char(menu); +} + +static void delete_word_back(struct bm_menu *menu){ + while (menu->cursor > 0 && isspace(menu->filter[menu->cursor - 1])){ + move_left(menu); + delete_char(menu); + } + + while (menu->cursor > 0 && !isspace(menu->filter[menu->cursor - 1])){ + move_left(menu); + delete_char(menu); + } +} + +static void delete_line(struct bm_menu *menu){ + if(menu->filter){ + menu->filter[0] = 0; + menu->cursor = 0; + menu->curses_cursor = 0; + } +} + +static void delete_to_line_end(struct bm_menu *menu){ + if(menu->filter){ + menu->filter[menu->cursor] = 0; + } +} + +static void delete_to_line_start(struct bm_menu *menu){ + if(menu->filter){ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wrestrict" + strcpy(menu->filter, menu->filter + menu->cursor); +#pragma GCC diagnostic pop + + menu->cursor = 0; + menu->curses_cursor = 0; + } +} + +static void toggle_item_selection(struct bm_menu *menu){ + struct bm_item *highlighted = bm_menu_get_highlighted_item(menu); + if (highlighted){ + if(!bm_menu_item_is_selected(menu, highlighted)){ + list_add_item(&menu->selection, highlighted); + } else { + list_remove_item(&menu->selection, highlighted); + } + } +} + +enum bm_vim_code bm_vim_key_press(struct bm_menu *menu, enum bm_key key, uint32_t unicode, uint32_t item_count, uint32_t items_displayed){ + if(key == BM_KEY_ESCAPE && unicode == 99) return BM_VIM_EXIT; + + if(menu->vim_mode == 'n'){ + if(key == BM_KEY_ESCAPE) return BM_VIM_CONSUME; + if(unicode == 0 || unicode > 128) return BM_VIM_IGNORE; + + if(menu->vim_last_key == 0) return vim_on_first_key(menu, unicode, item_count, items_displayed); + else return vim_on_second_key(menu, unicode, item_count, items_displayed); + } else if(menu->vim_mode == 'i'){ + if(key == BM_KEY_ESCAPE && unicode == 0){ + menu->vim_mode = 'n'; + return BM_VIM_CONSUME; + } + } + + return BM_VIM_IGNORE; +} + +static enum bm_vim_code vim_on_first_key(struct bm_menu *menu, uint32_t unicode, uint32_t item_count, uint32_t items_displayed){ + size_t filter_length = 0; + + switch(unicode){ + case 'q': + return BM_VIM_EXIT; + case 'v': + toggle_item_selection(menu); + goto action_executed; + case 'i': + goto insert_action_executed; + case 'I': + move_line_start(menu); + goto insert_action_executed; + case 'a': + if(menu->filter) filter_length = strlen(menu->filter); + move_right(menu, filter_length); + goto insert_action_executed; + case 'A': + move_line_end(menu); + goto insert_action_executed; + case 'h': + move_left(menu); + goto action_executed; + case 'n': + case 'j': + menu_next(menu, item_count, menu->wrap); + goto action_executed; + case 'p': + case 'k': + menu_prev(menu, item_count, menu->wrap); + goto action_executed; + case 'l': + if(menu->filter) filter_length = strlen(menu->filter); + move_right(menu, filter_length); + goto action_executed; + case 'w': + move_word(menu); + goto action_executed; + case 'b': + move_word_back(menu); + goto action_executed; + case 'e': + move_word_end(menu); + goto action_executed; + case 'x': + delete_char(menu); + goto action_executed; + case 'X': + delete_char_back(menu); + goto action_executed; + case '0': + move_line_start(menu); + goto action_executed; + case '$': + move_line_end(menu); + goto action_executed; + case 'G': + menu_last(menu, item_count); + goto action_executed; + case 'H': + menu_view_high(menu, item_count); + goto action_executed; + case 'M': + menu_view_mid(menu, item_count, items_displayed); + goto action_executed; + case 'L': + menu_view_low(menu, item_count, items_displayed); + goto action_executed; + case 'F': + menu_page_down(menu, item_count, items_displayed); + goto action_executed; + case 'B': + menu_page_up(menu, items_displayed); + goto action_executed; + case 'c': + case 'd': + case 'g': + menu->vim_last_key = unicode; + return BM_VIM_CONSUME; + default: + menu->vim_last_key = 0; + return BM_VIM_CONSUME; + } + +insert_action_executed: + menu->vim_mode = 'i'; +action_executed: + menu->vim_last_key = 0; + return BM_VIM_CONSUME; +} + +static enum bm_vim_code vim_on_second_key(struct bm_menu *menu, uint32_t unicode, uint32_t item_count, uint32_t items_displayed){ + if(menu->vim_last_key == 'd'){ + switch(unicode){ + case 'd': + delete_line(menu); + goto action_executed; + case 'w': + delete_word(menu); + goto action_executed; + case 'b': + delete_word_back(menu); + goto action_executed; + case '$': + delete_to_line_end(menu); + goto action_executed; + case '0': + delete_to_line_start(menu); + goto action_executed; + } + } else if(menu->vim_last_key == 'c'){ + switch(unicode){ + case 'c': + delete_line(menu); + goto insert_action_executed; + case 'w': + delete_word(menu); + goto insert_action_executed; + case 'b': + delete_word_back(menu); + goto insert_action_executed; + case '$': + delete_to_line_end(menu); + goto insert_action_executed; + case '0': + delete_to_line_start(menu); + goto insert_action_executed; + } + } else if(menu->vim_last_key == 'g'){ + switch(unicode){ + case 'g': + menu_first(menu, item_count); + goto action_executed; + } + } + + return vim_on_first_key(menu, unicode, item_count, items_displayed); + +insert_action_executed: + menu->vim_mode = 'i'; +action_executed: + menu->vim_last_key = 0; + return BM_VIM_CONSUME; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/lib/vim.h new/bemenu-0.6.14/lib/vim.h --- old/bemenu-0.6.13/lib/vim.h 1970-01-01 01:00:00.000000000 +0100 +++ new/bemenu-0.6.14/lib/vim.h 2022-12-16 01:15:13.000000000 +0100 @@ -0,0 +1,14 @@ +#ifndef _VIM_H_ +#define _VIM_H_ + +#include "internal.h" + +enum bm_vim_code { + BM_VIM_CONSUME, + BM_VIM_IGNORE, + BM_VIM_EXIT +}; + +enum bm_vim_code bm_vim_key_press(struct bm_menu *menu, enum bm_key key, uint32_t unicode, uint32_t item_count, uint32_t items_displayed); + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bemenu-0.6.13/man/bemenu.1.scd.in new/bemenu-0.6.14/man/bemenu.1.scd.in --- old/bemenu-0.6.13/man/bemenu.1.scd.in 2022-10-11 07:49:11.000000000 +0200 +++ new/bemenu-0.6.14/man/bemenu.1.scd.in 2022-12-16 01:15:13.000000000 +0100 @@ -234,9 +234,13 @@ *C-y* Paste the clipboard. -*M-[0-9]* - Print selected items and exit with a custom error code. See _EXIT - STATUS_. +*M-[1-9]* + Print selected items and exit with a custom error code 10 (*M-1*) + through 18 (*M-9*), see _EXIT STATUS_. + +*M-0* + Print selected items and exit with the custom error code 19, see _EXIT + STATUS_. # ENVIRONMENT @@ -256,8 +260,15 @@ # EXIT STATUS -*bemenu* exits 0 on success, 1 if the user exited without selecting or an error, -and if exiting with a custom error code, 10 plus the number specified. +*0* + bemenu ran successfully. + +*1* + The user exited without selecting, or bemenu encountered an error. + +*10-19* + The user specified a custom exit code with *M-[0-9]*, see _KEYBOARD + COMMANDS_. # SEE ALSO
