rework some things: - sob - simple output bar | |
git clone git://git.codemadness.org/sob | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 12656a030acf296f0b6299175f982a6eae630646 | |
parent b072bb3bd5fdff06b0a12cd7bc6a8f94962ab97d | |
Author: Hiltjo Posthuma <[email protected]> | |
Date: Thu, 2 Oct 2014 20:55:49 +0000 | |
rework some things: | |
- remove dependency on ncurses. | |
- just use stdout for output instead of -f, this makes using it with tee | |
trivial. use stderr for the "interface". | |
- fix resize bug select() == 1 with errno EINTR. | |
Diffstat: | |
M README | 24 ++++++++++++++++++------ | |
M TODO | 25 +++++-------------------- | |
M config.def.h | 74 ++++++++++++++++++-----------… | |
M sob.1 | 5 ----- | |
M sob.c | 417 +++++++++++++++++++----------… | |
5 files changed, 318 insertions(+), 227 deletions(-) | |
--- | |
diff --git a/README b/README | |
@@ -1,25 +1,37 @@ | |
-Simple output bar | |
-================= | |
+sob - simple output bar | |
+======================= | |
Dependencies | |
------------ | |
-- Ncurses (at the moment, alternatives will be investigated). | |
- libc | |
Features | |
-------- | |
-- Custom prompt. | |
-- Easy to write scripts to pipe input/output. | |
+- Small (in size and memory), not much dependencies. | |
+- Custom prompt (including color support). | |
+- Easy to write custom completion scripts or special actions. | |
- Custom action on SIGWINCH (window resize). | |
- Familiar and customizable keybinds (in config.h). | |
- Example scripts for: | |
+ - History list. | |
+ - Nickname completion (for IRC). | |
- Word completion. | |
- - History | |
- Yank line (xsel). | |
+Known issues | |
+------------ | |
+line yank doesn't work with xclip, but does work with xsel. | |
+ | |
+ | |
+Author | |
+------ | |
+Hiltjo Posthuma <[email protected]>, don't hesitate to contact me for | |
+bug reports or patches! | |
+ | |
+ | |
License | |
------- | |
See LICENSE file. | |
diff --git a/TODO b/TODO | |
@@ -1,22 +1,7 @@ | |
-13:32 <@TLH> Evil_Bob: please support C-p for up in history C-n for down in hi… | |
- C-e, C-u, C-k (kill to rest of line), C-y, C-w | |
- 13:32 <@TLH> what else | |
- 13:32 <@TLH> C-j | |
- 13:32 <@TLH> :P | |
- 13:33 <@TLH> C-m as an alias to C-j | |
- | |
+- tmux: on newline, sometimes there are render issues. | |
+- tmux: arrow up and down dont start history script. | |
+- for history, on exit failure, don't clear line. | |
- scripts: for word complete, if there is only one match, just print directly. | |
- | |
-- test draw on wrapped lines. | |
- | |
-- line_yank doesn't work with xclip, but works with xsel... | |
- | |
- optimize: | |
- reduce redraws (line_redraw and line_cursor_update). | |
- | |
-- selections / marks? (delete/pipe etc on selection)? | |
-- cycle completions? (with tab for example). | |
-- keybind to go to word next and previous (ctrl+arrow left/right). | |
-- prompt callback? allow to update prompt? | |
- | |
-- try libedit, else just use ncurses. | |
+ reduce redraws (line_redraw and line_cursor_update). | |
+- make example url grab script. | |
diff --git a/config.def.h b/config.def.h | |
@@ -1,4 +1,4 @@ | |
-static const char *prompt = "> "; | |
+static const char *prompt = "\x01\x1b[32m\x01> \x01\x1b[0m"; | |
static const char *completenickcmd[] = { "/bin/sh", "-c", "$HOME/.sob/scripts/… | |
static const char *historycmd[] = { "/bin/sh", "-c", "$HOME/.sob/scripts/… | |
static const char *yankcmd[] = { "/bin/sh", "-c", "/bin/xsel -i -p", … | |
@@ -22,38 +22,48 @@ complete_nick(void) | |
line_wordpipeto((char**)completenickcmd); | |
} | |
+#define CONTROL(ch) ((ch)^0x40) | |
+ | |
+#define KEY_HOME "\x1b[\x31\x7e" | |
+#define KEY_END "\x1b[\x34\x7e" | |
+#define KEY_CTRL_LEFT "\x1b\x5b\x31\x3b\x35\x44" | |
+#define KEY_CTRL_RIGHT "\x1b\x5b\x31\x3b\x35\x43" | |
+#define KEY_LEFT "\x1b\x4f\x44" | |
+#define KEY_RIGHT "\x1b\x4f\x43" | |
+#define KEY_DOWN "\x1b\x4f\x42" | |
+#define KEY_UP "\x1b\x4f\x41" | |
+#define KEY_DC "\x1b\x5b\x33\7e" /* del */ | |
+ | |
static struct keybind { | |
- int key; | |
+ unsigned char key[16]; | |
void (*func)(void); | |
} keybinds[] = { | |
- { CONTROL('A'), line_cursor_begin }, | |
- { CONTROL('E'), line_cursor_end }, | |
- { KEY_HOME, line_cursor_begin }, | |
- { KEY_END, line_cursor_end }, | |
- { CONTROL('B'), line_cursor_prev }, | |
- { KEY_LEFT, line_cursor_prev }, | |
- { CONTROL('F'), line_cursor_next }, | |
- { KEY_RIGHT, line_cursor_next }, | |
- { CONTROL('W'), line_delwordback }, | |
- { CONTROL('H'), line_delcharback }, | |
- { CONTROL('U'), line_clear }, | |
- { KEY_DL, line_clear }, | |
- { CONTROL('K'), line_deltoend }, | |
- { KEY_SDC, line_delcharnext }, | |
- { KEY_DC, line_delcharnext }, | |
- { KEY_BACKSPACE, line_delcharback }, | |
- { CONTROL('M'), line_newline }, | |
- { CONTROL('J'), line_newline }, | |
- { '\r', line_newline }, | |
- { '\n', line_newline }, | |
- { KEY_ENTER, line_newline }, | |
- { CONTROL('Y'), line_yank }, | |
- { KEY_EXIT, line_exit }, | |
- { 0x04, line_exit }, /* EOT */ | |
- { KEY_EOL, line_deltoend }, | |
- { KEY_UP, history_menu }, | |
- { KEY_DOWN, history_menu }, | |
- { CONTROL('P'), history_menu }, | |
- { CONTROL('N'), history_menu }, | |
- { '\t', complete_nick }, | |
+ { { CONTROL('A') }, line_cursor_begin }, | |
+ { { CONTROL('E') }, line_cursor_end }, | |
+ { { KEY_HOME }, line_cursor_begin }, | |
+ { { KEY_END }, line_cursor_end }, | |
+ { { CONTROL('B') }, line_cursor_prev }, | |
+ { { KEY_LEFT }, line_cursor_prev }, | |
+ { { CONTROL('F') }, line_cursor_next }, | |
+ { { KEY_RIGHT }, line_cursor_next }, | |
+ { { KEY_CTRL_LEFT }, line_cursor_wordprev }, | |
+ { { KEY_CTRL_RIGHT }, line_cursor_wordnext }, | |
+ { { CONTROL('W') }, line_delwordback }, | |
+ { { CONTROL('H') }, line_delcharback }, | |
+ { { CONTROL('U') }, line_clear }, | |
+ { { CONTROL('K') }, line_deltoend }, | |
+ { { KEY_DC }, line_delcharnext }, | |
+ { { CONTROL('H') }, line_delcharback }, | |
+ { { CONTROL('M') }, line_newline }, | |
+ { { CONTROL('J') }, line_newline }, | |
+ { { '\r' }, line_newline }, | |
+ { { '\n' }, line_newline }, | |
+ { { CONTROL('Y') }, line_yank }, | |
+ { { CONTROL('D') }, line_exit }, | |
+ { { CONTROL('E') }, line_deltoend }, | |
+ { { KEY_UP }, history_menu }, | |
+ { { KEY_DOWN }, history_menu }, | |
+ { { CONTROL('P') }, history_menu }, | |
+ { { CONTROL('N') }, history_menu }, | |
+ { { '\t' }, complete_nick }, | |
}; | |
diff --git a/sob.1 b/sob.1 | |
@@ -3,8 +3,6 @@ | |
sob \- simple output bar | |
.SH SYNOPSIS | |
.B sob | |
-.RB < \-f | |
-.IR outfile > | |
.RB [ \-l | |
.IR line ] | |
.RB [ \-p | |
@@ -13,9 +11,6 @@ sob \- simple output bar | |
sob is a simple line editor. | |
.SH OPTIONS | |
.TP | |
-.B \-f " outfile" | |
-output file. | |
-.TP | |
.B \-l " line" | |
initial input on line. | |
.TP | |
diff --git a/sob.c b/sob.c | |
@@ -7,19 +7,19 @@ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
+#include <sys/ioctl.h> | |
#include <sys/select.h> | |
#include <unistd.h> | |
- | |
-#include <ncurses.h> | |
+#include <termios.h> | |
#include "arg.h" | |
char *argv0; | |
#include "util.h" | |
-#define CONTROL(ch) ((ch)^0x40) | |
-#define LEN(x) (sizeof (x) / sizeof *(x)) | |
-#define MAX(A, B) ((A) > (B) ? (A) : (B)) | |
+#define LEN(x) (sizeof (x) / sizeof *(x)) | |
+#define MAX(A, B) ((A) > (B) ? (A) : (B)) | |
+#define MIN(A, B) ((A) < (B) ? (A) : (B)) | |
struct line { | |
char line[BUFSIZ]; | |
@@ -27,58 +27,54 @@ struct line { | |
size_t pos; | |
}; | |
+static void line_clear(void); | |
+static void line_copywordcursor(char *, size_t); | |
+static void line_cursor_begin(void); | |
+static void line_cursor_end(void); | |
+static void line_cursor_move(size_t); | |
+static void line_cursor_next(void); | |
+static void line_cursor_prev(void); | |
+static void line_cursor_wordprev(void); | |
+static void line_cursor_wordnext(void); | |
+static void line_delcharback(void); | |
+static void line_delcharnext(void); | |
+static void line_deltoend(void); | |
+static void line_delwordback(void); | |
+static void line_delwordcursor(void); | |
+static void line_draw(void); | |
+static void line_exit(void); | |
+static void line_getwordpos(size_t *, size_t *); | |
+static void line_inserttext(const char *); | |
+static void line_newline(void); | |
+static void line_out(void); | |
+static void line_prompt(void); | |
+static int line_promptlen(void); | |
+static int line_pipeto(char **); | |
+static void line_set(const char *); | |
+static void line_wordpipeto(char **); | |
+static int pipe_readline(int, int, char *, char *, size_t); | |
+static int pipe_cmd(char *[], char *, char *, size_t); | |
+ | |
+static void cleanup(void); | |
+static void gettermsize(void); | |
+static void handleinput(const unsigned char *, size_t); | |
+static void resize(void); | |
+static int run(void); | |
+static void setup(void); | |
+static void sighandler(int); | |
+static void usage(void); | |
+ | |
+static struct termios ttystate, ttysave; | |
+ | |
static struct line line; | |
-static int isrunning = 1; | |
-static char * outname = NULL; | |
-static WINDOW * win = NULL; | |
- | |
-static void line_clear(void); | |
-static void line_copywordcursor(char *buf, size_t bufsiz); | |
-static void line_cursor_begin(void); | |
-static void line_cursor_end(void); | |
-static void line_cursor_next(void); | |
-static void line_cursor_prev(void); | |
-static void line_cursor_update(void); | |
-static void line_delcharback(void); | |
-static void line_delcharnext(void); | |
-static void line_deltoend(void); | |
-static void line_delwordback(void); | |
-static void line_delwordcursor(void); | |
-static void line_exit(void); | |
-static void line_getwordpos(unsigned int *start, unsigned int *end); | |
-static void line_insertchar(int c); | |
-static void line_inserttext(const char *s); | |
-static void line_newline(void); | |
-static int line_out(void); | |
-static void line_prompt(void); | |
-static int line_pipeto(char **cmd); | |
-static void line_redraw(size_t max); | |
-static void line_set(const char *s); | |
-static void line_wordpipeto(char **cmd); | |
-static int pipe_readline(int fd_in, int fd_out, char *writestr, | |
- char *outbuf, size_t outbufsiz); | |
-static int pipe_cmd(char *cmd[], char *writestr, char *outbuf, | |
- size_t outbufsiz); | |
-static void resize(void); | |
-static void sighandler(int signum); | |
-static void setup(void); | |
-static void cleanup(void); | |
-static void run(void); | |
-static void usage(void); | |
+static int cols, rows; | |
+static int isrunning = 1; | |
+static FILE * outfp = NULL; | |
+static FILE * lineoutfp = NULL; | |
#include "config.h" | |
static void | |
-line_insertchar(int c) | |
-{ | |
- char s[2]; | |
- | |
- s[0] = c; | |
- s[1] = '\0'; | |
- line_inserttext(s); | |
-} | |
- | |
-static void | |
line_inserttext(const char *s) | |
{ | |
size_t len; | |
@@ -94,9 +90,10 @@ line_inserttext(const char *s) | |
memmove(&line.line[line.pos + len], &line.line[line.pos], line… | |
memcpy(&line.line[line.pos], s, len); | |
} | |
- line.pos += len; | |
line.len += len; | |
+ line.pos += len; | |
line.line[line.len + 1] = '\0'; | |
+ line_draw(); | |
} | |
static void | |
@@ -107,94 +104,137 @@ line_set(const char *s) | |
line.pos = line.len; | |
} | |
+/* like mksh, toggle counting of escape codes in prompt with "\x01" */ | |
+static int | |
+line_promptlen(void) | |
+{ | |
+ size_t i; | |
+ int t = 0, n = 0; | |
+ | |
+ for(i = 0; prompt[i]; i++) { | |
+ if(prompt[i] == 1) | |
+ t = !t; | |
+ else if(!t) | |
+ n++; | |
+ } | |
+ return n; | |
+} | |
+ | |
static void | |
line_prompt(void) | |
{ | |
size_t i; | |
- wmove(win, 0, 0); | |
- for(i = 0; prompt[i]; i++) | |
- waddch(win, prompt[i]); | |
+ for(i = 0; prompt[i]; i++) { | |
+ if(prompt[i] != 1) | |
+ fputc(prompt[i], outfp); | |
+ } | |
} | |
static void | |
-line_redraw(size_t max) | |
+line_draw(void) | |
{ | |
size_t n; | |
+ /* clear */ | |
+ fprintf(outfp, "\x1b[2J\x1b[H"); | |
+ | |
line_prompt(); | |
+ for(n = 0; line.line[n] && n < line.len; n++) | |
+ fputc(line.line[n], outfp); | |
- for(n = 0; line.line[n] && n < line.len && n < max; n++) | |
- waddch(win, line.line[n]); | |
- for(; n < max; n++) | |
- waddch(win, ' '); | |
- wrefresh(win); | |
+ line_cursor_move(line.pos); | |
} | |
-static int | |
+static void | |
line_out(void) | |
{ | |
- FILE *fp; | |
- if(!(fp = fopen(outname, "a"))) { | |
- fprintf(stderr, "fopen: '%s': %s\n", outname, strerror(errno)); | |
- return -1; | |
+ fprintf(lineoutfp, "%s\n", line.line); | |
+ fflush(lineoutfp); | |
+} | |
+ | |
+static void | |
+line_cursor_move(size_t newpos) | |
+{ | |
+ size_t len, y = 0, x = newpos; | |
+ | |
+ len = line_promptlen(); | |
+ x += len; | |
+ | |
+ /* linewrap */ | |
+ if(x > cols - 1) { | |
+ x = x % cols; | |
+ y = ((newpos + len) - x) / cols; | |
} | |
- fprintf(fp, "%s\n", line.line); | |
- fflush(fp); | |
- fclose(fp); | |
- return 0; | |
+ fprintf(outfp, "\x1b[%lu;%luH", y + 1, x + 1); | |
+ fflush(outfp); | |
+ line.pos = newpos; | |
+} | |
+ | |
+static void | |
+line_cursor_wordprev(void) | |
+{ | |
+ size_t s, e; | |
+ | |
+ line_getwordpos(&s, &e); | |
+ if(s == line.pos) { | |
+ while(s > 0 && isspace(line.line[s - 1])) | |
+ s--; | |
+ } | |
+ line_cursor_move(s); | |
} | |
static void | |
-line_cursor_update(void) | |
+line_cursor_wordnext(void) | |
{ | |
- wmove(win, 0, line.pos + strlen(prompt)); | |
+ size_t s, e; | |
+ | |
+ line_getwordpos(&s, &e); | |
+ if(e == line.pos) { | |
+ while(e < line.len && line.line[e] && isspace(line.line[e])) | |
+ e++; | |
+ } | |
+ line_cursor_move(e); | |
} | |
static void | |
line_cursor_begin(void) | |
{ | |
- line.pos = 0; | |
- line_cursor_update(); | |
+ line_cursor_move(0); | |
} | |
static void | |
line_cursor_prev(void) | |
{ | |
if(line.pos > 0) | |
- line.pos--; | |
- line_cursor_update(); | |
+ line_cursor_move(line.pos - 1); | |
} | |
static void | |
line_cursor_next(void) | |
{ | |
if(line.pos < line.len) | |
- line.pos++; | |
- line_cursor_update(); | |
+ line_cursor_move(line.pos + 1); | |
} | |
static void | |
line_cursor_end(void) | |
{ | |
- line.pos = line.len; | |
- line_cursor_update(); | |
+ line_cursor_move(line.len); | |
} | |
static void | |
line_clear(void) | |
{ | |
+ line_cursor_begin(); | |
line.line[0] = '\0'; | |
- line_redraw(line.len); | |
line.len = 0; | |
- line_cursor_begin(); | |
+ line_draw(); | |
} | |
static void | |
line_delcharnext(void) | |
{ | |
- size_t oldlen = line.len; | |
- | |
if(line.pos == line.len || line.len <= 0) | |
return; | |
@@ -202,41 +242,35 @@ line_delcharnext(void) | |
line.line[line.len - line.pos - 1]); | |
line.len--; | |
line.line[line.len] = '\0'; | |
- line_redraw(oldlen); | |
- line_cursor_update(); | |
+ line_draw(); | |
} | |
static void | |
line_delcharback(void) | |
{ | |
- size_t oldlen = line.len; | |
- | |
if(line.pos <= 0 || line.len <= 0) | |
return; | |
memmove(&line.line[line.pos - 1], &line.line[line.pos], | |
line.line[line.len - line.pos]); | |
line.len--; | |
line.line[line.len] = '\0'; | |
- line_redraw(oldlen); | |
line_cursor_prev(); | |
+ line_draw(); | |
} | |
static void | |
line_deltoend(void) | |
{ | |
- size_t oldlen = line.len; | |
- | |
line.line[line.pos] = '\0'; | |
line.len = line.pos; | |
- line_redraw(oldlen); | |
line_cursor_end(); | |
+ line_draw(); | |
} | |
static void | |
line_delwordcursor(void) | |
{ | |
- unsigned int s, e; | |
- size_t len, oldlen = line.len; | |
+ size_t len, s, e; | |
line_getwordpos(&s, &e); | |
@@ -245,14 +279,13 @@ line_delwordcursor(void) | |
line.len -= len; | |
line.pos = s; | |
line.line[line.len] = '\0'; | |
- line_redraw(MAX(line.len, oldlen)); | |
- line_cursor_update(); | |
+ line_draw(); | |
} | |
static void | |
line_delwordback(void) | |
{ | |
- size_t i, len, oldlen = line.len; | |
+ size_t i, len; | |
if(line.pos <= 0 || line.len <= 0) | |
return; | |
@@ -271,8 +304,7 @@ line_delwordback(void) | |
line.pos = i; | |
line.len -= len; | |
line.line[line.len] = '\0'; | |
- line_redraw(oldlen); | |
- line_cursor_update(); | |
+ line_draw(); | |
} | |
static void | |
@@ -280,19 +312,17 @@ line_newline(void) | |
{ | |
line_out(); | |
line_clear(); | |
- line_prompt(); | |
- wrefresh(win); | |
} | |
static void | |
line_exit(void) | |
{ | |
- line_newline(); | |
+ line_out(); | |
isrunning = 0; | |
} | |
static void | |
-line_getwordpos(unsigned int *start, unsigned int *end) | |
+line_getwordpos(size_t *start, size_t *end) | |
{ | |
size_t i; | |
@@ -311,8 +341,7 @@ line_getwordpos(unsigned int *start, unsigned int *end) | |
static void | |
line_copywordcursor(char *buf, size_t bufsiz) | |
{ | |
- unsigned int s, e; | |
- size_t len; | |
+ size_t s, e, len; | |
line_getwordpos(&s, &e); | |
len = e - s; | |
@@ -358,9 +387,11 @@ pipe_readline(int fd_in, int fd_out, char *writestr, char … | |
if((r = read(fd_in, buf, sizeof(buf))) == -1) | |
goto fini; | |
buf[r] = '\0'; | |
- if((p = strpbrk(buf, "\r\n"))) | |
- *p = '\0'; | |
- strlcpy(outbuf, buf, sizeof(outbuf)); | |
+ if(outbuf) { | |
+ if((p = strpbrk(buf, "\r\n"))) | |
+ *p = '\0'; | |
+ strlcpy(outbuf, buf, outbufsiz); | |
+ } | |
status = 0; | |
goto fini; | |
} | |
@@ -434,21 +465,25 @@ pipe_cmd(char *cmd[], char *writestr, char *outbuf, size_… | |
static int | |
line_pipeto(char **cmd) | |
{ | |
- size_t oldlen = line.len; | |
+ char buf[BUFSIZ]; | |
+ size_t len; | |
- if(pipe_cmd(cmd, line.line, line.line, sizeof(line.line)) == -1) | |
+ if(pipe_cmd(cmd, line.line, buf, sizeof(buf)) == -1) | |
return -1; | |
- line.len = strlen(line.line); | |
- line_redraw(MAX(line.len, oldlen)); | |
+ if(buf[0] == '\0') | |
+ return -1; | |
+ len = strlcpy(line.line, buf, sizeof(line.line)); | |
+ line.len = len; | |
line_cursor_end(); | |
+ line_draw(); | |
return 0; | |
} | |
+/* pipe word under cursor and replace it */ | |
static void | |
line_wordpipeto(char **cmd) | |
{ | |
char wordbuf[BUFSIZ], outbuf[BUFSIZ]; | |
- size_t oldlen = line.len; | |
outbuf[0] = '\0'; | |
wordbuf[0] = '\0'; | |
@@ -462,8 +497,7 @@ line_wordpipeto(char **cmd) | |
line_delwordcursor(); | |
line_inserttext(outbuf); | |
- line_redraw(MAX(line.len, oldlen)); | |
- line_cursor_update(); | |
+ line_draw(); | |
} | |
static void | |
@@ -472,6 +506,10 @@ sighandler(int signum) | |
if(signum == SIGTERM) { | |
isrunning = 0; | |
cleanup(); | |
+ } else if(signum == SIGWINCH) { | |
+ gettermsize(); | |
+ resize(); | |
+ line_draw(); | |
} | |
} | |
@@ -480,79 +518,134 @@ setup(void) | |
{ | |
struct sigaction sa; | |
- initscr(); | |
- win = stdscr; | |
- cbreak(); | |
- noecho(); | |
- nonl(); | |
- nodelay(win, FALSE); | |
- keypad(win, TRUE); | |
- curs_set(1); | |
- ESCDELAY = 20; | |
+ tcgetattr(STDIN_FILENO, &ttystate); | |
+ ttysave = ttystate; | |
+ /* turn off canonical mode and echo */ | |
+ ttystate.c_lflag &= ~(ICANON | ECHO); | |
+ ttystate.c_cc[VMIN] = 1; | |
+ | |
+ /* set the terminal attributes */ | |
+ tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); | |
+ | |
+ /* get terminal window size */ | |
+ gettermsize(); | |
/* signal handling */ | |
memset(&sa, 0, sizeof(sa)); | |
sa.sa_flags = SA_RESTART; | |
sa.sa_handler = sighandler; | |
sigaction(SIGTERM, &sa, NULL); | |
+ sigaction(SIGWINCH, &sa, NULL); | |
+} | |
+ | |
+static void | |
+gettermsize(void) | |
+{ | |
+ struct winsize w; | |
+ | |
+ if(ioctl(STDIN_FILENO, TIOCGWINSZ, &w) == -1) | |
+ return; | |
+ cols = w.ws_col; | |
+ rows = w.ws_row; | |
} | |
static void | |
resize(void) | |
{ | |
- line_pipeto((char **)resizecmd); | |
+ pipe_cmd((char **)resizecmd, line.line, NULL, 0); | |
} | |
static void | |
cleanup(void) | |
{ | |
- endwin(); | |
+ ttystate.c_lflag = ttysave.c_lflag; | |
+ /* set the terminal attributes. */ | |
+ tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); | |
} | |
+#if 0 | |
static void | |
-run(void) | |
+debuginput(const unsigned char *key, size_t len) | |
{ | |
size_t i; | |
- int c, ismatch = 0; | |
- line_redraw(line.len); | |
- while(isrunning) { | |
- c = wgetch(win); | |
- switch(c) { | |
- case ERR: | |
- isrunning = 0; | |
- break; | |
- case 0x1b: /* ignore unbinded escape sequences */ | |
- nodelay(win, TRUE); | |
- while((c = wgetch(win)) != ERR); | |
- nodelay(win, FALSE); | |
- break; | |
- case KEY_RESIZE: | |
- resize(); | |
+ for(i = 0; i < len; i++) | |
+ fprintf(stdout, "\\x%2x", key[i]); | |
+ fputc('\n', stdout); | |
+ fflush(stdout); | |
+} | |
+#endif | |
+ | |
+static void | |
+handleinput(const unsigned char *key, size_t len) | |
+{ | |
+ size_t i; | |
+ int ismatch = 0; | |
+ | |
+ if(key[0] == '\0') | |
+ return; | |
+ for(i = 0; i < LEN(keybinds); i++) { | |
+ if(len == strlen((char*)keybinds[i].key) && | |
+ memcmp(key, keybinds[i].key, len) == 0) { | |
+ keybinds[i].func(); | |
+ ismatch = 1; | |
break; | |
- default: | |
- ismatch = 0; | |
- for(i = 0; i < LEN(keybinds); i++) { | |
- if(keybinds[i].key == c) { | |
- ismatch = 1; | |
- keybinds[i].func(); | |
- break; | |
- } | |
- } | |
- if(!ismatch) { | |
- line_insertchar(c); | |
- line_redraw(line.len); | |
- line_cursor_update(); | |
- wrefresh(win); | |
+ } | |
+ } | |
+ if(!ismatch) { | |
+ /* ignore unhandled escape sequence */ | |
+ if(key[0] == '\x1b' || iscntrl(key[0])) | |
+ return; | |
+ line_inserttext((char*)key); | |
+ } | |
+} | |
+ | |
+static int | |
+run(void) | |
+{ | |
+ struct timeval tv; | |
+ fd_set fdr; | |
+ int fd_in, r, status = -1; | |
+ unsigned char buf[BUFSIZ]; | |
+ | |
+ line_draw(); | |
+ | |
+ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); | |
+ while(isrunning) { | |
+ FD_ZERO(&fdr); | |
+ FD_SET(STDIN_FILENO, &fdr); | |
+ | |
+ memset(&tv, 0, sizeof(tv)); | |
+ tv.tv_sec = 0; | |
+ tv.tv_usec = 50000; /* 50 ms */ | |
+ | |
+ errno = 0; | |
+ if((r = select(STDIN_FILENO + 1, &fdr, NULL, NULL, &tv)) == -1… | |
+ if(errno != EINTR) | |
+ goto fini; /* E_INTR can happen on SIGWINCH */ | |
+ } else if(!r) { | |
+ continue; /* timeout */ | |
+ } | |
+ | |
+ if(FD_ISSET(fd_in, &fdr)) { | |
+ errno = 0; | |
+ if((r = read(STDIN_FILENO, buf, sizeof(buf))) == -1) { | |
+ if(errno != EAGAIN && errno != EWOULDBLOCK) | |
+ goto fini; | |
+ } else { | |
+ buf[r] = '\0'; | |
+ handleinput(buf, r); | |
} | |
} | |
} | |
+fini: | |
+ return status; | |
} | |
static void | |
usage(void) | |
{ | |
- fprintf(stderr, "usage: %s <-f outfile> [-l line] [-p prompt]\n", argv… | |
+ fprintf(stderr, "usage: %s [-l line] [-p prompt]\n", argv0); | |
exit(EXIT_FAILURE); | |
} | |
@@ -560,9 +653,6 @@ int | |
main(int argc, char **argv) | |
{ | |
ARGBEGIN { | |
- case 'f': | |
- outname = EARGF(usage()); | |
- break; | |
case 'l': | |
line_set(EARGF(usage())); | |
break; | |
@@ -573,9 +663,8 @@ main(int argc, char **argv) | |
usage(); | |
} ARGEND; | |
- if(!outname) | |
- usage(); | |
- | |
+ lineoutfp = stdout; | |
+ outfp = stderr; | |
setlocale(LC_ALL, ""); | |
setup(); | |
run(); |