st-clickurl-0.8.5.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
st-clickurl-0.8.5.diff (5778B) | |
--- | |
1 From d5b492049f48dc411b0dd7dc01a403304c20438d Mon Sep 17 00:00:00 2001 | |
2 From: Jishnu Sen <[email protected]> | |
3 Date: Sun, 7 Apr 2024 22:54:46 -0700 | |
4 Subject: [PATCH] Highlight URLs with control and follow with click | |
5 | |
6 --- | |
7 config.def.h | 11 +++++++ | |
8 st.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
9 st.h | 9 ++++++ | |
10 x.c | 24 +++++++++++++- | |
11 4 files changed, 132 insertions(+), 1 deletion(-) | |
12 | |
13 diff --git a/config.def.h b/config.def.h | |
14 index 91ab8ca..4961830 100644 | |
15 --- a/config.def.h | |
16 +++ b/config.def.h | |
17 @@ -472,3 +472,14 @@ static char ascii_printable[] = | |
18 " !\"#$%&'()*+,-./0123456789:;<=>?" | |
19 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" | |
20 "`abcdefghijklmnopqrstuvwxyz{|}~"; | |
21 + | |
22 +/* | |
23 + * Open urls starting with urlprefixes, contatining urlchars | |
24 + * by passing as ARG1 to urlhandler. | |
25 + */ | |
26 +char* urlhandler = "xdg-open"; | |
27 +char urlchars[] = | |
28 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
29 + "abcdefghijklmnopqrstuvwxyz" | |
30 + "0123456789-._~:/?#@!$&'*+,;=%"; | |
31 +char* urlprefixes[] = {"http://", "https://", NULL}; | |
32 diff --git a/st.c b/st.c | |
33 index 51049ba..8f2156c 100644 | |
34 --- a/st.c | |
35 +++ b/st.c | |
36 @@ -643,6 +643,95 @@ getsel(void) | |
37 return str; | |
38 } | |
39 | |
40 +char * | |
41 +strstrany(char* s, char** strs) { | |
42 + char *match; | |
43 + for (int i = 0; strs[i]; i++) { | |
44 + if ((match = strstr(s, strs[i]))) { | |
45 + return match; | |
46 + } | |
47 + } | |
48 + return NULL; | |
49 +} | |
50 + | |
51 +void | |
52 +highlighturls(void) | |
53 +{ | |
54 + char *match; | |
55 + char *linestr = calloc(sizeof(char), term.col+1); /* assume asc… | |
56 + for (int i = term.top; i < term.bot; i++) { | |
57 + int url_start = -1; | |
58 + for (int j = 0; j < term.col; j++) { | |
59 + if (term.line[i][j].u < 127) { | |
60 + linestr[j] = term.line[i][j].u; | |
61 + } | |
62 + linestr[term.col] = '\0'; | |
63 + } | |
64 + while ((match = strstrany(linestr + url_start + 1, urlp… | |
65 + url_start = match - linestr; | |
66 + for (int c = url_start; c < term.col && strchr(… | |
67 + term.line[i][c].mode |= ATTR_URL; | |
68 + tsetdirt(i, c); | |
69 + } | |
70 + } | |
71 + } | |
72 + free(linestr); | |
73 +} | |
74 + | |
75 +void | |
76 +unhighlighturls(void) | |
77 +{ | |
78 + for (int i = term.top; i < term.bot; i++) { | |
79 + for (int j = 0; j < term.col; j++) { | |
80 + Glyph* g = &term.line[i][j]; | |
81 + if (g->mode & ATTR_URL) { | |
82 + g->mode &= ~ATTR_URL; | |
83 + tsetdirt(i, j); | |
84 + } | |
85 + } | |
86 + } | |
87 + return; | |
88 +} | |
89 + | |
90 +void | |
91 +followurl(int x, int y) { | |
92 + char *linestr = calloc(sizeof(char), term.col+1); /* assume asc… | |
93 + char *match; | |
94 + for (int i = 0; i < term.col; i++) { | |
95 + if (term.line[x][i].u < 127) { | |
96 + linestr[i] = term.line[x][i].u; | |
97 + } | |
98 + linestr[term.col] = '\0'; | |
99 + } | |
100 + int url_start = -1; | |
101 + while ((match = strstrany(linestr + url_start + 1, urlprefixes)… | |
102 + url_start = match - linestr; | |
103 + int url_end = url_start; | |
104 + for (int c = url_start; c < term.col && strchr(urlchars… | |
105 + url_end++; | |
106 + } | |
107 + if (url_start <= y && y < url_end) { | |
108 + linestr[url_end] = '\0'; | |
109 + break; | |
110 + } | |
111 + } | |
112 + if (url_start == -1) { | |
113 + free(linestr); | |
114 + return; | |
115 + } | |
116 + | |
117 + pid_t chpid; | |
118 + if ((chpid = fork()) == 0) { | |
119 + if (fork() == 0) | |
120 + execlp(urlhandler, urlhandler, linestr + url_st… | |
121 + exit(1); | |
122 + } | |
123 + if (chpid > 0) | |
124 + waitpid(chpid, NULL, 0); | |
125 + free(linestr); | |
126 + unhighlighturls(); | |
127 +} | |
128 + | |
129 void | |
130 selclear(void) | |
131 { | |
132 diff --git a/st.h b/st.h | |
133 index 519b9bd..354e7f9 100644 | |
134 --- a/st.h | |
135 +++ b/st.h | |
136 @@ -34,6 +34,7 @@ enum glyph_attribute { | |
137 ATTR_WIDE = 1 << 9, | |
138 ATTR_WDUMMY = 1 << 10, | |
139 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, | |
140 + ATTR_URL = 1 << 14, | |
141 }; | |
142 | |
143 enum selection_mode { | |
144 @@ -105,6 +106,10 @@ void selextend(int, int, int, int); | |
145 int selected(int, int); | |
146 char *getsel(void); | |
147 | |
148 +void highlighturls(void); | |
149 +void unhighlighturls(void); | |
150 +void followurl(int, int); | |
151 + | |
152 size_t utf8encode(Rune, char *); | |
153 | |
154 void *xmalloc(size_t); | |
155 @@ -126,3 +131,7 @@ extern unsigned int tabspaces; | |
156 extern unsigned int defaultfg; | |
157 extern unsigned int defaultbg; | |
158 extern unsigned int defaultcs; | |
159 +extern char *urlhandler; | |
160 +extern char urlchars[]; | |
161 +extern char *urlprefixes[]; | |
162 +extern int nurlprefixes; | |
163 diff --git a/x.c b/x.c | |
164 index 8a16faa..13f68e4 100644 | |
165 --- a/x.c | |
166 +++ b/x.c | |
167 @@ -191,6 +191,7 @@ static void usage(void); | |
168 | |
169 static void (*handler[LASTEvent])(XEvent *) = { | |
170 [KeyPress] = kpress, | |
171 + [KeyRelease] = kpress, | |
172 [ClientMessage] = cmessage, | |
173 [ConfigureNotify] = resize, | |
174 [VisibilityNotify] = visibility, | |
175 @@ -445,6 +446,15 @@ mouseaction(XEvent *e, uint release) | |
176 /* ignore Button<N>mask for Button<N> - it's set on release */ | |
177 uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); | |
178 | |
179 + if (release == 0 && | |
180 + e->xbutton.button == Button1 && | |
181 + (match(ControlMask, state) || | |
182 + match(ControlMask, state & ~forcemousemod))) { | |
183 + followurl(evrow(e), evcol(e)); | |
184 + return 1; | |
185 + } | |
186 + | |
187 + | |
188 for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { | |
189 if (ms->release == release && | |
190 ms->button == e->xbutton.button && | |
191 @@ -1476,7 +1486,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs,… | |
192 XftDrawGlyphFontSpec(xw.draw, fg, specs, len); | |
193 | |
194 /* Render underline and strikethrough. */ | |
195 - if (base.mode & ATTR_UNDERLINE) { | |
196 + if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) { | |
197 XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + … | |
198 width, 1); | |
199 } | |
200 @@ -1831,6 +1841,18 @@ kpress(XEvent *ev) | |
201 len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &… | |
202 else | |
203 len = XLookupString(e, buf, sizeof buf, &ksym, NULL); | |
204 + | |
205 + /* 0. highlight URLs when control held */ | |
206 + if (ksym == XK_Control_L) { | |
207 + highlighturls(); | |
208 + } else if (ev->type == KeyRelease && e->keycode == XKeysymToKey… | |
209 + unhighlighturls(); | |
210 + } | |
211 + | |
212 + /* KeyRelease not relevant to shortcuts */ | |
213 + if (ev->type == KeyRelease) | |
214 + return; | |
215 + | |
216 /* 1. shortcuts */ | |
217 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { | |
218 if (ksym == bp->keysym && match(bp->mod, e->state)) { | |
219 -- | |
220 2.44.0 | |
221 |