st-copyurl-20190202-3be4cf1.diff (4677B)
1 From f0d27279e47dac9bc413830cc116662dde91837c Mon Sep 17 00:00:00 2001 2 From: Michael Buch <michaelbuch12@gmail.com> 3 Date: Sat, 2 Feb 2019 14:10:31 +0000 4 Subject: [PATCH] Highlight selected urls 5 6 --- 7 config.def.h | 1 + 8 st.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ 9 st.h | 1 + 10 3 files changed, 126 insertions(+) 11 12 diff --git a/config.def.h b/config.def.h 13 index 0e01717..3fb13ec 100644 14 --- a/config.def.h 15 +++ b/config.def.h 16 @@ -178,6 +178,7 @@ static Shortcut shortcuts[] = { 17 { TERMMOD, XK_Y, selpaste, {.i = 0} }, 18 { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 19 { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 20 + { MODKEY, XK_l, copyurl, {.i = 0} }, 21 }; 22 23 /* 24 diff --git a/st.c b/st.c 25 index b8e6077..6970e51 100644 26 --- a/st.c 27 +++ b/st.c 28 @@ -200,6 +200,8 @@ static void tdefutf8(char); 29 static int32_t tdefcolor(int *, int *, int); 30 static void tdeftran(char); 31 static void tstrsequence(uchar); 32 +static void tsetcolor(int, int, int, uint32_t, uint32_t); 33 +static char * findlastany(char *, const char**, size_t); 34 35 static void drawregion(int, int, int, int); 36 37 @@ -2602,3 +2604,125 @@ redraw(void) 38 tfulldirt(); 39 draw(); 40 } 41 + 42 +void 43 +tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg ) 44 +{ 45 + int i = start; 46 + for( ; i < end; ++i ) 47 + { 48 + term.line[row][i].fg = fg; 49 + term.line[row][i].bg = bg; 50 + } 51 +} 52 + 53 +char * 54 +findlastany(char *str, const char** find, size_t len) 55 +{ 56 + char* found = NULL; 57 + int i = 0; 58 + for(found = str + strlen(str) - 1; found >= str; --found) { 59 + for(i = 0; i < len; i++) { 60 + if(strncmp(found, find[i], strlen(find[i])) == 0) { 61 + return found; 62 + } 63 + } 64 + } 65 + 66 + return NULL; 67 +} 68 + 69 +/* 70 +** Select and copy the previous url on screen (do nothing if there's no url). 71 +** 72 +** FIXME: doesn't handle urls that span multiple lines; will need to add support 73 +** for multiline "getsel()" first 74 +*/ 75 +void 76 +copyurl(const Arg *arg) { 77 + /* () and [] can appear in urls, but excluding them here will reduce false 78 + * positives when figuring out where a given url ends. 79 + */ 80 + static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 81 + "abcdefghijklmnopqrstuvwxyz" 82 + "0123456789-._~:/?#@!$&'*+,;=%"; 83 + 84 + static const char* URLSTRINGS[] = {"http://", "https://"}; 85 + 86 + /* remove highlighting from previous selection if any */ 87 + if(sel.ob.x >= 0 && sel.oe.x >= 0) 88 + tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg); 89 + 90 + int i = 0, 91 + row = 0, /* row of current URL */ 92 + col = 0, /* column of current URL start */ 93 + startrow = 0, /* row of last occurrence */ 94 + colend = 0, /* column of last occurrence */ 95 + passes = 0; /* how many rows have been scanned */ 96 + 97 + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ 98 + char *c = NULL, 99 + *match = NULL; 100 + 101 + row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; 102 + LIMIT(row, term.top, term.bot); 103 + startrow = row; 104 + 105 + colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; 106 + LIMIT(colend, 0, term.col); 107 + 108 + /* 109 + ** Scan from (term.bot,term.col) to (0,0) and find 110 + ** next occurrance of a URL 111 + */ 112 + while(passes !=term.bot + 2) { 113 + /* Read in each column of every row until 114 + ** we hit previous occurrence of URL 115 + */ 116 + for (col = 0, i = 0; col < colend; ++col,++i) { 117 + /* assume ascii */ 118 + if (term.line[row][col].u > 127) 119 + continue; 120 + linestr[i] = term.line[row][col].u; 121 + } 122 + linestr[term.col] = '\0'; 123 + 124 + if ((match = findlastany(linestr, URLSTRINGS, 125 + sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0])))) 126 + break; 127 + 128 + if (--row < term.top) 129 + row = term.bot; 130 + 131 + colend = term.col; 132 + passes++; 133 + }; 134 + 135 + if (match) { 136 + /* must happen before trim */ 137 + selclear(); 138 + sel.ob.x = strlen(linestr) - strlen(match); 139 + 140 + /* trim the rest of the line from the url match */ 141 + for (c = match; *c != '\0'; ++c) 142 + if (!strchr(URLCHARS, *c)) { 143 + *c = '\0'; 144 + break; 145 + } 146 + 147 + /* highlight selection by inverting terminal colors */ 148 + tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ), defaultbg, defaultfg); 149 + 150 + /* select and copy */ 151 + sel.mode = 1; 152 + sel.type = SEL_REGULAR; 153 + sel.oe.x = sel.ob.x + strlen(match)-1; 154 + sel.ob.y = sel.oe.y = row; 155 + selnormalize(); 156 + tsetdirt(sel.nb.y, sel.ne.y); 157 + xsetsel(getsel()); 158 + xclipcopy(); 159 + } 160 + 161 + free(linestr); 162 +} 163 diff --git a/st.h b/st.h 164 index 38c61c4..67e7419 100644 165 --- a/st.h 166 +++ b/st.h 167 @@ -84,6 +84,7 @@ void printscreen(const Arg *); 168 void printsel(const Arg *); 169 void sendbreak(const Arg *); 170 void toggleprinter(const Arg *); 171 +void copyurl(const Arg *); 172 173 int tattrset(int); 174 void tnew(int, int); 175 -- 176 2.20.1 177