| st-copyurl-multiline-20220221-0.8.5.diff - sites - public wiki contents of suck… | |
| git clone git://git.suckless.org/sites | |
| Log | |
| Files | |
| Refs | |
| --- | |
| st-copyurl-multiline-20220221-0.8.5.diff (4012B) | |
| --- | |
| 1 From 30a04d9ecb3998953bdbe42e5617d00d6002869b Mon Sep 17 00:00:00 2001 | |
| 2 From: Santtu Lakkala <[email protected]> | |
| 3 Date: Wed, 16 Feb 2022 20:34:20 +0200 | |
| 4 Subject: [PATCH] Loop through urls on screen and copy to clipboard | |
| 5 | |
| 6 Replace url detection heuristics with a DFA, enabling urls that span | |
| 7 multiple lines. Also fix the selection not to use snapping so that urls | |
| 8 are selected exactly. | |
| 9 --- | |
| 10 config.def.h | 1 + | |
| 11 st.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 12 st.h | 1 + | |
| 13 3 files changed, 95 insertions(+) | |
| 14 | |
| 15 diff --git a/config.def.h b/config.def.h | |
| 16 index 91ab8ca..3f365c7 100644 | |
| 17 --- a/config.def.h | |
| 18 +++ b/config.def.h | |
| 19 @@ -201,6 +201,7 @@ static Shortcut shortcuts[] = { | |
| 20 { TERMMOD, XK_Y, selpaste, {.i = … | |
| 21 { ShiftMask, XK_Insert, selpaste, {.i = … | |
| 22 { TERMMOD, XK_Num_Lock, numlock, {.i = … | |
| 23 + { MODKEY, XK_l, copyurl, {.i = … | |
| 24 }; | |
| 25 | |
| 26 /* | |
| 27 diff --git a/st.c b/st.c | |
| 28 index 51049ba..5b6d919 100644 | |
| 29 --- a/st.c | |
| 30 +++ b/st.c | |
| 31 @@ -152,6 +152,11 @@ typedef struct { | |
| 32 int narg; /* nb of args */ | |
| 33 } STREscape; | |
| 34 | |
| 35 +typedef struct { | |
| 36 + int state; | |
| 37 + size_t length; | |
| 38 +} URLdfa; | |
| 39 + | |
| 40 static void execsh(char *, char **); | |
| 41 static void stty(char **); | |
| 42 static void sigchld(int); | |
| 43 @@ -200,6 +205,7 @@ static void tdefutf8(char); | |
| 44 static int32_t tdefcolor(const int *, int *, int); | |
| 45 static void tdeftran(char); | |
| 46 static void tstrsequence(uchar); | |
| 47 +static int daddch(URLdfa *, char); | |
| 48 | |
| 49 static void drawregion(int, int, int, int); | |
| 50 | |
| 51 @@ -2688,3 +2694,90 @@ redraw(void) | |
| 52 tfulldirt(); | |
| 53 draw(); | |
| 54 } | |
| 55 + | |
| 56 +int | |
| 57 +daddch(URLdfa *dfa, char c) | |
| 58 +{ | |
| 59 + /* () and [] can appear in urls, but excluding them here will r… | |
| 60 + * positives when figuring out where a given url ends. | |
| 61 + */ | |
| 62 + static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| 63 + "abcdefghijklmnopqrstuvwxyz" | |
| 64 + "0123456789-._~:/?#@!$&'*+,;=%"; | |
| 65 + static const char RPFX[] = "//:sptth"; | |
| 66 + | |
| 67 + if (!strchr(URLCHARS, c)) { | |
| 68 + dfa->length = 0; | |
| 69 + dfa->state = 0; | |
| 70 + | |
| 71 + return 0; | |
| 72 + } | |
| 73 + | |
| 74 + dfa->length++; | |
| 75 + | |
| 76 + if (dfa->state == 2 && c == '/') { | |
| 77 + dfa->state = 0; | |
| 78 + } else if (dfa->state == 3 && c == 'p') { | |
| 79 + dfa->state++; | |
| 80 + } else if (c != RPFX[dfa->state]) { | |
| 81 + dfa->state = 0; | |
| 82 + return 0; | |
| 83 + } | |
| 84 + | |
| 85 + if (dfa->state++ == 7) { | |
| 86 + dfa->state = 0; | |
| 87 + return 1; | |
| 88 + } | |
| 89 + | |
| 90 + return 0; | |
| 91 +} | |
| 92 + | |
| 93 +/* | |
| 94 +** Select and copy the previous url on screen (do nothing if there's no… | |
| 95 +*/ | |
| 96 +void | |
| 97 +copyurl(const Arg *arg) { | |
| 98 + int row = 0, /* row of current URL */ | |
| 99 + col = 0, /* column of current URL start */ | |
| 100 + colend = 0, /* column of last occurrence */ | |
| 101 + passes = 0; /* how many rows have been scanned */ | |
| 102 + | |
| 103 + const char *c = NULL, | |
| 104 + *match = NULL; | |
| 105 + URLdfa dfa = { 0 }; | |
| 106 + | |
| 107 + row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; | |
| 108 + LIMIT(row, term.top, term.bot); | |
| 109 + | |
| 110 + colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; | |
| 111 + LIMIT(colend, 0, term.col); | |
| 112 + | |
| 113 + /* | |
| 114 + ** Scan from (term.row - 1,term.col - 1) to (0,0) and find | |
| 115 + ** next occurrance of a URL | |
| 116 + */ | |
| 117 + for (passes = 0; passes < term.row; passes++) { | |
| 118 + /* Read in each column of every row until | |
| 119 + ** we hit previous occurrence of URL | |
| 120 + */ | |
| 121 + for (col = colend; col--;) | |
| 122 + if (daddch(&dfa, term.line[row][col].u < 128 ? … | |
| 123 + break; | |
| 124 + | |
| 125 + if (col >= 0) | |
| 126 + break; | |
| 127 + | |
| 128 + if (--row < 0) | |
| 129 + row = term.row - 1; | |
| 130 + | |
| 131 + colend = term.col; | |
| 132 + } | |
| 133 + | |
| 134 + if (passes < term.row) { | |
| 135 + selstart(col, row, 0); | |
| 136 + selextend((col + dfa.length - 1) % term.col, row + (col… | |
| 137 + selextend((col + dfa.length - 1) % term.col, row + (col… | |
| 138 + xsetsel(getsel()); | |
| 139 + xclipcopy(); | |
| 140 + } | |
| 141 +} | |
| 142 diff --git a/st.h b/st.h | |
| 143 index 519b9bd..0458005 100644 | |
| 144 --- a/st.h | |
| 145 +++ b/st.h | |
| 146 @@ -85,6 +85,7 @@ void printscreen(const Arg *); | |
| 147 void printsel(const Arg *); | |
| 148 void sendbreak(const Arg *); | |
| 149 void toggleprinter(const Arg *); | |
| 150 +void copyurl(const Arg *); | |
| 151 | |
| 152 int tattrset(int); | |
| 153 void tnew(int, int); | |
| 154 -- | |
| 155 2.32.0 | |
| 156 |