diff options
| author | ruki <[email protected]> | 2022-11-30 23:17:56 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2022-11-30 23:17:56 +0800 |
| commit | 6ab4c11e415f5cb5de30f150e21649b48c45a3c8 (patch) | |
| tree | 7f056b1c3bb331407a1adec4b374683d761f4746 /core/src/xmake | |
| parent | 8617fc332b913cc666b9f2afb20b2d61f6a79481 (diff) | |
rewrite curses
Diffstat (limited to 'core/src/xmake')
| -rw-r--r-- | core/src/xmake/curses/curses.c | 839 | ||||
| -rw-r--r-- | core/src/xmake/curses/prefix.h | 29 | ||||
| -rw-r--r-- | core/src/xmake/engine.c | 9 | ||||
| -rw-r--r-- | core/src/xmake/makefile | 1 | ||||
| -rw-r--r-- | core/src/xmake/xmake.lua | 14 |
5 files changed, 882 insertions, 10 deletions
diff --git a/core/src/xmake/curses/curses.c b/core/src/xmake/curses/curses.c new file mode 100644 index 000000000..e22207eb7 --- /dev/null +++ b/core/src/xmake/curses/curses.c @@ -0,0 +1,839 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, TBOOX Open Source Group. + * + * @author ruki + * @file curses.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "curses" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#ifdef XM_CONFIG_API_HAVE_CURSES +#include "prefix.h" +#include <stdlib.h> +#if defined(PDCURSES) +// fix macro redefinition +# undef MOUSE_MOVED +#endif +#include <curses.h> +#if defined(NCURSES_VERSION) +# include <locale.h> +#endif + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +#define XM_CURSES_STDSCR "curses.stdscr" +#define XM_CURSES_WINDOW "curses.window" +#define XM_CURSES_OK(v) (((v) == ERR) ? 0 : 1) + +// define functions +#define XM_CURSES_NUMBER(n) \ + static int xm_curses_ ## n(lua_State* lua) \ + { \ + lua_pushnumber(lua, n()); \ + return 1; \ + } + +#define XM_CURSES_NUMBER2(n, v) \ + static int xm_curses_ ## n(lua_State* lua) \ + { \ + lua_pushnumber(lua, v); \ + return 1; \ + } + +#define XM_CURSES_BOOL(n) \ + static int xm_curses_ ## n(lua_State* lua) \ + { \ + lua_pushboolean(lua, n()); \ + return 1; \ + } + +#define XM_CURSES_BOOLOK(n) \ + static int xm_curses_ ## n(lua_State* lua) \ + { \ + lua_pushboolean(lua, XM_CURSES_OK(n())); \ + return 1; \ + } + +#define XM_CURSES_WINDOW_BOOLOK(n) \ + static int xm_curses_window_ ## n(lua_State* lua) \ + { \ + WINDOW* w = xm_curses_window_check(lua, 1); \ + lua_pushboolean(lua, XM_CURSES_OK(n(w))); \ + return 1; \ + } + +// define constants +#define XM_CURSES_CONST_(n, v) \ + lua_pushstring(lua, n); \ + lua_pushnumber(lua, v); \ + lua_settable(lua, lua_upvalueindex(1)); + +#define XM_CURSES_CONST(s) XM_CURSES_CONST_(#s, s) +#define XM_CURSES_CONST2(s, v) XM_CURSES_CONST_(#s, v) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * globals + */ + +// map key for pdcurses, keeping the keys consistent with ncurses +static int g_mapkey = 0; + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static chtype xm_curses_checkch(lua_State* lua, int index) +{ + if (lua_type(lua, index) == LUA_TNUMBER) + return (chtype)luaL_checknumber(lua, index); + if (lua_type(lua, index) == LUA_TSTRING) + return *lua_tostring(lua, index); +#ifdef USE_LUAJIT + luaL_typerror(lua, index, "chtype"); +#endif + return (chtype)0; +} + +// get character and map key +static int xm_curses_window_getch_impl(WINDOW* w) +{ +#ifdef PDCURSES + static int has_key = 0; + static int temp_key = 0; + + int key; + if (g_mapkey && has_key) + { + has_key = 0; + return temp_key; + } + + key = wgetch(w); + if (key == ERR || !g_mapkey) return key; + if (key >= ALT_A && key <= ALT_Z) + { + has_key = 1; + temp_key = key - ALT_A + 'A'; + } + else if (key >= ALT_0 && key <= ALT_9) + { + has_key = 1; + temp_key = key - ALT_0 + '0'; + } + else + { + switch (key) + { + case ALT_DEL: temp_key = KEY_DC; break; + case ALT_INS: temp_key = KEY_IC; break; + case ALT_HOME: temp_key = KEY_HOME; break; + case ALT_END: temp_key = KEY_END; break; + case ALT_PGUP: temp_key = KEY_PPAGE; break; + case ALT_PGDN: temp_key = KEY_NPAGE; break; + case ALT_UP: temp_key = KEY_UP; break; + case ALT_DOWN: temp_key = KEY_DOWN; break; + case ALT_RIGHT: temp_key = KEY_RIGHT; break; + case ALT_LEFT: temp_key = KEY_LEFT; break; + case ALT_BKSP: temp_key = KEY_BACKSPACE; break; + default: return key; + } + } + has_key = 1; + return 27; +#else + return wgetch(w); +#endif +} + +// new a window object +static void xm_curses_window_new(lua_State* lua, WINDOW* nw) +{ + if (nw) + { + WINDOW** w = (WINDOW**)lua_newuserdata(lua, sizeof(WINDOW*)); + luaL_getmetatable(lua, XM_CURSES_WINDOW); + lua_setmetatable(lua, -2); + *w = nw; + } + else + { + lua_pushliteral(lua, "failed to create window"); + lua_error(lua); + } +} + +// get window +static WINDOW** xm_curses_window_get(lua_State* lua, int index) +{ + WINDOW** w = (WINDOW**)luaL_checkudata(lua, index, XM_CURSES_WINDOW); + if (w == NULL) luaL_argerror(lua, index, "bad curses window"); + return w; +} + +// get and check window +static WINDOW* xm_curses_window_check(lua_State* lua, int index) +{ + WINDOW** w = xm_curses_window_get(lua, index); + if (*w == NULL) luaL_argerror(lua, index, "attempt to use closed curses window"); + return *w; +} + +// tostring(window) +static int xm_curses_window_tostring(lua_State* lua) +{ + WINDOW** w = xm_curses_window_get(lua, 1); + char const* s = NULL; + if (*w) s = (char const*)lua_touserdata(lua, 1); + lua_pushfstring(lua, "curses window (%s)", s? s : "closed"); + return 1; +} + +// window:move(y, x) +static int xm_curses_window_move(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int y = luaL_checkint(lua, 2); + int x = luaL_checkint(lua, 3); + lua_pushboolean(lua, XM_CURSES_OK(wmove(w, y, x))); + return 1; +} + +// window:getyx(y, x) +static int xm_curses_window_getyx(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int y, x; + getyx(w, y, x); + lua_pushnumber(lua, y); + lua_pushnumber(lua, x); + return 2; +} + +// window:getmaxyx(y, x) +static int xm_curses_window_getmaxyx(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int y, x; + getmaxyx(w, y, x); + lua_pushnumber(lua, y); + lua_pushnumber(lua, x); + return 2; +} + +// window:delwin() +static int xm_curses_window_delwin(lua_State* lua) +{ + WINDOW** w = xm_curses_window_get(lua, 1); + if (*w && *w != stdscr) + { + delwin(*w); + *w = NULL; + } + return 0; +} + +// window:addch(ch) +static int xm_curses_window_addch(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + chtype ch = xm_curses_checkch(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(waddch(w, ch))); + return 1; +} + +// window:addnstr(str) +static int xm_curses_window_addnstr(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + const char* str = luaL_checkstring(lua, 2); + int n = luaL_optint(lua, 3, -1); + if (n < 0) n = (int)lua_strlen(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(waddnstr(w, str, n))); + return 1; +} + +// window:keypad(true) +static int xm_curses_window_keypad(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int enabled = lua_isnoneornil(lua, 2) ? 1 : lua_toboolean(lua, 2); + if (enabled) + { + // on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys, + // only makes sense when using keypad(true) and echo(false) + g_mapkey = 1; + } + lua_pushboolean(lua, XM_CURSES_OK(keypad(w, enabled))); + return 1; +} + +// window:meta(true) +static int xm_curses_window_meta(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int enabled = lua_toboolean(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(meta(w, enabled))); + return 1; +} + +// window:nodelay(true) +static int xm_curses_window_nodelay(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int enabled = lua_toboolean(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(nodelay(w, enabled))); + return 1; +} + +// window:leaveok(true) +static int xm_curses_window_leaveok(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int enabled = lua_toboolean(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(leaveok(w, enabled))); + return 1; +} + +// window:getch() +static int xm_curses_window_getch(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int c = xm_curses_window_getch_impl(w); + if (c == ERR) return 0; + lua_pushnumber(lua, c); + return 1; +} + +// window:attroff(attrs) +static int xm_curses_window_attroff(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int attrs = luaL_checkint(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(wattroff(w, attrs))); + return 1; +} + +// window:attron(attrs) +static int xm_curses_window_attron(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int attrs = luaL_checkint(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(wattron(w, attrs))); + return 1; +} + +// window:attrset(attrs) +static int xm_curses_window_attrset(lua_State* lua) +{ + WINDOW* w = xm_curses_window_check(lua, 1); + int attrs = luaL_checkint(lua, 2); + lua_pushboolean(lua, XM_CURSES_OK(wattrset(w, attrs))); + return 1; +} + +// window:copywin(...) +static int xm_curses_window_copywin(lua_State* lua) +{ + WINDOW* srcwin = xm_curses_window_check(lua, 1); + WINDOW* dstwin = xm_curses_window_check(lua, 2); + int sminrow = luaL_checkint(lua, 3); + int smincol = luaL_checkint(lua, 4); + int dminrow = luaL_checkint(lua, 5); + int dmincol = luaL_checkint(lua, 6); + int dmaxrow = luaL_checkint(lua, 7); + int dmaxcol = luaL_checkint(lua, 8); + int overlay = lua_toboolean(lua, 9); + lua_pushboolean(lua, XM_CURSES_OK(copywin(srcwin, dstwin, sminrow, + smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay))); + return 1; +} + +// clean window after exiting program +static void xm_curses_cleanup() +{ + if (!isendwin()) + { + wclear(stdscr); + wrefresh(stdscr); + endwin(); + } +} + +// register constants +static void xm_curses_register_constants(lua_State* lua) +{ + // colors + XM_CURSES_CONST(COLOR_BLACK) + XM_CURSES_CONST(COLOR_RED) + XM_CURSES_CONST(COLOR_GREEN) + XM_CURSES_CONST(COLOR_YELLOW) + XM_CURSES_CONST(COLOR_BLUE) + XM_CURSES_CONST(COLOR_MAGENTA) + XM_CURSES_CONST(COLOR_CYAN) + XM_CURSES_CONST(COLOR_WHITE) + + // alternate character set + XM_CURSES_CONST(ACS_BLOCK) + XM_CURSES_CONST(ACS_BOARD) + XM_CURSES_CONST(ACS_BTEE) + XM_CURSES_CONST(ACS_TTEE) + XM_CURSES_CONST(ACS_LTEE) + XM_CURSES_CONST(ACS_RTEE) + XM_CURSES_CONST(ACS_LLCORNER) + XM_CURSES_CONST(ACS_LRCORNER) + XM_CURSES_CONST(ACS_URCORNER) + XM_CURSES_CONST(ACS_ULCORNER) + XM_CURSES_CONST(ACS_LARROW) + XM_CURSES_CONST(ACS_RARROW) + XM_CURSES_CONST(ACS_UARROW) + XM_CURSES_CONST(ACS_DARROW) + XM_CURSES_CONST(ACS_HLINE) + XM_CURSES_CONST(ACS_VLINE) + XM_CURSES_CONST(ACS_BULLET) + XM_CURSES_CONST(ACS_CKBOARD) + XM_CURSES_CONST(ACS_LANTERN) + XM_CURSES_CONST(ACS_DEGREE) + XM_CURSES_CONST(ACS_DIAMOND) + XM_CURSES_CONST(ACS_PLMINUS) + XM_CURSES_CONST(ACS_PLUS) + XM_CURSES_CONST(ACS_S1) + XM_CURSES_CONST(ACS_S9) + + // attributes + XM_CURSES_CONST(A_NORMAL) + XM_CURSES_CONST(A_STANDOUT) + XM_CURSES_CONST(A_UNDERLINE) + XM_CURSES_CONST(A_REVERSE) + XM_CURSES_CONST(A_BLINK) + XM_CURSES_CONST(A_DIM) + XM_CURSES_CONST(A_BOLD) + XM_CURSES_CONST(A_PROTECT) + XM_CURSES_CONST(A_INVIS) + XM_CURSES_CONST(A_ALTCHARSET) + XM_CURSES_CONST(A_CHARTEXT) + + // key functions + XM_CURSES_CONST(KEY_BREAK) + XM_CURSES_CONST(KEY_DOWN) + XM_CURSES_CONST(KEY_UP) + XM_CURSES_CONST(KEY_LEFT) + XM_CURSES_CONST(KEY_RIGHT) + XM_CURSES_CONST(KEY_HOME) + XM_CURSES_CONST(KEY_BACKSPACE) + + XM_CURSES_CONST(KEY_DL) + XM_CURSES_CONST(KEY_IL) + XM_CURSES_CONST(KEY_DC) + XM_CURSES_CONST(KEY_IC) + XM_CURSES_CONST(KEY_EIC) + XM_CURSES_CONST(KEY_CLEAR) + XM_CURSES_CONST(KEY_EOS) + XM_CURSES_CONST(KEY_EOL) + XM_CURSES_CONST(KEY_SF) + XM_CURSES_CONST(KEY_SR) + XM_CURSES_CONST(KEY_NPAGE) + XM_CURSES_CONST(KEY_PPAGE) + XM_CURSES_CONST(KEY_STAB) + XM_CURSES_CONST(KEY_CTAB) + XM_CURSES_CONST(KEY_CATAB) + XM_CURSES_CONST(KEY_ENTER) + XM_CURSES_CONST(KEY_SRESET) + XM_CURSES_CONST(KEY_RESET) + XM_CURSES_CONST(KEY_PRINT) + XM_CURSES_CONST(KEY_LL) + XM_CURSES_CONST(KEY_A1) + XM_CURSES_CONST(KEY_A3) + XM_CURSES_CONST(KEY_B2) + XM_CURSES_CONST(KEY_C1) + XM_CURSES_CONST(KEY_C3) + XM_CURSES_CONST(KEY_BTAB) + XM_CURSES_CONST(KEY_BEG) + XM_CURSES_CONST(KEY_CANCEL) + XM_CURSES_CONST(KEY_CLOSE) + XM_CURSES_CONST(KEY_COMMAND) + XM_CURSES_CONST(KEY_COPY) + XM_CURSES_CONST(KEY_CREATE) + XM_CURSES_CONST(KEY_END) + XM_CURSES_CONST(KEY_EXIT) + XM_CURSES_CONST(KEY_FIND) + XM_CURSES_CONST(KEY_HELP) + XM_CURSES_CONST(KEY_MARK) + XM_CURSES_CONST(KEY_MESSAGE) +#ifdef PDCURSES + // https://github.com/xmake-io/xmake/issues/1610#issuecomment-971149885 + XM_CURSES_CONST(KEY_C2) + XM_CURSES_CONST(KEY_A2) + XM_CURSES_CONST(KEY_B1) + XM_CURSES_CONST(KEY_B3) +#endif +#if !defined(XCURSES) +# ifndef NOMOUSE + XM_CURSES_CONST(KEY_MOUSE) +# endif +#endif + XM_CURSES_CONST(KEY_MOVE) + XM_CURSES_CONST(KEY_NEXT) + XM_CURSES_CONST(KEY_OPEN) + XM_CURSES_CONST(KEY_OPTIONS) + XM_CURSES_CONST(KEY_PREVIOUS) + XM_CURSES_CONST(KEY_REDO) + XM_CURSES_CONST(KEY_REFERENCE) + XM_CURSES_CONST(KEY_REFRESH) + XM_CURSES_CONST(KEY_REPLACE) + XM_CURSES_CONST(KEY_RESIZE) + XM_CURSES_CONST(KEY_RESTART) + XM_CURSES_CONST(KEY_RESUME) + XM_CURSES_CONST(KEY_SAVE) + XM_CURSES_CONST(KEY_SBEG) + XM_CURSES_CONST(KEY_SCANCEL) + XM_CURSES_CONST(KEY_SCOMMAND) + XM_CURSES_CONST(KEY_SCOPY) + XM_CURSES_CONST(KEY_SCREATE) + XM_CURSES_CONST(KEY_SDC) + XM_CURSES_CONST(KEY_SDL) + XM_CURSES_CONST(KEY_SELECT) + XM_CURSES_CONST(KEY_SEND) + XM_CURSES_CONST(KEY_SEOL) + XM_CURSES_CONST(KEY_SEXIT) + XM_CURSES_CONST(KEY_SFIND) + XM_CURSES_CONST(KEY_SHELP) + XM_CURSES_CONST(KEY_SHOME) + XM_CURSES_CONST(KEY_SIC) + XM_CURSES_CONST(KEY_SLEFT) + XM_CURSES_CONST(KEY_SMESSAGE) + XM_CURSES_CONST(KEY_SMOVE) + XM_CURSES_CONST(KEY_SNEXT) + XM_CURSES_CONST(KEY_SOPTIONS) + XM_CURSES_CONST(KEY_SPREVIOUS) + XM_CURSES_CONST(KEY_SPRINT) + XM_CURSES_CONST(KEY_SREDO) + XM_CURSES_CONST(KEY_SREPLACE) + XM_CURSES_CONST(KEY_SRIGHT) + XM_CURSES_CONST(KEY_SRSUME) + XM_CURSES_CONST(KEY_SSAVE) + XM_CURSES_CONST(KEY_SSUSPEND) + XM_CURSES_CONST(KEY_SUNDO) + XM_CURSES_CONST(KEY_SUSPEND) + XM_CURSES_CONST(KEY_UNDO) + + // KEY_Fx 0 <= x <= 63 + XM_CURSES_CONST(KEY_F0) + XM_CURSES_CONST2(KEY_F1, KEY_F(1)) + XM_CURSES_CONST2(KEY_F2, KEY_F(2)) + XM_CURSES_CONST2(KEY_F3, KEY_F(3)) + XM_CURSES_CONST2(KEY_F4, KEY_F(4)) + XM_CURSES_CONST2(KEY_F5, KEY_F(5)) + XM_CURSES_CONST2(KEY_F6, KEY_F(6)) + XM_CURSES_CONST2(KEY_F7, KEY_F(7)) + XM_CURSES_CONST2(KEY_F8, KEY_F(8)) + XM_CURSES_CONST2(KEY_F9, KEY_F(9)) + XM_CURSES_CONST2(KEY_F10, KEY_F(10)) + XM_CURSES_CONST2(KEY_F11, KEY_F(11)) + XM_CURSES_CONST2(KEY_F12, KEY_F(12)) + +#if !defined(XCURSES) +# ifndef NOMOUSE + // mouse constants + XM_CURSES_CONST(BUTTON1_RELEASED) + XM_CURSES_CONST(BUTTON1_PRESSED) + XM_CURSES_CONST(BUTTON1_CLICKED) + XM_CURSES_CONST(BUTTON1_DOUBLE_CLICKED) + XM_CURSES_CONST(BUTTON1_TRIPLE_CLICKED) + XM_CURSES_CONST(BUTTON2_RELEASED) + XM_CURSES_CONST(BUTTON2_PRESSED) + XM_CURSES_CONST(BUTTON2_CLICKED) + XM_CURSES_CONST(BUTTON2_DOUBLE_CLICKED) + XM_CURSES_CONST(BUTTON2_TRIPLE_CLICKED) + XM_CURSES_CONST(BUTTON3_RELEASED) + XM_CURSES_CONST(BUTTON3_PRESSED) + XM_CURSES_CONST(BUTTON3_CLICKED) + XM_CURSES_CONST(BUTTON3_DOUBLE_CLICKED) + XM_CURSES_CONST(BUTTON3_TRIPLE_CLICKED) + XM_CURSES_CONST(BUTTON4_RELEASED) + XM_CURSES_CONST(BUTTON4_PRESSED) + XM_CURSES_CONST(BUTTON4_CLICKED) + XM_CURSES_CONST(BUTTON4_DOUBLE_CLICKED) + XM_CURSES_CONST(BUTTON4_TRIPLE_CLICKED) + XM_CURSES_CONST(BUTTON_CTRL) + XM_CURSES_CONST(BUTTON_SHIFT) + XM_CURSES_CONST(BUTTON_ALT) + XM_CURSES_CONST(REPORT_MOUSE_POSITION) + XM_CURSES_CONST(ALL_MOUSE_EVENTS) +# if NCURSES_MOUSE_VERSION > 1 + XM_CURSES_CONST(BUTTON5_RELEASED) + XM_CURSES_CONST(BUTTON5_PRESSED) + XM_CURSES_CONST(BUTTON5_CLICKED) + XM_CURSES_CONST(BUTTON5_DOUBLE_CLICKED) + XM_CURSES_CONST(BUTTON5_TRIPLE_CLICKED) +# else + XM_CURSES_CONST(BUTTON1_RESERVED_EVENT) + XM_CURSES_CONST(BUTTON2_RESERVED_EVENT) + XM_CURSES_CONST(BUTTON3_RESERVED_EVENT) + XM_CURSES_CONST(BUTTON4_RESERVED_EVENT) +# endif +# endif +#endif +} + +// init curses +static int xm_curses_initscr(lua_State* lua) +{ + WINDOW* w = initscr(); + if (!w) return 0; + xm_curses_window_new(lua, w); + +#if defined(NCURSES_VERSION) + ESCDELAY = 0; +#endif + + lua_pushstring(lua, XM_CURSES_STDSCR); + lua_pushvalue(lua, -2); + lua_rawset(lua, LUA_REGISTRYINDEX); + + xm_curses_register_constants(lua); + +#ifndef PDCURSES + atexit(xm_curses_cleanup); +#endif + return 1; +} + +static int xm_curses_endwin(lua_State* lua) +{ + endwin(); +#ifdef XCURSES + XCursesExit(); + exit(0); +#endif + return 0; +} + +static int xm_curses_stdscr(lua_State* lua) +{ + lua_pushstring(lua, XM_CURSES_STDSCR); + lua_rawget(lua, LUA_REGISTRYINDEX); + return 1; +} + +#if !defined(XCURSES) && !defined(NOMOUSE) +static int xm_curses_getmouse(lua_State* lua) +{ + MEVENT e; + if (getmouse(&e) == OK) + { + lua_pushinteger(lua, e.bstate); + lua_pushinteger(lua, e.x); + lua_pushinteger(lua, e.y); + lua_pushinteger(lua, e.z); + lua_pushinteger(lua, e.id); + return 5; + } + + lua_pushnil(lua); + return 1; +} + +static int xm_curses_mousemask(lua_State* lua) +{ + mmask_t m = luaL_checkint(lua, 1); + mmask_t om; + m = mousemask(m, &om); + lua_pushinteger(lua, m); + lua_pushinteger(lua, om); + return 2; +} +#endif + +static int xm_curses_init_pair(lua_State* lua) +{ + short pair = luaL_checkint(lua, 1); + short f = luaL_checkint(lua, 2); + short b = luaL_checkint(lua, 3); + + lua_pushboolean(lua, XM_CURSES_OK(init_pair(pair, f, b))); + return 1; +} + +static int xm_curses_COLOR_PAIR(lua_State* lua) +{ + int n = luaL_checkint(lua, 1); + lua_pushnumber(lua, COLOR_PAIR(n)); + return 1; +} + +static int xm_curses_curs_set(lua_State* lua) +{ + int vis = luaL_checkint(lua, 1); + int state = curs_set(vis); + if (state == ERR) + return 0; + + lua_pushnumber(lua, state); + return 1; +} + +static int xm_curses_napms(lua_State* lua) +{ + int ms = luaL_checkint(lua, 1); + lua_pushboolean(lua, XM_CURSES_OK(napms(ms))); + return 1; +} + +static int xm_curses_cbreak(lua_State* lua) +{ + if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) + lua_pushboolean(lua, XM_CURSES_OK(cbreak())); + else + lua_pushboolean(lua, XM_CURSES_OK(nocbreak())); + return 1; +} + +static int xm_curses_echo(lua_State* lua) +{ + if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) + lua_pushboolean(lua, XM_CURSES_OK(echo())); + else + lua_pushboolean(lua, XM_CURSES_OK(noecho())); + return 1; +} + +static int xm_curses_nl(lua_State* lua) +{ + if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) + lua_pushboolean(lua, XM_CURSES_OK(nl())); + else + lua_pushboolean(lua, XM_CURSES_OK(nonl())); + return 1; +} + +static int xm_curses_newpad(lua_State* lua) +{ + int nlines = luaL_checkint(lua, 1); + int ncols = luaL_checkint(lua, 2); + xm_curses_window_new(lua, newpad(nlines, ncols)); + return 1; +} + +XM_CURSES_NUMBER2(COLS, COLS) +XM_CURSES_NUMBER2(LINES, LINES) +XM_CURSES_BOOL(isendwin) +XM_CURSES_BOOLOK(start_color) +XM_CURSES_BOOL(has_colors) +XM_CURSES_BOOLOK(doupdate) +XM_CURSES_WINDOW_BOOLOK(wclear) +XM_CURSES_WINDOW_BOOLOK(wnoutrefresh) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * globals + */ + +static const luaL_Reg g_window_functions[] = +{ + { "close", xm_curses_window_delwin }, + { "keypad", xm_curses_window_keypad }, + { "meta", xm_curses_window_meta }, + { "nodelay", xm_curses_window_nodelay }, + { "leaveok", xm_curses_window_leaveok }, + { "move", xm_curses_window_move }, + { "clear", xm_curses_window_wclear }, + { "noutrefresh",xm_curses_window_wnoutrefresh }, + { "attroff", xm_curses_window_attroff }, + { "attron", xm_curses_window_attron }, + { "attrset", xm_curses_window_attrset }, + { "getch", xm_curses_window_getch }, + { "getyx", xm_curses_window_getyx }, + { "getmaxyx", xm_curses_window_getmaxyx }, + { "addch", xm_curses_window_addch }, + { "addstr", xm_curses_window_addnstr }, + { "copy", xm_curses_window_copywin }, + {"__gc", xm_curses_window_delwin }, + {"__tostring", xm_curses_window_tostring }, + {NULL, NULL } +}; + +static const luaL_Reg g_curses_functions[] = +{ + { "done", xm_curses_endwin }, + { "isdone", xm_curses_isendwin }, + { "main_window", xm_curses_stdscr }, + { "columns", xm_curses_COLS }, + { "lines", xm_curses_LINES }, + { "start_color", xm_curses_start_color }, + { "has_colors", xm_curses_has_colors }, + { "init_pair", xm_curses_init_pair }, + { "color_pair", xm_curses_COLOR_PAIR }, + { "napms", xm_curses_napms }, + { "cursor_set", xm_curses_curs_set }, + { "new_pad", xm_curses_newpad }, + { "doupdate", xm_curses_doupdate }, + { "cbreak", xm_curses_cbreak }, + { "echo", xm_curses_echo }, + { "nl", xm_curses_nl }, +#if !defined(XCURSES) +#ifndef NOMOUSE + { "mousemask", xm_curses_mousemask }, + { "getmouse", xm_curses_getmouse }, +#endif +#endif + {NULL, NULL} +}; + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementations + */ +int xm_lua_curses_register(lua_State* lua, const char* module) +{ + // create new metatable for window objects + luaL_newmetatable(lua, XM_CURSES_WINDOW); + lua_pushliteral(lua, "__index"); + lua_pushvalue(lua, -2); /* push metatable */ + lua_rawset(lua, -3); /* metatable.__index = metatable */ + luaL_setfuncs(lua, g_window_functions, 0); + lua_pop(lua, 1); /* remove metatable from stack */ + + // create global table with curses methods/variables/constants + lua_newtable(lua); + luaL_setfuncs(lua, g_curses_functions, 0); + + // add curses.init() + lua_pushstring(lua, "init"); + lua_pushvalue(lua, -2); + lua_pushcclosure(lua, xm_curses_initscr, 1); + lua_settable(lua, -3); + + // register global curses module + lua_setglobal(lua, module); + + /* since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function. + * that means that you have to call setlocale() in the application and encode Unicode strings using one of the system’s available encodings. + * + * and we need link libncurses_window.so for drawing vline, hline characters + */ +#if defined(NCURSES_VERSION) + setlocale(LC_ALL, ""); +#endif + return 1; +} +#endif diff --git a/core/src/xmake/curses/prefix.h b/core/src/xmake/curses/prefix.h new file mode 100644 index 000000000..74ee74a62 --- /dev/null +++ b/core/src/xmake/curses/prefix.h @@ -0,0 +1,29 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, TBOOX Open Source Group. + * + * @author uael + * @file prefix.h + * + */ +#ifndef XM_CURSES_PREFIX_H +#define XM_CURSES_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + +#endif diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index 9fc13f4a5..0ecafd064 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -286,10 +286,8 @@ tb_int_t xm_libc_setbyte(lua_State* lua); tb_int_t xm_tty_term_mode(lua_State* lua); #ifdef XM_CONFIG_API_HAVE_CURSES -// register curses -__tb_extern_c_enter__ -tb_int_t xm_curses_register(lua_State* lua); -__tb_extern_c_leave__ +// register curses functions +tb_int_t xm_lua_curses_register(lua_State* lua, tb_char_t const* module); #endif // open cjson @@ -1108,8 +1106,7 @@ xm_engine_ref_t xm_engine_init(tb_char_t const* name, xm_engine_lni_initalizer_c #ifdef XM_CONFIG_API_HAVE_CURSES // bind curses - xm_curses_register(engine->lua); - lua_setglobal(engine->lua, "curses"); + xm_lua_curses_register(engine->lua, "curses"); #endif // bind cjson diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index 5ce8942bb..627f6a13c 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -128,6 +128,7 @@ xmake_C_FILES += \ semver/satisfies \ semver/select \ semver/semver \ + curses/curses \ readline/readline \ readline/history_list \ readline/add_history \ diff --git a/core/src/xmake/xmake.lua b/core/src/xmake/xmake.lua index db3971209..1745313fa 100644 --- a/core/src/xmake/xmake.lua +++ b/core/src/xmake/xmake.lua @@ -4,11 +4,11 @@ target("xmake") set_kind("static") -- add deps - if has_config("curses") or has_config("pdcurses") then - add_deps("lcurses") - end add_deps("sv", "lua-cjson", "lz4", "tbox") add_deps(get_config("runtime")) + if is_plat("windows") and has_config("pdcurses") then + add_deps("pdcurses") + end -- add defines add_defines("__tb_prefix__=\"xmake\"") @@ -39,7 +39,13 @@ target("xmake") -- add options add_options("readline") if is_plat("windows") then - add_defines("UNICODE", "_UNICODE") + add_options("pdcurses") + else + add_options("curses") end + -- add defines + if is_plat("windows") then + add_defines("UNICODE", "_UNICODE") + end |
