sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

st-copyurl-0.9.3.diff (5237B)


      1 From 35ae18e5c351739b2d80acd0d77db7856caf2596 Mon Sep 17 00:00:00 2001
      2 From: Coral Pink <coral.pink@disr.it>
      3 Date: Fri, 26 Dec 2025 00:11:31 +0100
      4 Subject: [PATCH] highlight & loop through urls in both directions
      5 
      6 Based on a previous patch (st-copyurl-20230406-211964d.diff).
      7 This patch fixes two bugs when looping forward:
      8 1. URLs on the same line iterated the same way as when looping backward
      9    (right-to-left). Now it's left-to-right.
     10 2. When an URL in the first row was selected, looping forward didn't
     11    work, it just got stuck there.
     12 
     13 Co-authored-by: Gildasio Junior <gildasiojunior@riseup.net>
     14 ---
     15  config.def.h |   2 +
     16  st.c         | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++
     17  st.h         |   1 +
     18  3 files changed, 130 insertions(+)
     19 
     20 diff --git a/config.def.h b/config.def.h
     21 index 2cd740a..f2d8d77 100644
     22 --- a/config.def.h
     23 +++ b/config.def.h
     24 @@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
     25  	{ TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
     26  	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
     27  	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
     28 +	{ MODKEY,               XK_l,           copyurl,        {.i =  0} },
     29 +	{ MODKEY|ShiftMask,     XK_L,           copyurl,        {.i =  1} }
     30  };
     31  
     32  /*
     33 diff --git a/st.c b/st.c
     34 index 8e57991..10dd9d5 100644
     35 --- a/st.c
     36 +++ b/st.c
     37 @@ -201,6 +201,8 @@ static void tdefutf8(char);
     38  static int32_t tdefcolor(const int *, int *, int);
     39  static void tdeftran(char);
     40  static void tstrsequence(uchar);
     41 +static const char *findlastany(const char *, const char**, size_t);
     42 +static const char *findfirstany(const char *, const char**, size_t);
     43  
     44  static void drawregion(int, int, int, int);
     45  
     46 @@ -2699,3 +2701,128 @@ redraw(void)
     47  	tfulldirt();
     48  	draw();
     49  }
     50 +
     51 +const char *
     52 +findlastany(const char *str, const char**find, size_t len)
     53 +{
     54 +	const char *found = NULL;
     55 +	int i = 0;
     56 +
     57 +	for (found = str + strlen(str) - 1; found >= str; --found) {
     58 +		for(i = 0; i < len; i++) {
     59 +			if (strncmp(found, find[i], strlen(find[i])) == 0) {
     60 +				return found;
     61 +			}
     62 +		}
     63 +	}
     64 +
     65 +	return NULL;
     66 +}
     67 +
     68 +const char *
     69 +findfirstany(const char *str, const char**find, size_t len)
     70 +{
     71 +	const char *found = NULL;
     72 +	int i = 0;
     73 +
     74 +	for (found = str; found < str + strlen(str); ++found) {
     75 +		for(i = 0; i < len; i++) {
     76 +			if (strncmp(found, find[i], strlen(find[i])) == 0) {
     77 +				return found;
     78 +			}
     79 +		}
     80 +	}
     81 +
     82 +	return NULL;
     83 +}
     84 +
     85 +/*
     86 + * Select and copy the previous url on screen (do nothing if there's no url).
     87 + *
     88 + * FIXME: doesn't handle urls that span multiple lines; will need to add support
     89 + *        for multiline "getsel()" first
     90 + */
     91 +void
     92 +copyurl(const Arg *arg) {
     93 +	/*
     94 +	 * () and [] can appear in urls, but excluding them here will reduce false
     95 +	 * positives when figuring out where a given url ends.
     96 +	 */
     97 +	static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     98 +		"abcdefghijklmnopqrstuvwxyz"
     99 +		"0123456789-._~:/?#@!$&'*+,;=%";
    100 +
    101 +	static const char* URLSTRINGS[] = {"http://", "https://"};
    102 +
    103 +	int row = 0, /* row of current URL */
    104 +		col = 0, /* index of current URL start */
    105 +		colend = 0, /* column of last occurrence */
    106 +		passes = 0; /* how many rows have been scanned */
    107 +
    108 +	char linestr[term.col + 1];
    109 +	const char *c = NULL,
    110 +		 *match = NULL;
    111 +
    112 +	/*
    113 +	 * arg->i = 0 --> botton-up
    114 +	 * arg->i = 1 --> top-down
    115 +	 */
    116 +	row = sel.ob.x == -1 ? term.bot : arg->i ? sel.ne.y : sel.nb.y;
    117 +	LIMIT(row, term.top, term.bot);
    118 +
    119 +	colend = sel.ob.x == -1 ? term.col : arg->i ? sel.ne.x : sel.nb.x;
    120 +	LIMIT(colend, 0, term.col);
    121 +
    122 +	/*
    123 +	 * Scan from (term.row - 1,term.col - 1) to (0,0) (or in reverse,
    124 +	 * when arg->i = 1) and find previous/next occurrance of a URL.
    125 +	 */
    126 +	for (passes = 0; passes < term.row; passes++) {
    127 +		if (!arg->i) {
    128 +			/*
    129 +			 * Read in each column of every row until
    130 +			 * we hit previous occurrence of URL.
    131 +			 */
    132 +			for (col = 0; col < colend; ++col)
    133 +				linestr[col] = term.line[row][col].u < 128
    134 +					? term.line[row][col].u : ' ';
    135 +			linestr[col] = '\0';
    136 +
    137 +			if ((match = findlastany(linestr, URLSTRINGS,
    138 +						sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
    139 +				break;
    140 +
    141 +			if (--row < 0)
    142 +				row = term.row - 1;
    143 +
    144 +			colend = term.col;
    145 +		} else {
    146 +			/*
    147 +			 * Read in each column of every row until
    148 +			 * we hit next occurrence of URL.
    149 +			 */
    150 +			for (col = colend + 1; col < term.col; ++col)
    151 +				linestr[col] = term.line[row][col].u < 128
    152 +					? term.line[row][col].u : ' ';
    153 +			linestr[col] = '\0';
    154 +
    155 +			if ((match = findfirstany(linestr + colend + 1, URLSTRINGS,
    156 +						sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
    157 +				break;
    158 +
    159 +			if (++row >= term.row)
    160 +				row = 0;
    161 +
    162 +			colend = -1;
    163 +		}
    164 +	}
    165 +
    166 +	if (match) {
    167 +		size_t l = strspn(match, URLCHARS);
    168 +		selstart(match - linestr, row, 0);
    169 +		selextend(match - linestr + l - 1, row, SEL_REGULAR, 0);
    170 +		selextend(match - linestr + l - 1, row, SEL_REGULAR, 1);
    171 +		xsetsel(getsel());
    172 +		xclipcopy();
    173 +	}
    174 +}
    175 diff --git a/st.h b/st.h
    176 index fd3b0d8..baa8f29 100644
    177 --- a/st.h
    178 +++ b/st.h
    179 @@ -85,6 +85,7 @@ void printscreen(const Arg *);
    180  void printsel(const Arg *);
    181  void sendbreak(const Arg *);
    182  void toggleprinter(const Arg *);
    183 +void copyurl(const Arg *);
    184  
    185  int tattrset(int);
    186  void tnew(int, int);
    187 -- 
    188 2.51.2
    189