[dev] [PATCH] [st] copyurl patch with corrected clipboard behaviour

From: David Phillips <dbphillipsnz_AT_gmail.com>
Date: Tue, 16 Feb 2016 14:01:00 +1300

Previous version of the patch incorrectly set sel.primary, issue fixed.

The original implementation of this patch copied the URL to the PRIMARY
clipboard. st has since changed its behaviour to align with the freedesktop
standard [0] on the issue such that, in general, explicit copy+paste actions
use CLIPBOARD while implicit (eg selection-based) copying will use PRIMARY.

I feel the behaviour the original patch is showing is now (since st changed)
wrong. A keypress etc to invoke copyurl is surely an explicit clipboard copy
action. As such, this patch is a slight modification on the original copyurl
patch. Calling copyurl will now put the URLs into CLIPBOARD and not PRIMARY.

I am aware this patch will not be merged. If there is no opposition, I will
replace the old one on the wiki in the next few days.

[0]: https://specifications.freedesktop.org/clipboards-spec/clipboards-latest.txt
---
 config.def.h |  1 +
 st.c         | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)
diff --git a/config.def.h b/config.def.h
index fd09d72..05fbba5 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -157,6 +157,7 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,     XK_C,           clipcopy,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_V,           clippaste,      {.i =  0} },
 	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
+	{ MODKEY,               XK_l,           copyurl,        {.i =  0} },
 };
 
 /*
diff --git a/st.c b/st.c
index 0536b6f..b1e5da0 100644
--- a/st.c
+++ b/st.c
_AT_@ -335,6 +335,7 @@ static void printsel(const Arg *);
 static void printscreen(const Arg *) ;
 static void toggleprinter(const Arg *);
 static void sendbreak(const Arg *);
+static void copyurl(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
_AT_@ -4413,3 +4414,64 @@ run:
 	return 0;
 }
 
+/* select and copy the previous url on screen (do nothing if there's no url).
+ * known bug: doesn't handle urls that span multiple lines (wontfix)
+ * known bug: only finds first url on line (mightfix)
+ */
+void
+copyurl(const Arg *arg) {
+	/* () and [] can appear in urls, but excluding them here will reduce false
+	 * positives when figuring out where a given url ends.
+	 */
+	static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		"abcdefghijklmnopqrstuvwxyz"
+		"0123456789-._~:/?#_AT_!$&'*+,;=%";
+
+	int i, row, startrow;
+	char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */
+	char *c, *match = NULL;
+
+	row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y-1 : term.bot;
+	LIMIT(row, term.top, term.bot);
+	startrow = row;
+
+	/* find the start of the last url before selection */
+	do {
+		for (i = 0; i < term.col; ++i) {
+			if (term.line[row][i].u > 127) /* assume ascii */
+				continue;
+			linestr[i] = term.line[row][i].u;
+		}
+		linestr[term.col] = '\0';
+		if ((match = strstr(linestr, "http://"))
+				|| (match = strstr(linestr, "https://")))
+			break;
+		if (--row < term.top)
+			row = term.bot;
+	} while (row != startrow);
+
+	if (match) {
+		/* must happen before trim */
+		selclear(NULL);
+		sel.ob.x = strlen(linestr) - strlen(match);
+
+		/* trim the rest of the line from the url match */
+		for (c = match; *c != '\0'; ++c)
+			if (!strchr(URLCHARS, *c)) {
+				*c = '\0';
+				break;
+			}
+
+		/* select and copy */
+		sel.mode = 1;
+		sel.type = SEL_REGULAR;
+		sel.oe.x = sel.ob.x + strlen(match)-1;
+		sel.ob.y = sel.oe.y = row;
+		selnormalize();
+		tsetdirt(sel.nb.y, sel.ne.y);
+		sel.primary = xstrdup(match);
+		clipcopy(NULL);
+	}
+
+	free(linestr);
+}
-- 
2.7.0
Received on Tue Feb 16 2016 - 02:01:00 CET

This archive was generated by hypermail 2.3.0 : Tue Feb 16 2016 - 02:12:13 CET