On 4 April 2011 16:18, Bryan Bennett <bbenn...@gmail.com> wrote:
> While I understand wanting applications to adhere to the Unix
> Philosophy, it seems to me that inputting and outputting text
> is what a terminal essentially does and copying & pasting is
> just a small extension of that role. I'd like to see a sane
> way of copying & pasting with the keyboard, rather than
> relying on the mouse for that.

How about something similar to Vimperator's edit-textbox idea?
You hit a key-combo, and the terminal writes what is visible on the
screen to a temporary file, then fires up $EDITOR on said file. You
delete what you don't want, then the rest is inserted into X's
selection.

I've knocked together a quick patch, attached, along with a whitespace
patch that removes trailing whitespace. At the moment, the "key-combo"
is middle mouse.

The patch is a bit of a bodge too - it doesn't support unicode
characters properly and for the system() call to work, SIGCHLD is reset
temporarily, which could be a problem if the shell dies mid-selection
edit. I'm open to suggestions. Avoid system() entirely?

Also, I wasn't sure how to open $EDITOR in st's terminal itself, if
people are interested I'll give it a go, but for the moment it just
fires up another st to host the editor.

Cheers,
Rob.
diff -r fe61798f04a5 st.c
--- a/st.c	Sun Apr 03 21:40:33 2011 +0200
+++ b/st.c	Tue Apr 05 13:04:11 2011 +0100
@@ -45,7 +45,7 @@
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
 #define LEN(a)     (sizeof(a) / sizeof(a[0]))
-#define DEFAULT(a, b)     (a) = (a) ? (a) : (b)    
+#define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
 #define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
@@ -57,7 +57,7 @@
        CURSOR_SAVE, CURSOR_LOAD };
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8, 
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8,
        MODE_CRLF=16 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { SCREEN_UPDATE, SCREEN_REDRAW };
@@ -96,7 +96,7 @@
 
 /* Internal representation of the screen */
 typedef struct {
-	int row;	/* nb row */  
+	int row;	/* nb row */
 	int col;	/* nb col */
 	Line* line;	/* screen */
 	Line* alt;	/* alternate screen */
@@ -125,7 +125,7 @@
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
-} XWindow; 
+} XWindow;
 
 typedef struct {
 	KeySym k;
@@ -340,7 +340,7 @@
 	else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1)
 		return 0;
 	else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
-	    ((b == 1) || 
+	    ((b == 1) ||
 	    ((b == 2) && (*c2&(B7|B6)) == B7)))
 		return 0;
 	else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
@@ -362,7 +362,7 @@
 		return 2;
 	else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5))
 		return 3;
-	else 
+	else
 		return 4;
 }
 
@@ -376,20 +376,20 @@
 		sel.xtarget = XA_STRING;
 }
 
-static inline int 
+static inline int
 selected(int x, int y) {
 	if(sel.ey == y && sel.by == y) {
 		int bx = MIN(sel.bx, sel.ex);
 		int ex = MAX(sel.bx, sel.ex);
 		return BETWEEN(x, bx, ex);
 	}
-	return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x)) 
+	return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x))
 		|| (y==sel.b.y && x>=sel.b.x && (x<=sel.e.x || sel.b.y!=sel.e.y));
 }
 
 void
 getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
-	if(b) 
+	if(b)
 		*b = e->xbutton.button;
 
 	*x = (e->xbutton.x - BORDER)/xw.cw;
@@ -560,7 +560,7 @@
 	exit(EXIT_FAILURE);
 }
 
