commit edeecc048ca095b927082835a4a85508663f1104
parent 95746bd6204c5def1c87bdcba1814145d623c891
Author: Mahdi Mirzade <[email protected]>
Date: Thu, 14 Apr 2022 15:04:27 +0430
Add new scripts for bindings, little tweaks
Diffstat:
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("&", "\\&");
+ gsub("<", "<");
+ gsub(">", ">");
+ $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("&", "\\&");
+
+ 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);