Added new ]] and [[ commands.
authorDaniel Carl <danielcarl@gmx.de>
Sun, 27 Oct 2013 22:42:45 +0000 (23:42 +0100)
committerDaniel Carl <danielcarl@gmx.de>
Sun, 27 Oct 2013 22:48:52 +0000 (23:48 +0100)
These commands allow to open next/previous page by regex pattern configured
using new settings 'previouspattern' and 'nextpattern'.

doc/vimb.1
src/default.h
src/hints.c
src/hints.h
src/hints.js
src/main.h
src/normal.c
src/setting.c

index 5603656..247a187 100644 (file)
@@ -167,6 +167,12 @@ Scroll page \fIN\fP steps down.
 .TP
 .BI [ N ]k
 Scroll page \fIN\fP steps up.
+.TP
+.BI [ N ]]\-]
+Follow the last \fIN\fPth link matching `nextpattern'.
+.TP
+.BI [ N ][\-[
+Follow the last \fIN\fPth link matching `previouspattern'.
 .SS Hinting
 The hinting is the way to do what you would do with the mouse in common
 mouse-driven browsers. Open URI, yank URI, save page and so on. If the hinting
@@ -696,6 +702,16 @@ Font user in inputbox if error is shown.
 .B input-font-normal (string)
 Font used for inputbox.
 .TP
+.B nextpattern (string)
+Patterns to use when guessing the next page in a document. Each pattern is
+successively tested against each link in the page beginning from the last
+link. Default "'\\bnext\\b','^(>|>>|»)$','^(>|>>|»)','(>|>>|»)$','\\bmore\\b'"
+.TP
+.B previouspattern (string)
+Patterns to use when guessing the previous page in a document. Each pattern is
+successively tested against each link in the page beginning from the last
+link. Default "\\bprev|previous\\b','^(<|<<|«)$','^(<|<<|«)','(<|<<|«)$'"
+.TP
 .B proxy (bool)
 Indicates if the environment variable `http_proxy' is evaluated.
 .TP
index 944c7e7..8b97abf 100644 (file)
@@ -67,6 +67,8 @@ static char *default_config[] = {
     "set insecure-content-run=off",
 #endif
     "set timeoutlen=1000",
+    "set previouspattern='\\bprev\\|previous\\b','^(<\\|<<\\|«)$','^(<\\|<<\\|«)','(<\\|<<\\|«)$'",
+    "set nextpattern='\\bnext\\b','^(>\\|>>\\|»)$','^(>\\|>>\\|»)','(>\\|>>\\|»)$','\\bmore\\b'",
     NULL
 };
 
index b2d659b..fe7cda1 100644 (file)
@@ -158,8 +158,22 @@ void hints_fire(void)
     g_free(js);
 }
 
+void hints_follow_link(const gboolean back, int count)
+{
+    char *pattern = back ? vb.config.prevpattern : vb.config.nextpattern;
+    char *js      = g_strdup_printf(
+        "%s.followLink('%s', [%s], %d);", HINT_VAR,
+        back ? "prev" : "next",
+        pattern,
+        count
+    );
+    run_script(js);
+    g_free(js);
+}
+
 static void run_script(char *js)
 {
+    PRINT_DEBUG("%s", js);
     char mode, *value = NULL;
 
     gboolean success = vb_eval_script(
index f721883..386e7ca 100644 (file)
@@ -27,6 +27,7 @@ VbResult hints_keypress(int key);
 void hints_create(const char *input);
 void hints_update(int num);
 void hints_fire(void);
+void hints_follow_link(const gboolean back, int count);
 void hints_clear(void);
 void hints_focus_next(const gboolean back);
 
index 55a79b5..1beea66 100644 (file)
@@ -392,6 +392,53 @@ var VbHint = (function(){
         }
     }
 
+    /* follow the count last link on pagematching the given pattern */
+    function followLink(rel, pattern, count) {
+        /* returns array of matching elements */
+        function followFrame(frame) {
+            var i, p, reg, res = [],
+                elems = frame.document.getElementsByTagName("a");
+
+            /* first match links by rel attribute */
+            for (i = elems.length - 1; i >= 0; i--) {
+                if (elems[i].rel.toLowerCase() === rel) {
+                    res.push(elems[i]);
+                    elems.splice(i, 1);
+                }
+            }
+            /* match each pattern successively against each link in the page */
+            for (p = 0; p < pattern.length; p++) {
+                reg = pattern[p];
+                /* begin with the last link on page */
+                for (i = elems.length - 1; i >= 0; i--) {
+                    if (elems[i].innerText.match(reg)) {
+                        res.push(elems[i]);
+                    }
+                }
+            }
+            return res;
+        }
+        var i, j, elems, frames = allFrames(window);
+        for (i = 0; i < frames.length; i++) {
+            elems = followFrame(frames[i]);
+            for (j = 0; j < elems.length; j++) {
+                if (--count == 0) {
+                    open(elems[j], false);
+                    return "DONE:";
+                }
+            }
+        }
+        return "NONE:";
+    }
+
+    function allFrames(win) {
+        var i, f, frames = [win];
+        for (i = 0; i < win.frames.length; i++) {
+            frames.push(win.frames[i].frameElement);
+        }
+        return frames;
+    }
+
     /* the api */
     return {
         init: function init(prefix, maxHints) {
@@ -423,11 +470,13 @@ var VbHint = (function(){
                 config.usage = map[prefix][1];
             }
         },
-        create: create,
-        update: update,
-        clear:  clear,
-        fire:   fire,
-        focus:  focus
+        create:     create,
+        update:     update,
+        clear:      clear,
+        fire:       fire,
+        focus:      focus,
+        /* not really hintings but uses similar logic */
+        followLink: followLink
     };
 })();
 Object.freeze(VbHint);
index e79e0a9..7b65589 100644 (file)
@@ -282,6 +282,8 @@ typedef struct {
     guint      timeoutlen;      /* timeout for ambiguous mappings */
     gboolean   strict_focus;
     GHashTable *headers;        /* holds user defined header appended to requests */
+    char       *nextpattern;    /* regex patter nfor prev link matching */
+    char       *prevpattern;    /* regex patter nfor next link matching */
 } Config;
 
 typedef struct {
index 26e4dc5..b55160b 100644 (file)
@@ -61,6 +61,7 @@ static VbResult normal_navigate(const NormalCmdInfo *info);
 static VbResult normal_open_clipboard(const NormalCmdInfo *info);
 static VbResult normal_open(const NormalCmdInfo *info);
 static VbResult normal_pass(const NormalCmdInfo *info);
+static VbResult normal_prevnext(const NormalCmdInfo *info);
 static VbResult normal_queue(const NormalCmdInfo *info);
 static VbResult normal_quit(const NormalCmdInfo *info);
 static VbResult normal_scroll(const NormalCmdInfo *info);
@@ -165,9 +166,9 @@ static struct {
 /* X   0x58 */ {NULL},
 /* Y   0x59 */ {normal_yank},
 /* Z   0x5a */ {NULL},
-/* [   0x5b */ {NULL},
+/* [   0x5b */ {normal_prevnext},
 /* \   0x5c */ {NULL},
-/* ]   0x5d */ {NULL},
+/* ]   0x5d */ {normal_prevnext},
 /* ^   0x5e */ {NULL},
 /* _   0x5f */ {NULL},
 /* `   0x60 */ {NULL},
