Merge pull request #76 from veltza/add-scrollback-support-to-openurlonclick
Add scrollback support to the openurlonclick patch
This commit is contained in:
commit
b12cd70e8b
|
@ -33,6 +33,8 @@ static int borderpx = 2;
|
|||
#endif // RELATIVEBORDER_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
/* modkey options: ControlMask, ShiftMask or XK_ANY_MOD */
|
||||
static uint url_opener_modkey = XK_ANY_MOD;
|
||||
static char *url_opener = "xdg-open";
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
|
||||
|
@ -752,4 +754,4 @@ static char *plumb_cmd = "plumb";
|
|||
#define UNDERCURL_CAPPED 2
|
||||
// Active style
|
||||
#define UNDERCURL_STYLE UNDERCURL_SPIKY
|
||||
#endif // UNDERCURL_PATCH
|
||||
#endif // UNDERCURL_PATCH
|
||||
|
|
|
@ -1,59 +1,140 @@
|
|||
#if SCROLLBACK_PATCH && !VIM_BROWSE_PATCH
|
||||
#define TLINEURL(y) TLINE(y)
|
||||
#else
|
||||
#define TLINEURL(y) term.line[y]
|
||||
#endif // SCROLLBACK_PATCH
|
||||
|
||||
#if VIM_BROWSE_PATCH
|
||||
extern int buffCols;
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
|
||||
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 */
|
||||
static int
|
||||
findeowl(int row)
|
||||
{
|
||||
#if VIM_BROWSE_PATCH
|
||||
int col = buffCols - 1;
|
||||
#elif COLUMNS_PATCH
|
||||
int col = term.maxcol - 1;
|
||||
#else
|
||||
int col = term.col - 1;
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
|
||||
do {
|
||||
if (TLINEURL(row)[col].mode & ATTR_WRAP)
|
||||
return col;
|
||||
} while (TLINEURL(row)[col].u == ' ' && --col >= 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
clearurl(void)
|
||||
{
|
||||
while (url_y1 <= url_y2)
|
||||
term.dirty[url_y1++] = 1;
|
||||
url_y2 = -1;
|
||||
}
|
||||
|
||||
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;
|
||||
#if SCROLLBACK_PATCH && !VIM_BROWSE_PATCH
|
||||
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;
|
||||
#endif // scrollback_patch
|
||||
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;
|
||||
#if VIM_BROWSE_PATCH
|
||||
if (++col >= buffCols || wrapped) {
|
||||
#elif COLUMNS_PATCH
|
||||
if (++col >= term.maxcol || wrapped) {
|
||||
#else
|
||||
if (++col >= term.col || wrapped) {
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
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];
|
||||
}
|
||||
|
||||
void
|
||||
openUrlOnClick(int col, int row, char* url_opener)
|
||||
{
|
||||
int row_start = row;
|
||||
int col_start = col;
|
||||
int row_end = row;
|
||||
int col_end = col;
|
||||
|
||||
if (term.line[row][col].u == ' ')
|
||||
return;
|
||||
|
||||
/* while previous character is not space */
|
||||
while (term.line[row_start][col_start-1].u != ' ') {
|
||||
if (col_start == 0)
|
||||
{
|
||||
// Before moving start pointer to the previous line we check if it ends with space
|
||||
if (term.line[row_start - 1][term.col - 1].u == ' ')
|
||||
break;
|
||||
col_start=term.col - 1;
|
||||
row_start--;
|
||||
} else {
|
||||
col_start--;
|
||||
}
|
||||
}
|
||||
|
||||
/* while next character is not space nor end of line */
|
||||
while (term.line[row_end][col_end].u != ' ') {
|
||||
col_end++;
|
||||
if (col_end == term.col - 1)
|
||||
{
|
||||
if (term.line[row_end + 1][0].u == ' ')
|
||||
break;
|
||||
col_end=0;
|
||||
row_end++;
|
||||
}
|
||||
}
|
||||
|
||||
char url[200] = "";
|
||||
int url_index=0;
|
||||
do {
|
||||
url[url_index] = term.line[row_start][col_start].u;
|
||||
url_index++;
|
||||
col_start++;
|
||||
if (col_start == term.col)
|
||||
{
|
||||
col_start = 0;
|
||||
row_start++;
|
||||
}
|
||||
} while (url_index < (sizeof(url)-1) &&
|
||||
(row_start != row_end || col_start != col_end));
|
||||
|
||||
if (strncmp("http", url, 4) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char command[strlen(url_opener)+strlen(url)+2];
|
||||
sprintf(command, "%s %s", url_opener, url);
|
||||
system(command);
|
||||
char *url = detecturl(col, row, 1);
|
||||
if (url) {
|
||||
char command[strlen(url_opener) + strlen(url) + 5];
|
||||
sprintf(command, "%s \"%s\"&", url_opener, url);
|
||||
system(command);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
static void openUrlOnClick(int col, int row, char* url_opener);
|
||||
static inline void restoremousecursor(void) {
|
||||
if (!(win.mode & MODE_MOUSE) && xw.pointerisvisible)
|
||||
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
|
||||
}
|
||||
static void clearurl(void);
|
||||
static void openUrlOnClick(int col, int row, char* url_opener);
|
||||
|
|
|
@ -18,6 +18,11 @@ kscrolldown(const Arg* a)
|
|||
#if SIXEL_PATCH
|
||||
scroll_images(-1*n);
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
if (n > 0)
|
||||
restoremousecursor();
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -42,4 +47,9 @@ kscrollup(const Arg* a)
|
|||
#if SIXEL_PATCH
|
||||
scroll_images(n);
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
if (n > 0)
|
||||
restoremousecursor();
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#if KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_st.h"
|
||||
#endif
|
||||
#if OPENURLONCLICK_PATCH
|
||||
#include "openurlonclick.h"
|
||||
#endif
|
||||
#if RIGHTCLICKTOPLUMB_PATCH
|
||||
#include "rightclicktoplumb_st.h"
|
||||
#endif
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
#if NETWMICON_PATCH
|
||||
#include "netwmicon.h"
|
||||
#endif
|
||||
#if OPENURLONCLICK_PATCH
|
||||
#include "openurlonclick.h"
|
||||
#endif
|
||||
#if RIGHTCLICKTOPLUMB_PATCH
|
||||
#include "rightclicktoplumb_x.h"
|
||||
#endif
|
||||
|
@ -34,4 +31,4 @@
|
|||
#endif
|
||||
#if VIM_BROWSE_PATCH
|
||||
#include "normalMode.h"
|
||||
#endif
|
||||
#endif
|
||||
|
|
8
st.c
8
st.c
|
@ -1387,6 +1387,10 @@ tswapscreen(void)
|
|||
void
|
||||
tscrolldown(int orig, int n)
|
||||
{
|
||||
#if OPENURLONCLICK_PATCH
|
||||
restoremousecursor();
|
||||
#endif //OPENURLONCLICK_PATCH
|
||||
|
||||
#if VIM_BROWSE_PATCH
|
||||
if (!orig && historyBufferScroll(-n))
|
||||
return;
|
||||
|
@ -1435,6 +1439,10 @@ tscrollup(int orig, int n, int copyhist)
|
|||
tscrollup(int orig, int n)
|
||||
#endif // SCROLLBACK_PATCH
|
||||
{
|
||||
#if OPENURLONCLICK_PATCH
|
||||
restoremousecursor();
|
||||
#endif //OPENURLONCLICK_PATCH
|
||||
|
||||
#if VIM_BROWSE_PATCH
|
||||
if (!orig && historyBufferScroll(n))
|
||||
return;
|
||||
|
|
5
st.h
5
st.h
|
@ -219,13 +219,16 @@ typedef struct {
|
|||
#endif // BACKGROUND_IMAGE_PATCH
|
||||
Visual *vis;
|
||||
XSetWindowAttributes attrs;
|
||||
#if HIDECURSOR_PATCH
|
||||
#if HIDECURSOR_PATCH || OPENURLONCLICK_PATCH
|
||||
/* Here, we use the term *pointer* to differentiate the cursor
|
||||
* one sees when hovering the mouse over the terminal from, e.g.,
|
||||
* a green rectangle where text would be entered. */
|
||||
Cursor vpointer, bpointer; /* visible and hidden pointers */
|
||||
int pointerisvisible;
|
||||
#endif // HIDECURSOR_PATCH
|
||||
#if OPENURLONCLICK_PATCH
|
||||
Cursor upointer;
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
int scr;
|
||||
int isfixed; /* is fixed geometry? */
|
||||
#if ALPHA_PATCH
|
||||
|
|
87
x.c
87
x.c
|
@ -536,6 +536,11 @@ bpress(XEvent *e)
|
|||
#if !VIM_BROWSE_PATCH
|
||||
selstart(evcol(e), evrow(e), snap);
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
clearurl();
|
||||
url_click = 1;
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,14 +791,16 @@ brelease(XEvent *e)
|
|||
if (btn == Button1 && !IS_SET(MODE_NORMAL)) {
|
||||
mousesel(e, 1);
|
||||
#if OPENURLONCLICK_PATCH
|
||||
openUrlOnClick(evcol(e), evrow(e), url_opener);
|
||||
if (url_click && e->xkey.state & url_opener_modkey)
|
||||
openUrlOnClick(evcol(e), evrow(e), url_opener);
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
#else
|
||||
if (btn == Button1) {
|
||||
mousesel(e, 1);
|
||||
#if OPENURLONCLICK_PATCH
|
||||
openUrlOnClick(evcol(e), evrow(e), url_opener);
|
||||
if (url_click && e->xkey.state & url_opener_modkey)
|
||||
openUrlOnClick(evcol(e), evrow(e), url_opener);
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
|
@ -821,6 +828,18 @@ bmotion(XEvent *e)
|
|||
xsetpointermotion(0);
|
||||
}
|
||||
#endif // HIDECURSOR_PATCH
|
||||
#if OPENURLONCLICK_PATCH
|
||||
#if VIM_BROWSE_PATCH
|
||||
if (!IS_SET(MODE_NORMAL))
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
if (!IS_SET(MODE_MOUSE)) {
|
||||
if (!(e->xbutton.state & Button1Mask) && detecturl(evcol(e), evrow(e), 1))
|
||||
XDefineCursor(xw.dpy, xw.win, xw.upointer);
|
||||
else
|
||||
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
|
||||
}
|
||||
url_click = 0;
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
|
||||
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
|
||||
mousereport(e);
|
||||
|
@ -911,6 +930,10 @@ xloadcolor(int i, const char *name, Color *ncolor)
|
|||
#if VIM_BROWSE_PATCH
|
||||
void normalMode()
|
||||
{
|
||||
#if OPENURLONCLICK_PATCH
|
||||
clearurl();
|
||||
restoremousecursor();
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
historyModeToggle((win.mode ^=MODE_NORMAL) & MODE_NORMAL);
|
||||
}
|
||||
#endif // VIM_BROWSE_PATCH
|
||||
|
@ -1443,6 +1466,9 @@ xinit(int cols, int rows)
|
|||
#endif // ST_EMBEDDER_PATCH
|
||||
;
|
||||
xw.attrs.colormap = xw.cmap;
|
||||
#if OPENURLONCLICK_PATCH
|
||||
xw.attrs.event_mask |= PointerMotionMask;
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
|
||||
#if !ALPHA_PATCH
|
||||
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
|
||||
|
@ -1534,6 +1560,14 @@ xinit(int cols, int rows)
|
|||
XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
|
||||
#endif // HIDECURSOR_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
xw.upointer = XCreateFontCursor(xw.dpy, XC_hand2);
|
||||
#if !HIDECURSOR_PATCH
|
||||
xw.vpointer = cursor;
|
||||
xw.pointerisvisible = 1;
|
||||
#endif // HIDECURSOR_PATCH
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
|
||||
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
|
||||
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
|
||||
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
|
||||
|
@ -2365,6 +2399,28 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||
}
|
||||
#endif // WIDE_GLYPHS_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
if (url_draw && y >= url_y1 && y <= url_y2) {
|
||||
int x1 = (y == url_y1) ? url_x1 : 0;
|
||||
int x2 = (y == url_y2) ? MIN(url_x2, term.col-1) : url_maxcol;
|
||||
if (x + charlen > x1 && x <= x2) {
|
||||
int xu = MAX(x, x1);
|
||||
int wu = (x2 - xu + 1) * win.cw;
|
||||
#if ANYSIZE_PATCH
|
||||
xu = win.hborderpx + xu * win.cw;
|
||||
#else
|
||||
xu = borderpx + xu * win.cw;
|
||||
#endif // ANYSIZE_PATCH
|
||||
#if VERTCENTER_PATCH
|
||||
XftDrawRect(xw.draw, fg, xu, winy + win.cyo + dc.font.ascent * chscale + 2, wu, 1);
|
||||
#else
|
||||
XftDrawRect(xw.draw, fg, xu, winy + dc.font.ascent * chscale + 2, wu, 1);
|
||||
#endif // VERTCENTER_PATCH
|
||||
url_draw = (y != url_y2 || x + charlen <= x2);
|
||||
}
|
||||
}
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
|
||||
#if !WIDE_GLYPHS_PATCH
|
||||
/* Reset clip to none. */
|
||||
XftDrawSetClip(xw.draw, 0);
|
||||
|
@ -2865,6 +2921,9 @@ xsetpointermotion(int set)
|
|||
if (!set && !xw.pointerisvisible)
|
||||
return;
|
||||
#endif // HIDECURSOR_PATCH
|
||||
#if OPENURLONCLICK_PATCH
|
||||
set = 1; /* keep MotionNotify event enabled */
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
|
||||
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
|
||||
}
|
||||
|
@ -2883,8 +2942,15 @@ xsetmode(int set, unsigned int flags)
|
|||
if (win.mode & MODE_MOUSE)
|
||||
XUndefineCursor(xw.dpy, xw.win);
|
||||
else
|
||||
#if HIDECURSOR_PATCH
|
||||
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
|
||||
#else
|
||||
XDefineCursor(xw.dpy, xw.win, cursor);
|
||||
#endif // HIDECURSOR_PATCH
|
||||
}
|
||||
#elif OPENURLONCLICK_PATCH
|
||||
if (win.mode & MODE_MOUSE && xw.pointerisvisible)
|
||||
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
|
||||
#endif // SWAPMOUSE_PATCH
|
||||
if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
|
||||
redraw();
|
||||
|
@ -3042,9 +3108,26 @@ kpress(XEvent *ev)
|
|||
|
||||
#if HIDECURSOR_PATCH
|
||||
if (xw.pointerisvisible) {
|
||||
#if OPENURLONCLICK_PATCH
|
||||
#if ANYSIZE_PATCH
|
||||
int x = e->x - win.hborderpx;
|
||||
int y = e->y - win.vborderpx;
|
||||
#else
|
||||
int x = e->x - borderpx;
|
||||
int y = e->y - borderpx;
|
||||
#endif // ANYSIZE_PATCH
|
||||
LIMIT(x, 0, win.tw - 1);
|
||||
LIMIT(y, 0, win.th - 1);
|
||||
if (!detecturl(x / win.cw, y / win.ch, 0)) {
|
||||
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
|
||||
xsetpointermotion(1);
|
||||
xw.pointerisvisible = 0;
|
||||
}
|
||||
#else
|
||||
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
|
||||
xsetpointermotion(1);
|
||||
xw.pointerisvisible = 0;
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
#endif // HIDECURSOR_PATCH
|
||||
|
||||
|
|
Loading…
Reference in New Issue