# st

Unnamed repository; edit this file 'description' to name the repository.

| Log | Files | Refs | README | LICENSE

    commit 22705a886e0f6833ee8dd6c667f7951fc663584d
    parent 47352b9a9223bc73ef43f3ba436f681a0e965bde
    Author: c0dev0id <sh+github@codevoid.de>
    Date:   Sat, 31 Jul 2021 19:26:45 +0200

    sdk-copyurl-w3m

    Diffstat:
    Mconfig.def.h | 1+
    Mconfig.h | 1+
    Mst.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Mst.h | 1+
    Mx.c | 2++

    5 files changed, 126 insertions(+), 0 deletions(-)
    diff --git a/config.def.h b/config.def.h
    @@ -213,6 +213,7 @@ static Shortcut shortcuts[] = {
     	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
     	{ ShiftMask,            XK_Page_Up,     kscrollup,      {.i = -1} },
     	{ ShiftMask,            XK_Page_Down,   kscrolldown,    {.i = -1} },
    +	{ ShiftMask,            XK_l,           copyurl,        {.i =  0} },
     };

     /*
    diff --git a/config.h b/config.h
    @@ -213,6 +213,7 @@ static Shortcut shortcuts[] = {
     	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
     	{ ShiftMask,            XK_Page_Up,     kscrollup,      {.i = -1} },
     	{ ShiftMask,            XK_Page_Down,   kscrolldown,    {.i = -1} },
    +	{ ShiftMask,            XK_l,           copyurl,        {.i =  0} },
     };

     /*
    diff --git a/st.c b/st.c
    @@ -207,6 +207,8 @@ static void tdefutf8(char);
     static int32_t tdefcolor(const int *, int *, int);
     static void tdeftran(char);
     static void tstrsequence(uchar);
    +static void tsetcolor(int, int, int, uint32_t, uint32_t);
    +static char * findlastany(char *, const char**, size_t);

     static void drawregion(int, int, int, int);

    @@ -2680,3 +2682,122 @@ redraw(void)
     	tfulldirt();
     	draw();
     }
    +
    +void
    +tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg )
    +{
    +	int i = start;
    +	for( ; i < end; ++i )
    +	{
    +		term.line[row][i].fg = fg;
    +		term.line[row][i].bg = bg;
    +	}
    +}
    +
    +char *
    +findlastany(char *str, const char** find, size_t len)
    +{
    +	char* found = NULL;
    +	int i = 0;
    +	for(found = str + strlen(str) - 1; found >= str; --found) {
    +		for(i = 0; i < len; i++) {
    +			if(strncmp(found, find[i], strlen(find[i])) == 0) {
    +				return found;
    +			}
    +		}
    +	}
    +
    +	return NULL;
    +}
    +
    +/*
    +** Select and copy the previous url on screen (do nothing if there's no url).
    +**
    +** FIXME: doesn't handle urls that span multiple lines; will need to add support
    +**        for multiline "getsel()" first
    +*/
    +void
    +copyurl(const Arg *arg) {
    +	/* () and [] can appear in urls, but excluding them here will reduce false
    +	 * positives when figuring out where a given url ends.
    +	 */
    +	static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    +		"abcdefghijklmnopqrstuvwxyz"
    +		"0123456789-._~:/?#@!$&'*+,;=%";
    +
    +	static const char* URLSTRINGS[] = {"http://", "https://"};
    +
    +	/* remove highlighting from previous selection if any */
    +	if(sel.ob.x >= 0 && sel.oe.x >= 0)
    +		tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg);
    +
    +	int i = 0,
    +		row = 0, /* row of current URL */
    +		col = 0, /* column of current URL start */
    +		startrow = 0, /* row of last occurrence */
    +		colend = 0, /* column of last occurrence */
    +		passes = 0; /* how many rows have been scanned */
    +
    +	char *linestr = calloc(term.col+1, sizeof(Rune));
    +	char *c = NULL,
    +		 *match = NULL;
    +
    +	row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
    +	LIMIT(row, term.top, term.bot);
    +	startrow = row;
    +
    +	colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
    +	LIMIT(colend, 0, term.col);
    +
    +	/*
    + 	** Scan from (term.bot,term.col) to (0,0) and find
    +	** next occurrance of a URL
    +	*/
    +	while(passes !=term.bot + 2) {
    +		/* Read in each column of every row until
    + 		** we hit previous occurrence of URL
    +		*/
    +		for (col = 0, i = 0; col < colend; ++col,++i) {
    +			linestr[i] = term.line[row][col].u;
    +		}
    +		linestr[term.col] = '\0';
    +
    +		if ((match = findlastany(linestr, URLSTRINGS,
    +						sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
    +			break;
    +
    +		if (--row < term.top)
    +			row = term.bot;
    +
    +		colend = term.col;
    +		passes++;
    +	};
    +
    +	if (match) {
    +		/* must happen before trim */
    +		selclear();
    +		sel.ob.x = strlen(linestr) - strlen(match);
    +
    +		/* trim the rest of the line from the url match */
    +		for (c = match; *c != '\0'; ++c)
    +			if (!strchr(URLCHARS, *c)) {
    +				*c = '\0';
    +				break;
    +			}
    +
    +		/* highlight selection by inverting terminal colors */
    +		tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ), defaultbg, defaultfg);
    +
    +		/* select and copy */
    +		sel.mode = 1;
    +		sel.type = SEL_REGULAR;
    +		sel.oe.x = sel.ob.x + strlen(match)-1;
    +		sel.ob.y = sel.oe.y = row;
    +		selnormalize();
    +		tsetdirt(sel.nb.y, sel.ne.y);
    +		xsetsel(getsel());
    +		xclipcopy();
    +	}
    +
    +	free(linestr);
    +}
    diff --git a/st.h b/st.h
    @@ -88,6 +88,7 @@ void printscreen(const Arg *);
     void printsel(const Arg *);
     void sendbreak(const Arg *);
     void toggleprinter(const Arg *);
    +void copyurl(const Arg *);

     int tattrset(int);
     void tnew(int, int);
    diff --git a/x.c b/x.c
    @@ -1624,6 +1624,8 @@ xsettitle(char *p)
     int
     xstartdraw(void)
     {
    +	if (IS_SET(MODE_VISIBLE))
    +		XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
     	return IS_SET(MODE_VISIBLE);
     }