aboutsummaryrefslogtreecommitdiff
path: root/patches/st-copyurl-multiline-20220221-0.8.5.diff
blob: 7cd26e27c9dfec496775c30de54513bf4d494214 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
From 30a04d9ecb3998953bdbe42e5617d00d6002869b Mon Sep 17 00:00:00 2001
From: Santtu Lakkala <inz@inz.fi>
Date: Wed, 16 Feb 2022 20:34:20 +0200
Subject: [PATCH] Loop through urls on screen and copy to clipboard

Replace url detection heuristics with a DFA, enabling urls that span
multiple lines. Also fix the selection not to use snapping so that urls
are selected exactly.
---
 config.def.h |  1 +
 st.c         | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 st.h         |  1 +
 3 files changed, 95 insertions(+)

diff --git a/config.def.h b/config.def.h
index 91ab8ca..3f365c7 100644
--- a/config.def.h
+++ b/config.def.h
@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = {
 	{ TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
+	{ MODKEY,               XK_l,           copyurl,        {.i =  0} },
 };
 
 /*
diff --git a/st.c b/st.c
index 51049ba..5b6d919 100644
--- a/st.c
+++ b/st.c
@@ -152,6 +152,11 @@ typedef struct {
 	int narg;              /* nb of args */
 } STREscape;
 
+typedef struct {
+	int state;
+	size_t length;
+} URLdfa;
+
 static void execsh(char *, char **);
 static void stty(char **);
 static void sigchld(int);
@@ -200,6 +205,7 @@ static void tdefutf8(char);
 static int32_t tdefcolor(const int *, int *, int);
 static void tdeftran(char);
 static void tstrsequence(uchar);
+static int daddch(URLdfa *, char);
 
 static void drawregion(int, int, int, int);
 
@@ -2688,3 +2694,90 @@ redraw(void)
 	tfulldirt();
 	draw();
 }
+
+int
+daddch(URLdfa *dfa, char c)
+{
+	/* () and [] can appear in urls, but excluding them here will reduce false
+	 * positives when figuring out where a given url ends.
+	 */
+	static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		"abcdefghijklmnopqrstuvwxyz"
+		"0123456789-._~:/?#@!$&'*+,;=%";
+	static const char RPFX[] = "//:sptth";
+
+	if (!strchr(URLCHARS, c)) {
+		dfa->length = 0;
+		dfa->state = 0;
+
+		return 0;
+	}
+
+	dfa->length++;
+
+	if (dfa->state == 2 && c == '/') {
+		dfa->state = 0;
+	} else if (dfa->state == 3 && c == 'p') {
+		dfa->state++;
+	} else if (c != RPFX[dfa->state]) {
+		dfa->state = 0;
+		return 0;
+	}
+
+	if (dfa->state++ == 7) {
+		dfa->state = 0;
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+** Select and copy the previous url on screen (do nothing if there's no url).
+*/
+void
+copyurl(const Arg *arg) {
+	int row = 0, /* row of current URL */
+		col = 0, /* column of current URL start */
+		colend = 0, /* column of last occurrence */
+		passes = 0; /* how many rows have been scanned */
+
+	const char *c = NULL,
+		 *match = NULL;
+	URLdfa dfa = { 0 };
+
+	row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
+	LIMIT(row, term.top, term.bot);
+
+	colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
+	LIMIT(colend, 0, term.col);
+
+	/*
+	** Scan from (term.row - 1,term.col - 1) to (0,0) and find
+	** next occurrance of a URL
+	*/
+	for (passes = 0; passes < term.row; passes++) {
+		/* Read in each column of every row until
+		** we hit previous occurrence of URL
+		*/
+		for (col = colend; col--;)
+			if (daddch(&dfa, term.line[row][col].u < 128 ? term.line[row][col].u : ' '))
+				break;
+
+		if (col >= 0)
+			break;
+
+		if (--row < 0)
+			row = term.row - 1;
+
+		colend = term.col;
+	}
+
+	if (passes < term.row) {
+		selstart(col, row, 0);
+		selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0);
+		selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1);
+		xsetsel(getsel());
+		xclipcopy();
+	}
+}
diff --git a/st.h b/st.h
index 519b9bd..0458005 100644
--- a/st.h
+++ b/st.h
@@ -85,6 +85,7 @@ void printscreen(const Arg *);
 void printsel(const Arg *);
 void sendbreak(const Arg *);
 void toggleprinter(const Arg *);
+void copyurl(const Arg *);
 
 int tattrset(int);
 void tnew(int, int);
-- 
2.32.0