From 81aa3cfc503a98f670b86db51de80660c3b96008 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Sun, 27 Oct 2013 23:42:45 +0100 Subject: [PATCH] Added new ]] and [[ commands. These commands allow to open next/previous page by regex pattern configured using new settings 'previouspattern' and 'nextpattern'. --- doc/vimb.1 | 16 ++++++++++++++ src/default.h | 2 ++ src/hints.c | 14 ++++++++++++ src/hints.h | 1 + src/hints.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++----- src/main.h | 2 ++ src/normal.c | 20 ++++++++++++++--- src/setting.c | 16 ++++++++++++++ 8 files changed, 122 insertions(+), 8 deletions(-) diff --git a/doc/vimb.1 b/doc/vimb.1 index 5603656..247a187 100644 --- a/doc/vimb.1 +++ b/doc/vimb.1 @@ -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 diff --git a/src/default.h b/src/default.h index 944c7e7..8b97abf 100644 --- a/src/default.h +++ b/src/default.h @@ -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 }; diff --git a/src/hints.c b/src/hints.c index b2d659b..fe7cda1 100644 --- a/src/hints.c +++ b/src/hints.c @@ -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( diff --git a/src/hints.h b/src/hints.h index f721883..386e7ca 100644 --- a/src/hints.h +++ b/src/hints.h @@ -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); diff --git a/src/hints.js b/src/hints.js index 55a79b5..1beea66 100644 --- a/src/hints.js +++ b/src/hints.js @@ -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); diff --git a/src/main.h b/src/main.h index e79e0a9..7b65589 100644 --- a/src/main.h +++ b/src/main.h @@ -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 { diff --git a/src/normal.c b/src/normal.c index 26e4dc5..b55160b 100644 --- a/src/normal.c +++ b/src/normal.c @@ -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})); diff --git a/src/setting.c b/src/setting.c index 994b24c..f2082b3 100644 --- a/src/setting.c +++ b/src/setting.c @@ -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; +} -- 2.20.1