vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit a9d7a730c319d4ff00b9feddfc0237b3e25f47a8
parent a34e1b4b49bd5c0e8d9fb23bcee3905aa09a0de2
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Fri, 17 Oct 2014 15:43:48 +0200

Make editor usable as a filter: echo foo | vis - | cat

The terminal output is by default redirected to stderr,
making stdout available for communications purposes.

If a file is "opened" from stdin (i.e. vis is given '-' as
argument) and a subsequent write without a filename is performed
as in ":wq" the output is written to stdout.

Diffstat:
Mconfig.def.h | 2+-
Mtext.c | 32+++++++++++++++++++++++++++++++-
Mtext.h | 6+++++-
Mvis.c | 26++++++++++++++++----------
4 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -1,5 +1,5 @@ /** start by reading from the top of vis.c up until config.h is included */ - +#define DEFAULT_TERM "xterm" /* default term to use if $TERM isn't set */ /* macros used to specify keys for key bindings */ #define ESC 0x1B #define NONE(k) { .str = { k }, .code = 0 } diff --git a/text.c b/text.c @@ -645,12 +645,36 @@ err: return -1; } +ssize_t text_write(Text *txt, int fd) { + ssize_t len = 0; + text_iterate(txt, it, 0) { + size_t plen = it.end - it.start, poff = 0; + while (plen > 0) { + ssize_t res = write(fd, it.start + poff, plen); + if (res < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + return -1; + } + if (res == 0) + break; + poff += res; + plen -= res; + } + len += plen; + } + txt->saved_action = txt->undo; + text_snapshot(txt); + return len; +} + /* load the given file as starting point for further editing operations. * to start with an empty document, pass NULL as filename. */ Text *text_load(const char *filename) { Text *txt = calloc(1, sizeof(Text)); if (!txt) return NULL; + txt->fd = -1; txt->begin.index = 1; txt->end.index = 2; txt->piece_count = 2; @@ -686,8 +710,10 @@ Text *text_load(const char *filename) { } return txt; out: - if (txt->fd > 2) + if (txt->fd > 2) { close(txt->fd); + txt->fd = -1; + } text_free(txt); return NULL; } @@ -1124,6 +1150,10 @@ void text_mark_clear_all(Text *txt) { text_mark_clear(txt, mark); } +int text_fd_get(Text *txt) { + return txt->fd; +} + const char *text_filename_get(Text *txt) { return txt->filename; } diff --git a/text.h b/text.h @@ -2,7 +2,7 @@ #define TEXT_H #include <stdbool.h> -#include <stddef.h> +#include <sys/types.h> #define EPOS ((size_t)-1) /* invalid position */ @@ -34,6 +34,9 @@ typedef struct { Text *text_load(const char *file); Text *text_load_fd(int fd); +/* return the fd from which this text was loaded or -1 if it was + * loaded from a filename */ +int text_fd_get(Text*); /* the filename from which this text was loaded or first saved to */ const char *text_filename_get(Text*); /* associate a filename with the yet unnamed buffer */ @@ -82,6 +85,7 @@ bool text_modified(Text*); /* test whether the underlying file uses UNIX style \n or Windows style \r\n newlines */ bool text_newlines_crnl(Text*); int text_save(Text*, const char *file); +ssize_t text_write(Text*, int fd); void text_free(Text*); typedef struct Regex Regex; diff --git a/vis.c b/vis.c @@ -1416,6 +1416,8 @@ static bool cmd_write(const char *argv[]) { if (!argv[1]) argv[1] = text_filename_get(text); if (!argv[1]) { + if (text_fd_get(text) == STDIN_FILENO) + return text_write(text, STDOUT_FILENO) >= 0; editor_info_show(vis, "Filename expected"); return false; } @@ -1490,6 +1492,15 @@ static struct Screen { bool need_resize; } screen = { .need_resize = true }; +static void die(const char *errstr, ...) { + va_list ap; + endwin(); + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + static void sigwinch_handler(int sig) { screen.need_resize = true; } @@ -1513,7 +1524,11 @@ static void setup() { setlocale(LC_CTYPE, ""); if (!getenv("ESCDELAY")) set_escdelay(50); - initscr(); + char *term = getenv("TERM"); + if (!term) + term = DEFAULT_TERM; + if (!newterm(term, stderr, stdin) == ERR) + die("Can not initialize terminal\n"); start_color(); raw(); noecho(); @@ -1574,15 +1589,6 @@ static Key getkey(void) { return key; } -static void die(const char *errstr, ...) { - va_list ap; - endwin(); - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - static void mainloop() { struct timeval idle = { .tv_usec = 0 }, *timeout = NULL; Key key, key_prev, *key_mod = NULL;