testing version

This commit is contained in:
anon 2024-08-03 15:14:52 +02:00
parent 0480db08fa
commit 29accaf24e
14 changed files with 278 additions and 53 deletions

@ -11,3 +11,31 @@ p argv[0]
p * argv[0] p * argv[0]
p (char *)argv[0] p (char *)argv[0]
p argc p argc
r
where
frame 5
l
r
where
frame 5
r
where
r
where
frame 3
l
frame 2
l
start
l
start
n
n
s
n
where
c
where
frame 1
frame 2
p stmt

@ -1,7 +1,6 @@
.PHONY: clean run .PHONY: clean run
ifeq (${DEBUG}, 1) ifeq (${DEBUG}, 1)
LFLAGS += --debug --trace
CXXFLAGS += -DDEBUG -O0 -ggdb -fno-inline CXXFLAGS += -DDEBUG -O0 -ggdb -fno-inline
WRAP := valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all WRAP := valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all
else else
@ -15,7 +14,7 @@ LINKasd += $$(pkgconf --libs ncurses readline sqlite3)
OBJECT.d:=object/ OBJECT.d:=object/
SOURCE.d:=source/ SOURCE.d:=source/
SOURCE:=bash_history.yy.cpp main.cpp tui.cpp storage.cpp damerau_levenshtein.cpp SOURCE:=bash_history.yy.cpp main.cpp cli.cpp tui.cpp storage.cpp damerau_levenshtein.cpp
OBJECT:=$(addprefix ${OBJECT.d},$(addsuffix .o,$(basename ${SOURCE}))) OBJECT:=$(addprefix ${OBJECT.d},$(addsuffix .o,$(basename ${SOURCE})))
SOURCE:=$(addprefix ${SOURCE.d},${SOURCE}) SOURCE:=$(addprefix ${SOURCE.d},${SOURCE})
@ -25,7 +24,7 @@ ${OUTPUT}: ${OBJECT}
${LINK.cpp} ${OBJECT} ${LINKasd} -o ${OUTPUT} ${LINK.cpp} ${OBJECT} ${LINKasd} -o ${OUTPUT}
object/%.yy.cpp: source/%.l object/%.yy.cpp: source/%.l
${LEX} ${LFLAGS} --prefix=$*_ --header-file=$(basename $@).hpp -o $@ $< ${LEX} --prefix=$*_ --header-file=$(basename $@).hpp -o $@ $<
object/%.o: object/%.l.cpp object/%.o: object/%.l.cpp
${COMPILE.cpp} $< -o $@ ${COMPILE.cpp} $< -o $@

@ -2,13 +2,12 @@
#include "storage.hpp" #include "storage.hpp"
long timestamp; long timestamp;
%} %}
%option nodefault
%option noyywrap %option noyywrap
%option nounput
%% %%
\#[[:digit:]]+ { \#[[:digit:]]+ { timestamp = strtoll(yytext+1, NULL, 10);
timestamp = strtoll(yytext+1, NULL, 10);
} }
[^\#\n].* { .* { insert_entry(timestamp, yytext); }
insert_entry(timestamp, yytext); \n { ; }
}
\n { ; }
%% %%

