summaryrefslogtreecommitdiff
path: root/patches/st-copyurl-multiline-20230406-211964d.diff
blob: 8fbac9f6bb667297b30981dd53b00cbaf752f6f1 (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
157
158
159
160
161
162
163
164
165
166
167
From 7405bdc89e4c43cfbeabd0d4d822bc62d1e76730 Mon Sep 17 00:00:00 2001
From: Gildasio Junior <gildasiojunior@riseup.net>
Date: Thu, 6 Apr 2023 14:51:06 -0300
Subject: [PATCH] Loop through urls on screen in both directions

Using previous patches one can loop through urls in the screen in one
direction: botton-up. This patch add a way that can go in the opposite
direction: top-down.

This is usefull in a screen with lots of urls.
---
 config.def.h |   2 +
 st.c         | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++
 st.h         |   1 +
 3 files changed, 104 insertions(+)

diff --git a/config.def.h b/config.def.h
index 91ab8ca..4df78eb 100644
--- a/config.def.h
+++ b/config.def.h
@@ -201,6 +201,8 @@ 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} },
+	{ MODKEY|ShiftMask,     XK_L,           copyurl,        {.i =  1} },
 };
 
 /*
diff --git a/st.c b/st.c
index 134e724..c451015 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);
@@ -201,6 +206,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);
 
@@ -2666,3 +2672,98 @@ 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;
+
+        /* .i = 0 --> botton-up
+         * .i = 1 --> top-down
+         */
+        if (!arg->i) {
+            if (--row < 0)
+                row = term.row - 1;
+        } else {
+            if (++row >= term.row)
+                row = 0;
+        }
+
+		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 fd3b0d8..baa8f29 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.40.0