-void 
+void
 sigchld(int a) {
 	int stat = 0;
 	if(waitpid(pid, &stat, 0) < 0)
@@ -574,7 +574,7 @@
 void
 ttynew(void) {
 	int m, s;
-	
+
 	/* seems to work fine on linux, openbsd and freebsd */
 	struct winsize w = {term.row, term.col, 0, 0};
 	if(openpty(&m, &s, NULL, NULL, &w) < 0)
@@ -613,7 +613,7 @@
 void
 ttyread(void) {
 	static char buf[BUFSIZ];
-	static int buflen = 0; 
+	static int buflen = 0;
 	char *ptr;
 	char s[UTF_SIZ];
 	int charsize; /* size of utf8 char in bytes */
@@ -669,11 +669,11 @@
 void
 treset(void) {
 	term.c = (TCursor){{
-		.mode = ATTR_NULL, 
-		.fg = DefaultFG, 
+		.mode = ATTR_NULL,
+		.fg = DefaultFG,
 		.bg = DefaultBG
 	}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
-	
+
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
 	tclearregion(0, 0, term.col-1, term.row-1);
@@ -705,11 +705,11 @@
 tscrolldown(int orig, int n) {
 	int i;
 	Line temp;
-	
+
 	LIMIT(n, 0, term.bot-orig+1);
 
 	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
-	
+
 	for(i = term.bot; i >= orig+n; i--) {
 		temp = term.line[i];
 		term.line[i] = term.line[i-n];
@@ -722,12 +722,12 @@
 	int i;
 	Line temp;
 	LIMIT(n, 0, term.bot-orig+1);
-	
+
 	tclearregion(0, orig, term.col-1, orig+n-1);
-	
-	for(i = orig; i <= term.bot-n; i++) { 
+
+	for(i = orig; i <= term.bot-n; i++) {
 		 temp = term.line[i];
-		 term.line[i] = term.line[i+n]; 
+		 term.line[i] = term.line[i+n];
 		 term.line[i+n] = temp;
 	}
 }
@@ -750,7 +750,7 @@
 	escseq.narg = 0;
 	if(*p == '?')
 		escseq.priv = 1, p++;
-	
+
 	while(p < escseq.buf+escseq.len) {
 		while(isdigit(*p)) {
 			escseq.arg[escseq.narg] *= 10;
@@ -857,22 +857,22 @@
 			term.c.attr.bg = DefaultBG;
 			break;
 		case 1:
-			term.c.attr.mode |= ATTR_BOLD;	 
+			term.c.attr.mode |= ATTR_BOLD;
 			break;
-		case 4: 
+		case 4:
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
-		case 7: 
-			term.c.attr.mode |= ATTR_REVERSE;	
+		case 7:
+			term.c.attr.mode |= ATTR_REVERSE;
 			break;
-		case 22: 
-			term.c.attr.mode &= ~ATTR_BOLD;	 
+		case 22:
+			term.c.attr.mode &= ~ATTR_BOLD;
 			break;
-		case 24: 
+		case 24:
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
-		case 27: 
-			term.c.attr.mode &= ~ATTR_REVERSE;	 
+		case 27:
+			term.c.attr.mode &= ~ATTR_REVERSE;
 			break;
 		case 38:
 			if (i + 2 < l && attr[i + 1] == 5) {
@@ -883,7 +883,7 @@
 					fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
 			}
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
 			break;
 		case 39:
 			term.c.attr.fg = DefaultFG;
@@ -897,7 +897,7 @@
 					fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
 			}
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
 			break;
 		case 49:
 			term.c.attr.bg = DefaultBG;
@@ -911,9 +911,9 @@
 				term.c.attr.fg = attr[i] - 90 + 8;
 			else if(BETWEEN(attr[i], 100, 107))
 				term.c.attr.fg = attr[i] - 100 + 8;
-			else 
+			else
 				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]), csidump();
-			
+
 			break;
 		}
 	}
@@ -931,7 +931,7 @@
 		b = temp;
 	}
 	term.top = t;
-	term.bot = b;	 
+	term.bot = b;
 }
 
 void
@@ -1156,7 +1156,7 @@
 }
 
 void
-csidump(void) { 
+csidump(void) {
 	int i;
 	printf("ESC [ %s", escseq.priv ? "? " : "");
 	if(escseq.narg)
@@ -1189,7 +1189,7 @@
 				csiparse(), csihandle();
 			}
 			/* TODO: handle other OSC */
-		} else if(term.esc & ESC_OSC) { 
+		} else if(term.esc & ESC_OSC) {
 			if(ascii == ';') {
 				term.titlelen = 0;
 				term.esc = ESC_START | ESC_TITLE;
@@ -1354,7 +1354,7 @@
 		term.line[i] = calloc(col, sizeof(Glyph));
 		term.alt [i] = calloc(col, sizeof(Glyph));
 	}
-	
+
 	/* update terminal size */
 	term.col = col, term.row = row;
 	/* make use of the LIMIT in tmoveto */
@@ -1513,7 +1513,7 @@
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dpy);
-	
+
 	/* font */
 	initfonts(FONT, BOLDFONT);
 
@@ -1550,16 +1550,16 @@
 
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
-	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing 
-					   | XIMStatusNothing, XNClientWindow, xw.win, 
+	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
+					   | XIMStatusNothing, XNClientWindow, xw.win,
 					   XNFocusWindow, xw.win, NULL);
 	/* gc */
 	dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
-	
+
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, XC_xterm);
 	XDefineCursor(xw.dpy, xw.win, cursor);
