Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding support structure for :bind command, allowing users to specify…

… their

own keybindings.

Still needs testing, though this is a simple addition.
  • Loading branch information...
commit 4af6f273d4379409833fed7999312600355e34d3 1 parent 07c5395
@ryanflannery authored
View
106 config.h
@@ -24,112 +24,6 @@ playmode DEFAULT_PLAYER_MODE = PLAYER_MODE_LOOP;
char *DEFAULT_PLAYER_PATH = "/usr/local/bin/mplayer";
char *DEFAULT_PLAYER_ARGS[] = { "mplayer", "-slave", "-idle", "-quiet", "-msglevel", "cplayer=0:ao=0:vo=0:decaudio=0:decvideo=0:demuxer=0", NULL };
-/*
- * XXX IMPORTANT NOTE:
- * If you're having problems with the keybindings on your platform, most
- * likely it's because the key-mappings below between "CONTROL+x" are
- * different on your system. I'm trying to find a better way of mapping
- * these, but ncurses(3) does not appear to be able to handle these (via
- * keypad(3) or any other mechanism) in some reasonable fashion.
- * Thoughts? Investigate further... TODO
- */
-
-#define K_TAB 9
-#define K_ENTER 13
-#define K_CNTRL_B 2
-#define K_CNTRL_C 3
-#define K_CNTRL_D 4
-#define K_CNTRL_E 5
-#define K_CNTRL_F 6
-#define K_CNTRL_L 12
-#define K_CNTRL_P 16
-#define K_CNTRL_R 18
-#define K_CNTRL_U 21
-#define K_CNTRL_Y 25
-#define K_CNTRL_SLASH 28
-
-
-/*
- * List of keybindings. See input_handlers.h for relevant structs.
- * Each function listed here is in input_handlers.*
- */
-#define ARG_NOT_USED { .num = 0 }
-
-const keybinding KeyBindings[] = {
- { K_CNTRL_C, quit_vitunes, ARG_NOT_USED },
- { K_CNTRL_SLASH, quit_vitunes, ARG_NOT_USED },
-
- { K_ENTER, load_or_play, ARG_NOT_USED },
- { 'm', show_file_info, ARG_NOT_USED },
- { K_CNTRL_P, pause_playback, ARG_NOT_USED },
- { 'z', pause_playback, ARG_NOT_USED },
- { 's', stop_playback, ARG_NOT_USED },
- { '[', seek_playback, { .direction = BACKWARDS, .scale = SECONDS, .num = 10 }},
- { ']', seek_playback, { .direction = FORWARDS, .scale = SECONDS, .num = 10 }},
- { 'b', seek_playback, { .direction = BACKWARDS, .scale = SECONDS, .num = 10 }},
- { 'f', seek_playback, { .direction = FORWARDS, .scale = SECONDS, .num = 10 }},
- { '{', seek_playback, { .direction = BACKWARDS, .scale = MINUTES, .num = 1 }},
- { '}', seek_playback, { .direction = FORWARDS, .scale = MINUTES, .num = 1 }},
- { 'B', seek_playback, { .direction = BACKWARDS, .scale = MINUTES, .num = 1 }},
- { 'F', seek_playback, { .direction = FORWARDS, .scale = MINUTES, .num = 1 }},
-
- { K_TAB, switch_focus, ARG_NOT_USED },
- { K_CNTRL_L, redraw, ARG_NOT_USED },
-
- { 'j', scroll_row, { .direction = DOWN }},
- { KEY_DOWN, scroll_row, { .direction = DOWN }},
- { 'k', scroll_row, { .direction = UP }},
- { KEY_UP, scroll_row, { .direction = UP }},
- { '-', scroll_row, { .direction = UP }},
-
- { 'h', scroll_col, { .direction = LEFT, .amount = SINGLE }},
- { KEY_LEFT, scroll_col, { .direction = LEFT, .amount = SINGLE }},
- { KEY_BACKSPACE, scroll_col, { .direction = LEFT, .amount = SINGLE }},
- { 'l', scroll_col, { .direction = RIGHT, .amount = SINGLE }},
- { KEY_RIGHT, scroll_col, { .direction = RIGHT, .amount = SINGLE }},
- { ' ', scroll_col, { .direction = RIGHT, .amount = SINGLE }},
- { '$', scroll_col, { .direction = RIGHT, .amount = WHOLE }},
- { '^', scroll_col, { .direction = LEFT, .amount = WHOLE }},
- { '0', scroll_col, { .direction = LEFT, .amount = WHOLE }},
- { '|', scroll_col, { .direction = LEFT, .amount = WHOLE }},
-
- { K_CNTRL_E, scroll_page, { .direction = DOWN, .amount = SINGLE }},
- { K_CNTRL_Y, scroll_page, { .direction = UP, .amount = SINGLE }},
- { K_CNTRL_U, scroll_page, { .direction = UP, .amount = HALF }},
- { K_CNTRL_D, scroll_page, { .direction = DOWN, .amount = HALF }},
- { K_CNTRL_B, scroll_page, { .direction = UP, .amount = WHOLE }},
- { KEY_PPAGE, scroll_page, { .direction = UP, .amount = WHOLE }},
- { K_CNTRL_F, scroll_page, { .direction = DOWN, .amount = WHOLE }},
- { KEY_NPAGE, scroll_page, { .direction = DOWN, .amount = WHOLE }},
-
- { 'g', jumpto_file, { .scale = NUMBER, .num = 'g' }},
- { 'G', jumpto_file, { .scale = NUMBER, .num = 'G' }},
- { '%', jumpto_file, { .scale = PERCENT }},
-
- { 'H', jumpto_page, { .placement = TOP }},
- { 'M', jumpto_page, { .placement = MIDDLE }},
- { 'L', jumpto_page, { .placement = BOTTOM }},
-
- { 'y', yank, ARG_NOT_USED },
- { 'd', cut, ARG_NOT_USED },
- { 'p', paste, { .placement = AFTER }},
- { 'P', paste, { .placement = BEFORE }},
- { 'u', undo, ARG_NOT_USED },
- { K_CNTRL_R, redo, ARG_NOT_USED },
-
- { '/', search, { .direction = FORWARDS }},
- { '?', search, { .direction = BACKWARDS }},
- { 'n', search_find, { .direction = SAME }},
- { 'N', search_find, { .direction = OPPOSITE }},
-
- { ':', enter_cmd_mode, ARG_NOT_USED },
- { '!', external_command, ARG_NOT_USED }
-};
-const int KeyBindingsSize = (sizeof(KeyBindings) / sizeof(keybinding));
-
-#define ExecuteKeyBinding(i) \
- ((KeyBindings[(i)].func)(KeyBindings[(i)].args))
-
/*
* List of command-mode commands. See input_handlers.h for cmd struct.
View
24 enums.h
@@ -9,14 +9,22 @@
typedef enum {
UP, DOWN,
LEFT, RIGHT,
- TOP, MIDDLE, BOTTOM,
- SINGLE, HALF, PAGE, WHOLE,
- BEFORE, AFTER,
- FORWARDS, BACKWARDS,
- SECONDS, MINUTES,
- NUMBER, PERCENT,
+ BACKWARDS, FORWARDS,
SAME, OPPOSITE
-} venum;
-/* vitunes enum */
+} Direction;
+
+typedef enum {
+ SECONDS, MINUTES,
+ NUMBER, PERCENT
+} Scale;
+
+typedef enum {
+ SINGLE, HALF, WHOLE
+} Amount;
+
+typedef enum {
+ TOP, MIDDLE, BOTTOM,
+ BEFORE, AFTER
+} Placement;
#endif
View
1,476 keybindings.c
@@ -16,417 +16,426 @@
#include "keybindings.h"
-/*****************************************************************************
- * for working with number read from user for keybindings
- ****************************************************************************/
-int _global_input_num = 0;
-
-void gnum_clear()
-{ _global_input_num = 0; }
-
-int gnum_get()
-{ return _global_input_num; }
-
-void gnum_set(int x)
-{ _global_input_num = x; }
-
-void gnum_add(int x)
-{
- _global_input_num = _global_input_num * 10 + x;
-}
-
-
-/*****************************************************************************
- * for working with active search direction
- ****************************************************************************/
-venum _global_search_dir = FORWARDS;
-
-venum search_dir_get()
-{ return _global_search_dir; }
-
-void search_dir_set(venum dir)
-{ _global_search_dir = dir; }
+/* This table maps KeyActions to their string representations */
+typedef struct {
+ KeyAction action;
+ char *name;
+} KeyActionName;
+
+const KeyActionName KeyActionNames[] = {
+ { scroll_up, "scroll_up" },
+ { scroll_down, "scroll_down" },
+ { scroll_up_page, "scroll_up_page" },
+ { scroll_down_page, "scroll_down_page" },
+ { scroll_up_halfpage, "scroll_up_halfpage" },
+ { scroll_down_halfpage, "scroll_down_halfpage" },
+ { scroll_up_wholepage, "scroll_up_wholepage" },
+ { scroll_down_wholepage, "scroll_down_wholepage" },
+ { scroll_left, "scroll_left" },
+ { scroll_right, "scroll_right" },
+ { scroll_leftmost, "scroll_leftmost" },
+ { scroll_rightmost, "scroll_rightmost" },
+ { jumpto_screen_top, "jumpto_screen_top" },
+ { jumpto_screen_middle, "jumpto_screen_middle" },
+ { jumpto_screen_bottom, "jumpto_screen_bottom" },
+ { jumpto_line, "jumpto_line" },
+ { jumpto_percent, "jumpto_percent" },
+ { search_forward, "search_forward" },
+ { search_backward, "search_backward" },
+ { find_next_forward, "find_next_forward" },
+ { find_next_backward, "find_next_backward" },
+ { cut, "cut" },
+ { yank, "yank" },
+ { paste_after, "paste_after" },
+ { paste_before, "paste_before" },
+ { undo, "undo" },
+ { redo, "redo" },
+ { quit, "quit" },
+ { redraw, "redraw" },
+ { command_mode, "command_mode" },
+ { shell, "shell" },
+ { switch_windows, "switch_window" },
+ { show_file_info, "show_file_info" },
+ { load_playlist, "load_playlist" },
+ { media_play, "media_play" },
+ { media_pause, "media_pause" },
+ { media_stop, "media_stop" },
+ { seek_forward_seconds, "seek_forward_seconds" },
+ { seek_backward_seconds, "seek_backward_seconds" },
+ { seek_forward_minutes, "seek_forward_minutes" },
+ { seek_backward_minutes, "seek_backward_minutes" }
+};
+const int KeyActionNamesSize = sizeof(KeyActionNames) / sizeof(KeyActionName);
+
+
+/* This table maps KeyActions to their handler-functions (with arguments) */
+typedef struct {
+ KeyAction action;
+ void (*handler)(KbaArgs);
+ KbaArgs args;
+} KeyActionHandler;
+
+#define ARG_NOT_USED { .num = 0 }
+const KeyActionHandler KeyActionHandlers[] = {
+ { scroll_up, kba_scroll_row, { .direction = UP }},
+ { scroll_down, kba_scroll_row, { .direction = DOWN }},
+ { scroll_up_page, kba_scroll_page, { .direction = UP, .amount = SINGLE }},
+ { scroll_down_page, kba_scroll_page, { .direction = DOWN, .amount = SINGLE }},
+ { scroll_up_halfpage, kba_scroll_page, { .direction = UP, .amount = HALF }},
+ { scroll_down_halfpage, kba_scroll_page, { .direction = DOWN, .amount = HALF }},
+ { scroll_up_wholepage, kba_scroll_page, { .direction = UP, .amount = WHOLE }},
+ { scroll_down_wholepage, kba_scroll_page, { .direction = DOWN, .amount = WHOLE }},
+ { scroll_left, kba_scroll_col, { .direction = LEFT, .amount = SINGLE }},
+ { scroll_right, kba_scroll_col, { .direction = RIGHT, .amount = SINGLE }},
+ { scroll_leftmost, kba_scroll_col, { .direction = LEFT, .amount = WHOLE }},
+ { scroll_rightmost, kba_scroll_col, { .direction = RIGHT, .amount = WHOLE }},
+ { jumpto_screen_top, kba_jumpto_screen,{ .placement = TOP }},
+ { jumpto_screen_middle, kba_jumpto_screen,{ .placement = MIDDLE }},
+ { jumpto_screen_bottom, kba_jumpto_screen,{ .placement = BOTTOM }},
+ { jumpto_line, kba_jumpto_file, { .scale = NUMBER }},
+ { jumpto_percent, kba_jumpto_file, { .scale = PERCENT }},
+ { search_forward, kba_search, { .direction = FORWARDS }},
+ { search_backward, kba_search, { .direction = BACKWARDS }},
+ { find_next_forward, kba_search_find, { .direction = SAME }},
+ { find_next_backward, kba_search_find, { .direction = OPPOSITE }},
+ { cut, kba_cut, ARG_NOT_USED },
+ { yank, kba_yank, ARG_NOT_USED },
+ { paste_after, kba_paste, { .placement = AFTER }},
+ { paste_before, kba_paste, { .placement = BEFORE }},
+ { undo, kba_undo, ARG_NOT_USED },
+ { redo, kba_redo, ARG_NOT_USED },
+ { quit, kba_quit, ARG_NOT_USED },
+ { redraw, kba_redraw, ARG_NOT_USED },
+ { command_mode, kba_command_mode, ARG_NOT_USED },
+ { shell, kba_shell, ARG_NOT_USED },
+ { switch_windows, kba_switch_windows, ARG_NOT_USED },
+ { show_file_info, kba_show_file_info, ARG_NOT_USED },
+ { load_playlist, kba_load_playlist, ARG_NOT_USED },
+ { media_play, kba_play, ARG_NOT_USED },
+ { media_pause, kba_pause, ARG_NOT_USED },
+ { media_stop, kba_stop, ARG_NOT_USED },
+ { seek_forward_seconds, kba_seek, { .direction = FORWARDS, .scale = SECONDS, .num = 10 }},
+ { seek_backward_seconds, kba_seek, { .direction = BACKWARDS, .scale = SECONDS, .num = 10 }},
+ { seek_forward_minutes, kba_seek, { .direction = FORWARDS, .scale = MINUTES, .num = 1 }},
+ { seek_backward_minutes, kba_seek, { .direction = BACKWARDS, .scale = MINUTES, .num = 1 }}
+};
+const int KeyActionHandlersSize = sizeof(KeyActionHandlers) / sizeof(KeyActionHandler);
+
+
+/* This table contains the default keybindings */
+typedef struct {
+ KeyCode key;
+ KeyAction action;
+} KeyBinding;
+
+#define MY_K_TAB 9
+#define MY_K_ENTER 13
+#define kb_CONTROL(x) (x - 'a' + 1)
+
+const KeyBinding DefaultKeyBindings[] = {
+ { 'k', scroll_up },
+ { '-', scroll_up },
+ { KEY_UP, scroll_up },
+ { 'j', scroll_down },
+ { KEY_DOWN, scroll_down },
+ { kb_CONTROL('y'), scroll_up_page },
+ { kb_CONTROL('e'), scroll_down_page },
+ { kb_CONTROL('u'), scroll_up_halfpage },
+ { kb_CONTROL('d'), scroll_down_halfpage },
+ { kb_CONTROL('b'), scroll_up_wholepage },
+ { KEY_PPAGE, scroll_up_wholepage },
+ { kb_CONTROL('f'), scroll_down_wholepage },
+ { KEY_NPAGE, scroll_down_wholepage },
+ { 'h', scroll_left },
+ { KEY_LEFT, scroll_left },
+ { KEY_BACKSPACE, scroll_left },
+ { 'l', scroll_right },
+ { KEY_RIGHT, scroll_right },
+ { ' ', scroll_right },
+ { '^', scroll_leftmost },
+ { '0', scroll_leftmost },
+ { '|', scroll_leftmost },
+ { '$', scroll_rightmost },
+ { 'H', jumpto_screen_top },
+ { 'M', jumpto_screen_middle },
+ { 'L', jumpto_screen_bottom },
+ { 'G', jumpto_line },
+ { '%', jumpto_percent },
+ { '/', search_forward },
+ { '?', search_backward },
+ { 'n', find_next_forward },
+ { 'N', find_next_backward },
+ { 'd', cut },
+ { 'y', yank },
+ { 'p', paste_after },
+ { 'P', paste_before },
+ { 'u', undo },
+ { kb_CONTROL('r'), redo },
+ { kb_CONTROL('c'), quit },
+ { kb_CONTROL('/'), quit },
+ { kb_CONTROL('l'), redraw },
+ { ':', command_mode },
+ { '!', shell },
+ { MY_K_TAB, switch_windows },
+ { 'm', show_file_info },
+ { MY_K_ENTER, load_playlist },
+ { MY_K_ENTER, media_play },
+ { 'z', media_pause },
+ { 's', media_stop },
+ { 'f', seek_forward_seconds },
+ { 'b', seek_backward_seconds },
+ { 'F', seek_forward_minutes },
+ { 'B', seek_backward_minutes }
+};
+const int DefaultKeyBindingsSize = sizeof(DefaultKeyBindings) / sizeof(KeyBinding);
+
+
+/*
+ * This is the actual keybinding table mapping KeyCodes to actions. It is
+ * loaded at initial runtime (kb_init()), and modified thereafter, either via
+ * "bind" commands in the config file or issued during runtime.
+ */
+KeyBinding *KeyBindings;
+int KeyBindingsSize;
-/*****************************************************************************
- * functions for working with yank/cut buffer
+/****************************************************************************
+ *
+ * Routines for initializing, free'ing, manipulating,
+ * and retrieving keybindings.
+ *
****************************************************************************/
- /* the global yank/copy bufer */
-yank_buffer _yank_buffer;
-
void
-ybuffer_init()
+kb_init()
{
- _yank_buffer.files = calloc(YANK_BUFFER_CHUNK_SIZE, sizeof(meta_info*));
- if (_yank_buffer.files == NULL)
- err(1, "ybuffer_init: calloc(3) failed");
-
- _yank_buffer.capacity = YANK_BUFFER_CHUNK_SIZE;
- _yank_buffer.nfiles = 0;
-}
+ int i;
-void
-ybuffer_clear()
-{
- _yank_buffer.nfiles = 0;
+ KeyBindingsSize = 0;
+ for (i = 0; i < DefaultKeyBindingsSize; i++)
+ kb_bind(DefaultKeyBindings[i].action, DefaultKeyBindings[i].key);
}
void
-ybuffer_free()
+kb_free()
{
- free(_yank_buffer.files);
- _yank_buffer.capacity = 0;
- _yank_buffer.nfiles = 0;
+ free(KeyBindings);
+ KeyBindingsSize = 0;
}
void
-ybuffer_add(meta_info *f)
+kb_bind(KeyAction action, KeyCode key)
{
- meta_info **new_buff;
- int new_capacity;
-
- /* do we need to realloc()? */
- if (_yank_buffer.nfiles == _yank_buffer.capacity) {
- _yank_buffer.capacity += YANK_BUFFER_CHUNK_SIZE;
- new_capacity = _yank_buffer.capacity * sizeof(meta_info*);
- if ((new_buff = realloc(_yank_buffer.files, new_capacity)) == NULL)
- err(1, "ybuffer_add: realloc(3) failed [%i]", new_capacity);
-
- _yank_buffer.files = new_buff;
+ size_t nbytes;
+ int i, match;
+
+ /* Is the key already bound? */
+ match = -1;
+ for (i = 0; i < KeyBindingsSize; i++) {
+ if (KeyBindings[i].key == key) {
+ KeyBindings[i].action = action;
+ return;
+ }
}
- /* add the file */
- _yank_buffer.files[ _yank_buffer.nfiles++ ] = f;
-}
-
-
-/*****************************************************************************
- * misc. handy stuff used frequently
- ****************************************************************************/
+ /* No. Add it. */
+ nbytes = (KeyBindingsSize + 1) * sizeof(KeyBinding);
+ if ((KeyBindings = realloc(KeyBindings, nbytes)) == NULL)
+ err(1, "%s: realloc(3) failed", __FUNCTION__);
-void
-redraw_active()
-{
- if (ui.active == ui.library)
- paint_library();
- else
- paint_playlist();
+ KeyBindings[KeyBindingsSize].action = action;
+ KeyBindings[KeyBindingsSize].key = key;
+ KeyBindingsSize++;
}
-/*
- * Given string input from user (argv[0]) and a command name, check if the
- * input matches the command name, taking into acount '!' weirdness and
- * abbreviations.
- */
bool
-match_command_name(const char *input, const char *cmd)
+kb_execute(KeyCode k)
{
- bool found;
- char *icopy;
+ KeyAction action;
+ int i;
- if (input == NULL || strlen(input) == 0)
- return false;
+ action = NULL;
+ for (i = 0; i < KeyBindingsSize; i++) {
+ if (KeyBindings[i].key == k)
+ action = KeyBindings[i].action;
+ }
- if (strcmp(input, cmd) == 0)
- return true;
+ if (action == NULL)
+ return false;
- /* check for '!' weirdness and abbreviations */
+ for (i = 0; i < KeyActionHandlersSize; i++) {
+ if (KeyActionHandlers[i].action == action) {
+ ((KeyActionHandlers[i].handler)(KeyActionHandlers[i].args));
+ return true;
+ }
+ }
- if ((icopy = strdup(input)) == NULL)
- err(1, "match_command_name: strdup(3) failed");
+ return false;
+}
- /* remove '!' from input, if present */
- if (strstr(icopy, "!") != NULL)
- *strstr(icopy, "!") = '\0';
+bool
+kb_is_action(char *s)
+{
+ int i;
- /* now check against command & abbreviation */
- if (strstr(cmd, icopy) == cmd)
- found = true;
- else
- found = false;
+ for (i = 0; i < KeyActionNamesSize; i++) {
+ if (strcasecmp(KeyActionNames[i].name, s) == 0)
+ return true;
+ }
- free(icopy);
- return found;
+ return false;
}
-void
-execute_external_command(const char *cmd)
+KeyAction
+kb_str2action(char *s)
{
- def_prog_mode();
- endwin();
+ int i;
- system(cmd);
- printf("\nPress ENTER to continue");
- fflush(stdout);
- while (getchar() != '\n');
+ for (i = 0; i < KeyActionNamesSize; i++) {
+ if (strcasecmp(KeyActionNames[i].name, s) == 0)
+ return KeyActionNames[i].action;
+ }
- reset_prog_mode();
- paint_all();
+ return -1;
}
+
/*****************************************************************************
- * keybinding handlers
+ *
+ * Individual Keybinding Handlers
+ *
****************************************************************************/
void
-quit_vitunes(Args a UNUSED)
-{
- VSIG_QUIT = 1;
-}
-
-void
-load_or_play(Args a UNUSED)
+kba_scroll_row(KbaArgs a)
{
- Args dummy;
- int idx;
-
- if (ui.active == ui.library) {
- /* load playlist & switch focus */
- idx = ui.library->voffset + ui.library->crow;
- viewing_playlist = mdb.playlists[idx];
- ui.playlist->nrows = mdb.playlists[idx]->nfiles;
- ui.playlist->crow = 0;
- ui.playlist->voffset = 0;
- ui.playlist->hoffset = 0;
+ int n = gnum_retrieve();
- paint_playlist();
- switch_focus(dummy);
- } else {
- /* play song */
- if (ui.active->crow >= ui.active->nrows) {
- paint_message("no file here");
- return;
- }
- player_set_queue(viewing_playlist, ui.active->voffset + ui.active->crow);
- playing_playlist = viewing_playlist;
- player_play();
+ /* update current row */
+ switch (a.direction) {
+ case DOWN:
+ ui.active->crow += n;
+ break;
+ case UP:
+ ui.active->crow -= n;
+ break;
+ default:
+ errx(1, "%s: invalid direction", __FUNCTION__);
}
-}
-
-void
-show_file_info(Args a UNUSED)
-{
- int idx;
-
- if (ui.active == ui.library)
- return;
- if (ui.active->crow >= ui.active->nrows) {
- paint_message("no file here");
- return;
+ /* handle off-the-edge cases */
+ if (ui.active->crow < 0) {
+ swindow_scroll(ui.active, UP, -1 * ui.active->crow);
+ ui.active->crow = 0;
}
- if (showing_file_info)
- paint_playlist();
- else {
- /* get file index and show */
- idx = ui.active->voffset + ui.active->crow;
- paint_playlist_file_info(viewing_playlist->files[idx]);
+ if (ui.active->voffset + ui.active->crow >= ui.active->nrows)
+ ui.active->crow = ui.active->nrows - ui.active->voffset - 1;
+
+ if (ui.active->crow >= ui.active->h) {
+ swindow_scroll(ui.active, DOWN, ui.active->crow - ui.active->h + 1);
+ ui.active->crow = ui.active->h - 1;
}
-}
-void
-pause_playback(Args a UNUSED)
-{
- player_pause();
-}
+ if (ui.active->crow < 0)
+ ui.active->crow = 0;
-void
-stop_playback(Args a UNUSED)
-{
- player_stop();
- playing_playlist = NULL;
+ /* redraw */
+ redraw_active();
+ paint_status_bar();
}
void
-seek_playback(Args a)
+kba_scroll_page(KbaArgs a)
{
- int n, secs;
+ bool maintain_row_idx;
+ int voffset_original;
+ int max_row;
+ int diff;
+ int n;
- /* determine number of seconds to seek */
- switch (a.scale) {
- case SECONDS:
- secs = a.num;
- break;
- case MINUTES:
- secs = a.num * 60;
- break;
- default:
- errx(1, "seek_playback: invalid scale");
- }
+ voffset_original = ui.active->voffset;
- /* adjust for direction */
- switch (a.direction) {
- case FORWARDS:
- /* no change */
- break;
- case BACKWARDS:
- secs *= -1;
- break;
- default:
- errx(1, "seek_playback: invalid direction");
- }
+ /* determine max row number */
+ if (ui.active->voffset + ui.active->h >= ui.active->nrows)
+ max_row = ui.active->nrows - ui.active->voffset - 1;
+ else
+ max_row = ui.active->h - 1;
- /* is there a multiplier? */
+ /* determine how many pages to scroll */
n = 1;
if (gnum_get() > 0) {
n = gnum_get();
gnum_clear();
}
- /* apply n & seek */
- player_seek(secs * n);
-}
-
-void
-switch_focus(Args a UNUSED)
-{
- if (ui.active == ui.library) {
- ui.active = ui.playlist;
- if (ui.lhide) {
- ui_hide_library();
- paint_all();
- }
- } else {
- ui.active = ui.library;
- if (ui.lhide) {
- ui_unhide_library();
- paint_all();
- }
+ /* determine how much crow should change */
+ switch (a.amount) {
+ case SINGLE:
+ diff = 1 * n;
+ maintain_row_idx = true;
+ break;
+ case HALF:
+ diff = (ui.active->h / 2) * n;
+ maintain_row_idx = false;
+ break;
+ case WHOLE:
+ diff = ui.active->h * n;
+ maintain_row_idx = false;
+ break;
+ default:
+ errx(1, "scroll_page: invalid amount");
}
+ swindow_scroll(ui.active, a.direction, diff);
- paint_status_bar();
-}
+ /* handle updating the current row */
+ if (maintain_row_idx) {
-void
-redraw(Args a UNUSED)
-{
- ui_clear();
- paint_all();
-}
+ if (a.direction == DOWN)
+ ui.active->crow -= diff;
+ else
+ ui.active->crow += diff;
-void
-enter_cmd_mode(Args a UNUSED)
-{
- const char *errmsg = NULL;
- char *cmd;
- char **argv;
- int argc;
- int num_matches;
- bool found;
- int found_idx = 0;
- int i;
+ /* handle off-the-edge cases */
+ if (ui.active->crow < 0)
+ ui.active->crow = 0;
+ if (ui.active->voffset + ui.active->crow >= ui.active->nrows)
+ ui.active->crow = ui.active->nrows - ui.active->voffset - 1;
- /* get command from user */
- if (user_getstr(":", &cmd) != 0 || strlen(cmd) == 0) {
- werase(ui.command);
- wrefresh(ui.command);
- return;
- }
+ if (ui.active->crow >= ui.active->h)
+ ui.active->crow = ui.active->h - 1;
- /* check for '!' used for executing external commands */
- if (cmd[0] == '!') {
- execute_external_command(cmd + 1);
- free(cmd);
- return;
- }
+ if (ui.active->crow < 0)
+ ui.active->crow = 0;
- /* convert to argc/argv structure */
- if (str2argv(cmd, &argc, &argv, &errmsg) != 0) {
- paint_error("parse error: %s in '%s'", errmsg, cmd);
- free(cmd);
- return;
- }
+ } else {
+ /*
+ * We only move current row here if there was a change this time
+ * in the vertical offset
+ */
- /* search path for appropriate command to execute */
- found = false;
- num_matches = 0;
- for (i = 0; i < CommandPathSize; i++) {
- if (match_command_name(argv[0], CommandPath[i].name)) {
- found = true;
- found_idx = i;
- num_matches++;
+ if (a.direction == DOWN
+ && ui.active->voffset == voffset_original) {
+ ui.active->crow += diff;
+ if (ui.active->crow > max_row)
+ ui.active->crow = max_row;
}
- }
-
- /* execute command or indicate failure */
- if (found && num_matches == 1)
- (CommandPath[found_idx].func)(argc, argv);
- else if (num_matches > 1)
- paint_error("Ambiguous abbreviation '%s'", argv[0]);
- else
- paint_error("Unknown command '%s'", argv[0]);
- argv_free(&argc, &argv);
- free(cmd);
-}
-
-void
-external_command(Args a UNUSED)
-{
- char *cmd;
-
- /* get command from user */
- if (user_getstr("!", &cmd) != 0) {
- werase(ui.command);
- wrefresh(ui.command);
- return;
- }
-
- execute_external_command(cmd);
- free(cmd);
-}
-
-void
-scroll_row(Args a)
-{
- int n;
-
- /* determine how many rows to scroll */
- n = 1;
- if (gnum_get() > 0) {
- n = gnum_get();
- gnum_clear();
- }
-
- /* update current row */
- switch (a.direction) {
- case DOWN:
- ui.active->crow += n;
- break;
- case UP:
- ui.active->crow -= n;
- break;
- default:
- errx(1, "scroll_row: invalid direction");
- }
-
- /* handle off-the-edge cases */
- if (ui.active->crow < 0) {
- swindow_scroll(ui.active, UP, -1 * ui.active->crow);
- ui.active->crow = 0;
- }
-
- if (ui.active->voffset + ui.active->crow >= ui.active->nrows)
- ui.active->crow = ui.active->nrows - ui.active->voffset - 1;
-
- if (ui.active->crow >= ui.active->h) {
- swindow_scroll(ui.active, DOWN, ui.active->crow - ui.active->h + 1);
- ui.active->crow = ui.active->h - 1;
+ if (a.direction == UP
+ && ui.active->voffset == 0 && voffset_original == 0) {
+ ui.active->crow -= diff;
+ if (ui.active->crow < 0)
+ ui.active->crow = 0;
+ }
}
- if (ui.active->crow < 0)
- ui.active->crow = 0;
-
- /* redraw */
redraw_active();
paint_status_bar();
}
void
-scroll_col(Args a)
+kba_scroll_col(KbaArgs a)
{
int maxlen;
int maxhoff;
@@ -457,123 +466,34 @@ scroll_col(Args a)
/* scroll */
switch (a.amount) {
- case SINGLE:
- swindow_scroll(ui.active, a.direction, n);
- if (ui.active->hoffset > maxhoff)
+ case SINGLE:
+ swindow_scroll(ui.active, a.direction, n);
+ if (ui.active->hoffset > maxhoff)
+ ui.active->hoffset = maxhoff;
+ break;
+ case WHOLE:
+ switch (a.direction) {
+ case LEFT:
+ ui.active->hoffset = 0;
+ break;
+ case RIGHT:
ui.active->hoffset = maxhoff;
- break;
- case WHOLE:
- switch (a.direction) {
- case LEFT:
- ui.active->hoffset = 0;
- break;
- case RIGHT:
- ui.active->hoffset = maxhoff;
- break;
- default:
- errx(1, "scroll_col: invalid direction");
- }
- break;
- default:
- errx(1, "scroll_col: invalid amount");
- }
-
- /* redraw */
- redraw_active();
- paint_status_bar();
-}
-
-void
-scroll_page(Args a)
-{
- bool maintain_row_idx;
- int voffset_original;
- int max_row;
- int diff;
- int n;
-
- voffset_original = ui.active->voffset;
-
- /* determine max row number */
- if (ui.active->voffset + ui.active->h >= ui.active->nrows)
- max_row = ui.active->nrows - ui.active->voffset - 1;
- else
- max_row = ui.active->h - 1;
-
- /* determine how many pages to scroll */
- n = 1;
- if (gnum_get() > 0) {
- n = gnum_get();
- gnum_clear();
- }
-
- /* determine how much crow should change */
- switch (a.amount) {
- case SINGLE:
- diff = 1 * n;
- maintain_row_idx = true;
- break;
- case HALF:
- diff = (ui.active->h / 2) * n;
- maintain_row_idx = false;
- break;
- case WHOLE:
- diff = ui.active->h * n;
- maintain_row_idx = false;
- break;
- default:
- errx(1, "scroll_page: invalid amount");
- }
- swindow_scroll(ui.active, a.direction, diff);
-
- /* handle updating the current row */
- if (maintain_row_idx) {
-
- if (a.direction == DOWN)
- ui.active->crow -= diff;
- else
- ui.active->crow += diff;
-
- /* handle off-the-edge cases */
- if (ui.active->crow < 0)
- ui.active->crow = 0;
-
- if (ui.active->voffset + ui.active->crow >= ui.active->nrows)
- ui.active->crow = ui.active->nrows - ui.active->voffset - 1;
-
- if (ui.active->crow >= ui.active->h)
- ui.active->crow = ui.active->h - 1;
-
- if (ui.active->crow < 0)
- ui.active->crow = 0;
-
- } else {
- /*
- * We only move current row here if there was a change this time
- * in the vertical offset
- */
-
- if (a.direction == DOWN
- && ui.active->voffset == voffset_original) {
- ui.active->crow += diff;
- if (ui.active->crow > max_row)
- ui.active->crow = max_row;
- }
-
- if (a.direction == UP
- && ui.active->voffset == 0 && voffset_original == 0) {
- ui.active->crow -= diff;
- if (ui.active->crow < 0)
- ui.active->crow = 0;
+ break;
+ default:
+ errx(1, "scroll_col: invalid direction");
}
+ break;
+ default:
+ errx(1, "scroll_col: invalid amount");
}
+ /* redraw */
redraw_active();
paint_status_bar();
}
void
-jumpto_page(Args a)
+kba_jumpto_screen(KbaArgs a)
{
int n;
int max_row;
@@ -622,7 +542,7 @@ jumpto_page(Args a)
}
void
-jumpto_file(Args a)
+kba_jumpto_file(KbaArgs a)
{
float pct;
int n, line, input;
@@ -636,51 +556,51 @@ jumpto_file(Args a)
/* get line number to jump to */
switch (a.scale) {
- case NUMBER:
- switch (a.num) {
- case 'g':
- /* retrieve second 'g' (or cancel) and determine jump-point */
- while ((input = getch()) && input != 'g') {
- if (input != ERR) {
- ungetch(input);
- return;
- }
+ case NUMBER:
+ switch (a.num) {
+ case 'g':
+ /* retrieve second 'g' (or cancel) and determine jump-point */
+ while ((input = getch()) && input != 'g') {
+ if (input != ERR) {
+ ungetch(input);
+ return;
}
+ }
- if (n < 0)
- line = 1;
- else if (n >= ui.active->nrows)
- line = ui.active->nrows;
- else
- line = n;
+ if (n < 0)
+ line = 1;
+ else if (n >= ui.active->nrows)
+ line = ui.active->nrows;
+ else
+ line = n;
- break;
+ break;
- case 'G':
- /* determine jump-point */
- if (n < 0 || n >= ui.active->nrows)
- line = ui.active->nrows;
- else
- line = n;
+ case 'G':
+ /* determine jump-point */
+ if (n < 0 || n >= ui.active->nrows)
+ line = ui.active->nrows;
+ else
+ line = n;
- break;
+ break;
- default:
- errx(1, "jumpto_file: NUMBER type with no num!");
- }
+ default:
+ errx(1, "jumpto_file: NUMBER type with no num!");
+ }
- break;
+ break;
- case PERCENT:
- if (n <= 0 || n > 100)
- return;
+ case PERCENT:
+ if (n <= 0 || n > 100)
+ return;
- pct = (float) n / 100;
- line = pct * (float) ui.active->nrows;
- break;
+ pct = (float) n / 100;
+ line = pct * (float) ui.active->nrows;
+ break;
- default:
- errx(1, "jumpto_file: invalid scale");
+ default:
+ errx(1, "jumpto_file: invalid scale");
}
/* jump */
@@ -702,10 +622,10 @@ jumpto_file(Args a)
}
void
-search(Args a)
+kba_search(KbaArgs a)
{
const char *errmsg = NULL;
- Args find_args;
+ KbaArgs find_args;
char *search_phrase;
char *prompt = NULL;
char **argv = NULL;
@@ -750,13 +670,13 @@ search(Args a)
/* do the search */
find_args.direction = SAME;
- search_find(find_args);
+ kba_search_find(find_args);
}
void
-search_find(Args a)
+kba_search_find(KbaArgs a)
{
- Args foo;
+ KbaArgs foo;
bool matches;
char *msg;
int dir;
@@ -816,7 +736,7 @@ search_find(Args a)
gnum_set(idx + 1);
foo.scale = NUMBER;
foo.num = 'G';
- jumpto_file(foo);
+ kba_jumpto_file(foo);
return;
}
}
@@ -824,28 +744,21 @@ search_find(Args a)
paint_error("Pattern not found: %s", mi_query_getraw());
}
-
-/*****************************************************************************
- * yank, delete, and paste keybindings.
- ****************************************************************************/
-
+/*
+ * TODO so much of the logic in cut() is similar with that of yank() above.
+ * combine the two, use an Args parameter to determine if the operation is
+ * a yank or a delete
+ */
void
-yank(Args a UNUSED)
+kba_cut(KbaArgs a UNUSED)
{
- bool got_target;
- int start, end;
- int input;
- int n;
-
- if (ui.active == ui.library) {
- paint_error("cannot yank in library window");
- return;
- }
-
- if (viewing_playlist->nfiles == 0) {
- paint_error("nothing to yank!");
- return;
- }
+ playlist *p;
+ char *warning;
+ bool got_target;
+ int start, end;
+ int response;
+ int input;
+ int n;
/* determine range */
n = 1;
@@ -854,7 +767,7 @@ yank(Args a UNUSED)
gnum_clear();
}
- /* get next input from user */
+ /* get range */
got_target = false;
start = 0;
end = 0;
@@ -863,82 +776,13 @@ yank(Args a UNUSED)
continue;
switch (input) {
- case 'y': /* yank next n lines */
+ case 'd': /* delete next n lines */
start = ui.active->voffset + ui.active->crow;
end = start + n;
got_target = true;
break;
- case 'G': /* yank to end of current playlist */
- start = ui.active->voffset + ui.active->crow;
- end = ui.active->nrows;
- got_target = true;
- break;
-
- /*
- * TODO handle other directions ( j/k/H/L/M/^u/^d/ etc. )
- * here. this will be ... tricky.
- * might want to re-organize other stuff?
- */
-
- default:
- ungetch(input);
- return;
- }
- }
-
- /* sanitize start and end */
- if (end > ui.active->nrows)
- end = ui.active->nrows;
-
- /* clear existing yank buffer and add new stuff */
- ybuffer_clear();
- for (n = start; n < end; n++)
- ybuffer_add(viewing_playlist->files[n]);
-
- /* notify user # of rows yanked */
- paint_message("Yanked %d files.", end - start);
-}
-
-/*
- * TODO so much of the logic in cut() is similar with that of yank() above.
- * combine the two, use an Args parameter to determine if the operation is
- * a yank or a delete
- */
-void
-cut(Args a UNUSED)
-{
- playlist *p;
- char *warning;
- bool got_target;
- int start, end;
- int response;
- int input;
- int n;
-
- /* determine range */
- n = 1;
- if (gnum_get() > 0) {
- n = gnum_get();
- gnum_clear();
- }
-
- /* get range */
- got_target = false;
- start = 0;
- end = 0;
- while ((input = getch()) && !got_target) {
- if (input == ERR)
- continue;
-
- switch (input) {
- case 'd': /* delete next n lines */
- start = ui.active->voffset + ui.active->crow;
- end = start + n;
- got_target = true;
- break;
-
- case 'G': /* delete to end of current playlist */
+ case 'G': /* delete to end of current playlist */
start = ui.active->voffset + ui.active->crow;
end = ui.active->nrows;
got_target = true;
@@ -1040,7 +884,78 @@ cut(Args a UNUSED)
}
void
-paste(Args a)
+kba_yank(KbaArgs a UNUSED)
+{
+ bool got_target;
+ int start, end;
+ int input;
+ int n;
+
+ if (ui.active == ui.library) {
+ paint_error("cannot yank in library window");
+ return;
+ }
+
+ if (viewing_playlist->nfiles == 0) {
+ paint_error("nothing to yank!");
+ return;
+ }
+
+ /* determine range */
+ n = 1;
+ if (gnum_get() > 0) {
+ n = gnum_get();
+ gnum_clear();
+ }
+
+ /* get next input from user */
+ got_target = false;
+ start = 0;
+ end = 0;
+ while ((input = getch()) && !got_target) {
+ if (input == ERR)
+ continue;
+
+ switch (input) {
+ case 'y': /* yank next n lines */
+ start = ui.active->voffset + ui.active->crow;
+ end = start + n;
+ got_target = true;
+ break;
+
+ case 'G': /* yank to end of current playlist */
+ start = ui.active->voffset + ui.active->crow;
+ end = ui.active->nrows;
+ got_target = true;
+ break;
+
+ /*
+ * TODO handle other directions ( j/k/H/L/M/^u/^d/ etc. )
+ * here. this will be ... tricky.
+ * might want to re-organize other stuff?
+ */
+
+ default:
+ ungetch(input);
+ return;
+ }
+ }
+
+ /* sanitize start and end */
+ if (end > ui.active->nrows)
+ end = ui.active->nrows;
+
+ /* clear existing yank buffer and add new stuff */
+ ybuffer_clear();
+ for (n = start; n < end; n++)
+ ybuffer_add(viewing_playlist->files[n]);
+
+ /* notify user # of rows yanked */
+ paint_message("Yanked %d files.", end - start);
+}
+
+void
+kba_paste(KbaArgs a)
{
playlist *p;
int start = 0;
@@ -1112,7 +1027,7 @@ paste(Args a)
void
-undo(Args a UNUSED)
+kba_undo(KbaArgs a UNUSED)
{
if (ui.active == ui.library) {
paint_message("Cannot undo in library window.");
@@ -1134,7 +1049,7 @@ undo(Args a UNUSED)
}
void
-redo(Args a UNUSED)
+kba_redo(KbaArgs a UNUSED)
{
if (ui.active == ui.library) {
paint_message("Cannot redo in library window.");
@@ -1155,3 +1070,412 @@ redo(Args a UNUSED)
paint_playlist();
}
+void
+kba_command_mode(KbaArgs a UNUSED)
+{
+ const char *errmsg = NULL;
+ char *cmd;
+ char **argv;
+ int argc;
+ int num_matches;
+ bool found;
+ int found_idx = 0;
+ int i;
+
+
+ /* get command from user */
+ if (user_getstr(":", &cmd) != 0 || strlen(cmd) == 0) {
+ werase(ui.command);
+ wrefresh(ui.command);
+ return;
+ }
+
+ /* check for '!' used for executing external commands */
+ if (cmd[0] == '!') {
+ execute_external_command(cmd + 1);
+ free(cmd);
+ return;
+ }
+
+ /* convert to argc/argv structure */
+ if (str2argv(cmd, &argc, &argv, &errmsg) != 0) {
+ paint_error("parse error: %s in '%s'", errmsg, cmd);
+ free(cmd);
+ return;
+ }
+
+ /* search path for appropriate command to execute */
+ found = false;
+ num_matches = 0;
+ for (i = 0; i < CommandPathSize; i++) {
+ if (match_command_name(argv[0], CommandPath[i].name)) {
+ found = true;
+ found_idx = i;
+ num_matches++;
+ }
+ }
+
+ /* execute command or indicate failure */
+ if (found && num_matches == 1)
+ (CommandPath[found_idx].func)(argc, argv);
+ else if (num_matches > 1)
+ paint_error("Ambiguous abbreviation '%s'", argv[0]);
+ else
+ paint_error("Unknown command '%s'", argv[0]);
+
+ argv_free(&argc, &argv);
+ free(cmd);
+}
+
+void
+kba_shell(KbaArgs a UNUSED)
+{
+ char *cmd;
+
+ /* get command from user */
+ if (user_getstr("!", &cmd) != 0) {
+ werase(ui.command);
+ wrefresh(ui.command);
+ return;
+ }
+
+ execute_external_command(cmd);
+ free(cmd);
+}
+
+void
+kba_quit(KbaArgs a UNUSED)
+{
+ VSIG_QUIT = 1;
+}
+
+void
+kba_redraw(KbaArgs a UNUSED)
+{
+ ui_clear();
+ paint_all();
+}
+
+void
+kba_switch_windows(KbaArgs a UNUSED)
+{
+ if (ui.active == ui.library) {
+ ui.active = ui.playlist;
+ if (ui.lhide) {
+ ui_hide_library();
+ paint_all();
+ }
+ } else {
+ ui.active = ui.library;
+ if (ui.lhide) {
+ ui_unhide_library();
+ paint_all();
+ }
+ }
+
+ paint_status_bar();
+}
+
+void
+kba_show_file_info(KbaArgs a UNUSED)
+{
+ int idx;
+
+ if (ui.active == ui.library)
+ return;
+
+ if (ui.active->crow >= ui.active->nrows) {
+ paint_message("no file here");
+ return;
+ }
+
+ if (showing_file_info)
+ paint_playlist();
+ else {
+ /* get file index and show */
+ idx = ui.active->voffset + ui.active->crow;
+ paint_playlist_file_info(viewing_playlist->files[idx]);
+ }
+}
+
+void
+kba_load_playlist(KbaArgs a UNUSED)
+{
+ KbaArgs dummy;
+ int idx;
+
+ if (ui.active == ui.library) {
+ /* load playlist & switch focus */
+ idx = ui.library->voffset + ui.library->crow;
+ viewing_playlist = mdb.playlists[idx];
+ ui.playlist->nrows = mdb.playlists[idx]->nfiles;
+ ui.playlist->crow = 0;
+ ui.playlist->voffset = 0;
+ ui.playlist->hoffset = 0;
+
+ paint_playlist();
+ kba_switch_windows(dummy);
+ } else {
+ /* play song */
+ if (ui.active->crow >= ui.active->nrows) {
+ paint_message("no file here");
+ return;
+ }
+ player_set_queue(viewing_playlist, ui.active->voffset + ui.active->crow);
+ playing_playlist = viewing_playlist;
+ player_play();
+ }
+}
+
+void
+kba_play(KbaArgs a UNUSED)
+{
+ KbaArgs dummy;
+ int idx;
+
+ if (ui.active == ui.library) {
+ /* load playlist & switch focus */
+ idx = ui.library->voffset + ui.library->crow;
+ viewing_playlist = mdb.playlists[idx];
+ ui.playlist->nrows = mdb.playlists[idx]->nfiles;
+ ui.playlist->crow = 0;
+ ui.playlist->voffset = 0;
+ ui.playlist->hoffset = 0;
+
+ paint_playlist();
+ kba_switch_windows(dummy);
+ } else {
+ /* play song */
+ if (ui.active->crow >= ui.active->nrows) {
+ paint_message("no file here");
+ return;
+ }
+ player_set_queue(viewing_playlist, ui.active->voffset + ui.active->crow);
+ playing_playlist = viewing_playlist;
+ player_play();
+ }
+}
+
+void
+kba_pause(KbaArgs a UNUSED)
+{
+ player_pause();
+}
+
+void
+kba_stop(KbaArgs a UNUSED)
+{
+ player_stop();
+ playing_playlist = NULL;
+}
+
+void
+kba_seek(KbaArgs a)
+{
+ int n, secs;
+
+ /* determine number of seconds to seek */
+ switch (a.scale) {
+ case SECONDS:
+ secs = a.num;
+ break;
+ case MINUTES:
+ secs = a.num * 60;
+ break;
+ default:
+ errx(1, "seek_playback: invalid scale");
+ }
+
+ /* adjust for direction */
+ switch (a.direction) {
+ case FORWARDS:
+ /* no change */
+ break;
+ case BACKWARDS:
+ secs *= -1;
+ break;
+ default:
+ errx(1, "seek_playback: invalid direction");
+ }
+
+ /* is there a multiplier? */
+ n = 1;
+ if (gnum_get() > 0) {
+ n = gnum_get();
+ gnum_clear();
+ }
+
+ /* apply n & seek */
+ player_seek(secs * n);
+}
+
+
+/*****************************************************************************
+ *
+ * Routines for Working with 'gnum'
+ *
+ ****************************************************************************/
+
+int _global_input_num = 0;
+
+void gnum_clear()
+{ _global_input_num = 0; }
+
+int gnum_get()
+{ return _global_input_num; }
+
+void gnum_set(int x)
+{ _global_input_num = x; }
+
+void gnum_add(int x)
+{
+ _global_input_num = _global_input_num * 10 + x;
+}
+
+int
+gnum_retrieve()
+{
+ int n = 1;
+ if (gnum_get() > 0) {
+ n = gnum_get();
+ gnum_clear();
+ }
+ return n;
+}
+
+
+/*****************************************************************************
+ *
+ * Routines for Working with Search Direction
+ *
+ ****************************************************************************/
+
+Direction _global_search_dir = FORWARDS;
+
+Direction search_dir_get()
+{ return _global_search_dir; }
+
+void search_dir_set(Direction dir)
+{ _global_search_dir = dir; }
+
+
+/*****************************************************************************
+ *
+ * Routines for Working with Copy/Cut/Paste Buffer
+ *
+ ****************************************************************************/
+
+yank_buffer _yank_buffer;
+
+void
+ybuffer_init()
+{
+ _yank_buffer.files = calloc(YANK_BUFFER_CHUNK_SIZE, sizeof(meta_info*));
+ if (_yank_buffer.files == NULL)
+ err(1, "ybuffer_init: calloc(3) failed");
+
+ _yank_buffer.capacity = YANK_BUFFER_CHUNK_SIZE;
+ _yank_buffer.nfiles = 0;
+}
+
+void
+ybuffer_clear()
+{
+ _yank_buffer.nfiles = 0;
+}
+
+void
+ybuffer_free()
+{
+ free(_yank_buffer.files);
+ _yank_buffer.capacity = 0;
+ _yank_buffer.nfiles = 0;
+}
+
+void
+ybuffer_add(meta_info *f)
+{
+ meta_info **new_buff;
+ int new_capacity;
+
+ /* do we need to realloc()? */
+ if (_yank_buffer.nfiles == _yank_buffer.capacity) {
+ _yank_buffer.capacity += YANK_BUFFER_CHUNK_SIZE;
+ new_capacity = _yank_buffer.capacity * sizeof(meta_info*);
+ if ((new_buff = realloc(_yank_buffer.files, new_capacity)) == NULL)
+ err(1, "ybuffer_add: realloc(3) failed [%i]", new_capacity);
+
+ _yank_buffer.files = new_buff;
+ }
+
+ /* add the file */
+ _yank_buffer.files[ _yank_buffer.nfiles++ ] = f;
+}
+
+
+/*****************************************************************************
+ *
+ * Misc. Handy Routines
+ *
+ ****************************************************************************/
+
+void
+redraw_active()
+{
+ if (ui.active == ui.library)
+ paint_library();
+ else
+ paint_playlist();
+}
+
+/*
+ * Given string input from user (argv[0]) and a command name, check if the
+ * input matches the command name, taking into acount '!' weirdness and
+ * abbreviations.
+ */
+bool
+match_command_name(const char *input, const char *cmd)
+{
+ bool found;
+ char *icopy;
+
+ if (input == NULL || strlen(input) == 0)
+ return false;
+
+ if (strcmp(input, cmd) == 0)
+ return true;
+
+ /* check for '!' weirdness and abbreviations */
+
+ if ((icopy = strdup(input)) == NULL)
+ err(1, "match_command_name: strdup(3) failed");
+
+ /* remove '!' from input, if present */
+ if (strstr(icopy, "!") != NULL)
+ *strstr(icopy, "!") = '\0';
+
+ /* now check against command & abbreviation */
+ if (strstr(cmd, icopy) == cmd)
+ found = true;
+ else
+ found = false;
+
+ free(icopy);
+ return found;
+}
+
+void
+execute_external_command(const char *cmd)
+{
+ def_prog_mode();
+ endwin();
+
+ system(cmd);
+ printf("\nPress ENTER to continue");
+ fflush(stdout);
+ while (getchar() != '\n');
+
+ reset_prog_mode();
+ paint_all();
+}
+
View
182 keybindings.h
@@ -17,31 +17,151 @@
#ifndef KEYBINDINGS_H
#define KEYBINDINGS_H
+#include "debug.h"
#include "enums.h"
#include "paint.h"
-#include "str2argv.h"
#include "vitunes.h"
-#include "debug.h"
+/* keybinding actions */
+typedef enum {
+ /* scrolling vertically */
+ scroll_up,
+ scroll_down,
+ scroll_up_page,
+ scroll_down_page,
+ scroll_up_halfpage,
+ scroll_down_halfpage,
+ scroll_up_wholepage,
+ scroll_down_wholepage,
+ /* scrolling horizontally */
+ scroll_left,
+ scroll_right,
+ scroll_leftmost,
+ scroll_rightmost,
+ /* jumping within screen */
+ jumpto_screen_top,
+ jumpto_screen_middle,
+ jumpto_screen_bottom,
+ /* jumping within whole playlist/library */
+ jumpto_line,
+ jumpto_percent,
+ /* searching */
+ search_forward,
+ search_backward,
+ find_next_forward,
+ find_next_backward,
+ /* copy/cut/paste & undo/redo */
+ cut,
+ yank,
+ paste_after,
+ paste_before,
+ undo,
+ redo,
+ /* misc. */
+ quit,
+ redraw,
+ command_mode,
+ shell,
+ /* vitunes specific stuff */
+ switch_windows,
+ show_file_info,
+ load_playlist,
+ media_play,
+ media_pause,
+ media_stop,
+ seek_forward_seconds,
+ seek_backward_seconds,
+ seek_forward_minutes,
+ seek_backward_minutes,
+
+} KeyAction;
+
+typedef int KeyCode;
+
+
+/* keybinding manipulation & retrieval routines */
+void kb_init();
+void kb_free();
+void kb_bind(KeyAction, KeyCode);
+bool kb_execute(KeyCode k);
+
+bool kb_is_action(char *s);
+KeyAction kb_str2action(char * s);
+
+
+/*
+ * This is the generic argument structure for all keybinding action handlers.
+ * This is used liberally to prevent any intricate parsing and make the use
+ * of code-reuse.
+ */
+typedef struct {
+ Direction direction;
+ Scale scale;
+ Amount amount;
+ Placement placement;
+ int num;
+} KbaArgs;
+
+/* Function used to retrieve handler for a given keycode */
+typedef void(*ActionHandler)(KbaArgs a);
+ActionHandler kb_get_handler(KeyCode k);
+
+/* Individual keybinding action handlers */
+void kba_scroll_row(KbaArgs a);
+void kba_scroll_page(KbaArgs a);
+void kba_scroll_col(KbaArgs a);
+
+void kba_jumpto_screen(KbaArgs a);
+void kba_jumpto_file(KbaArgs a);
+
+void kba_search(KbaArgs a);
+void kba_search_find(KbaArgs a);
+
+void kba_cut(KbaArgs a);
+void kba_yank(KbaArgs a);
+void kba_paste(KbaArgs a);
+void kba_undo(KbaArgs a);
+void kba_redo(KbaArgs a);
+
+void kba_command_mode(KbaArgs a);
+void kba_shell(KbaArgs a);
+void kba_quit(KbaArgs a);
+void kba_redraw(KbaArgs a);
+
+void kba_switch_windows(KbaArgs a);
+void kba_show_file_info(KbaArgs a);
+void kba_load_playlist(KbaArgs a);
+void kba_play(KbaArgs a);
+void kba_pause(KbaArgs a);
+void kba_stop(KbaArgs a);
+void kba_seek(KbaArgs a);
-/* for working with number read from user for keybindings */
+
+/*
+ * The 'gnum' is the number n that can be applied to many keybindings. E.g.
+ * how the sequence "15j" will move down 15 lines. "15" is the gnum here.
+ * These are the routines used to init/set/clear the gnum.
+ */
void gnum_clear();
+void gnum_set(int x);
int gnum_get();
+int gnum_retrieve(); /* XXX returns 1 if gnum not set, num otherwise */
void gnum_add(int x);
-/* for working with active search direction */
-venum search_dir_get();
-void search_dir_set(venum dir);
+/* These are used to set/use the search direction */
+Direction search_dir_get();
+void search_dir_set(Direction d);
-/* for working with yank/cut buffer */
+/* These work with the copy/cut buffer */
#define YANK_BUFFER_CHUNK_SIZE 100
typedef struct {
meta_info **files;
int nfiles;
int capacity;
} yank_buffer;
+extern yank_buffer _yank_buffer;
void ybuffer_init();
void ybuffer_clear();
@@ -49,55 +169,9 @@ void ybuffer_free();
void ybuffer_add(meta_info *f);
-/* misc. handy functions used frequently */
+/* Misc. handy functions used frequently */
void redraw_active();
bool match_command_name(const char *s, const char *cmd);
void execute_external_command(const char *cmd);
-
-/*
- * The arguments passed to each keybinding. No parsing required.
- */
-typedef struct {
- venum amount;
- venum direction;
- venum placement;
- venum scale;
- int num;
-} Args;
-
-typedef struct {
- int keycode;
- void (*func)(Args);
- Args args;
-} keybinding;
-
-extern const keybinding KeyBindings[];
-extern const int KeyBindingsSize;
-
-
-/* keybinding handlers */
-void quit_vitunes(Args a);
-void load_or_play(Args a);
-void show_file_info(Args a);
-void pause_playback(Args a);
-void stop_playback(Args a);
-void seek_playback(Args a);
-void switch_focus(Args a);
-void redraw(Args a);
-void enter_cmd_mode(Args a);
-void external_command(Args a);
-void scroll_row(Args a);
-void scroll_col(Args a);
-void scroll_page(Args a);
-void jumpto_file(Args a);
-void jumpto_page(Args a);
-void yank(Args a);
-void paste(Args a);
-void cut(Args a);
-void undo(Args a);
-void redo(Args a);
-void search(Args a);
-void search_find(Args a);
-
#endif
View
8 meta_info.h
@@ -163,10 +163,10 @@ int mi_compare(const void *a, const void *b);
/* structure used to describe how to display meta_info structs */
typedef struct {
- int nfields;
- int order[MI_NUM_CINFO];
- int widths[MI_NUM_CINFO];
- venum align[MI_NUM_CINFO];
+ int nfields;
+ int order[MI_NUM_CINFO];
+ int widths[MI_NUM_CINFO];
+ Direction align[MI_NUM_CINFO];
} mi_display_description;
extern mi_display_description mi_display;
View
6 paint.c
@@ -21,7 +21,7 @@ _colors colors;
bool showing_file_info = false;
char *player_get_field2show(const meta_info *mi);
-char *num2fmt(int n, venum a);
+char *num2fmt(int n, Direction d);
/*
@@ -62,7 +62,7 @@ player_get_field2show(const meta_info *mi)
* style string ("%Ns" or "%-Ns")
*/
char *
-num2fmt(int n, venum a)
+num2fmt(int n, Direction d)
{
static char format[255];
@@ -71,7 +71,7 @@ num2fmt(int n, venum a)
errx(1, "num2sfmt: invalid number %d provided", n);
}
- if (a == LEFT)
+ if (d == LEFT)
snprintf(format, sizeof(format), "%%-%d.%ds", n, n);
else
snprintf(format, sizeof(format), "%%%d.%ds", n, n);
View
60 uinterface.c
@@ -64,38 +64,38 @@ swindow_free(swindow *win)
}
void
-swindow_scroll(swindow *win, venum d, int n)
+swindow_scroll(swindow *win, Direction d, int n)
{
switch (d) {
- case UP:
- win->voffset -= n;
- if (win->voffset < 0)
- win->voffset = 0;
- break;
-
- case DOWN:
- win->voffset += n;
- if (win->voffset >= win->nrows - win->h)
- win->voffset = win->nrows - win->h;
- if (win->voffset < 0)
- win->voffset = 0;
- break;
-
- case LEFT:
- win->hoffset -= n;
- if (win->hoffset < 0)
- win->hoffset = 0;
- break;
-
- case RIGHT:
- win->hoffset += n;
- /* NOTE: "overflow" here is handled elsewhere.
- * see input_handlers.c, scroll_col()
- */
- break;
-
- default:
- err(1, "swindow_scroll: bad direction");
+ case UP:
+ win->voffset -= n;
+ if (win->voffset < 0)
+ win->voffset = 0;
+ break;
+
+ case DOWN:
+ win->voffset += n;
+ if (win->voffset >= win->nrows - win->h)
+ win->voffset = win->nrows - win->h;
+ if (win->voffset < 0)
+ win->voffset = 0;
+ break;
+
+ case LEFT:
+ win->hoffset -= n;
+ if (win->hoffset < 0)
+ win->hoffset = 0;
+ break;
+
+ case RIGHT:
+ win->hoffset += n;
+ /* NOTE: "overflow" here is handled elsewhere.
+ * see input_handlers.c, scroll_col()
+ */
+ break;
+
+ default:
+ err(1, "swindow_scroll: bad direction");
}
}
View
2  uinterface.h
@@ -48,7 +48,7 @@ typedef struct
swindow *swindow_new(int h, int w, int y, int x);
void swindow_free(swindow *win);
void swindow_resize(swindow *win, int h, int w, int y, int x);
-void swindow_scroll(swindow *win, venum d, int n);
+void swindow_scroll(swindow *win, Direction d, int n);
/* user interface struct & methods */
View
17 vitunes.c
@@ -78,7 +78,7 @@ main(int argc, char *argv[])
{
struct passwd *pwd;
int previous_command;
- int input, i;
+ int input;
#ifdef DEBUG
if ((debug_log = fopen("vitunes-debug.log", "w")) == NULL)
@@ -163,6 +163,8 @@ main(int argc, char *argv[])
/* initial painting of the display */
paint_all();
+ kb_init();
+
/* -----------------------------------------------------------------------
* begin input loop
* -------------------------------------------------------------------- */
@@ -178,16 +180,9 @@ main(int argc, char *argv[])
if (isdigit(input) && (input != '0' || gnum_get() > 0))
gnum_add(input - '0');
else if (input == '\n' && gnum_get() > 0 && previous_command >= 0)
- ExecuteKeyBinding(previous_command);
- else {
- /* check if input is bound and execute... */
- for (i = 0; i < KeyBindingsSize; i++) {
- if (KeyBindings[i].keycode == input) {
- ExecuteKeyBinding(i);
- previous_command = i;
- }
- }
- }
+ kb_execute(previous_command);
+ else
+ kb_execute(input);
}
}
View
10 vitunes.h
@@ -35,16 +35,18 @@
#include "uinterface.h"
#include "e_commands.h"
+/*
+ * These are the various things defined in vitunes.c used elsewhere.
+ */
+
/* record keeping */
extern playlist *viewing_playlist;
extern playlist *playing_playlist;
-/* signal flags (references elsewhere) */
+/* signal flags referenced elsewhere */
extern volatile sig_atomic_t VSIG_QUIT;
-extern volatile sig_atomic_t VSIG_RESIZE;
-extern volatile sig_atomic_t VSIG_PLAYER_MONITOR;
-extern volatile sig_atomic_t VSIG_PLAYER_RESTART;
+/* other */
void load_config();
void process_signals(bool);
Please sign in to comment.
Something went wrong with that request. Please try again.