diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | README.org | 1 | ||||
-rw-r--r-- | config.h | 11 | ||||
-rwxr-xr-x | st-cpyout | 14 | ||||
-rw-r--r-- | st.c | 78 | ||||
-rw-r--r-- | st.h | 1 |
7 files changed, 107 insertions, 2 deletions
@@ -40,6 +40,7 @@ dist: clean install: st mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f st $(DESTDIR)$(PREFIX)/bin + cp -f st-cpyout $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/st mkdir -p $(DESTDIR)$(MANPREFIX)/man1 sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 @@ -32,8 +32,9 @@ doing on st's patches page. Here is my list: - anygeometry - - clipboard - bold is not bright + - clipboard + - externalpipe - hidecursor - keyboard select - scrollback @@ -32,6 +32,7 @@ Here is my list: - /anygeometry/ - /bold is not bright/ - /clipboard/ +- /externalpipe/ - /hidecursor/ - /keyboard select/ - /scrollback/ @@ -202,6 +202,11 @@ static MouseShortcut mshortcuts[] = { #define MODKEY Mod1Mask #define TERMMOD (ControlMask|ShiftMask) +static char *cpyurlcmd[] = { "/bin/sh", "-c", + "tmp=$(sed 's/.*│//g' | tr -d '\n' | grep -aEo '(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$#=_-~]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)' | uniq | sed 's/^www./http:\\/\\/www\\./g' ); IFS=; [ ! -z $tmp ] && echo $tmp | dmenu -i -l 10 | tr -d '\n' | xclip -selection clipboard", + "externalpipe", NULL }; +static char *cpyoutcmd[] = { "/bin/sh", "-c", "/usr/local/bin/st-cpyout", "externalpipe", NULL }; + static Shortcut shortcuts[] = { /* mask keysym function argument */ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, @@ -219,6 +224,12 @@ static Shortcut shortcuts[] = { { ControlMask|Mod1Mask, XK_c, keyboard_select,{.i = 0} }, { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, + { TERMMOD, XK_U, kscrollup, {.i = -1} }, + { TERMMOD, XK_D, kscrolldown, {.i = -1} }, + { TERMMOD, XK_K, kscrollup, {.i = 1} }, + { TERMMOD, XK_J, kscrolldown, {.i = 1} }, + { TERMMOD, XK_Y, externalpipe, {.v = cpyurlcmd} }, + { TERMMOD, XK_O, externalpipe, {.v = cpyoutcmd} }, }; /* diff --git a/st-cpyout b/st-cpyout new file mode 100755 index 0000000..1912dc8 --- /dev/null +++ b/st-cpyout @@ -0,0 +1,14 @@ +#!/bin/sh + +# Using external pipe with st, give a dmenu prompt of recent commands, +# allowing the user to copy the output of one. +# xclip required for this script. +# By Jaywalker and Luke +tmpfile=$(gmktemp /tmp/st-cmd-output.XXXXXX) +trap 'grm "$tmpfile"' 0 1 15 +gsed -n "w $tmpfile" +gsed -i 's/\x0//g' "$tmpfile" +ps1="$(grep "\S" "$tmpfile" | gtail -n 1 | gsed 's/^\s*//' | gcut -d' ' -f1)" +chosen="$(grep -F "$ps1" "$tmpfile" | gsed '$ d' | gtac | dmenu -i -l 10 | gsed 's/[^^]/[&]/g; s/\^/\\^/g')" +eps1="$(gecho "$ps1" | gsed 's/[^^]/[&]/g; s/\^/\\^/g')" +gawk "/^$chosen$/{p=1;print;next} p&&/$eps1/{p=0};p" "$tmpfile" | xclip -selection clipboard @@ -48,6 +48,7 @@ #define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ term.scr + HISTSIZE + 1) % HISTSIZE] : \ term.line[(y) - term.scr]) +#define TLINE_HIST(y) ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)]) enum term_mode { MODE_WRAP = 1 << 0, @@ -432,6 +433,20 @@ tlinelen(int y) return i; } +int +tlinehistlen(int y) +{ + int i = term.col; + + if (TLINE_HIST(y)[i - 1].mode & ATTR_WRAP) + return i; + + while (i > 0 && TLINE_HIST(y)[i - 1].u == ' ') + --i; + + return i; +} + void selstart(int col, int row, int snap) { @@ -732,8 +747,14 @@ sigchld(int a) if ((p = waitpid(pid, &stat, WNOHANG)) < 0) die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); - if (pid != p) + if (pid != p) { + if (p == 0 && wait(&stat) < 0) + die("wait: %s\n", strerror(errno)); + + /* reinstall sigchld handler */ + signal(SIGCHLD, sigchld); return; + } if (WIFEXITED(stat) && WEXITSTATUS(stat)) die("child exited with status %d\n", WEXITSTATUS(stat)); @@ -2004,6 +2025,61 @@ strparse(void) } void +externalpipe(const Arg *arg) +{ + int to[2]; + char buf[UTF_SIZ]; + void (*oldsigpipe)(int); + Glyph *bp, *end; + int lastpos, n, newline; + + if (pipe(to) == -1) + return; + + switch (fork()) { + case -1: + close(to[0]); + close(to[1]); + return; + case 0: + dup2(to[0], STDIN_FILENO); + close(to[0]); + close(to[1]); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]); + perror("failed"); + exit(0); + } + + close(to[0]); + /* ignore sigpipe for now, in case child exists early */ + oldsigpipe = signal(SIGPIPE, SIG_IGN); + newline = 0; + for (n = 0; n <= HISTSIZE + 2; n++) { + bp = TLINE_HIST(n); + lastpos = MIN(tlinehistlen(n) + 1, term.col) - 1; + if (lastpos < 0) + break; + if (lastpos == 0) + continue; + end = &bp[lastpos + 1]; + for (; bp < end; ++bp) + if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0) + break; + if ((newline = TLINE_HIST(n)[lastpos].mode & ATTR_WRAP)) + continue; + if (xwrite(to[1], "\n", 1) < 0) + break; + newline = 0; + } + if (newline) + (void)xwrite(to[1], "\n", 1); + close(to[1]); + /* restore */ + signal(SIGPIPE, oldsigpipe); +} + +void strdump(void) { size_t i; @@ -81,6 +81,7 @@ void die(const char *, ...); void redraw(void); void draw(void); +void externalpipe(const Arg *); void kscrolldown(const Arg *); void kscrollup(const Arg *); void printscreen(const Arg *); |