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