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
|
From 897c3958d01d8df80ebf1666b972b8a658b419ba 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
Based on the previous highlighting patches, slightly simplified and
fixes graphical issues with mixed copyurl and selection.
---
config.def.h | 1 +
st.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
st.h | 1 +
3 files changed, 84 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..bf3d81a 100644
--- a/st.c
+++ b/st.c
@@ -200,6 +200,7 @@ static void tdefutf8(char);
static int32_t tdefcolor(const int *, int *, int);
static void tdeftran(char);
static void tstrsequence(uchar);
+static const char *findlastany(const char *, const char**, size_t);
static void drawregion(int, int, int, int);
@@ -2688,3 +2689,84 @@ redraw(void)
tfulldirt();
draw();
}
+
+const char *
+findlastany(const char *str, const char**find, size_t len)
+{
+ const char *found = NULL;
+ int i = 0;
+
+ for (found = str + strlen(str) - 1; found >= str; --found) {
+ for(i = 0; i < len; i++) {
+ if (strncmp(found, find[i], strlen(find[i])) == 0) {
+ return found;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+** Select and copy the previous url on screen (do nothing if there's no url).
+**
+** FIXME: doesn't handle urls that span multiple lines; will need to add support
+** for multiline "getsel()" first
+*/
+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 const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~:/?#@!$&'*+,;=%";
+
+ static const char* URLSTRINGS[] = {"http://", "https://"};
+
+ 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 */
+
+ char linestr[term.col + 1];
+ const char *c = NULL,
+ *match = NULL;
+
+ 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 = 0; col < colend; ++col)
+ linestr[col] = term.line[row][col].u < 128 ? term.line[row][col].u : ' ';
+ linestr[col] = '\0';
+
+ if ((match = findlastany(linestr, URLSTRINGS,
+ sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
+ break;
+
+ if (--row < 0)
+ row = term.row - 1;
+
+ colend = term.col;
+ };
+
+ if (match) {
+ size_t l = strspn(match, URLCHARS);
+ selstart(match - linestr, row, 0);
+ selextend(match - linestr + l - 1, row, SEL_REGULAR, 0);
+ selextend(match - linestr + l - 1, row, 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
|