tmus

TUI Music Player
git clone https://git.sinitax.com/sinitax/tmus
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

commit bb0f1e2ea23bb278f02c2a4ff19e5c6fa6946b92
parent a1e28b9eb1c89a37d24ad50feb203f99504274b2
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon, 21 Feb 2022 17:17:08 +0100

Bug fixes, added select track shortcut and reindex command

Diffstat:
Msrc/cmd.c | 59++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/cmd.h | 8+++++++-
Msrc/player.c | 12++++--------
Msrc/ref.c | 18++++++++++++++++++
Msrc/ref.h | 1+
Msrc/tui.c | 146++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/tui.h | 2+-
Msrc/util.c | 23-----------------------
Msrc/util.h | 1-
9 files changed, 181 insertions(+), 89 deletions(-)

diff --git a/src/cmd.c b/src/cmd.c @@ -4,6 +4,7 @@ #include "list.h" #include "player.h" #include "ref.h" +#include "tag.h" #include "track.h" #include "tui.h" #include "util.h" @@ -11,24 +12,25 @@ #include <stdbool.h> #define CMD_ERROR(...) do { \ - free(cmd_status); \ - cmd_status = awprintf(__VA_ARGS__); \ + CMD_SET_STATUS(__VA_ARGS__); \ return false; \ } while (0) static bool cmd_save(const wchar_t *args); static bool cmd_move(const wchar_t *args); static bool cmd_add(const wchar_t *args); +static bool cmd_reindex(const wchar_t *args); const struct cmd commands[] = { { L"save", cmd_save }, { L"move", cmd_move }, { L"add", cmd_add }, + { L"reindex", cmd_reindex }, }; const size_t command_count = ARRLEN(commands); -wchar_t *cmd_status; +char *cmd_status; void cmd_init(void) @@ -36,6 +38,12 @@ cmd_init(void) cmd_status = NULL; } +void +cmd_deinit(void) +{ + free(cmd_status); +} + bool cmd_save(const wchar_t *args) { @@ -52,10 +60,10 @@ cmd_move(const wchar_t *name) char *newpath; tag = tag_find(name); - if (!tag) CMD_ERROR(L"Tag not found"); + if (!tag) CMD_ERROR("Tag not found"); link = list_at(tracks_vis, track_nav.sel); - if (!link) CMD_ERROR(L"No track selected"); + if (!link) CMD_ERROR("No track selected"); track = UPCAST(link, struct ref)->data; newpath = aprintf("%s/%s", tag->fpath, track->fname); @@ -99,3 +107,44 @@ cmd_add(const wchar_t *name) return 1; } + +bool +cmd_reindex(const wchar_t *name) +{ + struct link *link; + struct tag *tag; + struct list matches; + + list_init(&matches); + + if (!*name) { + link = list_at(&tags, tag_nav.sel); + tag = UPCAST(link, struct tag); + if (tag == NULL) return false; + list_push_back(&matches, LINK(ref_init(tag))); + } else if (!wcscmp(name, L"*")) { + for (LIST_ITER(&tags, link)) { + tag = UPCAST(link, struct tag); + list_push_back(&matches, LINK(ref_init(tag))); + } + } else { + for (LIST_ITER(&tags, link)) { + tag = UPCAST(link, struct tag); + if (!wcscmp(tag->name, name)) { + list_push_back(&matches, LINK(ref_init(tag))); + break; + } + } + } + + if (list_empty(&matches)) return false; + + for (LIST_ITER(&matches, link)) { + tag = UPCAST(link, struct ref)->data; + index_update(tag); + } + + refs_free(&matches); + + return true; +} diff --git a/src/cmd.h b/src/cmd.h @@ -4,6 +4,11 @@ #include <stdbool.h> +#define CMD_SET_STATUS(...) do { \ + free(cmd_status); \ + cmd_status = aprintf(__VA_ARGS__); \ + } while (0) + typedef bool (*cmd_func)(const wchar_t *args); struct cmd { @@ -12,7 +17,8 @@ struct cmd { }; void cmd_init(void); +void cmd_deinit(void); extern const struct cmd commands[]; extern const size_t command_count; -extern wchar_t *cmd_status; +extern char *cmd_status; diff --git a/src/player.c b/src/player.c @@ -145,11 +145,9 @@ player_update(void) const char *tmp; status = mpd_run_status(player->conn); - if (status == NULL) { - fprintf(stderr, "MPD Fatal Error: %s\n", + if (status == NULL) + PANIC("MPD Fatal Error: %s", mpd_connection_get_error_message(player->conn)); - exit(1); - } song = mpd_run_current_song(player->conn); if (!song) { @@ -204,11 +202,9 @@ player_update(void) /* TODO move prev / next handling to own functions */ status = mpd_run_status(player->conn); - if (status == NULL) { - fprintf(stderr, "MPD Fatal Error: %s\n", + if (status == NULL) + PANIC("MPD Fatal Error: %s", mpd_connection_get_error_message(player->conn)); - exit(1); - } song = mpd_run_current_song(player->conn); if (song) { diff --git a/src/ref.c b/src/ref.c @@ -41,6 +41,24 @@ refs_ffind(struct list *list, void *data) } int +refs_index(struct list *list, void *data) +{ + struct link *iter; + struct ref *ref; + int index; + + index = 0; + for (LIST_ITER(list, iter)) { + ref = UPCAST(iter, struct ref); + if (ref->data == data) + return index; + index++; + } + + return -1; +} + +int refs_incl(struct list *list, void *data) { struct link *ref; diff --git a/src/ref.h b/src/ref.h @@ -12,6 +12,7 @@ struct ref *ref_init(void *data); void ref_free(void *ref); void refs_free(struct list *list); +int refs_index(struct list *list, void *data); int refs_incl(struct list *list, void *data); void refs_rm(struct list *list, void *data); diff --git a/src/tui.c b/src/tui.c @@ -29,8 +29,9 @@ enum { IMODE_EXECUTE, - IMODE_TRACK_SEARCH, - IMODE_TAG_SEARCH, + IMODE_TRACK_PLAY, + IMODE_TRACK_SELECT, + IMODE_TAG_SELECT, IMODE_COUNT }; @@ -49,8 +50,10 @@ static void tag_pane_vis(struct pane *pane, int sel); static int track_pane_input(wint_t c); static void track_pane_vis(struct pane *pane, int sel); -static int play_track(const wchar_t *name); -static int select_tag(const wchar_t *name); +static bool run_cmd(const wchar_t *name); +static bool play_track(const wchar_t *name); +static bool select_track(const wchar_t *name); +static bool select_tag(const wchar_t *name); static int cmd_pane_input(wint_t c); static void cmd_pane_vis(struct pane *pane, int sel); @@ -74,8 +77,9 @@ static struct pane *const panes[] = { }; static struct history command_history; -static struct history track_search_history; -static struct history tag_search_history; +static struct history track_play_history; +static struct history track_select_history; +static struct history tag_select_history; static struct history *history; static int cmd_input_mode; @@ -86,7 +90,7 @@ static int completion_reset; static completion_gen completion; struct pane *cmd_pane, *tag_pane, *track_pane; -struct pane *pane_sel, *pane_top_sel; +struct pane *pane_sel, *pane_after_cmd; struct list *tracks_vis; int track_show_playlist; @@ -95,8 +99,9 @@ struct listnav track_nav; const char imode_prefix[IMODE_COUNT] = { [IMODE_EXECUTE] = ':', - [IMODE_TRACK_SEARCH] = '/', - [IMODE_TAG_SEARCH] = '?', + [IMODE_TRACK_PLAY] = '!', + [IMODE_TRACK_SELECT] = '/', + [IMODE_TAG_SELECT] = '?', }; static const char player_state_chars[] = { @@ -392,7 +397,7 @@ track_pane_vis(struct pane *pane, int sel) } } -int +bool run_cmd(const wchar_t *query) { const wchar_t *sep; @@ -403,20 +408,17 @@ run_cmd(const wchar_t *query) cmdlen = sep ? sep - query : wcslen(query); for (i = 0; i < command_count; i++) { if (!wcsncmp(commands[i].name, query, cmdlen)) { - success = commands[i].func(sep ? sep + 1 : NULL); - if (!success && !cmd_status) { - free(cmd_status); - cmd_status = wcsdup(L"Command Failed!\n"); - ASSERT(cmd_status != NULL); - } - return 1; + success = commands[i].func(sep ? sep + 1 : L""); + if (!success && !cmd_status) + CMD_SET_STATUS("Command Failed!"); + return true; } } - return 0; + return false; } -int +bool play_track(const wchar_t *query) { struct track *track; @@ -426,14 +428,35 @@ play_track(const wchar_t *query) track = UPCAST(iter, struct ref)->data; if (!wcscmp(track->name, query)) { player_play_track(track); - return 1; + return true; } } - return 0; + return false; } -int +bool +select_track(const wchar_t *query) +{ + struct track *track; + struct link *link; + int index; + + index = 0; + for (LIST_ITER(tracks_vis, link)) { + track = UPCAST(link, struct ref)->data; + if (!wcscmp(track->name, query)) { + listnav_update_sel(&track_nav, index); + pane_after_cmd = track_pane; + return true; + } + index += 1; + } + + return false; +} + +bool select_tag(const wchar_t *query) { struct tag *tag; @@ -444,13 +467,14 @@ select_tag(const wchar_t *query) for (LIST_ITER(&tags, iter)) { index += 1; tag = UPCAST(iter, struct tag); - if (wcscasestr(tag->name, query)) { + if (!wcscmp(tag->name, query)) { listnav_update_sel(&tag_nav, index); - return 1; + pane_after_cmd = tag_pane; + return true; } } - return 0; + return false; } int @@ -462,12 +486,14 @@ cmd_pane_input(wint_t c) switch (c) { case KEY_ESC: match = wcscmp(completion_query.buf, history->input->buf); - if (!completion_reset && match) + if (!completion_reset && match) { inputln_copy(history->input, &completion_query); - else if (history->sel == history->input) - pane_sel = pane_top_sel; - else + } else if (history->sel == history->input) { + inputln_replace(history->input, L""); + pane_sel = pane_after_cmd; + } else { history->sel = history->input; + } break; case KEY_LEFT: inputln_left(history->sel); @@ -486,20 +512,26 @@ cmd_pane_input(wint_t c) break; case KEY_ENTER: if (!*history->sel->buf) { - pane_sel = pane_top_sel; + pane_sel = pane_after_cmd; break; } if (cmd_input_mode == IMODE_EXECUTE) { - run_cmd(history->sel->buf); - } else if (cmd_input_mode == IMODE_TRACK_SEARCH) { - play_track(history->sel->buf); - } else if (cmd_input_mode == IMODE_TAG_SEARCH) { - select_tag(history->sel->buf); + if (!run_cmd(history->sel->buf)) + CMD_SET_STATUS("No such command"); + } else if (cmd_input_mode == IMODE_TRACK_PLAY) { + if (!play_track(history->sel->buf)) + CMD_SET_STATUS("Failed to find track"); + } else if (cmd_input_mode == IMODE_TRACK_SELECT) { + if (!select_track(history->sel->buf)) + CMD_SET_STATUS("Failed to find track"); + } else if (cmd_input_mode == IMODE_TAG_SELECT) { + if (!select_tag(history->sel->buf)) + CMD_SET_STATUS("Failed to find tag"); } history_submit(history); - pane_sel = pane_top_sel; + pane_sel = pane_after_cmd; break; case KEY_TAB: case KEY_BTAB: @@ -520,7 +552,7 @@ cmd_pane_input(wint_t c) break; case KEY_BACKSPACE: if (history->sel->cur == 0) { - pane_sel = pane_top_sel; + pane_sel = pane_after_cmd; break; } inputln_del(history->sel, 1); @@ -651,7 +683,7 @@ cmd_pane_vis(struct pane *pane, int sel) } else if (cmd_status) { pane_clearln(pane, 2); style_on(pane->win, STYLE_ERROR); - mvwaddwstr(pane->win, 2, 1, cmd_status); + mvwprintw(pane->win, 2, 0, ">%.*s", pane->w - 1, cmd_status); style_off(pane->win, STYLE_ERROR); } } @@ -692,10 +724,10 @@ main_input(wint_t c) case KEY_TAB: pane_sel = pane_sel == &pane_left ? &pane_right : &pane_left; - pane_top_sel = pane_sel; break; case KEY_ESC: - pane_sel = pane_top_sel; + if (pane_sel == cmd_pane) + pane_sel = pane_after_cmd; break; case KEY_LEFT: if (!player->loaded) break; @@ -749,23 +781,34 @@ main_input(wint_t c) break; case L':': cmd_input_mode = IMODE_EXECUTE; + pane_after_cmd = pane_sel; pane_sel = &pane_bot; completion_reset = 1; history = &command_history; completion = command_name_gen; break; case L'/': - cmd_input_mode = IMODE_TRACK_SEARCH; + cmd_input_mode = IMODE_TRACK_SELECT; + pane_after_cmd = pane_sel; pane_sel = &pane_bot; completion_reset = 1; - history = &track_search_history; + history = &track_select_history; + completion = track_name_gen; + break; + case L'!': + cmd_input_mode = IMODE_TRACK_PLAY; + pane_after_cmd = pane_sel; + pane_sel = &pane_bot; + completion_reset = 1; + history = &track_play_history; completion = track_name_gen; break; case L'?': - cmd_input_mode = IMODE_TAG_SEARCH; + cmd_input_mode = IMODE_TAG_SELECT; + pane_after_cmd = pane_sel; pane_sel = &pane_bot; completion_reset = 1; - history = &tag_search_history; + history = &tag_select_history; completion = tag_name_gen; break; case L'+': @@ -855,17 +898,19 @@ tui_resize(void) pane_resize(&pane_right, pane_left.ex + 1, 0, scrw, scrh - 3); pane_resize(&pane_bot, 0, scrh - 3, scrw, scrh); } + void tui_init(void) { quit = 0; - cmd_input_mode = IMODE_TRACK_SEARCH; + cmd_input_mode = IMODE_TRACK_SELECT; inputln_init(&completion_query); completion_reset = 1; - history_init(&track_search_history); - history_init(&tag_search_history); + history_init(&track_play_history); + history_init(&track_select_history); + history_init(&tag_select_history); history_init(&command_history); history = &command_history; @@ -878,7 +923,7 @@ tui_init(void) pane_init((cmd_pane = &pane_bot), cmd_pane_input, cmd_pane_vis); pane_sel = &pane_left; - pane_top_sel = pane_sel; + pane_after_cmd = pane_sel; listnav_init(&tag_nav); listnav_init(&track_nav); @@ -896,8 +941,9 @@ tui_deinit(void) pane_free(&pane_right); pane_free(&pane_bot); - history_free(&track_search_history); - history_free(&tag_search_history); + history_free(&track_play_history); + history_free(&track_select_history); + history_free(&tag_select_history); history_free(&command_history); if (!isendwin()) endwin(); diff --git a/src/tui.h b/src/tui.h @@ -14,7 +14,7 @@ bool tui_update(void); void tui_restore(void); extern struct pane *cmd_pane, *tag_pane, *track_pane; -extern struct pane *pane_sel, *pane_top_sel; +extern struct pane *pane_sel, *pane_after_cmd; extern struct list *tracks_vis; extern int track_show_playlist; diff --git a/src/util.c b/src/util.c @@ -98,29 +98,6 @@ error(const char *fmtstr, ...) exit(1); } -wchar_t * -awprintf(const wchar_t *fmtstr, ...) -{ - va_list ap, cpy; - size_t size; - wchar_t *str; - - va_copy(cpy, ap); - - va_start(ap, fmtstr); - size = swprintf(NULL, 0, fmtstr, ap); - va_end(ap); - - str = malloc((size + 1) * sizeof(wchar_t)); - if (!str) return NULL; - - va_start(cpy, fmtstr); - swprintf(str, size + 1, fmtstr, cpy); - va_end(cpy); - - return str; -} - char * aprintf(const char *fmtstr, ...) { diff --git a/src/util.h b/src/util.h @@ -24,7 +24,6 @@ void assert(int cond, const char *file, int line, const char *condstr); void error(const char *fmtstr, ...); char *aprintf(const char *fmtstr, ...); -wchar_t *awprintf(const wchar_t *fmtstr, ...); char *appendstrf(char *alloc, const char *fmtstr, ...); char *sanitized(const char *instr);