diff --git a/config.def.h b/config.def.h index ac6675e..cf56699 100644 --- a/config.def.h +++ b/config.def.h @@ -219,6 +219,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} }, + { MODKEY, XK_l, copyurl, {.i = 0} }, }; /* diff --git a/config.h b/config.h index a7f0bb3..cf56699 100644 --- a/config.h +++ b/config.h @@ -98,7 +98,7 @@ char *termname = "st-256color"; * * stty tabs */ -unsigned int tabspaces = 8; +unsigned int tabspaces = 4; /* Terminal colors (16 first used in escape sequence) */ static const char *colorname[] = { @@ -219,6 +219,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} }, + { MODKEY, XK_l, copyurl, {.i = 0} }, }; /* diff --git a/st b/st index 849599a..55eafb4 100755 Binary files a/st and b/st differ diff --git a/st.c b/st.c index 4b6e632..7fb02da 100644 --- a/st.c +++ b/st.c @@ -166,6 +166,11 @@ typedef struct { int narg; /* nb of args */ } STREscape; +typedef struct { + int state; + size_t length; +} URLdfa; + static void execsh(char *, char **); static void stty(char **); static void sigchld(int); @@ -215,6 +220,7 @@ static void tdefutf8(char); static int32_t tdefcolor(const int *, int *, int); static void tdeftran(char); static void tstrsequence(uchar); +static int daddch(URLdfa *, char); static void drawregion(int, int, int, int); static void clearline(Line, Glyph, int, int); @@ -2783,3 +2789,82 @@ redraw(void) tfulldirt(); draw(); } + +int +daddch(URLdfa *dfa, char c) +{ + /* () and [] can appear in urls, but excluding them here will reduce false + * positives when figuring out where a given url ends. + */ + static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-._~:/?#@!$&'*+,;=%"; + static const char RPFX[] = "//:sptth"; + + if(!strchr(URLCHARS, c)) { + dfa->length = 0; + dfa->state = 0; + + return 0; + } + + dfa->length++; + + if(dfa->state == 2 && c == '/') { + dfa->state = 0; + } + else if(dfa->state == 3 && c == 'p') { + dfa->state++; + } + else if(c != RPFX[dfa->state]) { + dfa->state = 0; + return 0; + } + + if(dfa->state++ == 7) { + dfa->state = 0; + return 1; + } + + return 0; +} + +void +copyurl(const Arg *arg) { + int row = 0, + col = 0, + colend = 0, + passes = 0; + + const char *c = NULL, + *match = NULL; + URLdfa dfa = { 0 }; + + row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; + LIMIT(row, term.top, term.bot); + + colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; + LIMIT(colend, 0, term.col); + + for(passes = 0; passes < term.row; passes++) { + for(col = colend; col--;) + if(daddch(&dfa, term.screen[0].buffer[row][col].u < 128 ? term.screen[0].buffer[row][col].u : ' ')) + break; + + if(col >= 0) + break; + + if(--row < 0) + row = term.row - 1; + + colend = term.col; + } + + if(passes < term.row) { + selstart(col, row, 0); + selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0); + selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1); + xsetsel(getsel()); + xclipcopy(); + } +} diff --git a/st.h b/st.h index ec35392..a848c6b 100644 --- a/st.h +++ b/st.h @@ -86,6 +86,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/st.o b/st.o index 8f7d2e1..24231ab 100644 Binary files a/st.o and b/st.o differ diff --git a/x.o b/x.o index 876eb3c..5011cac 100644 Binary files a/x.o and b/x.o differ