st-clickurl-nocontrol-0.8.5.diff (5591B)
1 From 8d13e4a296f0b2a625df10c8ee6d2fc96ec97580 Mon Sep 17 00:00:00 2001 2 From: Kyle Chui <kyle.chui+suckless@pm.me> 3 Date: Tue, 9 Apr 2024 16:31:25 -0700 4 Subject: [PATCH] Underline URLs and follow with click 5 6 --- 7 config.def.h | 11 +++++++ 8 st.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 st.h | 9 ++++++ 10 x.c | 12 ++++++- 11 4 files changed, 119 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..a7eb86e 100644 34 --- a/st.c 35 +++ b/st.c 36 @@ -643,6 +643,92 @@ 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 +highlighturlsline(int row) 53 +{ 54 + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ 55 + char *match; 56 + for (int j = 0; j < term.col; j++) { 57 + if (term.line[row][j].u < 127) { 58 + linestr[j] = term.line[row][j].u; 59 + } 60 + linestr[term.col] = '\0'; 61 + } 62 + int url_start = -1; 63 + while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { 64 + url_start = match - linestr; 65 + for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { 66 + term.line[row][c].mode |= ATTR_URL; 67 + tsetdirt(row, c); 68 + } 69 + } 70 + free(linestr); 71 +} 72 + 73 +void 74 +unhighlighturlsline(int row) 75 +{ 76 + for (int j = 0; j < term.col; j++) { 77 + Glyph* g = &term.line[row][j]; 78 + if (g->mode & ATTR_URL) { 79 + g->mode &= ~ATTR_URL; 80 + tsetdirt(row, j); 81 + } 82 + } 83 + return; 84 +} 85 + 86 +int 87 +followurl(int col, int row) { 88 + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ 89 + char *match; 90 + for (int i = 0; i < term.col; i++) { 91 + if (term.line[row][i].u < 127) { 92 + linestr[i] = term.line[row][i].u; 93 + } 94 + linestr[term.col] = '\0'; 95 + } 96 + int url_start = -1, found_url = 0; 97 + while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { 98 + url_start = match - linestr; 99 + int url_end = url_start; 100 + for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { 101 + url_end++; 102 + } 103 + if (url_start <= col && col < url_end) { 104 + found_url = 1; 105 + linestr[url_end] = '\0'; 106 + break; 107 + } 108 + } 109 + if (!found_url) { 110 + free(linestr); 111 + return 0; 112 + } 113 + 114 + pid_t chpid; 115 + if ((chpid = fork()) == 0) { 116 + if (fork() == 0) 117 + execlp(urlhandler, urlhandler, linestr + url_start, NULL); 118 + exit(1); 119 + } 120 + if (chpid > 0) 121 + waitpid(chpid, NULL, 0); 122 + free(linestr); 123 + return 1; 124 +} 125 + 126 void 127 selclear(void) 128 { 129 @@ -2652,6 +2738,8 @@ drawregion(int x1, int y1, int x2, int y2) 130 continue; 131 132 term.dirty[y] = 0; 133 + unhighlighturlsline(y); 134 + highlighturlsline(y); 135 xdrawline(term.line[y], x1, y, x2); 136 } 137 } 138 diff --git a/st.h b/st.h 139 index 519b9bd..5efc27e 100644 140 --- a/st.h 141 +++ b/st.h 142 @@ -33,6 +33,7 @@ enum glyph_attribute { 143 ATTR_WRAP = 1 << 8, 144 ATTR_WIDE = 1 << 9, 145 ATTR_WDUMMY = 1 << 10, 146 + ATTR_URL = 1 << 11, 147 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, 148 }; 149 150 @@ -105,6 +106,10 @@ void selextend(int, int, int, int); 151 int selected(int, int); 152 char *getsel(void); 153 154 +void highlighturlsline(int); 155 +void unhighlighturlsline(int); 156 +int followurl(int, int); 157 + 158 size_t utf8encode(Rune, char *); 159 160 void *xmalloc(size_t); 161 @@ -126,3 +131,7 @@ extern unsigned int tabspaces; 162 extern unsigned int defaultfg; 163 extern unsigned int defaultbg; 164 extern unsigned int defaultcs; 165 +extern char *urlhandler; 166 +extern char urlchars[]; 167 +extern char *urlprefixes[]; 168 +extern int nurlprefixes; 169 diff --git a/x.c b/x.c 170 index 8a16faa..c721f8b 100644 171 --- a/x.c 172 +++ b/x.c 173 @@ -191,6 +191,7 @@ static void usage(void); 174 175 static void (*handler[LASTEvent])(XEvent *) = { 176 [KeyPress] = kpress, 177 + [KeyRelease] = kpress, 178 [ClientMessage] = cmessage, 179 [ConfigureNotify] = resize, 180 [VisibilityNotify] = visibility, 181 @@ -445,6 +446,10 @@ mouseaction(XEvent *e, uint release) 182 /* ignore Button<N>mask for Button<N> - it's set on release */ 183 uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); 184 185 + if (release == 0 && e->xbutton.button == Button1) { 186 + return followurl(evcol(e), evrow(e)); 187 + } 188 + 189 for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { 190 if (ms->release == release && 191 ms->button == e->xbutton.button && 192 @@ -1476,7 +1481,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 193 XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 194 195 /* Render underline and strikethrough. */ 196 - if (base.mode & ATTR_UNDERLINE) { 197 + if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) { 198 XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, 199 width, 1); 200 } 201 @@ -1831,6 +1836,11 @@ kpress(XEvent *ev) 202 len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); 203 else 204 len = XLookupString(e, buf, sizeof buf, &ksym, NULL); 205 + 206 + /* KeyRelease not relevant to shortcuts */ 207 + if (ev->type == KeyRelease) 208 + return; 209 + 210 /* 1. shortcuts */ 211 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { 212 if (ksym == bp->keysym && match(bp->mod, e->state)) { 213 -- 214 2.42.0 215