myadm

Simple MySQL client for the terminal
git clone git://git.bitsmanent.org/myadm
Log | Files | Refs | README | LICENSE

commit 434476f733fa46f58ccb6d5906ca557245479683
parent d949367933abd5db11bee30b14bd8a4b6be4402f
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Mon, 14 Mar 2016 20:02:27 +0100

Make modes dynamics.
The first viewmode is now specified in config.h through the welcome pointer.

Diffstat:
Mconfig.def.h | 17++++++-----------
Mcore.c | 144++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Ahelp.stfl | 27+++++++++++++++++++++++++++
3 files changed, 113 insertions(+), 75 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -7,13 +7,7 @@ static const char *dbhost = ""; static const char *dbuser = ""; static const char *dbpass = ""; -static Mode modes[] = { - /* name function */ - { "databases", databases }, /* first entry is default */ - { "tables", tables }, - { "records", records }, - { "text", text }, -}; +static void (*welcome)(const Arg *arg) = databases; static Key keys[] = { /* mode modkey function argument */ @@ -23,11 +17,12 @@ static Key keys[] = { { NULL, L"j", itempos, {.i = +1} }, { NULL, L"I", reload, {0} }, { NULL, L"$", apply, {.i = 1} }, + { NULL, L"?", help, {0} }, { "databases", L"q", quit, {.i = 0} }, - { "databases", L"ENTER", usedb, {.v = &modes[1]} }, - { "databases", L"SPACE", usedb, {.v = &modes[1]} }, - { "tables", L"ENTER", setmode, {.v = &modes[2]} }, - { "tables", L"SPACE", setmode, {.v = &modes[2]} }, + { "databases", L"ENTER", tables, {0} }, + { "databases", L"SPACE", tables, {0} }, + { "tables", L"ENTER", records, {0} }, + { "tables", L"SPACE", records, {0} }, { "records", L"d", flagas, {.v = "D"} }, { "records", L"t", flagas, {.v = "*"} }, }; diff --git a/core.c b/core.c @@ -57,8 +57,8 @@ typedef struct { } Key; typedef struct { - const char *name; - void (*func)(void); + char *name; + void (*func)(const Arg *arg); } Mode; typedef struct View View; @@ -84,7 +84,7 @@ void cleanupfields(Field **fields); void cleanupitems(Item **items); void cleanupview(View *v); Item *cloneitem(Item *item); -void databases(void); +void databases(const Arg *arg); void detach(View *v); void detachfieldfrom(Field *f, Field **ff); void detachitemfrom(Item *i, Item **ii); @@ -93,26 +93,26 @@ void *ecalloc(size_t nmemb, size_t size); void flagas(const Arg *arg); Item *getitem(void); int *getmaxlengths(View *view); +void help(const Arg *arg); void itempos(const Arg *arg); MYSQL_RES *mysql_exec(const char *sqlstr, ...); int mysql_fields(MYSQL_RES *res, Field **fields); int mysql_items(MYSQL_RES *res, Item **items); void mysql_listview(MYSQL_RES *res, int showfds); +View *newaview(const char *name, void (*func)(const Arg *arg)); void stfl_showfields(Field *fds, int *lens); void stfl_showitems(Item *items, int *lens); void quit(const Arg *arg); -void records(void); +void records(const Arg *arg); void reload(const Arg *arg); void run(void); -void setmode(const Arg *arg); void setup(void); void sigint_handler(int sig); void stfl_setf(const char *name, const char *fmtstr, ...); void stfl_putitem(Item *item, int *lens); int stripesc(char *src, char *dst, int len); -void tables(void); -void text(void); -void usedb(const Arg *arg); +void tables(const Arg *arg); +void text(const Arg *arg); void viewprev(const Arg *arg); #include "config.h" @@ -120,7 +120,7 @@ void viewprev(const Arg *arg); /* variables */ static int running = 1; static MYSQL *mysql; -static View *views, *selview; +static View *views, *selview = NULL; static struct stfl_ipool *ipool; static int fldseplen; @@ -256,11 +256,14 @@ cloneitem(Item *item) { } void -databases(void) { +databases(const Arg *arg) { MYSQL_RES *res; + int refresh = (selview && !strcmp(selview->mode->name, "databases")); if(!(res = mysql_exec("show databases"))) - die("databases"); + die("databases\n"); + if(!refresh) + selview = newaview("databases", databases); mysql_listview(res, 0); mysql_free_result(res); stfl_setf("title", "Databases in `%s`", dbhost); @@ -316,12 +319,13 @@ flagas(const Arg *arg) { Item * getitem(void) { + const char *spos = stfl_ipool_fromwc(ipool, stfl_get(selview->form, L"pos")); Item *item; int pos, n; - if(!selview) + if(!(selview && spos)) return NULL; - pos = atoi(stfl_ipool_fromwc(ipool, stfl_get(selview->form, L"pos"))); + pos = atoi(spos); for(item = selview->items, n = 0; item; item = item->next, ++n) if(n == pos) @@ -353,6 +357,18 @@ getmaxlengths(View *view) { } void +help(const Arg *arg) { + int refresh = (selview && !strcmp(selview->mode->name, "help")); + + if(!refresh) { + selview = newaview("help", help); + selview->form = stfl_create(L"<help.stfl>"); + } + else + stfl_setf("status", "Text updated."); +} + +void itempos(const Arg *arg) { const char *spos = stfl_ipool_fromwc(ipool, stfl_get(selview->form, L"pos")); char tmp[8]; @@ -440,13 +456,15 @@ void mysql_listview(MYSQL_RES *res, int showfds) { int *lens; + cleanupitems(&selview->items); + selview->nitems = mysql_items(res, &selview->items); + if(!selview->form) { selview->form = stfl_create(L"<items.stfl>"); - stfl_run(selview->form, -1); /* init ncurses */ + stfl_run(selview->form, -1); /* refresh ncurses */ curs_set(0); } - cleanupitems(&selview->items); - selview->nitems = mysql_items(res, &selview->items); + if(showfds) { cleanupfields(&selview->fields); selview->nfields = mysql_fields(res, &selview->fields); @@ -461,6 +479,19 @@ mysql_listview(MYSQL_RES *res, int showfds) { free(lens); } +View * +newaview(const char *name, void (*func)(const Arg *arg)) { + View *v; + + v = ecalloc(1, sizeof(View)); + v->mode = ecalloc(1, sizeof(Mode)); + v->mode->name = ecalloc(strlen(name)+1, sizeof(char)); + strcpy(v->mode->name, name); + v->mode->func = func; + attach(v); + return v; +} + void stfl_showfields(Field *fds, int *lens) { Field *fld; @@ -519,17 +550,23 @@ quit(const Arg *arg) { } void -records(void) { +records(const Arg *arg) { + int refresh = (selview && !strcmp(selview->mode->name, "records")); + Item *choice = (refresh ? selview->choice : cloneitem(getitem())); MYSQL_RES *res; char *tbl; - tbl = calloc(selview->choice->lens[0] + 1, sizeof(char)); - memcpy(tbl, selview->choice->cols[0], selview->choice->lens[0]); - - if(!(selview->choice && selview->choice->ncols)) + choice = (refresh ? selview->choice : cloneitem(getitem())); + if(!choice->ncols) die("records: no choice.\n"); + tbl = calloc(choice->lens[0] + 1, sizeof(char)); + memcpy(tbl, choice->cols[0], choice->lens[0]); if(!(res = mysql_exec("select * from `%s`", tbl))) die("records: cannot select `%s`\n", tbl); + if(!refresh) { + selview = newaview("records", records); + selview->choice = choice; + } mysql_listview(res, 1); mysql_free_result(res); stfl_setf("title", "Records in `%s`", tbl); @@ -540,8 +577,11 @@ records(void) { void reload(const Arg *arg) { const wchar_t *pos = stfl_get(selview->form, L"pos"); - selview->mode->func(); - stfl_set(selview->form, L"pos", pos); + if(!selview->mode->func) + return; + selview->mode->func(NULL); + if(pos) + stfl_set(selview->form, L"pos", pos); } void @@ -565,31 +605,6 @@ run(void) { } void -setmode(const Arg *arg) { - const Mode *m = (arg ? arg->v : &modes[0]); - View *v; - unsigned int i; - - if(selview && selview->mode && !strcmp(selview->mode->name, m->name)) - return; - for(v = views; v; v = v->next) - if(!strcmp(v->mode->name, m->name)) - break; - if(!v) { - v = ecalloc(1, sizeof(View)); - for(i = 0; i < LENGTH(modes); ++i) - if(!strcmp(modes[i].name, m->name)) - v->mode = &modes[i]; - attach(v); - } - if(v->choice) - free(v->choice); - v->choice = cloneitem(getitem()); - selview = v; - selview->mode->func(); -} - -void setup(void) { struct sigaction sa; @@ -599,7 +614,7 @@ setup(void) { fldseplen = strlen(FLDSEP); ipool = stfl_ipool_create(nl_langinfo(CODESET)); - setmode(NULL); + welcome(NULL); stfl_setf("status", "Welcome to %s-%s", __FILE__, VERSION); sa.sa_flags = 0; @@ -675,31 +690,32 @@ stripesc(char *dst, char *src, int len) { } void -tables(void) { +usage(void) { + die("Usage: %s [-vhup <arg>]\n", argv0); +} + +void +tables(const Arg *arg) { + int refresh = (selview && !strcmp(selview->mode->name, "tables")); + Item *choice = (refresh ? selview->choice : cloneitem(getitem())); MYSQL_RES *res; + if(!refresh) { + selview = newaview("tables", tables); + selview->choice = choice; + mysql_select_db(mysql, choice->cols[0]); + } if(!(res = mysql_exec("show tables"))) die("tables\n"); mysql_listview(res, 0); mysql_free_result(res); - stfl_setf("title", "Tables in `%s`", selview->choice->cols[0]); + stfl_setf("title", "Tables in `%s`", choice->cols[0]); stfl_setf("info", "%d table(s)", selview->nitems); } void -text(void) { -} - -void -usage(void) { - die("Usage: %s [-vhup <arg>]\n", argv0); -} - -void -usedb(const Arg *arg) { - Item *item = getitem(); - mysql_select_db(mysql, item->cols[0]); - setmode(arg); +text(const Arg *arg) { + stfl_setf("status", "I don't know how to refresh the content."); } void diff --git a/help.stfl b/help.stfl @@ -0,0 +1,27 @@ +* See LICENSE file for copyright and license details. + +vbox[main] + @bind_up: @bind_down: @bind_left: @bind_right: + @bind_page_up: @bind_page_down: @bind_home: @bind_end: + @bind_delete: @bind_backspace: @bind_enter: + + label + @style_normal:fg=black,bg=white + text[title]:"The mutt of MySQL - Work in progress..." + .expand:0 + label + @style_normal:fg=blue,bg=black,attr=bold + text[subtle]:"" + .display[showsubtle]:0 + .expand:0 + textview + @style_normal:fg=white,bg=black + listitem + text:"Hello!" + label + @style_normal:fg=black,bg=white + .expand:0 + text[info]:"" + label + .expand:0 + text[status]:""