surf

Mahdi's build of surf
git clone git://mahdi.pw/surf.git
Log | Files | Refs | README | LICENSE

commit edeecc048ca095b927082835a4a85508663f1104
parent 95746bd6204c5def1c87bdcba1814145d623c891
Author: Mahdi Mirzade <me@mahdi.pw>
Date:   Thu, 14 Apr 2022 15:04:27 +0430

Add new scripts for bindings, little tweaks

Diffstat:
MMakefile | 6++++++
Mconfig.h | 84++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Apatches/surf-2.0-externalpipe.diff | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apatches/surf-2.0-homepage.diff | 24++++++++++++++++++++++++
Asurf-edit-source | 5+++++
Asurf-link-select | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf-open | 19+++++++++++++++++++
Dsurf-open.sh | 31-------------------------------
Msurf.c | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
9 files changed, 366 insertions(+), 55 deletions(-)

diff --git a/Makefile b/Makefile @@ -56,6 +56,12 @@ install: all mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f surf $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/surf + cp -f surf-open $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/surf-open + cp -f surf-edit-source $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/surf-edit-source + cp -f surf-link-select $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/surf-link-select mkdir -p $(DESTDIR)$(LIBDIR) cp -f $(WLIB) $(DESTDIR)$(LIBDIR) for wlib in $(WLIB); do \ diff --git a/config.h b/config.h @@ -1,13 +1,16 @@ /* modifier 0 means no modifier */ -static int surfuseragent = 1; /* Append Surf version to default WebKit user agent */ + +//#define HOMEPAGE "https://duckduckgo.com/" +#define HS_FILE "~/.config/surf/history" +#define BM_FILE "~/.config/surf/bookmarks" + +static int surfuseragent = 1; /* Append Surf version to default WebKit user agent */ static char *fulluseragent = ""; /* Or override the whole user agent string */ static char *scriptfile = "~/.config/surf/script.js"; static char *styledir = "~/.config/surf/styles/"; static char *certdir = "~/.config/surf/certificates/"; static char *cachedir = "~/.config/surf/cache/"; static char *cookiefile = "~/.config/surf/cookies.txt"; -#define HS_FILE "~/.config/surf/history" -#define BM_FILE "~/.config/surf/bookmarks" static char *bookmarkfile = BM_FILE; static char *historyfile = HS_FILE; @@ -25,7 +28,7 @@ static Parameter defconfig[ParameterLast] = { [Certificate] = { { .i = 0 }, }, [CaretBrowsing] = { { .i = 0 }, }, [CookiePolicies] = { { .v = "@Aa" }, }, - [DarkMode] = { { .i = 0 }, }, + [DarkMode] = { { .i = 1 }, }, [DefaultCharset] = { { .v = "UTF-8" }, }, [DiskCache] = { { .i = 1 }, }, [DNSPrefetch] = { { .i = 0 }, }, @@ -43,7 +46,7 @@ static Parameter defconfig[ParameterLast] = { [MediaManualPlay] = { { .i = 1 }, }, [PreferredLanguages] = { { .v = (char *[]){ NULL } }, }, [RunInFullscreen] = { { .i = 0 }, }, - [ScrollBars] = { { .i = 1 }, }, + [ScrollBars] = { { .i = 0 }, }, [ShowIndicators] = { { .i = 0 }, }, [SiteQuirks] = { { .i = 1 }, }, [SmoothScrolling] = { { .i = 0 }, }, @@ -57,6 +60,9 @@ static Parameter defconfig[ParameterLast] = { }; static UriParameters uriparams[] = { + { "(://|\\.)youtube\\.com(/|$)", { + [Style] = { { .i = 0 }, 1 }, + }, }, { "(://|\\.)suckless\\.org(/|$)", { [JavaScript] = { { .i = 0 }, 1 }, }, }, @@ -68,29 +74,50 @@ static int winsize[] = { 800, 600 }; static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND; -#define PROMPT_GO "Go:" -#define PROMPT_FIND "Find:" +#define PROMPT_GO "Open" +#define PROMPT_GO_N "Open (new window)" +#define PROMPT_FIND "Find" /* SETPROP(readprop, setprop, prompt)*/ #define SETPROP(r, s, p) { \ .v = (const char *[]){ "/bin/sh", "-c", \ "prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \ - " -e 's/\\\\\\(.\\)/\\1/g' -e 's/\$//g'" \ - " && cat " BM_FILE " " \ - " && tail -100 " HS_FILE " | sort -r )\" " \ - "| dmenu -b -l 20 -p '"p"' -w $1 | awk -F'|' '{if ($2 =="") print $1; else print $2}')\" " \ + " -e 's/\\\\\\(.\\)/\\1/g')\" " \ + "| dmenu -i -b -l 1 -p '"p"' -w $1)\" " \ "&& xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \ "surf-setprop", winid, NULL \ } \ } -#define SETPROP_DEFAULT(r, s, p) { \ + +#define SETPROP_GO(r, s, p) { \ .v = (const char *[]){ "/bin/sh", "-c", \ - "prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ + "HIST=\"$(tac " HS_FILE " | awk -F'|' '!a[$2]++')\" " \ + "&& prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \ - " -e 's/\\\\\\(.\\)/\\1/g' -e 's/\$//g')\"" \ - "| dmenu -b -p '"p"' -w $1 | awk '{print $NF}')\" " \ - "&& xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \ + " -e 's/\\\\\\(.\\)/\\1/g' "\ + " && cat " BM_FILE " && printf '%s\n' \"${HIST}\" " \ + " | awk -F'|' '{if(length($2) > 80){print NR\"|\"$1\"|\"substr($2,0,80)\"...|\"$3}else{print NR\"|\"$1\"|\"$2\"|\"$3}}' | column -t -s '|' -o ' ')\" " \ + "| dmenu -i -b -l 20 -p '"p"' -w $1 | awk '{if(length($3)!=0){print $1}else{print $0}}')\"; " \ + "[ \"$prop\" ] || exit; " \ + "[ \"$(echo \"$prop\" | grep -Eo '^\-?[0-9]+$')\" -gt 0 ] && prop=\"$(printf '%s\n' \"${HIST}\" | sed \"${prop}q;d\" | awk -F'|' '{print $2}')\"; " \ + "xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \ + "surf-setprop", winid, NULL \ + } \ +} + +#define SETPROP_GO_N(r, s, p) { \ + .v = (const char *[]){ "/bin/sh", "-c", \ + "HIST=\"$(tac " HS_FILE " | awk -F'|' '!a[$2]++')\" " \ + "&& prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ + "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \ + " -e 's/\\\\\\(.\\)/\\1/g' "\ + " && cat " BM_FILE " && printf '%s\n' \"${HIST}\" " \ + " | awk -F'|' '{if(length($2) > 80){print NR\"|\"$1\"|\"substr($2,0,80)\"...|\"$3}else{print NR\"|\"$1\"|\"$2\"|\"$3}}' | column -t -s '|' -o ' ')\" " \ + "| dmenu -i -b -l 20 -p '"p"' -w $1 | awk '{if(length($3)!=0){print $1}else{print $0}}')\"; " \ + "[ \"$prop\" ] || exit; " \ + "[ \"$(echo \"$prop\" | grep -Eo '^\-?[0-9]+$')\" -gt 0 ] && prop=\"$(printf '%s\n' \"${HIST}\" | sed \"${prop}q;d\" | awk -F'|' '{print $2}')\"; " \ + "surf-open \"$prop\"", \ "surf-setprop", winid, NULL \ } \ } @@ -140,10 +167,9 @@ static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | */ static SiteSpecific styles[] = { /* regexp file in $styledir */ - /*{ ".*", "default.css" },*/ + //{ ".*", "default.css" }, { ".*startpage.com.*", "default.css" }, { ".*suckless.org.*", "default.css" }, - { "about:.*", "default.css" }, }; /* certificates */ @@ -157,6 +183,16 @@ static SiteSpecific certs[] = { #define MODKEY GDK_CONTROL_MASK +static char *editscreen[] = { "/bin/sh", "-c", "surf-edit-source", NULL }; +static char *linkselect_curwin [] = { "/bin/sh", "-c", + "surf-link-select $0 'Link' | xargs -r xprop -id $0 -f _SURF_GO 8u -set _SURF_GO $1", + winid, NULL +}; +static char *linkselect_newwin [] = { "/bin/sh", "-c", + "surf-link-select $0 'Link (new window)' | xargs -r surf-open", + winid, NULL +}; + /* hotkeys */ /* * If you use anything else but MODKEY and GDK_SHIFT_MASK, don't forget to @@ -164,10 +200,14 @@ static SiteSpecific certs[] = { */ static Key keys[] = { /* modifier keyval function arg */ - { MODKEY, GDK_KEY_Return, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, - { MODKEY, GDK_KEY_g, spawn, SETPROP_DEFAULT("_SURF_URI", "_SURF_GO", PROMPT_GO) }, - { MODKEY, GDK_KEY_f, spawn, SETPROP_DEFAULT("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, - { MODKEY, GDK_KEY_slash, spawn, SETPROP_DEFAULT("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + { MODKEY, GDK_KEY_o, externalpipe, { .v = editscreen } }, + { MODKEY, GDK_KEY_d, externalpipe, { .v = linkselect_curwin } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_d, externalpipe, { .v = linkselect_newwin } }, + { MODKEY, GDK_KEY_Return, spawn, SETPROP_GO("_SURF_URI", "_SURF_GO", PROMPT_GO) }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_Return, spawn, SETPROP_GO_N("_SURF_URI", "_SURF_GO", PROMPT_GO_N) }, + { MODKEY, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, + { MODKEY, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + { MODKEY, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, { MODKEY, GDK_KEY_m, spawn, BM_ADD("_SURF_URI") }, { MODKEY, GDK_KEY_w, playexternal, { 0 } }, diff --git a/patches/surf-2.0-externalpipe.diff b/patches/surf-2.0-externalpipe.diff @@ -0,0 +1,93 @@ +diff --git a/surf.c b/surf.c +index 93a1629..ba53b94 100644 +--- a/surf.c ++++ b/surf.c +@@ -217,6 +217,7 @@ static void togglefullscreen(Client *c, const Arg *a); + static void togglecookiepolicy(Client *c, const Arg *a); + static void toggleinspector(Client *c, const Arg *a); + static void find(Client *c, const Arg *a); ++static void externalpipe(Client *c, const Arg *a); + + /* Buttons */ + static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h); +@@ -241,6 +242,80 @@ char *argv0; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++static void ++externalpipe_execute(char* buffer, Arg *arg) { ++ int to[2]; ++ void (*oldsigpipe)(int); ++ ++ if (pipe(to) == -1) ++ return; ++ ++ switch (fork()) { ++ case -1: ++ close(to[0]); ++ close(to[1]); ++ return; ++ case 0: ++ dup2(to[0], STDIN_FILENO); close(to[0]); close(to[1]); ++ execvp(((char **)arg->v)[0], (char **)arg->v); ++ fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]); ++ perror("failed"); ++ exit(0); ++ } ++ ++ close(to[0]); ++ oldsigpipe = signal(SIGPIPE, SIG_IGN); ++ write(to[1], buffer, strlen(buffer)); ++ close(to[1]); ++ signal(SIGPIPE, oldsigpipe); ++} ++ ++static void ++externalpipe_resource_done(WebKitWebResource *r, GAsyncResult *s, Arg *arg) ++{ ++ GError *gerr = NULL; ++ guchar *buffer = webkit_web_resource_get_data_finish(r, s, NULL, &gerr); ++ if (gerr == NULL) { ++ externalpipe_execute((char *) buffer, arg); ++ } else { ++ g_error_free(gerr); ++ } ++ g_free(buffer); ++} ++ ++static void ++externalpipe_js_done(WebKitWebView *wv, GAsyncResult *s, Arg *arg) ++{ ++ WebKitJavascriptResult *j = webkit_web_view_run_javascript_finish( ++ wv, s, NULL); ++ if (!j) { ++ return; ++ } ++ JSCValue *v = webkit_javascript_result_get_js_value(j); ++ if (jsc_value_is_string(v)) { ++ char *buffer = jsc_value_to_string(v); ++ externalpipe_execute(buffer, arg); ++ g_free(buffer); ++ } ++ webkit_javascript_result_unref(j); ++} ++ ++void ++externalpipe(Client *c, const Arg *arg) ++{ ++ if (curconfig[JavaScript].val.i) { ++ webkit_web_view_run_javascript( ++ c->view, "window.document.documentElement.outerHTML", ++ NULL, externalpipe_js_done, arg); ++ } else { ++ WebKitWebResource *resource = webkit_web_view_get_main_resource(c->view); ++ if (resource != NULL) { ++ webkit_web_resource_get_data( ++ resource, NULL, externalpipe_resource_done, arg); ++ } ++ } ++} ++ + void + usage(void) + { diff --git a/patches/surf-2.0-homepage.diff b/patches/surf-2.0-homepage.diff @@ -0,0 +1,24 @@ +diff --git a/config.def.h b/config.def.h +--- a/config.def.h ++++ b/config.def.h +@@ -164,3 +164,5 @@ static Button buttons[] = { + { OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 }, + { OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 }, + }; ++ ++#define HOMEPAGE "https://duckduckgo.com/" +diff --git a/surf.c b/surf.c +--- a/surf.c ++++ b/surf.c +@@ -1751,7 +1751,11 @@ main(int argc, char *argv[]) + if (argc > 0) + arg.v = argv[0]; + else ++#ifdef HOMEPAGE ++ arg.v = HOMEPAGE; ++#else + arg.v = "about:blank"; ++#endif + + setup(); + c = newclient(NULL); diff --git a/surf-edit-source b/surf-edit-source @@ -0,0 +1,5 @@ +#!/bin/sh +tmpfile=$(mktemp /tmp/st-edit.XXXXXX) +trap 'rm "$tmpfile"' 0 1 15 +cat > "$tmpfile" +st -e "$EDITOR" "$tmpfile" diff --git a/surf-link-select b/surf-link-select @@ -0,0 +1,76 @@ +#!/bin/sh +# surf_linkselect.sh: +# Usage: curl somesite.com | surf_linkselect [SURFWINDOWID] [PROMPT] +# Deps: xmllint, dmenu +# Info: +# Designed to be used w/ surf externalpipe patch. Enables keyboard-only +# link selection via dmenu. Given HTML stdin, extracts links one per line +# Selected link is normalized based on current URI and printed to STDOUT. +# Pipe the result to a new surf or xprop _SURF_URI accordingly. +SURF_WINDOW="${1:-$(xprop -root | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* //p')}" +DMENU_PROMPT="${2:-Link}" + +dump_links_with_titles() { + awk '{ + input = $0; + + $0 = input; + gsub("<[^>]*>", ""); + gsub(/[ ]+/, " "); + gsub("&amp;", "\\&"); + gsub("&lt;", "<"); + gsub("&gt;", ">"); + $1 = $1; + title = ($0 == "" ? "None" : $0); + + $0 = input; + match($0, /\<[ ]*[aA][^>]* [hH][rR][eE][fF]=["]([^"]+)["]/, linkextract); + $0 = linkextract[1]; + gsub(/^[ \t]+/,""); + gsub(/[ \t]+$/,""); + gsub("[ ]", "%20"); + link = $0; + + if (link != "") { + print title ": " link; + } + }' +} + +link_normalize() { + URI=$1 + awk -v uri=$URI '{ + gsub("&amp;", "\\&"); + + if ($0 ~ /^https?:\/\// || $0 ~ /^\/\/.+$/) { + print $0; + } else if ($0 ~/^#/) { + gsub(/[#?][^#?]+/, "", uri); + print uri $0; + } else if ($0 ~/^\//) { + split(uri, uri_parts, "/"); + print uri_parts[3] $0; + } else { + gsub(/[#][^#]+/, "", uri); + uri_parts_size = split(uri, uri_parts, "/"); + delete uri_parts[uri_parts_size]; + for (v in uri_parts) { + uri_pagestripped = uri_pagestripped uri_parts[v] "/" + } + print uri_pagestripped $0; + } + }' +} + +link_select() { + tr '\n\r' ' ' | + xmllint --html --xpath "//a" - | + dump_links_with_titles | + awk '!x[$0]++' | + # sort | uniq + dmenu -i -b -l 20 -p "$DMENU_PROMPT" -w $SURF_WINDOW | + awk -F' ' '{print $NF}' | + link_normalize $(xprop -id $SURF_WINDOW _SURF_URI | cut -d '"' -f 2) +} + +link_select diff --git a/surf-open b/surf-open @@ -0,0 +1,19 @@ +#!/bin/sh +xidfile="/tmp/tabbed-surf.xid" +uri="" + +[ "$#" -gt 0 ] && uri="$1" +[ "$(xprop -id "$(cat "$xidfile")" | awk '/WM_CLASS/{sub(/",/, "", $3);sub(/"/, "", $3);print $3}')" = "tabbed-surf" ] || rm "$xidfile" + +runtabbed() { + tabbed -cdn tabbed-surf -r 2 surf -e '' "$uri" >"$xidfile" \ + 2>/dev/null & +} + +if [ ! -r "$xidfile" ]; then runtabbed; else + xid=$(cat "$xidfile") + xprop -id "$xid" >/dev/null 2>&1 + if [ $? -gt 0 ]; then runtabbed; else + surf -e "$xid" "$uri" >/dev/null 2>&1 & + fi +fi diff --git a/surf-open.sh b/surf-open.sh @@ -1,31 +0,0 @@ -#!/bin/sh -# -# See the LICENSE file for copyright and license details. -# - -xidfile="/tmp/tabbed-surf.xid" -uri="" - -if [ "$#" -gt 0 ]; -then - uri="$1" -fi - -runtabbed() { - tabbed -dn tabbed-surf -r 2 surf -e '' "$uri" >"$xidfile" \ - 2>/dev/null & -} - -if [ ! -r "$xidfile" ]; -then - runtabbed -else - xid=$(cat "$xidfile") - xprop -id "$xid" >/dev/null 2>&1 - if [ $? -gt 0 ]; - then - runtabbed - else - surf -e "$xid" "$uri" >/dev/null 2>&1 & - fi -fi diff --git a/surf.c b/surf.c @@ -238,6 +238,7 @@ static void togglefullscreen(Client *c, const Arg *a); static void togglecookiepolicy(Client *c, const Arg *a); static void toggleinspector(Client *c, const Arg *a); static void find(Client *c, const Arg *a); +static void externalpipe(Client *c, const Arg *a); static void playexternal(Client *c, const Arg *a); /* Buttons */ @@ -309,6 +310,80 @@ static ParamName loadfinished[] = { /* configuration, allows nested code to access above variables */ #include "config.h" +static void +externalpipe_execute(char* buffer, Arg *arg) { + int to[2]; + void (*oldsigpipe)(int); + + if (pipe(to) == -1) + return; + + switch (fork()) { + case -1: + close(to[0]); + close(to[1]); + return; + case 0: + dup2(to[0], STDIN_FILENO); close(to[0]); close(to[1]); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]); + perror("failed"); + exit(0); + } + + close(to[0]); + oldsigpipe = signal(SIGPIPE, SIG_IGN); + write(to[1], buffer, strlen(buffer)); + close(to[1]); + signal(SIGPIPE, oldsigpipe); +} + +static void +externalpipe_resource_done(WebKitWebResource *r, GAsyncResult *s, Arg *arg) +{ + GError *gerr = NULL; + guchar *buffer = webkit_web_resource_get_data_finish(r, s, NULL, &gerr); + if (gerr == NULL) { + externalpipe_execute((char *) buffer, arg); + } else { + g_error_free(gerr); + } + g_free(buffer); +} + +static void +externalpipe_js_done(WebKitWebView *wv, GAsyncResult *s, Arg *arg) +{ + WebKitJavascriptResult *j = webkit_web_view_run_javascript_finish( + wv, s, NULL); + if (!j) { + return; + } + JSCValue *v = webkit_javascript_result_get_js_value(j); + if (jsc_value_is_string(v)) { + char *buffer = jsc_value_to_string(v); + externalpipe_execute(buffer, arg); + g_free(buffer); + } + webkit_javascript_result_unref(j); +} + +void +externalpipe(Client *c, const Arg *arg) +{ + if (curconfig[JavaScript].val.i) { + webkit_web_view_run_javascript( + c->view, "window.document.documentElement.outerHTML", + NULL, externalpipe_js_done, arg); + } else { + WebKitWebResource *resource = webkit_web_view_get_main_resource(c->view); + if (resource != NULL) { + webkit_web_resource_get_data( + resource, NULL, externalpipe_resource_done, arg); + } + } +} + void die(const char *errstr, ...) { @@ -795,7 +870,7 @@ setparameter(Client *c, int refresh, ParamName p, const Arg *a) break; case DarkMode: g_object_set(gtk_settings_get_default(), - "gtk-application-prefer-dark-mode", a->i, NULL); + "gtk-application-prefer-dark-theme", a->i, NULL); return; break; case DiskCache: @@ -2164,7 +2239,11 @@ main(int argc, char *argv[]) if (argc > 0) arg.v = argv[0]; else - arg.v = "about:blank"; +#ifdef HOMEPAGE + arg.v = HOMEPAGE; +#else + arg.v = "about:blank"; +#endif setup(); c = newclient(NULL);