about summary refs log tree commit diff
path: root/main.c
diff options
context:
space:
mode:
authorvenomade <venomade@venomade.com>2026-05-21 16:57:22 +0100
committervenomade <venomade@venomade.com>2026-05-21 16:57:22 +0100
commit671e18febd45bba01d3d29db7a544d25d1b36a3b (patch)
tree61bb6654df52df2f2c3d77c9169ea4e0b84177f3 /main.c
Initial Commit main
Diffstat (limited to 'main.c')
-rw-r--r--main.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2edc588
--- /dev/null
+++ b/main.c
@@ -0,0 +1,278 @@
+#ifndef _XOPEN_SOURCE_EXTENDED
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <locale.h>
+#include <ncurses.h>
+#include <lua/lua.h>
+#include <lua/lauxlib.h>
+#include <lua/lualib.h>
+
+extern const char main_luac[];
+extern const unsigned int main_luac_len;
+
+static lua_State        *G_L      = NULL;
+static volatile int      g_resize = 0;
+
+static void on_sigwinch(int sig) { (void)sig; g_resize = 1; }
+
+static int push_error(lua_State *L, const char *msg) {
+    lua_pushnil(L);
+    lua_pushstring(L, msg);
+    return 2;
+}
+
+static int l_init_ncurses(lua_State *L) {
+    (void)L;
+    setlocale(LC_ALL, "");
+    initscr();
+    cbreak();
+    raw();
+    noecho();
+    keypad(stdscr, TRUE);
+    nodelay(stdscr, FALSE);
+    curs_set(0);
+    start_color();
+    use_default_colors();
+    init_pair(1, COLOR_BLACK, COLOR_WHITE);
+    signal(SIGWINCH, on_sigwinch);
+    return 0;
+}
+
+static int l_end_ncurses(lua_State *L) {
+    (void)L;
+    endwin();
+    return 0;
+}
+
+static int l_resize_terminal(lua_State *L) {
+    (void)L;
+    if (g_resize) {
+        g_resize = 0;
+        endwin();
+        refresh();
+        clearok(stdscr, TRUE);
+    }
+    return 0;
+}
+
+static int l_refresh_screen(lua_State *L) {
+    (void)L;
+    wrefresh(stdscr);
+    return 0;
+}
+
+static int l_get_wchar(lua_State *L) {
+    wint_t ch;
+    int res = wget_wch(stdscr, &ch);
+    if (res == ERR)
+        lua_pushinteger(L, -1);
+    else
+        lua_pushinteger(L, (lua_Integer)ch);
+    return 1;
+}
+
+static int l_set_title(lua_State *L) {
+    const char *title = luaL_checkstring(L, 1);
+    printf("\033]0;%s\007", title);
+    fflush(stdout);
+    return 0;
+}
+
+static int l_get_screen_size(lua_State *L) {
+    int rows, cols;
+    getmaxyx(stdscr, rows, cols);
+    lua_pushinteger(L, rows);
+    lua_pushinteger(L, cols + 1);
+    return 2;
+}
+
+static int l_clear_screen(lua_State *L) {
+    (void)L;
+    clear();
+    return 0;
+}
+
+static int l_move_cursor(lua_State *L) {
+    int y = (int)luaL_checkinteger(L, 1);
+    int x = (int)luaL_checkinteger(L, 2);
+    move(y, x);
+    return 0;
+}
+
+static int l_print_at(lua_State *L) {
+    int         y   = (int)luaL_checkinteger(L, 1);
+    int         x   = (int)luaL_checkinteger(L, 2);
+    const char *str = luaL_checkstring(L, 3);
+    mvprintw(y, x, "%s", str);
+    return 0;
+}
+
+static int l_set_reverse(lua_State *L) {
+    if (lua_toboolean(L, 1)) attron(A_REVERSE); else attroff(A_REVERSE);
+    return 0;
+}
+
+static int l_set_bold(lua_State *L) {
+    if (lua_toboolean(L, 1)) attron(A_BOLD); else attroff(A_BOLD);
+    return 0;
+}
+
+static int l_set_color(lua_State *L) {
+    int pair   = (int)luaL_checkinteger(L, 1);
+    int enable = lua_toboolean(L, 2);
+    if (enable) attron(COLOR_PAIR(pair)); else attroff(COLOR_PAIR(pair));
+    return 0;
+}
+
+static int l_init_color_pair(lua_State *L) {
+    int pair = (int)luaL_checkinteger(L, 1);
+    int fg   = (int)luaL_checkinteger(L, 2);
+    int bg   = (int)luaL_checkinteger(L, 3);
+    init_pair((short)pair, (short)fg, (short)bg);
+    return 0;
+}
+
+static int l_save_file(lua_State *L) {
+    const char *fname   = luaL_checkstring(L, 1);
+    const char *content = luaL_checkstring(L, 2);
+    FILE *f = fopen(fname, "w");
+    if (!f) return push_error(L, "Open failed");
+    size_t len = strlen(content);
+    if (len > 0 && fwrite(content, 1, len, f) != len) {
+        fclose(f);
+        return push_error(L, "Write failed");
+    }
+    fclose(f);
+    lua_pushboolean(L, 1);
+    return 1;
+}
+
+static int l_load_file(lua_State *L) {
+    const char *fname = luaL_checkstring(L, 1);
+    FILE *f = fopen(fname, "r");
+    if (!f) return push_error(L, "Open failed");
+    fseek(f, 0, SEEK_END);
+    long size = ftell(f);
+    fseek(f, 0, SEEK_SET);
+    if (size < 0) { fclose(f); return push_error(L, "Seek failed"); }
+    char *buf = malloc((size_t)size + 1);
+    if (!buf) { fclose(f); return push_error(L, "Alloc failed"); }
+    size_t r = fread(buf, 1, (size_t)size, f);
+    buf[r] = '\0';
+    fclose(f);
+    lua_pushlstring(L, buf, r);
+    free(buf);
+    return 1;
+}
+
+static int l_list_dir(lua_State *L) {
+    const char *path = luaL_checkstring(L, 1);
+    DIR *d = opendir(path);
+    if (!d) { lua_pushnil(L); return 1; }
+    lua_newtable(L);
+    int idx = 1;
+    struct dirent *ent;
+    while ((ent = readdir(d)) != NULL) {
+        lua_pushstring(L, ent->d_name);
+        lua_rawseti(L, -2, idx++);
+    }
+    closedir(d);
+    return 1;
+}
+
+static int l_stat_file(lua_State *L) {
+    const char *path = luaL_checkstring(L, 1);
+    struct stat st;
+    if (stat(path, &st) != 0) { lua_pushnil(L); return 1; }
+    if      (S_ISREG(st.st_mode)) lua_pushstring(L, "file");
+    else if (S_ISDIR(st.st_mode)) lua_pushstring(L, "dir");
+    else                           lua_pushstring(L, "other");
+    return 1;
+}
+
+static int l_lua_eval(lua_State *L) {
+    const char *code     = luaL_checkstring(L, 1);
+    int         top_before = lua_gettop(G_L);
+
+    if (luaL_loadstring(G_L, code) != LUA_OK) {
+        const char *err = lua_tostring(G_L, -1);
+        lua_pop(G_L, 1);
+        lua_pushstring(L, err ? err : "compile error");
+        return 1;
+    }
+    if (lua_pcall(G_L, 0, LUA_MULTRET, 0) != LUA_OK) {
+        const char *err = lua_tostring(G_L, -1);
+        lua_pop(G_L, 1);
+        lua_pushstring(L, err ? err : "runtime error");
+        return 1;
+    }
+    int nret = lua_gettop(G_L) - top_before;
+    if (nret > 0) {
+        const char *res = lua_tostring(G_L, -1);
+        lua_pushstring(L, res ? res : "(non-string result)");
+        lua_settop(G_L, top_before);
+    } else {
+        lua_pushstring(L, "ok");
+    }
+    return 1;
+}
+
+static const struct { const char *name; lua_CFunction func; } bindings[] = {
+    {"init_ncurses",    l_init_ncurses},
+    {"end_ncurses",     l_end_ncurses},
+    {"resize_terminal", l_resize_terminal},
+    {"refresh_screen",  l_refresh_screen},
+    {"get_wchar",       l_get_wchar},
+    {"set_title",       l_set_title},
+    {"get_screen_size", l_get_screen_size},
+    {"clear_screen",    l_clear_screen},
+    {"move_cursor",     l_move_cursor},
+    {"print_at",        l_print_at},
+    {"set_reverse",     l_set_reverse},
+    {"set_bold",        l_set_bold},
+    {"set_color",       l_set_color},
+    {"init_color_pair", l_init_color_pair},
+    {"save_file",       l_save_file},
+    {"load_file",       l_load_file},
+    {"list_dir",        l_list_dir},
+    {"stat_file",       l_stat_file},
+    {"lua_eval",        l_lua_eval},
+    {NULL, NULL}
+};
+
+int main(int argc, char *argv[]) {
+    lua_State *L = luaL_newstate();
+    if (!L) { fprintf(stderr, "Lua init failed\n"); return 1; }
+    G_L = L;
+    luaL_openlibs(L);
+
+    for (int i = 0; bindings[i].name; i++) {
+        lua_pushcfunction(L, bindings[i].func);
+        lua_setglobal(L, bindings[i].name);
+    }
+
+    lua_newtable(L);
+    for (int i = 1; i < argc; i++) {
+        lua_pushstring(L, argv[i]);
+        lua_rawseti(L, -2, i);
+    }
+    lua_setglobal(L, "arg");
+
+    if (luaL_loadbuffer(L, main_luac, main_luac_len, "main.lua") ||
+        lua_pcall(L, 0, 0, 0)) {
+        fprintf(stderr, "Lume: %s\n", lua_tostring(L, -1));
+        lua_pop(L, 1);
+        lua_close(L);
+        return 1;
+    }
+
+    lua_close(L);
+    return 0;
+}