From: Michael D. Lowis Date: Thu, 6 Jul 2017 19:45:39 +0000 (-0400) Subject: Crude prototype of terminal emulator functions now. Input/Output handling needs lots... X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=2855670675717f5e46374b5d91b33cd4cb75c2cf;p=projs%2Ftide.git Crude prototype of terminal emulator functions now. Input/Output handling needs lots of work --- diff --git a/inc/edit.h b/inc/edit.h index 00981bd..411a054 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -234,9 +234,6 @@ enum { /* Configuration Variables */ ClrTagsSel, ClrTagsCsr, ClrEditNor, ClrEditSel, ClrEditCsr, ClrEditRul, ClrBorders, - //BkgRuler, BkgGutter, BkgTags, BkgEdit, BkgScroll, BkgThumb, BkgBorder, - //TxtCursor, TxtNormal, TxtSelected, TxtGutter, TxtCurrentLine, - SynNormal, SynComment, SynConstant, SynString, SynChar, SynNumber, SynBoolean, SynFloat, SynVariable, SynFunction, SynKeyword, SynOperator, SynPreProc, SynType, SynStatement, SynSpecial diff --git a/inc/win.h b/inc/win.h index 8306287..a54f0aa 100644 --- a/inc/win.h +++ b/inc/win.h @@ -46,7 +46,7 @@ void win_setlinenums(bool enable); bool win_getlinenums(void); void win_setruler(size_t ruler); Rune win_getkey(void); -void win_setkeys(KeyBinding* bindings); +void win_setkeys(KeyBinding* bindings, void (*inputfn)(Rune)); void win_setmouse(MouseConfig* mconfig); void win_warpptr(WinRegion id); View* win_view(WinRegion id); @@ -67,4 +67,5 @@ void onscroll(double percent); void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col); void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col); void onmouseright(WinRegion id, bool pressed, size_t row, size_t col); +bool update_needed(void); diff --git a/lib/win.c b/lib/win.c index 5ba621d..59a2df6 100644 --- a/lib/win.c +++ b/lib/win.c @@ -11,6 +11,7 @@ static void onmousedrag(int state, int x, int y); static void onmousebtn(int btn, bool pressed, int x, int y); static void onwheelup(WinRegion id, bool pressed, size_t row, size_t col); static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col); +static bool update_focus(void); static void draw_line_num(bool current, size_t x, size_t y, size_t gcols, size_t num); static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols); static WinRegion getregion(size_t x, size_t y); @@ -31,6 +32,7 @@ static WinRegion Focused = EDIT; static Region Regions[NREGIONS] = {0}; static Rune LastKey; static KeyBinding* Keys = NULL; +static void (*InputFunc)(Rune); static bool ShowLineNumbers = false; static void win_init(void (*errfn)(char*)) { @@ -58,27 +60,13 @@ void win_dialog(char* name, void (*errfn)(char*)) { x11_dialog(name, config_get_int(WinWidth), config_get_int(WinHeight)); } -static bool update_focus(void) { - static int prev_x = 0, prev_y = 0; - int ptr_x, ptr_y; - bool changed = false; - /* dont change focus if any mouse buttons are pressed */ - if ((x11_keybtnstate() & 0x1f00) == 0) { - x11_mouse_get(&ptr_x, &ptr_y); - if (prev_x != ptr_x || prev_y != ptr_y) - changed = win_setregion(getregion(ptr_x, ptr_y)); - prev_x = ptr_x, prev_y = ptr_y; - } - return changed; -} - void win_loop(void) { x11_show(); x11_flip(); while (x11_running()) { bool pending = x11_events_await(config_get_int(EventTimeout)); int nevents = x11_events_queued(); - if (update_focus() || pending || nevents) { + if (update_focus() || pending || nevents || update_needed()) { x11_events_take(); if (x11_running()) x11_flip(); @@ -114,8 +102,9 @@ Rune win_getkey(void) { return LastKey; } -void win_setkeys(KeyBinding* bindings) { +void win_setkeys(KeyBinding* bindings, void (*inputfn)(Rune)) { Keys = bindings; + InputFunc = inputfn; } bool win_btnpressed(int btn) { @@ -319,9 +308,13 @@ static void oninput(int mods, Rune key) { /* fallback to just inserting the rune if it doesn't fall in the private use area. * the private use area is used to encode special keys */ if (key < 0xE000 || key > 0xF8FF) { - if (key == '\n' && win_view(FOCUSED)->buffer.crlf) - key = RUNE_CRLF; - view_insert(win_view(FOCUSED), true, key); + if (InputFunc) { + InputFunc(key); + } else { + if (key == '\n' && win_view(FOCUSED)->buffer.crlf) + key = RUNE_CRLF; + view_insert(win_view(FOCUSED), true, key); + } } } @@ -390,6 +383,20 @@ static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col) { view_scroll(win_view(id), +(config_get_int(ScrollLines))); } +static bool update_focus(void) { + static int prev_x = 0, prev_y = 0; + int ptr_x, ptr_y; + bool changed = false; + /* dont change focus if any mouse buttons are pressed */ + if ((x11_keybtnstate() & 0x1f00) == 0) { + x11_mouse_get(&ptr_x, &ptr_y); + if (prev_x != ptr_x || prev_y != ptr_y) + changed = win_setregion(getregion(ptr_x, ptr_y)); + prev_x = ptr_x, prev_y = ptr_y; + } + return changed; +} + static void draw_line_num(bool current, size_t x, size_t y, size_t gcols, size_t num) { int color = config_get_int(ClrGutterNor); if (ShowLineNumbers) { diff --git a/lib/x11.c b/lib/x11.c index 5e9e2cd..3e091c2 100644 --- a/lib/x11.c +++ b/lib/x11.c @@ -41,7 +41,7 @@ static struct { Colormap colormap; unsigned depth; int screen; - /* assume a single window for now. these are it's attributes */ + /* assume a single window for now. these are its attributes */ Window window; XftDraw* xft; Pixmap pixmap; diff --git a/pick.c b/pick.c index 801b9a3..84d0087 100644 --- a/pick.c +++ b/pick.c @@ -170,6 +170,10 @@ void onshutdown(void) { x11_deinit(); } +bool update_needed(void) { + return false; +} + /* Main Routine *****************************************************************************/ static void onerror(char* msg) { @@ -224,7 +228,7 @@ int main(int argc, char** argv) { load_choices(); if (vec_size(&Choices) > 1) { win_dialog("pick", onerror); - win_setkeys(Bindings); + win_setkeys(Bindings, NULL); win_settext(STATUS, (title ? title : "pick")); if (argc >= 2) { for (char* str = argv[1]; *str; str++) diff --git a/term.c b/term.c index f2aca6e..8dcd54d 100644 --- a/term.c +++ b/term.c @@ -1,81 +1,136 @@ +#define _XOPEN_SOURCE 700 #include +#include +#ifdef __MACH__ + #include +#else + #include +#endif +#include +#include +#include +#include #include #include #include #include #include -static int ShellFD; +int CmdFD = -1; +char* ShellCmd[] = { NULL, NULL }; -void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col) { -} +bool fdready(int fd); -void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col) { -} +/* unused functions */ +void onfocus(bool focused) {} -void onmouseright(WinRegion id, bool pressed, size_t row, size_t col) { +void onerror(char* msg) { } void onscroll(double percent) { + size_t bend = buf_end(win_buf(EDIT)); + size_t off = (size_t)((double)bend * percent); + view_scrollto(win_view(EDIT), (off >= bend ? bend : off)); } -void onfocus(bool focused) { +void onlayout(void) { + /* calculate and update scroll region */ + View* view = win_view(EDIT); + size_t bend = buf_end(win_buf(EDIT)); + if (bend == 0) bend = 1; + if (!view->rows) return; + size_t vbeg = view->rows[0]->off; + size_t vend = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen; + double scroll_vis = (double)(vend - vbeg) / (double)bend; + double scroll_off = ((double)vbeg / (double)bend); + win_setscroll(scroll_off, scroll_vis); } void onupdate(void) { -} - -void onlayout(void) { + static char buf[8192]; + long n; + if (!fdready(CmdFD)) return; + if ((n = read(CmdFD, buf, sizeof(buf))) < 0) + die("read() subprocess :"); + for (long i = 0; i < n;) { + Rune rune = 0; + size_t length = 0; + while (!utf8decode(&rune, &length, buf[i++])); + view_insert(win_view(EDIT), false, rune); + } } void onshutdown(void) { x11_deinit(); } -void onerror(char* msg) { +void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col) { } -#ifndef TEST -#include -#include -#ifdef __MACH__ -#include -#else -#include -#endif +void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col) { +} -void spawn_shell(int master, int slave) { - static char* shell[] = { "/bin/sh", "-l", NULL }; - dup2(slave, 0); - dup2(slave, 1); - dup2(slave, 2); - if (ioctl(slave, TIOCSCTTY, NULL) < 0) - die("ioctl(TIOSCTTY) failed"); - close(slave); - close(master); - execvp(shell[0], shell); +void onmouseright(WinRegion id, bool pressed, size_t row, size_t col) { } -int main(int argc, char** argv) { - int pid, m, s; - if (openpty(&m, &s, NULL, NULL, NULL) < 0) - die("openpty failed: %s\n", strerror(errno)); - if ((pid = fork())) - die("fork failed"); - - if (pid == 0) { - spawn_shell(m, s); - } else { - close(s); - ShellFD = m; - //signal(SIGCHLD, sigchld); +static void oninput(Rune rune) { + char c = (char)rune; + write(CmdFD, &c, 1); + view_insert(win_view(FOCUSED), false, rune); +} + +bool update_needed(void) { + return fdready(CmdFD); +} + +/******************************************************************************/ + +bool fdready(int fd) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + struct timeval tv = { .tv_usec = 0 }; + return (select(fd+1, &fds, NULL, NULL, &tv) > 0); +} + +int pty_spawn(char** argv) { + int fd; + struct termios tio; + pid_t pid; + putenv("TERM=dumb"); + switch ( (pid = forkpty(&fd, NULL, NULL, NULL)) ) { + case -1: // Failed + die("forkpty() :"); + break; + + case 0: // Child Process + if (execvp(argv[0], argv) < 0) + die("execvp('%s', ...) :", argv[0]); + exit(EXIT_FAILURE); + break; + + default: // Parent Process + tcgetattr(fd, &tio); + tio.c_lflag &= ~(ECHO | ECHONL); + tio.c_cc[ VMIN ] = 1; + tio.c_cc[ VTIME ] = 0; + tcsetattr(fd, TCSANOW, &tio); + break; } + return fd; +} +/******************************************************************************/ + +#ifndef TEST +int main(int argc, char** argv) { + if (!ShellCmd[0]) ShellCmd[0] = getenv("SHELL"); + if (!ShellCmd[0]) ShellCmd[0] = "/bin/sh"; + CmdFD = pty_spawn(argc > 1 ? argv+1 : ShellCmd); win_window("term", onerror); - //win_setkeys(&Bindings); - //win_setmouse(&MouseHandlers); + win_setkeys(NULL, oninput); + win_buf(EDIT)->crlf = 1; win_loop(); - return 0; } #endif diff --git a/tests/tide.c b/tests/tide.c index e6c97ac..044d199 100644 --- a/tests/tide.c +++ b/tests/tide.c @@ -25,8 +25,7 @@ static void initialize(void) { ShellCmd[0] = "/bin/sh"; win_window("edit", ondiagmsg); XDisplay = XOpenDisplay(NULL); - win_setkeys(Bindings); - //win_setmouse(&MouseHandlers); + win_setkeys(Bindings, NULL); } /* Helper Functions diff --git a/tide.c b/tide.c index c93a76e..6fcd3e4 100644 --- a/tide.c +++ b/tide.c @@ -548,6 +548,10 @@ void onshutdown(void) { quit(); } +bool update_needed(void) { + return false; +} + void edit_relative(char* path) { char *currdir = NULL, *currpath = NULL, *relpath = NULL; char* origdir = getcurrdir(); @@ -617,7 +621,7 @@ int main(int argc, char** argv) { cmdrun(OpenCmd, NULL); } /* now create the window and start the event loop */ - win_setkeys(Bindings); + win_setkeys(Bindings, NULL); win_loop(); return 0; }