-	XRecolorCursor(xw.dpy, cursor, 
+	XRecolorCursor(xw.dpy, cursor,
 		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
@@ -1595,7 +1595,7 @@
 
 	XmbDrawImageString(xw.dpy, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.set : dc.font.set,
 	    dc.gc, winx, winy, s, bytelen);
-	
+
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
@@ -1606,10 +1606,10 @@
 	static int oldy = 0;
 	int sl;
 	Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0};
-	
+
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
-	
+
 	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
 		memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
 
@@ -1619,7 +1619,7 @@
 		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl);
 	} else
 		xclear(oldx, oldy, oldx, oldy);
-	
+
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
 		sl = utf8size(g.c);
@@ -1768,7 +1768,7 @@
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
-	
+
 	/* 1. custom keys from config.h */
 	if((customkey = kmap(ksym)))
 		ttywrite(customkey, strlen(customkey));
@@ -1806,10 +1806,10 @@
 void
 resize(XEvent *e) {
 	int col, row;
-	
+
 	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
 		return;
-	
+
 	xw.w = e->xconfigure.width;
 	xw.h = e->xconfigure.height;
 	col = (xw.w - 2*BORDER) / xw.cw;
@@ -1839,7 +1839,7 @@
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
-			draw(SCREEN_UPDATE); 
+			draw(SCREEN_UPDATE);
 		}
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
@@ -1854,7 +1854,7 @@
 int
 main(int argc, char *argv[]) {
 	int i;
-	
+
 	for(i = 1; i < argc; i++) {
 		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
 		case 't':
diff -r fe61798f04a5 st.c
--- a/st.c	Sun Apr 03 21:40:33 2011 +0200
+++ b/st.c	Tue Apr 05 13:01:54 2011 +0100
@@ -220,6 +220,7 @@
 static inline int selected(int, int);
 static void selcopy(void);
 static void selpaste(void);
+static void seledit(void);
 
 static int utf8decode(char *, long *);
 static int utf8encode(long *, char *);
@@ -402,9 +403,86 @@
 
 void
 bpress(XEvent *e) {
-	sel.mode = 1;
-	sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
-	sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
+	if(e->xbutton.button == 2){
+		seledit();
+	}else{
+		sel.mode = 1;
+		sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
+		sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
+	}
+}
+
+void
+seledit(void) {
+	struct stat st;
+	char fname[64], cmd[128];
+	char *env = getenv("TMPDIR");
+	char *sel = NULL;
+	int fd;
+	int x, y;
+
+	DEFAULT(env, "/tmp");
+	snprintf(fname, sizeof fname, "%s/st_edXXXXXX", env);
+
+	fd = mkstemp(fname);
+	if(fd == -1){
+		perror("mkstemp()");
+		return;
+	}
+
+	for(y = 0; y < term.row; y++) {
+		for(x = 0; x < term.col; x++)
+			if(isprint(term.line[y][x].c[0])) /* FIXME: unicode */
+				write(fd, term.line[y][x].c, utf8size(term.line[y][x].c));
+
+		write(fd, "\n", 1);
+	}
+	close(fd);
+
+	env = getenv("VISUAL");
+	DEFAULT(env, getenv("EDITOR"));
+	DEFAULT(env, "vi");
+
+	snprintf(cmd, sizeof cmd, "%s %s %s", EDIT_TERMINAL " -e", env, fname);
+
+	signal(SIGCHLD, SIG_DFL);
+	if(system(cmd) != 0){ /* FIXME: manual fork() and wait() */
+		signal(SIGCHLD, sigchld);
+		perror(cmd);
+		goto bail;
+	}
+	signal(SIGCHLD, sigchld);
+
+	fd = open(fname, O_RDONLY);
+	if(fd == -1){
+		perror(fname);
+		goto bail;
+	}
+
+	if(fstat(fd, &st) != 0){
+		perror("fstat()");
+		goto bail;
+	}
+
+	sel = malloc(st.st_size + 1);
+	if(!sel){
+		perror("malloc()");
+		goto bail;
+	}
+
+	if(read(fd, sel, st.st_size) == -1){
+		perror("read()");
+		goto bail;
+	}
+
+	sel[st.st_size] = '\0';
+	xsetsel(sel);
+	sel = NULL; /* prevent sel.clip deallocation */
+
+bail:
+	free(sel);
+	close(fd);
+	remove(fname);
 }
 
 void
diff -r fe61798f04a5 config.def.h
--- a/config.def.h	Sun Apr 03 21:40:33 2011 +0200
+++ b/config.def.h	Tue Apr 05 13:08:10 2011 +0100
@@ -4,6 +4,7 @@
 #define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-60-*-*"
 #define BORDER 2
 #define SHELL "/bin/sh"
+#define EDIT_TERMINAL "st"
 
 /* Terminal colors */
 static const char *colorname[] = {

Reply via email to