237 lines
7.5 KiB
D
237 lines
7.5 KiB
D
module patch.openurlonclick;
|
|
|
|
import core.stdc.string : strchr, strncmp;
|
|
import core.sys.posix.unistd : pid_t;
|
|
import std.algorithm : min, max;
|
|
import std.string : toStringz, fromStringz;
|
|
|
|
import patches : isPatchEnabled;
|
|
import st : term, Rune, Line, ATTR_WRAP;
|
|
import st : TLINE;
|
|
|
|
// Define ATTR_SET if not already defined
|
|
enum ATTR_SET = 1 << 15;
|
|
enum MODE_ALTSCREEN = 1 << 2;
|
|
|
|
// Define IS_SET helper
|
|
bool IS_SET(uint flag) {
|
|
import st : win;
|
|
return (win.mode & flag) != 0;
|
|
}
|
|
|
|
static if (isPatchEnabled!"OPENURLONCLICK_PATCH") {
|
|
static if (!isPatchEnabled!"REFLOW_PATCH") {
|
|
static if (isPatchEnabled!"SCROLLBACK_PATCH") {
|
|
alias TLINEURL = TLINE;
|
|
} else {
|
|
auto TLINEURL(int y) { return term.line[y]; }
|
|
}
|
|
}
|
|
|
|
extern(C) export __gshared int url_x1, url_y1, url_x2, url_y2 = -1;
|
|
extern(C) export __gshared int url_draw, url_click, url_maxcol;
|
|
|
|
private int isvalidurlchar(Rune u) {
|
|
static immutable string urlchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ~
|
|
"abcdefghijklmnopqrstuvwxyz" ~
|
|
"0123456789-._~:/?#@!$&'*+,;=%";
|
|
return u < 128 && strchr(urlchars.ptr, cast(int)u) != null;
|
|
}
|
|
|
|
static if (isPatchEnabled!"REFLOW_PATCH") {
|
|
private 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 {
|
|
private int findeowl(int row) {
|
|
static if (isPatchEnabled!"COLUMNS_PATCH") {
|
|
int col = term.maxcol - 1;
|
|
} else {
|
|
int col = term.col - 1;
|
|
}
|
|
|
|
do {
|
|
if (TLINEURL(row)[col].mode & ATTR_WRAP)
|
|
return col;
|
|
} while (TLINEURL(row)[col].u == ' ' && --col >= 0);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void clearurl() {
|
|
while (url_y1 <= url_y2 && url_y1 < term.row)
|
|
term.dirty[url_y1++] = 1;
|
|
url_y2 = -1;
|
|
}
|
|
|
|
static if (isPatchEnabled!"REFLOW_PATCH") {
|
|
char* detecturl(int col, int row, int draw) {
|
|
static char[2048] url;
|
|
Line line;
|
|
int x1, y1, x2, y2;
|
|
int i = url.length/2+1, j = cast(int)(url.length/2);
|
|
int row_start = row, col_start = col;
|
|
int minrow = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr - term.histf;
|
|
int maxrow = IS_SET(MODE_ALTSCREEN) ? term.row - 1 : term.scr + term.row - 1;
|
|
|
|
if (draw)
|
|
clearurl();
|
|
|
|
url_maxcol = 0;
|
|
line = TLINE(row);
|
|
|
|
if (!isvalidurlchar(line[col].u))
|
|
return null;
|
|
|
|
do {
|
|
x1 = col_start;
|
|
y1 = row_start;
|
|
url_maxcol = max(url_maxcol, x1);
|
|
url[--i] = cast(char)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);
|
|
|
|
if (url[i] != 'h')
|
|
return null;
|
|
|
|
line = TLINE(row);
|
|
do {
|
|
x2 = col;
|
|
y2 = row;
|
|
url_maxcol = max(url_maxcol, x2);
|
|
url[j++] = cast(char)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 < url.length-1);
|
|
|
|
url[j] = 0;
|
|
|
|
if (strncmp("https://".ptr, &url[i], 8) && strncmp("http://".ptr, &url[i], 7))
|
|
return null;
|
|
|
|
if (strchr(",.;:?!".ptr, cast(int)(url[j-1])) != null) {
|
|
x2 = max(x2-1, 0);
|
|
url[j-1] = 0;
|
|
}
|
|
|
|
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 {
|
|
char* detecturl(int col, int row, int draw) {
|
|
static char[2048] url;
|
|
int x1, y1, x2, y2, wrapped;
|
|
int row_start = row;
|
|
int col_start = col;
|
|
int i = url.length/2+1, j = cast(int)(url.length/2);
|
|
|
|
static if (isPatchEnabled!"SCROLLBACK_PATCH") {
|
|
int minrow = term.scr - term.histn, maxrow = term.scr + term.row - 1;
|
|
if ((term.mode & (1 << 2)) != 0)
|
|
minrow = 0, maxrow = term.row - 1;
|
|
} else {
|
|
int minrow = 0, maxrow = term.row - 1;
|
|
}
|
|
url_maxcol = 0;
|
|
|
|
if (draw)
|
|
clearurl();
|
|
|
|
if (!isvalidurlchar(TLINEURL(row)[col].u))
|
|
return null;
|
|
|
|
do {
|
|
x1 = col_start;
|
|
y1 = row_start;
|
|
url_maxcol = max(url_maxcol, x1);
|
|
url[--i] = cast(char)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));
|
|
|
|
if (url[i] != 'h')
|
|
return null;
|
|
|
|
do {
|
|
x2 = col;
|
|
y2 = row;
|
|
url_maxcol = max(url_maxcol, x2);
|
|
url[j++] = cast(char)TLINEURL(row)[col].u;
|
|
wrapped = TLINEURL(row)[col].mode & ATTR_WRAP;
|
|
static if (isPatchEnabled!"COLUMNS_PATCH") {
|
|
if (++col >= term.maxcol || wrapped) {
|
|
col = 0;
|
|
if (++row > maxrow || !wrapped)
|
|
break;
|
|
}
|
|
} else {
|
|
if (++col >= term.col || wrapped) {
|
|
col = 0;
|
|
if (++row > maxrow || !wrapped)
|
|
break;
|
|
}
|
|
}
|
|
} while (j < url.length-1 && isvalidurlchar(TLINEURL(row)[col].u));
|
|
|
|
url[j] = 0;
|
|
|
|
if (strncmp("https://".ptr, &url[i], 8) && strncmp("http://".ptr, &url[i], 7))
|
|
return null;
|
|
|
|
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];
|
|
}
|
|
}
|
|
|
|
void openUrlOnClick(int col, int row, char* url_opener) {
|
|
char* url = detecturl(col, row, 1);
|
|
if (url) {
|
|
import core.stdc.stdlib : system;
|
|
import std.format : format;
|
|
import std.process : spawnProcess;
|
|
|
|
// Use spawnProcess instead of posix_spawnp
|
|
string[] args = [cast(string)fromStringz(url_opener), cast(string)fromStringz(url)];
|
|
try {
|
|
spawnProcess(args);
|
|
} catch (Exception e) {
|
|
// Ignore errors
|
|
}
|
|
}
|
|
}
|
|
} |