@ -1,28 +1,40 @@
#include "cli.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <map>
#include <string>
using namespace std; using namespace std;
[[ noreturn ]] [[ noreturn ]]
void version() { void version() {
puts("Histui " puts(
#include "version.inc" # include "version.inc"
); );
exit(0); exit(0);
} }
[[ noreturn ]] [[ noreturn ]]
void usage(int exit_value = 0) { void usage(int exit_value) {
// TODO // TODO
puts(
"histui [options] <verb>\n"
"\tOptions:\n"
"\t\t-v --version\n"
"\t\t-h --help\n"
"\tVerbs:\n"
"\t\tenable : print a bash script to enable histui in the current shell\n"
"\t\ttui : run histui normally\n"
);
exit(exit_value); exit(exit_value);
} }
void global_options(const int argc, const char * const * const argv) { void parse_global_options(const int argc, const char * const * const argv) {
for(int i = 0; i < argc; i++) { for(int i = 1; i < argc; i++) {
if (argv[i][0] != '-') {
return;
}
if (not strcmp(argv[i], "-v") if (not strcmp(argv[i], "-v")
|| not strcmp(argv[i], "--version")) { || not strcmp(argv[i], "--version")) {
version(); version();
@ -34,9 +46,18 @@ void global_options(const int argc, const char * const * const argv) {
} }
} }
typedef signed (*mainlike_t)(int argc, char * * argv); verb_t get_verb(const int argc, const char * const * const argv) {
map<const char*, mainlike_t> verb_table = { for(int i = 1; i < argc; i++) {
{"tui", tui_main}, if (argv[i][0] == '-') {
{"import", import_main}, continue;
{"export", export_main}, }
}; if (not strcmp(argv[i], "tui")) {
return TUI;
}
if (not strcmp(argv[i], "enable")) {
return ENABLE;
}
return ERROR;
}
return ERROR;
}

11
source/cli.hpp Normal file

@ -0,0 +1,11 @@
#pragma once
typedef enum {
TUI,
ENABLE,
ERROR,
} verb_t;
extern void parse_global_options(const int argc, const char * const * const argv);
extern verb_t get_verb(const int argc, const char * const * const argv);
[[ noreturn ]] void usage(int exit_value = 0);

@ -65,7 +65,7 @@ damerau_levenshtein_(
} }
/* /*
function to determine damerau-levenshtein distance sqlite3 wrapper to determine damerau-levenshtein distance
damerau_levenshtein(src,dts) => int damerau_levenshtein(src,dts) => int
*/ */
void void
@ -85,8 +85,28 @@ damerau_levenshtein(
sqlite3_result_int(context, distance); sqlite3_result_int(context, distance);
} }
// XXX
void
damerau_levenshtein_substring(
sqlite3_context *context,
[[maybe_unused]] int argc,
sqlite3_value **argv
){
const char *const s = (const char *)sqlite3_value_text(argv[0]);
const char *const t = (const char *)sqlite3_value_text(argv[1]);
int n = strlen(s);
int m = strlen(t);
n = (n < m ? n : m);
m = n;
const int distance = damerau_levenshtein_(n, s, m, t);
sqlite3_result_int(context, distance);
}
/* /*
function ensure damerau-levenshtein distance sqlite wrapper to ensure damerau-levenshtein distance
damerau_levenshtein(src,dts,max_distance) => bool damerau_levenshtein(src,dts,max_distance) => bool
*/ */
void void

@ -1,3 +1,4 @@
#pragma once #pragma once
extern void damerau_levenshtein(sqlite3_context *context, int argc, sqlite3_value **argv); extern void damerau_levenshtein(sqlite3_context *context, int argc, sqlite3_value **argv);
extern void is_damerau_levenshtein(sqlite3_context *context, int argc, sqlite3_value **argv); extern void is_damerau_levenshtein(sqlite3_context *context, int argc, sqlite3_value **argv);
extern void damerau_levenshtein_substring(sqlite3_context *context, int argc, sqlite3_value **argv);

@ -0,0 +1,9 @@
function _histui_run() {
COMMANDFILE="${XDG_CACHE_HOME}/histui_command.txt"
histui tui 3> "${COMMANDFILE}"
READLINE_LINE=$(cat "${COMMANDFILE}")
READLINE_POINT=${#READLINE_LINE}
}
bind -x '"\e[A": _histui_run'
bind -x '"\C-r": _histui_run'

@ -1,39 +1,83 @@
#include <locale.h> #include <locale.h>
#include "cli.hpp"
#include "bash_history.yy.hpp"
#include "storage.hpp" #include "storage.hpp"
#include "tui.hpp" #include "tui.hpp"
#include "bash_history.yy.hpp"
bool do_run = true;
void init() { void init() {
setlocale(LC_TIME, "C"); setlocale(LC_TIME, "C");
init_storage(); init_storage();
bash_history_in = fopen("/home/anon/stow/.cache/.bash_history", "r");
bash_history_lex();
init_tui(); init_tui();
} }
void deinit() { void deinit() {
deinit_storage();
deinit_tui(); deinit_tui();
deinit_storage();
}
[[ noreturn ]]
void enable() {
// XXX one day...
/*
puts(
# embed "histui_enable.sh.inc"
);
*/
puts(
R"delim(
function _histui_run() {
COMMANDFILE="${XDG_CACHE_HOME}/histui_command.txt"
histui tui 3> "${COMMANDFILE}"
READLINE_LINE=$(cat "${COMMANDFILE}")
READLINE_POINT=${#READLINE_LINE}
}
bind -x '"\e[A": _histui_run'
bind -x '"\C-r": _histui_run'
)delim"
);
exit(0);
} }
signed main(int argc, char * argv[]) { signed main(int argc, char * argv[]) {
// TODO cli stuff parse_global_options(argc, argv);
verb_t verb = get_verb(argc, argv);
switch (verb) {
case ENABLE: enable();
case ERROR: usage(1);
case TUI: break;
}
init(); init();
bash_history_in = fopen("/home/anon/stow/.cache/.bash_history", "r");
bash_history_lex();
tui_refresh(); tui_refresh();
entry_t entry; entry_t entry;
while (true) { while (do_run) {
query(rl_line_buffer); if (is_input_changed) {
query(rl_line_buffer, entry_lines, selection_offset);
is_input_changed = false;
} else {
requery();
}
while (entry = get_entry(), entry.command != NULL) { while (entry = get_entry(), entry.command != NULL) {
tui_append_back(entry); tui_append_back(entry);
} }
tui_take_input();
tui_refresh(); tui_refresh();
tui_take_input();
} }
query(rl_line_buffer, 1, selection_offset + selection_relative);
int fd[2];
pipe(fd);
dprintf(3, get_entry().command);
close(fd[0]);
close(fd[1]);
deinit(); deinit();
return 0; return 0;

@ -5,14 +5,15 @@
#include "damerau_levenshtein.hpp" #include "damerau_levenshtein.hpp"
static sqlite3 * db; static sqlite3 * db;
static sqlite3_stmt * stmt; static sqlite3_stmt * stmt = NULL;
int init_storage(void) { int init_storage(void) {
sqlite3_open(":memory:", &db); sqlite3_open(":memory:", &db);
sqlite3_create_function(db, "damerau_levenshtein_substring", 2, SQLITE_ANY, 0, damerau_levenshtein_substring, NULL, NULL);
sqlite3_create_function(db, "is_damerau_levenshtein", 3, SQLITE_ANY, 0, is_damerau_levenshtein, NULL, NULL); sqlite3_create_function(db, "is_damerau_levenshtein", 3, SQLITE_ANY, 0, is_damerau_levenshtein, NULL, NULL);
sqlite3_create_function(db, "damerau_levenshtein", 2, SQLITE_ANY, 0, damerau_levenshtein, NULL, NULL); sqlite3_create_function(db, "damerau_levenshtein", 2, SQLITE_ANY, 0, damerau_levenshtein, NULL, NULL);
static const char * sql_create_table = "CREATE TABLE test (stamp INTEGER, data TEXT);"; static const char * sql_create_table = "CREATE TABLE entries (stamp INTEGER, data TEXT);";
sqlite3_exec(db, sql_create_table, 0, 0, 0); sqlite3_exec(db, sql_create_table, 0, 0, 0);
return 0; return 0;
@ -25,7 +26,8 @@ int deinit_storage(void) {
} }
int insert_entry(int timestamp, const char * const command) { int insert_entry(int timestamp, const char * const command) {
static const char * sql_insert = "INSERT INTO test (stamp, data) VALUES (?, ?);"; static const char * sql_insert = "INSERT INTO entries (stamp, data) VALUES (?, ?);";
sqlite3_stmt * stmt;
sqlite3_prepare_v2(db, sql_insert, -1, &stmt, 0); sqlite3_prepare_v2(db, sql_insert, -1, &stmt, 0);
sqlite3_bind_int64(stmt, 1, timestamp); sqlite3_bind_int64(stmt, 1, timestamp);
@ -36,14 +38,36 @@ int insert_entry(int timestamp, const char * const command) {
return 0; return 0;
} }
void query(const char * const string) { void query(const char * const string, const size_t limit, const size_t offset) {
sqlite3_prepare_v2(db, "SELECT * FROM test ORDER BY DAMERAU_LEVENSHTEIN(data, ?) LIMIT 40;", -1, &stmt, 0); sqlite3_finalize(stmt);
sqlite3_bind_text(stmt, 1, string, -1, SQLITE_TRANSIENT); const char * sql_query;
if (string[0] != '\0') {
sql_query = "SELECT * FROM entries "
"ORDER BY DAMERAU_LEVENSHTEIN_SUBSTRING(data, ?) "
"LIMIT ? "
"OFFSET ?;"
;
sqlite3_prepare_v2(db, sql_query, -1, &stmt, 0);
sqlite3_bind_text(stmt, 1, string, -1, SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 2, (long)limit);
sqlite3_bind_int64(stmt, 3, (long)offset);
} else {
sql_query = "SELECT * FROM entries "
"ORDER BY stamp DESC "
"LIMIT ? "
"OFFSET ?;";
sqlite3_prepare_v2(db, sql_query, -1, &stmt, 0);
sqlite3_bind_int64(stmt, 1, (long)limit);
sqlite3_bind_int64(stmt, 2, (long)offset);
}
}
void requery(void) {
sqlite3_reset(stmt);
} }
entry_t get_entry(void) { entry_t get_entry(void) {
if (sqlite3_step(stmt) != SQLITE_ROW) { if (sqlite3_step(stmt) != SQLITE_ROW) {
sqlite3_finalize(stmt);
return (entry_t){ return (entry_t){
.timestamp = 0, .timestamp = 0,
.command = NULL .command = NULL

@ -1,9 +1,11 @@
#pragma once #pragma once
#include <stddef.h>
#include "entry.h" #include "entry.h"
int init_storage(void); int init_storage(void);
int deinit_storage(void); int deinit_storage(void);
int insert_entry(int timestamp, const char * const command); int insert_entry(int timestamp, const char * const command);
void query(const char * const string); void query(const char * const string, const size_t limit, const size_t offset);
void requery(void);
entry_t get_entry(void); entry_t get_entry(void);

@ -5,31 +5,54 @@
#include <ncurses.h> #include <ncurses.h>
#include <readline/readline.h> #include <readline/readline.h>
// XXX #include <stdlib.h>
#include <cstdlib>
extern bool do_run;
size_t entry_lines;
bool is_input_changed = true;
static WINDOW * main_window; static WINDOW * main_window;
static WINDOW * entry_window; static WINDOW * entry_window;
static WINDOW * input_window; static WINDOW * input_window;
static WINDOW * version_window;
static int input_available = false; static int input_available = false;
static char input; 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); static void refresh_input(void);
int init_tui(void) { int init_tui(void) {
// Ncurses // Ncurses
initscr(); initscr();
nonl();
cbreak();
noecho(); noecho();
curs_set(0); curs_set(0);
keypad(stdscr, TRUE);
main_window = newwin(LINES-1, COLS, 0, 0); entry_lines = LINES-3;
entry_window = subwin(main_window, LINES-3, COLS-2, 1, 1);
input_window = newwin(1, COLS, LINES-1, 0); 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(); refresh();
box(main_window, 0, 0); box(main_window, 0, 0);
// XXX
waddstr(version_window, version_string);
wrefresh(version_window);
// Readline // Readline
rl_bind_key('\t', rl_insert); rl_bind_key('\t', rl_insert);
rl_catch_signals = 0; rl_catch_signals = 0;
@ -69,13 +92,23 @@ void tui_append_back(const entry_t entry) {
char time_buffer[TIME_BUFFER_SIZE]; char time_buffer[TIME_BUFFER_SIZE];
strftime(time_buffer, TIME_BUFFER_SIZE, "%Y-%m-%d %H:%M:%S", tm_info); strftime(time_buffer, TIME_BUFFER_SIZE, "%Y-%m-%d %H:%M:%S", tm_info);
wprintw(entry_window, "%s %s\n", if (entry_line_index == selection_relative) {
time_buffer, wattron(entry_window, A_REVERSE);
entry.command }
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) { static void refresh_input(void) {
entry_line_index = 0;
wmove(input_window, 0, 0); wmove(input_window, 0, 0);
wclrtoeol(input_window); wclrtoeol(input_window);
waddstr(input_window, "$ "); waddstr(input_window, "$ ");
@ -94,6 +127,34 @@ void tui_refresh(void) {
void tui_take_input(void) { void tui_take_input(void) {
input = wgetch(stdscr); input = wgetch(stdscr);
input_available = true; switch (input) {
rl_callback_read_char(); 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;
}
} }

@ -1,8 +1,14 @@
#pragma once #pragma once
#include <stddef.h>
#include "entry.h" #include "entry.h"
extern "C" char * rl_line_buffer; extern "C" char * rl_line_buffer;
extern size_t entry_lines;
extern size_t selection_offset;
extern size_t selection_relative;
extern bool is_input_changed;
int init_tui(void); int init_tui(void);
int deinit_tui(void); int deinit_tui(void);
void tui_refresh(void); void tui_refresh(void);

@ -1 +1 @@
"0.2" "Histui v0.2"