161 lines
3.9 KiB
C++
161 lines
3.9 KiB
C++
#include "tui.hpp"
|
|
|
|
#include <time.h>
|
|
#include <locale.h>
|
|
#include <ncurses.h>
|
|
#include <readline/readline.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
extern bool do_run;
|
|
|
|
size_t entry_lines;
|
|
bool is_input_changed = true;
|
|
|
|
static WINDOW * main_window;
|
|
static WINDOW * entry_window;
|
|
static WINDOW * input_window;
|
|
static WINDOW * version_window;
|
|
|
|
static int input_available = false;
|
|
static int input;
|
|
|
|
size_t selection_offset = 0;
|
|
size_t selection_relative = 0;
|
|
static size_t entry_line_index = 0;
|
|
|
|
static char version_string[] =
|
|
# include "version.inc"
|
|
;
|
|
|
|
static void refresh_input(void);
|
|
|
|
int init_tui(void) {
|
|
// Ncurses
|
|
initscr();
|
|
nonl();
|
|
cbreak();
|
|
noecho();
|
|
curs_set(0);
|
|
keypad(stdscr, TRUE);
|
|
|
|
entry_lines = LINES-3;
|
|
|
|
main_window = newwin(LINES-1, COLS, 0, 0);
|
|
entry_window = subwin(main_window, entry_lines, COLS-2, 1, 1);
|
|
version_window = subwin(main_window, 1, strlen(version_string), 0, 5);
|
|
input_window = newwin(1, COLS, LINES-1, 0);
|
|
refresh();
|
|
|
|
box(main_window, 0, 0);
|
|
|
|
// XXX
|
|
waddstr(version_window, version_string);
|
|
wrefresh(version_window);
|
|
|
|
// Readline
|
|
rl_bind_key('\t', rl_insert);
|
|
rl_catch_signals = 0;
|
|
rl_catch_sigwinch = 0;
|
|
rl_prep_term_function = NULL;
|
|
rl_deprep_term_function = NULL;
|
|
rl_change_environment = 0;
|
|
|
|
rl_getc_function = []([[maybe_unused]] FILE* ignore){
|
|
input_available = false;
|
|
return (int)input;
|
|
};
|
|
rl_input_available_hook = []{
|
|
return input_available;
|
|
};
|
|
rl_redisplay_function = refresh_input;
|
|
/* We must specify an input handler or readline chimps out,
|
|
* but we dont want the line to be actually submittable,
|
|
* (search is continous and that would delete what the user
|
|
* has typedso far)
|
|
* so we also override enter to do nothing.
|
|
*/
|
|
rl_callback_handler_install("", []([[maybe_unused]] char *line){ ; });
|
|
rl_bind_key('\n', []([[maybe_unused]] int i, [[maybe_unused]] int h){ return 0; });
|
|
|
|
return 0;
|
|
}
|
|
|
|
int deinit_tui(void) {
|
|
endwin();
|
|
return 0;
|
|
}
|
|
|
|
void tui_append_back(const entry_t entry) {
|
|
struct tm *tm_info = localtime((time_t*)&entry.timestamp);
|
|
const int TIME_BUFFER_SIZE = 30;
|
|
char time_buffer[TIME_BUFFER_SIZE];
|
|
strftime(time_buffer, TIME_BUFFER_SIZE, "%Y-%m-%d %H:%M:%S", tm_info);
|
|
|
|
if (entry_line_index == selection_relative) {
|
|
wattron(entry_window, A_REVERSE);
|
|
}
|
|
mvwprintw(entry_window, (entry_lines-1)-entry_line_index, 0,
|
|
"%s %s\n",
|
|
time_buffer,
|
|
entry.command
|
|
);
|
|
if (entry_line_index == selection_relative) {
|
|
wattroff(entry_window, A_REVERSE);
|
|
}
|
|
|
|
++entry_line_index;
|
|
}
|
|
|
|
static void refresh_input(void) {
|
|
entry_line_index = 0;
|
|
wmove(input_window, 0, 0);
|
|
wclrtoeol(input_window);
|
|
waddstr(input_window, "$ ");
|
|
waddstr(input_window, rl_line_buffer);
|
|
waddch(input_window, ACS_BLOCK);
|
|
wrefresh(input_window);
|
|
}
|
|
|
|
void tui_refresh(void) {
|
|
wmove(entry_window, 0, 0);
|
|
wrefresh(entry_window);
|
|
wrefresh(main_window);
|
|
refresh_input();
|
|
}
|
|
|
|
|
|
void tui_take_input(void) {
|
|
input = wgetch(stdscr);
|
|
switch (input) {
|
|
case CTRL('p'):
|
|
case CTRL('k'): {
|
|
if (selection_relative != entry_lines-1) {
|
|
++selection_relative;
|
|
} else {
|
|
++selection_offset;
|
|
is_input_changed = true;
|
|
}
|
|
} break;
|
|
case CTRL('n'):
|
|
case CTRL('j'): {
|
|
if (selection_relative != 0) {
|
|
--selection_relative;
|
|
} else {
|
|
if (selection_offset != 0) {
|
|
--selection_offset;
|
|
is_input_changed = true;
|
|
}
|
|
}
|
|
} break;
|
|
case '\r': {
|
|
do_run = false;
|
|
} break;
|
|
default: {
|
|
input_available = true;
|
|
rl_callback_read_char();
|
|
is_input_changed = true;
|
|
} break;
|
|
}
|
|
}
|