openurlonclick.c (5295B)
1 #if !REFLOW_PATCH 2 #if SCROLLBACK_PATCH 3 #define TLINEURL(y) TLINE(y) 4 #else 5 #define TLINEURL(y) term.line[y] 6 #endif // SCROLLBACK_PATCH 7 #endif // REFLOW_PATCH 8 9 int url_x1, url_y1, url_x2, url_y2 = -1; 10 int url_draw, url_click, url_maxcol; 11 12 static int 13 isvalidurlchar(Rune u) 14 { 15 /* () and [] can appear in urls, but excluding them here will reduce false 16 * positives when figuring out where a given url ends. See copyurl patch. 17 */ 18 static char urlchars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 19 "abcdefghijklmnopqrstuvwxyz" 20 "0123456789-._~:/?#@!$&'*+,;=%"; 21 return u < 128 && strchr(urlchars, (int)u) != NULL; 22 } 23 24 /* find the end of the wrapped line */ 25 #if REFLOW_PATCH 26 static int 27 findeowl(Line line) 28 { 29 int i = term.col - 1; 30 31 do { 32 if (line[i].mode & ATTR_WRAP) 33 return i; 34 } while (!(line[i].mode & ATTR_SET) && --i >= 0); 35 36 return -1; 37 } 38 #else 39 static int 40 findeowl(int row) 41 { 42 #if COLUMNS_PATCH 43 int col = term.maxcol - 1; 44 #else 45 int col = term.col - 1; 46 #endif // COLUMNS_PATCH 47 48 do { 49 if (TLINEURL(row)[col].mode & ATTR_WRAP) 50 return col; 51 } while (TLINEURL(row)[col].u == ' ' && --col >= 0); 52 return -1; 53 } 54 #endif // REFLOW_PATCH 55 56 void 57 clearurl(void) 58 { 59 while (url_y1 <= url_y2 && url_y1 < term.row) 60 term.dirty[url_y1++] = 1; 61 url_y2 = -1; 62 } 63 64 #if REFLOW_PATCH 65 char * 66 detecturl(int col, int row, int draw) 67 { 68 static char url[2048]; 69 Line line; 70 int x1, y1, x2, y2; 71 int i = sizeof(url)/2+1, j = sizeof(url)/2; 72 int row_start = row, col_start = col; 73 int minrow = tisaltscr() ? 0 : term.scr - term.histf; 74 int maxrow = tisaltscr() ? term.row - 1 : term.scr + term.row - 1; 75 76 /* clear previously underlined url */ 77 if (draw) 78 clearurl(); 79 80 url_maxcol = 0; 81 line = TLINE(row); 82 83 if (!isvalidurlchar(line[col].u)) 84 return NULL; 85 86 /* find the first character of url */ 87 do { 88 x1 = col_start, y1 = row_start; 89 url_maxcol = MAX(url_maxcol, x1); 90 url[--i] = line[col_start].u; 91 if (--col_start < 0) { 92 if (--row_start < minrow || (col_start = findeowl(TLINE(row_start))) < 0) 93 break; 94 line = TLINE(row_start); 95 } 96 } while (isvalidurlchar(line[col_start].u) && i > 0); 97 98 /* early detection */ 99 if (url[i] != 'h') 100 return NULL; 101 102 /* find the last character of url */ 103 line = TLINE(row); 104 do { 105 x2 = col, y2 = row; 106 url_maxcol = MAX(url_maxcol, x2); 107 url[j++] = line[col].u; 108 if (line[col++].mode & ATTR_WRAP) { 109 if (++row > maxrow) 110 break; 111 col = 0; 112 line = TLINE(row); 113 } 114 } while (col < term.col && isvalidurlchar(line[col].u) && j < sizeof(url)-1); 115 116 url[j] = 0; 117 118 if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7)) 119 return NULL; 120 121 /* Ignore some trailing characters to improve detection. */ 122 /* Alacritty and many other terminals also ignore these. */ 123 if (strchr(",.;:?!", (int)(url[j-1])) != NULL) { 124 x2 = MAX(x2-1, 0); 125 url[j-1] = 0; 126 } 127 128 /* underline url (see xdrawglyphfontspecs() in x.c) */ 129 if (draw) { 130 url_x1 = (y1 >= 0) ? x1 : 0; 131 url_x2 = (y2 < term.row) ? x2 : url_maxcol; 132 url_y1 = MAX(y1, 0); 133 url_y2 = MIN(y2, term.row-1); 134 url_draw = 1; 135 for (y1 = url_y1; y1 <= url_y2; y1++) 136 term.dirty[y1] = 1; 137 } 138 139 return &url[i]; 140 } 141 #else 142 char * 143 detecturl(int col, int row, int draw) 144 { 145 static char url[2048]; 146 int x1, y1, x2, y2, wrapped; 147 int row_start = row; 148 int col_start = col; 149 int i = sizeof(url)/2+1, j = sizeof(url)/2; 150 151 #if SCROLLBACK_PATCH 152 int minrow = term.scr - term.histn, maxrow = term.scr + term.row - 1; 153 /* Fixme: MODE_ALTSCREEN is not defined here, I had to use the magic number 1<<2 */ 154 if ((term.mode & (1 << 2)) != 0) 155 minrow = 0, maxrow = term.row - 1; 156 #else 157 int minrow = 0, maxrow = term.row - 1; 158 #endif // SCROLLBACK_PATCH 159 url_maxcol = 0; 160 161 /* clear previously underlined url */ 162 if (draw) 163 clearurl(); 164 165 if (!isvalidurlchar(TLINEURL(row)[col].u)) 166 return NULL; 167 168 /* find the first character of url */ 169 do { 170 x1 = col_start, y1 = row_start; 171 url_maxcol = MAX(url_maxcol, x1); 172 url[--i] = TLINEURL(row_start)[col_start].u; 173 if (--col_start < 0) { 174 if (--row_start < minrow || (col_start = findeowl(row_start)) < 0) 175 break; 176 } 177 } while (i > 0 && isvalidurlchar(TLINEURL(row_start)[col_start].u)); 178 179 /* early detection */ 180 if (url[i] != 'h') 181 return NULL; 182 183 /* find the last character of url */ 184 do { 185 x2 = col, y2 = row; 186 url_maxcol = MAX(url_maxcol, x2); 187 url[j++] = TLINEURL(row)[col].u; 188 wrapped = TLINEURL(row)[col].mode & ATTR_WRAP; 189 #if COLUMNS_PATCH 190 if (++col >= term.maxcol || wrapped) { 191 #else 192 if (++col >= term.col || wrapped) { 193 #endif // COLUMNS_PATCH 194 col = 0; 195 if (++row > maxrow || !wrapped) 196 break; 197 } 198 } while (j < sizeof(url)-1 && isvalidurlchar(TLINEURL(row)[col].u)); 199 200 url[j] = 0; 201 202 if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7)) 203 return NULL; 204 205 /* underline url (see xdrawglyphfontspecs() in x.c) */ 206 if (draw) { 207 url_x1 = (y1 >= 0) ? x1 : 0; 208 url_x2 = (y2 < term.row) ? x2 : url_maxcol; 209 url_y1 = MAX(y1, 0); 210 url_y2 = MIN(y2, term.row-1); 211 url_draw = 1; 212 for (y1 = url_y1; y1 <= url_y2; y1++) 213 term.dirty[y1] = 1; 214 } 215 216 return &url[i]; 217 } 218 #endif // REFLOW_PATCH 219 220 void 221 openUrlOnClick(int col, int row, char* url_opener) 222 { 223 char *url = detecturl(col, row, 1); 224 if (url) { 225 extern char **environ; 226 pid_t junk; 227 char *argv[] = { url_opener, url, NULL }; 228 posix_spawnp(&junk, argv[0], NULL, NULL, argv, environ); 229 } 230 }