2024-03-13 09:33:51 +00:00
|
|
|
#if !REFLOW_PATCH
|
2024-03-07 21:35:11 +00:00
|
|
|
#if SCROLLBACK_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
#define TLINEURL(y) TLINE(y)
|
|
|
|
#else
|
|
|
|
#define TLINEURL(y) term.line[y]
|
|
|
|
#endif // SCROLLBACK_PATCH
|
2024-03-13 09:33:51 +00:00
|
|
|
#endif // REFLOW_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
|
|
|
|
int url_x1, url_y1, url_x2, url_y2 = -1;
|
|
|
|
int url_draw, url_click, url_maxcol;
|
|
|
|
|
|
|
|
static int
|
|
|
|
isvalidurlchar(Rune u)
|
|
|
|
{
|
|
|
|
/* () and [] can appear in urls, but excluding them here will reduce false
|
|
|
|
* positives when figuring out where a given url ends. See copyurl patch.
|
|
|
|
*/
|
|
|
|
static char urlchars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"0123456789-._~:/?#@!$&'*+,;=%";
|
|
|
|
return u < 128 && strchr(urlchars, (int)u) != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the end of the wrapped line */
|
2024-03-13 09:33:51 +00:00
|
|
|
#if REFLOW_PATCH
|
|
|
|
static int
|
|
|
|
findeowl(Line line)
|
|
|
|
{
|
|
|
|
int i = term.col - 1;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (line[i].mode & ATTR_WRAP)
|
|
|
|
return i;
|
|
|
|
} while (!(line[i].mode & ATTR_SET) && --i >= 0);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
2022-08-07 14:21:55 +00:00
|
|
|
static int
|
|
|
|
findeowl(int row)
|
|
|
|
{
|
2024-03-07 21:35:11 +00:00
|
|
|
#if COLUMNS_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
int col = term.maxcol - 1;
|
|
|
|
#else
|
|
|
|
int col = term.col - 1;
|
2024-03-07 21:35:11 +00:00
|
|
|
#endif // COLUMNS_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (TLINEURL(row)[col].mode & ATTR_WRAP)
|
|
|
|
return col;
|
|
|
|
} while (TLINEURL(row)[col].u == ' ' && --col >= 0);
|
|
|
|
return -1;
|
|
|
|
}
|
2024-03-13 09:33:51 +00:00
|
|
|
#endif // REFLOW_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
clearurl(void)
|
|
|
|
{
|
2022-08-11 07:13:29 +00:00
|
|
|
while (url_y1 <= url_y2 && url_y1 < term.row)
|
2022-08-07 14:21:55 +00:00
|
|
|
term.dirty[url_y1++] = 1;
|
|
|
|
url_y2 = -1;
|
|
|
|
}
|
|
|
|
|
2024-03-13 09:33:51 +00:00
|
|
|
#if REFLOW_PATCH
|
|
|
|
char *
|
|
|
|
detecturl(int col, int row, int draw)
|
|
|
|
{
|
|
|
|
static char url[2048];
|
|
|
|
Line line;
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
int i = sizeof(url)/2+1, j = sizeof(url)/2;
|
|
|
|
int row_start = row, col_start = col;
|
|
|
|
int minrow = tisaltscr() ? 0 : term.scr - term.histf;
|
|
|
|
int maxrow = tisaltscr() ? term.row - 1 : term.scr + term.row - 1;
|
|
|
|
|
|
|
|
/* clear previously underlined url */
|
|
|
|
if (draw)
|
|
|
|
clearurl();
|
|
|
|
|
|
|
|
url_maxcol = 0;
|
|
|
|
line = TLINE(row);
|
|
|
|
|
|
|
|
if (!isvalidurlchar(line[col].u))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* find the first character of url */
|
|
|
|
do {
|
|
|
|
x1 = col_start, y1 = row_start;
|
|
|
|
url_maxcol = MAX(url_maxcol, x1);
|
|
|
|
url[--i] = line[col_start].u;
|
|
|
|
if (--col_start < 0) {
|
|
|
|
if (--row_start < minrow || (col_start = findeowl(TLINE(row_start))) < 0)
|
|
|
|
break;
|
|
|
|
line = TLINE(row_start);
|
|
|
|
}
|
|
|
|
} while (isvalidurlchar(line[col_start].u) && i > 0);
|
|
|
|
|
|
|
|
/* early detection */
|
|
|
|
if (url[i] != 'h')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* find the last character of url */
|
|
|
|
line = TLINE(row);
|
|
|
|
do {
|
|
|
|
x2 = col, y2 = row;
|
|
|
|
url_maxcol = MAX(url_maxcol, x2);
|
|
|
|
url[j++] = line[col].u;
|
|
|
|
if (line[col++].mode & ATTR_WRAP) {
|
|
|
|
if (++row > maxrow)
|
|
|
|
break;
|
|
|
|
col = 0;
|
|
|
|
line = TLINE(row);
|
|
|
|
}
|
|
|
|
} while (col < term.col && isvalidurlchar(line[col].u) && j < sizeof(url)-1);
|
|
|
|
|
|
|
|
url[j] = 0;
|
|
|
|
|
|
|
|
if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Ignore some trailing characters to improve detection. */
|
|
|
|
/* Alacritty and many other terminals also ignore these. */
|
|
|
|
if (strchr(",.;:?!", (int)(url[j-1])) != NULL) {
|
|
|
|
x2 = MAX(x2-1, 0);
|
|
|
|
url[j-1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* underline url (see xdrawglyphfontspecs() in x.c) */
|
|
|
|
if (draw) {
|
|
|
|
url_x1 = (y1 >= 0) ? x1 : 0;
|
|
|
|
url_x2 = (y2 < term.row) ? x2 : url_maxcol;
|
|
|
|
url_y1 = MAX(y1, 0);
|
|
|
|
url_y2 = MIN(y2, term.row-1);
|
|
|
|
url_draw = 1;
|
|
|
|
for (y1 = url_y1; y1 <= url_y2; y1++)
|
|
|
|
term.dirty[y1] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &url[i];
|
|
|
|
}
|
|
|
|
#else
|
2022-08-07 14:21:55 +00:00
|
|
|
char *
|
|
|
|
detecturl(int col, int row, int draw)
|
|
|
|
{
|
|
|
|
static char url[2048];
|
|
|
|
int x1, y1, x2, y2, wrapped;
|
|
|
|
int row_start = row;
|
|
|
|
int col_start = col;
|
|
|
|
int i = sizeof(url)/2+1, j = sizeof(url)/2;
|
2024-03-13 09:33:51 +00:00
|
|
|
|
2024-03-07 21:35:11 +00:00
|
|
|
#if SCROLLBACK_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
int minrow = term.scr - term.histn, maxrow = term.scr + term.row - 1;
|
|
|
|
/* Fixme: MODE_ALTSCREEN is not defined here, I had to use the magic number 1<<2 */
|
|
|
|
if ((term.mode & (1 << 2)) != 0)
|
|
|
|
minrow = 0, maxrow = term.row - 1;
|
|
|
|
#else
|
|
|
|
int minrow = 0, maxrow = term.row - 1;
|
2024-03-13 09:33:51 +00:00
|
|
|
#endif // SCROLLBACK_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
url_maxcol = 0;
|
|
|
|
|
|
|
|
/* clear previously underlined url */
|
|
|
|
if (draw)
|
|
|
|
clearurl();
|
|
|
|
|
|
|
|
if (!isvalidurlchar(TLINEURL(row)[col].u))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* find the first character of url */
|
|
|
|
do {
|
|
|
|
x1 = col_start, y1 = row_start;
|
|
|
|
url_maxcol = MAX(url_maxcol, x1);
|
|
|
|
url[--i] = TLINEURL(row_start)[col_start].u;
|
|
|
|
if (--col_start < 0) {
|
|
|
|
if (--row_start < minrow || (col_start = findeowl(row_start)) < 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (i > 0 && isvalidurlchar(TLINEURL(row_start)[col_start].u));
|
|
|
|
|
|
|
|
/* early detection */
|
|
|
|
if (url[i] != 'h')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* find the last character of url */
|
|
|
|
do {
|
|
|
|
x2 = col, y2 = row;
|
|
|
|
url_maxcol = MAX(url_maxcol, x2);
|
|
|
|
url[j++] = TLINEURL(row)[col].u;
|
|
|
|
wrapped = TLINEURL(row)[col].mode & ATTR_WRAP;
|
2024-03-07 21:35:11 +00:00
|
|
|
#if COLUMNS_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
if (++col >= term.maxcol || wrapped) {
|
|
|
|
#else
|
|
|
|
if (++col >= term.col || wrapped) {
|
2024-03-07 21:35:11 +00:00
|
|
|
#endif // COLUMNS_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
col = 0;
|
|
|
|
if (++row > maxrow || !wrapped)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (j < sizeof(url)-1 && isvalidurlchar(TLINEURL(row)[col].u));
|
|
|
|
|
|
|
|
url[j] = 0;
|
|
|
|
|
|
|
|
if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* underline url (see xdrawglyphfontspecs() in x.c) */
|
|
|
|
if (draw) {
|
|
|
|
url_x1 = (y1 >= 0) ? x1 : 0;
|
|
|
|
url_x2 = (y2 < term.row) ? x2 : url_maxcol;
|
|
|
|
url_y1 = MAX(y1, 0);
|
|
|
|
url_y2 = MIN(y2, term.row-1);
|
|
|
|
url_draw = 1;
|
|
|
|
for (y1 = url_y1; y1 <= url_y2; y1++)
|
|
|
|
term.dirty[y1] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &url[i];
|
|
|
|
}
|
2024-03-13 09:33:51 +00:00
|
|
|
#endif // REFLOW_PATCH
|
2022-08-07 14:21:55 +00:00
|
|
|
|
2021-07-07 08:08:43 +00:00
|
|
|
void
|
|
|
|
openUrlOnClick(int col, int row, char* url_opener)
|
|
|
|
{
|
2022-08-07 14:21:55 +00:00
|
|
|
char *url = detecturl(col, row, 1);
|
|
|
|
if (url) {
|
2022-08-11 13:04:44 +00:00
|
|
|
extern char **environ;
|
|
|
|
pid_t junk;
|
|
|
|
char *argv[] = { url_opener, url, NULL };
|
|
|
|
posix_spawnp(&junk, argv[0], NULL, NULL, argv, environ);
|
2022-08-07 14:21:55 +00:00
|
|
|
}
|
2021-08-03 14:20:58 +00:00
|
|
|
}
|