tcmd: execute shell commands - neatvi - [fork] simple vi-type editor with UTF-8 support
(HTM) git clone git://src.adamsgaard.dk/neatvi
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
(DIR) commit 58191346a45866137a12738b1b82b31f40a673aa
(DIR) parent 6e9f030b017fe128151501d6c0bad0c6e72a8c73
(HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
Date: Fri, 15 May 2015 14:20:23 +0430
cmd: execute shell commands
Diffstat:
M Makefile | 2 +-
A cmd.c | 91 +++++++++++++++++++++++++++++++
M vi.c | 42 +++++++++++++++++++++++++------
M vi.h | 3 +++
4 files changed, 129 insertions(+), 9 deletions(-)
---
(DIR) diff --git a/Makefile b/Makefile
t@@ -2,7 +2,7 @@ CC = cc
CFLAGS = -Wall -O2
LDFLAGS =
-OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o reg.o led.o uc.o term.o rset.o
+OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o reg.o led.o uc.o term.o rset.o cmd.o
all: vi
%.o: %.c
(DIR) diff --git a/cmd.c b/cmd.c
t@@ -0,0 +1,91 @@
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include "vi.h"
+
+static int cmd_make(char **argv, int *ifd, int *ofd)
+{
+ int pid;
+ int pipefds0[2];
+ int pipefds1[2];
+ if (ifd)
+ pipe(pipefds0);
+ if (ofd)
+ pipe(pipefds1);
+ if (!(pid = fork())) {
+ if (ifd) { /* setting up stdin */
+ close(0);
+ dup(pipefds0[0]);
+ close(pipefds0[1]);
+ close(pipefds0[0]);
+ }
+ if (ofd) { /* setting up stdout */
+ close(1);
+ dup(pipefds1[1]);
+ close(pipefds1[0]);
+ close(pipefds1[1]);
+ }
+ execvp(argv[0], argv);
+ exit(1);
+ }
+ if (ifd)
+ close(pipefds0[0]);
+ if (ofd)
+ close(pipefds1[1]);
+ if (pid < 0) {
+ if (ifd)
+ close(pipefds0[1]);
+ if (ofd)
+ close(pipefds1[0]);
+ return -1;
+ }
+ if (ifd)
+ *ifd = pipefds0[1];
+ if (ofd)
+ *ofd = pipefds1[0];
+ return pid;
+}
+
+char *cmd_pipe(char *cmd, char *s)
+{
+ char *argv[] = {"/bin/sh", "-c", cmd, NULL};
+ struct pollfd fds[2];
+ struct sbuf *sb;
+ char buf[512];
+ int ifd = 0, ofd = 0;
+ int slen = strlen(s);
+ int nw = 0;
+ int pid = cmd_make(argv, &ifd, &ofd);
+ if (pid <= 0)
+ return NULL;
+ sb = sbuf_make();
+ fds[0].fd = ofd;
+ fds[0].events = POLLIN;
+ fds[1].fd = ifd;
+ fds[1].events = POLLOUT;
+ while ((fds[0].fd >= 0 || fds[1].fd >= 0) && poll(fds, 3, 200) >= 0) {
+ if (fds[0].revents & POLLIN) {
+ int ret = read(fds[0].fd, buf, sizeof(buf));
+ if (ret > 0)
+ sbuf_mem(sb, buf, ret);
+ if (ret < 0)
+ close(fds[0].fd);
+ } else if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ fds[0].fd = -1;
+ }
+ if (fds[1].revents & POLLOUT) {
+ int ret = write(fds[1].fd, s + nw, slen - nw);
+ if (ret > 0)
+ nw += ret;
+ if (ret <= 0 || nw == slen)
+ close(fds[1].fd);
+ } else if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ fds[1].fd = -1;
+ }
+ }
+ waitpid(pid, NULL, 0);
+ return sbuf_done(sb);
+}
(DIR) diff --git a/vi.c b/vi.c
t@@ -62,6 +62,13 @@ static char *vi_char(void)
return TK_INT(key) ? NULL : led_keymap(key);
}
+static char *vi_prompt(char *msg)
+{
+ term_pos(xrows, led_pos(msg, 0));
+ term_kill();
+ return led_prompt(msg, "");
+}
+
static int vi_yankbuf(void)
{
int c = vi_read();
t@@ -189,10 +196,8 @@ static int vi_search(int cmd, int cnt, int *row, int *col)
char *off = "";
if (cmd == '/' || cmd == '?') {
char sign[4] = {cmd};
- char *kw;
- term_pos(xrows, led_pos(sign, 0));
- term_kill();
- if (!(kw = led_prompt(sign, "")))
+ char *kw = vi_prompt(sign);
+ if (!kw)
return 1;
vi_finddir = cmd == '/' ? +1 : -1;
if (kw[0])
t@@ -332,7 +337,7 @@ static int vi_motionln(int *row, int cmd)
break;
default:
if (c == cmd) {
- *row = MIN(*row + cnt - 1, lbuf_len(xb) - 1);
+ *row = MAX(0, MIN(*row + cnt - 1, lbuf_len(xb) - 1));
break;
}
vi_back(c);
t@@ -667,6 +672,26 @@ static void vi_change(int r1, int c1, int r2, int c2, int lnmode, int closed)
free(post);
}
+static void vi_pipe(int r1, int c1, int r2, int c2, int lnmode, int closed)
+{
+ char *text;
+ char *rep;
+ char *cmd = vi_prompt("!");
+ if (!cmd)
+ return;
+ if (r2 < r1)
+ swap(&r1, &r2);
+ text = lbuf_cp(xb, r1, r2 + 1);
+ rep = cmd_pipe(cmd, text);
+ if (rep) {
+ lbuf_rm(xb, r1, r2 + 1);
+ lbuf_put(xb, r1, rep);
+ }
+ free(cmd);
+ free(text);
+ free(rep);
+}
+
static int vc_motion(int cmd)
{
int r1 = xrow, r2 = xrow; /* region rows */
t@@ -698,6 +723,8 @@ static int vc_motion(int cmd)
vi_delete(r1, c1, r2, c2, lnmode, closed);
if (cmd == 'c')
vi_change(r1, c1, r2, c2, lnmode, closed);
+ if (cmd == '!')
+ vi_pipe(r1, c1, r2, c2, lnmode, closed);
return 0;
}
t@@ -950,9 +977,7 @@ static void vi(void)
redraw = 1;
break;
case ':':
- term_pos(xrows, led_pos(":", 0));
- term_kill();
- ln = led_prompt(":", "");
+ ln = vi_prompt(":");
if (ln && ln[0]) {
ex_command(ln);
redraw = 1;
t@@ -964,6 +989,7 @@ static void vi(void)
case 'c':
case 'd':
case 'y':
+ case '!':
if (!vc_motion(c))
redraw = 1;
break;
(DIR) diff --git a/vi.h b/vi.h
t@@ -119,6 +119,9 @@ int led_pos(char *s, int pos);
void ex(void);
void ex_command(char *cmd);
+/* process management */
+char *cmd_pipe(char *cmd, char *s);
+
/* global variables */
extern int xvis;
extern struct lbuf *xb;