@@ -243,7 +244,7 @@ VbResult normal_keypress(int key)
         info.phase = PHASE_COMPLETE;
     } else if (info.phase == PHASE_START && isdigit(key)) {
         info.count = info.count * 10 + key - '0';
-    } else if (strchr(";zg", (char)key)) {
+    } else if (strchr(";zg[]", (char)key)) {
         /* handle commands that needs additional char */
         info.phase = PHASE_KEY2;
         info.cmd   = key;
@@ -546,6 +547,19 @@ static VbResult normal_pass(const NormalCmdInfo *info)
     return RESULT_COMPLETE;
 }
 
+static VbResult normal_prevnext(const NormalCmdInfo *info)
+{
+    int count = info->count ? info->count : 1;
+    if (info->ncmd == ']') {
+        hints_follow_link(false, count);
+    } else if (info->ncmd == '[') {
+        hints_follow_link(true, count);
+    } else {
+        return RESULT_ERROR;
+    }
+    return RESULT_COMPLETE;
+}
+
 static VbResult normal_queue(const NormalCmdInfo *info)
 {
     command_queue(&((Arg){COMMAND_QUEUE_POP}));
index 994b24c..f2082b3 100644 (file)
@@ -47,6 +47,7 @@ static gboolean history_max_items(const Setting *s, const SettingType type);
 static gboolean editor_command(const Setting *s, const SettingType type);
 static gboolean timeoutlen(const Setting *s, const SettingType type);
 static gboolean headers(const Setting *s, const SettingType type);
+static gboolean nextpattern(const Setting *s, const SettingType type);
 
 static Setting default_settings[] = {
     /* webkit settings */
@@ -111,6 +112,8 @@ static Setting default_settings[] = {
     {NULL, "history-max-items", TYPE_INTEGER, history_max_items, {0}},
     {NULL, "editor-command", TYPE_CHAR, editor_command, {0}},
     {NULL, "header", TYPE_CHAR, headers, {0}},
+    {NULL, "nextpattern", TYPE_CHAR, nextpattern, {0}},
+    {NULL, "previouspattern", TYPE_CHAR, nextpattern, {0}},
 };
 
 void setting_init(void)
@@ -775,3 +778,16 @@ static gboolean headers(const Setting *s, const SettingType type)
 
     return true;
 }
+
+static gboolean nextpattern(const Setting *s, const SettingType type)
+{
+    if (type == SETTING_GET) {
+        print_value(s, s->name[0] == 'n' ? vb.config.nextpattern : vb.config.prevpattern);
+    } else if (*s->name == 'n') {
+        OVERWRITE_STRING(vb.config.nextpattern, s->arg.s);
+    } else {
+        OVERWRITE_STRING(vb.config.prevpattern, s->arg.s);
+    }
+
+    return true;
+}