aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--text-io.c2
-rw-r--r--text.h6
-rw-r--r--vis-lua.c30
-rw-r--r--vis.c74
-rw-r--r--vis.h14
5 files changed, 104 insertions, 22 deletions
diff --git a/text-io.c b/text-io.c
index 509df35..97fc138 100644
--- a/text-io.c
+++ b/text-io.c
@@ -182,7 +182,7 @@ Text *text_load_method(const char *filename, enum TextLoadMethod method) {
return text_loadat_method(AT_FDCWD, filename, method);
}
-static ssize_t write_all(int fd, const char *buf, size_t count) {
+ssize_t write_all(int fd, const char *buf, size_t count) {
size_t rem = count;
while (rem > 0) {
ssize_t written = write(fd, buf, rem > INT_MAX ? INT_MAX : rem);
diff --git a/text.h b/text.h
index 048aef7..3249e21 100644
--- a/text.h
+++ b/text.h
@@ -413,6 +413,12 @@ ssize_t text_write_range(const Text*, const Filerange*, int fd);
* this text instance.
*/
bool text_mmaped(const Text*, const char *ptr);
+
+/**
+ * Write complete buffer to file descriptor.
+ * @return The number of bytes written or ``-1`` in case of an error.
+ */
+ssize_t write_all(int fd, const char *buf, size_t count);
/** @} */
#endif
diff --git a/vis-lua.c b/vis-lua.c
index e3e85c3..0a435b4 100644
--- a/vis-lua.c
+++ b/vis-lua.c
@@ -1234,14 +1234,34 @@ static int exit_func(lua_State *L) {
* @treturn string stdout the data written to stdout
* @treturn string stderr the data written to stderr
*/
+/***
+ * Pipe a string to external process and collect output.
+ *
+ * The editor core will be blocked while the external process is running.
+ *
+ * @function pipe
+ * @tparam string text the text written to the external command
+ * @tparam string command the command to execute
+ * @tparam[opt] bool fullscreen whether command is a fullscreen program (e.g. curses based)
+ * @treturn int code the exit status of the executed command
+ * @treturn string stdout the data written to stdout
+ * @treturn string stderr the data written to stderr
+ */
static int pipe_func(lua_State *L) {
Vis *vis = obj_ref_check(L, 1, "vis");
int cmd_idx = 4;
char *out = NULL, *err = NULL;
+ const char *text = NULL;
File *file = vis->win ? vis->win->file : NULL;
Filerange range = text_range_new(0, 0);
- if (lua_gettop(L) <= 3) {
+ if (lua_gettop(L) == 2) {
cmd_idx = 2;
+ } else if (lua_gettop(L) == 3) {
+ text = luaL_checkstring(L, 2);
+ if (text != NULL)
+ cmd_idx = 3;
+ else
+ cmd_idx = 2;
} else if (!(lua_isnil(L, 2) && lua_isnil(L, 3))) {
file = obj_ref_check(L, 2, VIS_LUA_TYPE_FILE);
range = getrange(L, 3);
@@ -1249,10 +1269,14 @@ static int pipe_func(lua_State *L) {
const char *cmd = luaL_checkstring(L, cmd_idx);
bool fullscreen = lua_isboolean(L, cmd_idx + 1) && lua_toboolean(L, cmd_idx + 1);
- if (!file)
+ if (!text && !file)
return luaL_error(L, "vis:pipe(cmd = '%s'): win not open, file can't be nil", cmd);
- int status = vis_pipe_collect(vis, file, &range, (const char*[]){ cmd, NULL }, &out, &err, fullscreen);
+ int status;
+ if (text)
+ status = vis_pipe_buf_collect(vis, text, (const char*[]){ cmd, NULL }, &out, &err, fullscreen);
+ else
+ status = vis_pipe_collect(vis, file, &range, (const char*[]){ cmd, NULL }, &out, &err, fullscreen);
lua_pushinteger(L, status);
if (out)
lua_pushstring(L, out);
diff --git a/vis.c b/vis.c
index 7d3dd6a..10c3df5 100644
--- a/vis.c
+++ b/vis.c
@@ -1593,17 +1593,17 @@ Regex *vis_regex(Vis *vis, const char *pattern) {
return regex;
}
-int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[],
+static int _vis_pipe(Vis *vis, File *file, Filerange *range, const char* buf, const char *argv[],
void *stdout_context, ssize_t (*read_stdout)(void *stdout_context, char *data, size_t len),
void *stderr_context, ssize_t (*read_stderr)(void *stderr_context, char *data, size_t len),
bool fullscreen) {
/* if an invalid range was given, stdin (i.e. key board input) is passed
* through the external command. */
- Text *text = file->text;
+ Text *text = file != NULL ? file->text : NULL;
int pin[2], pout[2], perr[2], status = -1;
- bool interactive = !text_range_valid(range);
- Filerange rout = interactive ? text_range_new(0, 0) : *range;
+ bool interactive = buf == NULL && (range == NULL || !text_range_valid(range));
+ Filerange rout = (interactive || buf != NULL) ? text_range_new(0, 0) : *range;
if (pipe(pin) == -1)
return -1;
@@ -1654,7 +1654,7 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[],
* closed. Some programs behave differently when used
* in a pipeline.
*/
- if (text_range_size(range) == 0)
+ if (range && text_range_size(range) == 0)
dup2(null, STDIN_FILENO);
else
dup2(pin[0], STDIN_FILENO);
@@ -1688,7 +1688,7 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[],
close(perr[1]);
close(null);
- if (file->name) {
+ if (file != NULL && file->name) {
char *name = strrchr(file->name, '/');
setenv("vis_filepath", file->name, 1);
setenv("vis_filename", name ? name+1 : file->name, 1);
@@ -1737,20 +1737,36 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[],
}
if (pin[1] != -1 && FD_ISSET(pin[1], &wfds)) {
+ ssize_t written = 0;
Filerange junk = rout;
- if (junk.end > junk.start + PIPE_BUF)
- junk.end = junk.start + PIPE_BUF;
- ssize_t len = text_write_range(text, &junk, pin[1]);
- if (len > 0) {
- rout.start += len;
- if (text_range_size(&rout) == 0) {
- close(pin[1]);
- pin[1] = -1;
+ if (text_range_size(&rout)) {
+ if (junk.end > junk.start + PIPE_BUF)
+ junk.end = junk.start + PIPE_BUF;
+ written = text_write_range(text, &junk, pin[1]);
+ if (written > 0) {
+ rout.start += written;
+ if (text_range_size(&rout) == 0) {
+ close(pin[1]);
+ pin[1] = -1;
+ }
}
- } else {
+ } else if (buf != NULL) {
+ size_t len = strlen(buf);
+ if (len > 0) {
+ if (len > PIPE_BUF)
+ len = PIPE_BUF;
+
+ written = write_all(pin[1], buf, len);
+ if (written > 0) {
+ buf += written;
+ }
+ }
+ }
+
+ if (written <= 0) {
close(pin[1]);
pin[1] = -1;
- if (len == -1)
+ if (written == -1)
vis_info_show(vis, "Error writing to external command");
}
}
@@ -1823,16 +1839,30 @@ err:
return -1;
}
+int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[],
+ void *stdout_context, ssize_t (*read_stdout)(void *stdout_context, char *data, size_t len),
+ void *stderr_context, ssize_t (*read_stderr)(void *stderr_context, char *data, size_t len),
+ bool fullscreen) {
+ return _vis_pipe(vis, file, range, NULL, argv, stdout_context, read_stdout, stderr_context, read_stderr, fullscreen);
+}
+
+int vis_pipe_buf(Vis *vis, const char* buf, const char *argv[],
+ void *stdout_context, ssize_t (*read_stdout)(void *stdout_context, char *data, size_t len),
+ void *stderr_context, ssize_t (*read_stderr)(void *stderr_context, char *data, size_t len),
+ bool fullscreen) {
+ return _vis_pipe(vis, NULL, NULL, buf, argv, stdout_context, read_stdout, stderr_context, read_stderr, fullscreen);
+}
+
static ssize_t read_buffer(void *context, char *data, size_t len) {
buffer_append(context, data, len);
return len;
}
-int vis_pipe_collect(Vis *vis, File *file, Filerange *range, const char *argv[], char **out, char **err, bool fullscreen) {
+static int _vis_pipe_collect(Vis *vis, File *file, Filerange *range, const char* buf, const char *argv[], char **out, char **err, bool fullscreen) {
Buffer bufout, buferr;
buffer_init(&bufout);
buffer_init(&buferr);
- int status = vis_pipe(vis, file, range, argv,
+ int status = _vis_pipe(vis, file, range, buf, argv,
&bufout, out ? read_buffer : NULL,
&buferr, err ? read_buffer : NULL,
fullscreen);
@@ -1847,6 +1877,14 @@ int vis_pipe_collect(Vis *vis, File *file, Filerange *range, const char *argv[],
return status;
}
+int vis_pipe_collect(Vis *vis, File *file, Filerange *range, const char *argv[], char **out, char **err, bool fullscreen) {
+ return _vis_pipe_collect(vis, file, range, NULL, argv, out, err, fullscreen);
+}
+
+int vis_pipe_buf_collect(Vis *vis, const char* buf, const char *argv[], char **out, char **err, bool fullscreen) {
+ return _vis_pipe_collect(vis, NULL, NULL, buf, argv, out, err, fullscreen);
+}
+
bool vis_cmd(Vis *vis, const char *cmdline) {
if (!cmdline)
return true;
diff --git a/vis.h b/vis.h
index eb8ec92..1a249ee 100644
--- a/vis.h
+++ b/vis.h
@@ -883,6 +883,20 @@ int vis_pipe(Vis*, File*, Filerange*, const char *argv[],
int vis_pipe_collect(Vis*, File*, Filerange*, const char *argv[], char **out, char **err, bool fullscreen);
/**
+ * Pipe a buffer to an external process, return its exit status and capture
+ * everything that is written to stdout/stderr.
+ * @param argv Argument list, must be ``NULL`` terminated.
+ * @param out Data written to ``stdout``, will be ``NUL`` terminated.
+ * @param err Data written to ``stderr``, will be ``NUL`` terminated.
+ * @param fullscreen Whether the external process is a fullscreen program (e.g. curses based)
+ * @rst
+ * .. warning:: The pointers stored in ``out`` and ``err`` need to be `free(3)`-ed
+ * by the caller.
+ * @endrst
+ */
+int vis_pipe_buf_collect(Vis*, const char*, const char *argv[], char **out, char **err, bool fullscreen);
+
+/**
* @}
* @defgroup vis_keys
* @{