diff --git a/asana/asana.c b/asana/asana.c index 6672674..883adb0 100644 --- a/asana/asana.c +++ b/asana/asana.c @@ -217,7 +217,8 @@ asana_err user_task_list(char *task_list_gid, Project *task_list) { task_list->tasks = (Task *)asana_parse_array(task_list_resp->body, sizeof(Task), &(task_list->tasks_len)); ret = task_list->tasks == NULL ? ASANA_ERR_PARSE : ASANA_ERR_OK; } else { - fprintf(stderr, "Error fetching user_Task_list: %d\n", task_list_resp->status); + fprintf(stderr, "Error fetching user_task_list: %d\n", + task_list_resp->status); } asana_free_response(task_list_resp); diff --git a/ncac.c b/ncac.c index 700c8bd..dcebd78 100644 --- a/ncac.c +++ b/ncac.c @@ -1,39 +1,80 @@ #include "ncac.h" #include +#include #include #include +#include #include #include "asana/asana.h" #include "asana/fetch.h" #include "ui/base.h" +#include "ui/commands.h" +#include "ui/model.h" + +void append_to_buffer(ui_state *state, char c) { + if (state->buffer_size < UI_INPUT_BUFFER_SIZE - 1) { + state->input_buffer[state->buffer_size++] = c; + state->input_buffer[state->buffer_size] = '\0'; + } +} + +bool handle_command(ui_state *state) { + for (size_t i = 0; i < UI_NUM_COMMANDS; i++) { + if (strncmp(state->input_buffer, ui_commands[i].command, + UI_INPUT_BUFFER_SIZE) == 0) { + return ui_commands[i].handler(state); + } + } + + state->curs_y = 0; + state->curs_x = 0; + + draw_text("Unknown command. Type \":help\" for a list of commands", state); + + return false; +} int main(/*int argc, char **argv*/) { setup(); - int curs_x = 0; - int curs_y = 0; + int input; - char input; + ui_state state; + state.mode = 0; + state.buffer_size = 0; + state.input_buffer[0] = '\0'; + + while (true) { + draw_status_line(&state); - while (1) { switch (input = getch()) { - case 'a': - draw_text("Hello, world!", &curs_x, &curs_y); - break; - case 'b': - draw_text("Goodbye, world!", &curs_x, &curs_y); - break; - case 'j': - get_me(&curs_x, &curs_y); - break; - case 'm': - get_my_tasks(&curs_x, &curs_y); - break; - case 'q': - finish(SIGTERM); - break; + case '\r': + if (state.mode == COMMAND) { + state.mode = NORMAL; + if (handle_command(&state)) { + finish(SIGTERM); + } + } else if (state.mode == NORMAL) { + state.curs_y++; + } + break; + case KEY_EXIT: + state.mode = NORMAL; + break; + case ':': + if (state.mode == NORMAL) { + state.mode = COMMAND; + state.buffer_size = 0; + state.input_buffer[0] = '\0'; + } else { + append_to_buffer(&state, input); + } + break; + default: + append_to_buffer(&state, input); + break; } } return 0; @@ -71,6 +112,8 @@ static void setup() { } noecho(); nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); // install handlers signal(SIGINT, &finish); @@ -95,7 +138,7 @@ void get_me(int *curs_x, int *curs_y) { *curs_x = 0; (*curs_y)++; - draw_text(gid, curs_x, curs_y); + // draw_text(gid, curs_x, curs_y); } void get_my_tasks(int *curs_x, int *curs_y) { @@ -124,12 +167,12 @@ void get_my_tasks(int *curs_x, int *curs_y) { *curs_x = 0; *curs_y = 0; - draw_text("My Tasks", curs_x, curs_y); + // draw_text("My Tasks", curs_x, curs_y); *curs_x = 0; (*curs_y)+=2; for (size_t i=0; i +#include #include -void draw_text(char *text, int *x, int *y) { +#include "commands.h" +#include "model.h" + +void draw_status_line(ui_state *state) { + int old_x = state->curs_x; + int old_y = state->curs_y; + + state->curs_y = LINES - 1; + state->curs_x = 0; + + if (state->mode == NORMAL) { + draw_text("NORMAL", state); + } else { + draw_text(":", state); + draw_text(state->input_buffer, state); + } + clrtoeol(); + + state->curs_x = old_x; + state->curs_y = old_y; +} + +void draw_text(const char *text, ui_state *state) { if (!text || strnlen(text, 1) == 0) return; - mvaddch(*y, *x, *text); + mvaddch(state->curs_y, state->curs_x, *text); ++text; for (; *text != '\0'; ++text) { addch(*text); } - getyx(stdscr, *y, *x); + getyx(stdscr, state->curs_y, state->curs_x); } diff --git a/ui/base.h b/ui/base.h index cc907c8..b97eb2c 100644 --- a/ui/base.h +++ b/ui/base.h @@ -1,10 +1,19 @@ #ifndef UI_BASE_H_ #define UI_BASE_H_ +#include + +#include "model.h" + /** * Prints the string text starting at position *x, *y. x and y are updated to * the position after the last character */ -void draw_text(char *text, int *x, int *y); +void draw_text(const char *text, ui_state *state); + +/** + * Render the input status bar + */ +void draw_status_line(ui_state *state); #endif // UI_BASE_H_ diff --git a/ui/commands.c b/ui/commands.c new file mode 100644 index 0000000..1312110 --- /dev/null +++ b/ui/commands.c @@ -0,0 +1,92 @@ +#include "commands.h" + +#include +#include + +#include "../asana/asana.h" +#include "base.h" + +bool ui_quit(ui_state *state) { return true; } + +bool ui_help(ui_state *state) { + state->curs_x = 0; + state->curs_y = 0; + + draw_text("Commands:", state); + state->curs_x = 0; + state->curs_y += 2; + + for (size_t i = 0; i < UI_NUM_COMMANDS; i++) { + draw_text("\t", state); + draw_text(ui_commands[i].command, state); + draw_text("\t", state); + draw_text(ui_commands[i].help_text, state); + clrtoeol(); + + state->curs_x = 0; + state->curs_y++; + } + + return false; +} + +bool ui_mytasks(ui_state *state) { + state->curs_x = 0; + state->curs_y = 0; + draw_text("Fetching user...", state); + clrtoeol(); + + /* + User me; + user_info(&me); + + if (me.workspaces == NULL || me.workspaces_len == 0) { + fprintf(stderr, "Unable to get workspaces.\n"); + return true; + } + */ + + state->curs_x = 0; + state->curs_y = 0; + draw_text("Fetching user task list ID...", state); + clrtoeol(); + + char gid[64]; + gid[0] = '\0'; + if (user_task_list_gid( + /*me.workspaces[me.workspaces_len-1].gid*/ "15793206719", gid) != + ASANA_ERR_OK) { + fprintf(stderr, "Unable to get task list ID. %s\n", gid); + return true; + } + + state->curs_x = 0; + state->curs_y = 0; + draw_text("Fetching user task list", state); + clrtoeol(); + + Project my_tasks; + if (user_task_list(gid, &my_tasks) != ASANA_ERR_OK) { + fprintf(stderr, "Unable to get task list.\n"); + return true; + } + + state->curs_x = 0; + state->curs_y = 0; + draw_text("My Tasks", state); + clrtoeol(); + + for (size_t i = 0; i < my_tasks.tasks_len; i++) { + state->curs_y++; + state->curs_x = 0; + draw_text(my_tasks.tasks[i].name, state); + clrtoeol(); + } + + return false; +} + +ui_command ui_commands[UI_NUM_COMMANDS] = { + {"help", "print this help message", ui_help}, + {"q", "quit the application", ui_quit}, + {"mytasks", "fetch and display your task list", ui_mytasks}}; diff --git a/ui/commands.h b/ui/commands.h new file mode 100644 index 0000000..1dfc09e --- /dev/null +++ b/ui/commands.h @@ -0,0 +1,19 @@ +#ifndef UI_COMMANDS_H_ +#define UI_COMMANDS_H_ + +#include + +#include "model.h" + +typedef struct ui_command { + const char *command; + const char *help_text; + bool (*handler)(ui_state *); +} ui_command; + +#define UI_NUM_COMMANDS 3 +extern ui_command ui_commands[]; + +bool handle_command(ui_state *state); + +#endif // UI_COMMANDS_H_ diff --git a/ui/model.c b/ui/model.c new file mode 100644 index 0000000..0e1234c --- /dev/null +++ b/ui/model.c @@ -0,0 +1 @@ +#include "model.h" diff --git a/ui/model.h b/ui/model.h new file mode 100644 index 0000000..5b68c72 --- /dev/null +++ b/ui/model.h @@ -0,0 +1,21 @@ +#ifndef UI_MODEL_H_ +#define UI_MODEL_H_ + +#include + +enum UI_MODE { + NORMAL, + COMMAND, +}; + +#define UI_INPUT_BUFFER_SIZE 4096 + +typedef struct ui_state { + int curs_x; + int curs_y; + enum UI_MODE mode; + size_t buffer_size; + char input_buffer[UI_INPUT_BUFFER_SIZE]; +} ui_state; + +#endif // UI_MODEL_H_