diff --git a/NEWS b/NEWS index ce7f0810..df3880b8 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ * THIS VERSION ONLY WORKS WITH FIREFOX 3.0 * IMPORTANT! options are no longer automatically stored - use the ~/.vimperatorrc file instead for persistent options + * IMPORTANT! Major hints rewrite + read up the new help for the f, F and ; commands for details * added new :mkvimperatorrc command * you can edit textfields with Ctrl-i now using an external editor (thanks to Joseph Xu) * :open, :bmarks, etc. filter on space separated tokens now, so you can diff --git a/TODO b/TODO index 91f2af4d..949bc602 100644 --- a/TODO +++ b/TODO @@ -3,21 +3,15 @@ Priority list: 1-9 as in vim (9=required for next release, 5=would be nice, 1=probably not) BUGS: -- http://en.wikipedia.org/wiki/Portal:Current_events - 'f' shows more hints than 'F' (on left side of nav bar) -- dpb| 09:09:56 dpb :: when I save a page with vimperator, it adds near the end of it.. kinda annoying - dpb| 09:11:50 dpb :: and this happens only when saving the complete - webpage, saving only the html works just fine.. - add window resize support to hints - can't reverse tab through the vimperator toolbar -- gu and gU don't work on local files properly +- gu and gU don't work on local files properly - still valid? - :noremap does not work fully - pvh option not working - searching backwards incrementally does not work i.e. with 'incsearch' set FEATURES: 9 :command for new commands -9 make hints smarter, not only with characters from from hintchars, but use "NE" or "NP" for 'new posts' e.g. (might be too slow) 8 add an interface for navigating document relationships 8 middleclick in content == p, and if command line is open, paste there the clipboard buffer 7 use ctrl-n/p in insert mode for word completion diff --git a/content/events.js b/content/events.js index a256d46c..5c881a9d 100644 --- a/content/events.js +++ b/content/events.js @@ -52,11 +52,15 @@ vimperator.Events = function() //{{{ vimperator.buffer.updateBufferList(); }, false); tabcontainer.addEventListener("TabSelect", function(event) { + if (vimperator.mode == vimperator.modes.HINTS) + vimperator.modes.reset(); + vimperator.commandline.clear(); vimperator.modes.show(); vimperator.statusline.updateTabCount(); vimperator.buffer.updateBufferList(); vimperator.tabs.updateSelectionHistory(); + setTimeout(function() { vimperator.focusContent(true); }, 10); // just make sure, that no widget has focus }, false); @@ -620,7 +624,8 @@ vimperator.Events = function() //{{{ vimperator.hints.onEvent(event); event.preventDefault(); event.stopPropagation(); - return false; + return true; + } } diff --git a/content/hints.js b/content/hints.js index 12056745..2b31f48e 100644 --- a/content/hints.js +++ b/content/hints.js @@ -35,10 +35,10 @@ vimperator.Hints = function() //{{{ var hints = []; var valid_hints = []; // store the indices of the "hints" array with valid elements - var canUpdate = true; + var canUpdate = false; + var hintsGenerated = false; var timeout = 200; // only update every 200ms when typing fast, not used yet - - var wins = []; // keep track of the windows which we display the hints for + var docs = []; // keep track of the documents which we display the hints for // this function 'click' an element, which also works // for javascript links @@ -148,7 +148,7 @@ vimperator.Hints = function() //{{{ win = window.content; var doc = win.document; - wins.push(doc); + docs.push(doc); var baseNodeAbsolute = doc.createElementNS("http://www.w3.org/1999/xhtml", "span"); baseNodeAbsolute.style.backgroundColor = "red"; @@ -201,9 +201,21 @@ vimperator.Hints = function() //{{{ hints.push([elem, text, span, elem.style.backgroundColor, elem.style.color]); } + hintsGenerated = true; return true; } + // reset all important variables + function reset() + { + vimperator.statusline.updateInputBuffer(""); + linkNumString = ""; + hints = []; + valid_hints = []; + canUpdate = false; + hintsGenerated = false; + } + function showHints(win, str, start_idx) { if (!win) @@ -275,6 +287,7 @@ outer: function removeHints(doc, timeout) { + vimperator.log(timeout); if (!doc) { vimperator.log("Argument doc is required for internal removeHints() method", 9); @@ -336,8 +349,11 @@ outer: firstElem.style.color = firstElemColor; }, timeout); } + } catch (e) { vimperator.log("Error hiding hints, probably wrong window"); } + + reset(); }; function processHints(followFirst) @@ -347,47 +363,57 @@ outer: vimperator.beep(); return false; } - else + + if (!followFirst) { - if (!followFirst) + var first_href = valid_hints[0].getAttribute("href") || null; + if (first_href) { - var first_href = valid_hints[0].getAttribute("href") || null; - if (first_href) - { - if (valid_hints.some( function(e) { return e.getAttribute("href") != first_href; } )) - return false; - } - else if (valid_hints.length > 1) + if (valid_hints.some( function(e) { return e.getAttribute("href") != first_href; } )) return false; } - - if (vimperator.modes.extended & vimperator.modes.QUICK_HINT) - openHint(false, false); - else - { - var loc = valid_hints.length > 0 ? valid_hints[0].href : ""; - switch (submode) - { - case "f": focusHint(); break; - case "o": openHint(false, false); break; - case "O": vimperator.commandline.open(":", "open " + loc, vimperator.modes.EX); break; - case "t": openHint(true, false); break; - case "T": openHint(true, false); break; - case "T": vimperator.commandline.open(":", "tabopen " + loc, vimperator.modes.EX); break; - case "w": openHint(false, true); break; - case "W": vimperator.commandline.open(":", "winopen " + loc, vimperator.modes.EX); break; - case "a": saveHint(false); break; - case "s": saveHint(true); break; - case "y": yankHint(false); break; - case "Y": yankHint(true); break; - default: - vimperator.echoerr("INTERNAL ERROR: unknown submode: " + submode); - } - } - - // I KNOW, ugly but this. is not available in this context :( - vimperator.hints.hide(null, !followFirst); + else if (valid_hints.length > 1) + return false; } + + var loc = valid_hints.length > 0 ? valid_hints[0].href : ""; + switch (submode) + { + case "f": focusHint(); break; + case "o": openHint(false, false); break; + case "O": vimperator.commandline.open(":", "open " + loc, vimperator.modes.EX); break; + case "t": openHint(true, false); break; + case "T": openHint(true, false); break; + case "T": vimperator.commandline.open(":", "tabopen " + loc, vimperator.modes.EX); break; + case "w": openHint(false, true); break; + case "W": vimperator.commandline.open(":", "winopen " + loc, vimperator.modes.EX); break; + case "a": saveHint(false); break; + case "s": saveHint(true); break; + case "y": yankHint(false); break; + case "Y": yankHint(true); break; + default: + vimperator.echoerr("INTERNAL ERROR: unknown submode: " + submode); + } + + var timeout = followFirst ? 0 : 500; + removeHints(docs.pop(), timeout); + + if (vimperator.modes.extended & vimperator.modes.ALWAYS_HINT) + { + setTimeout(function() { + canUpdate = true; + linkNumString = ""; + vimperator.statusline.updateInputBuffer(""); + }, timeout); + } + else + { + setTimeout( function() { + if (vimperator.mode == vimperator.modes.HINTS) + vimperator.modes.reset(false); + }, timeout); + } + return true; }; @@ -405,7 +431,7 @@ outer: } vimperator.modes.set(vimperator.modes.HINTS, mode); - submode = minor; + submode = minor || "o"; // open is the default mode linkNumString = filter || ""; canUpdate = false; @@ -432,26 +458,14 @@ outer: return true; }; - this.hide = function(win, delayModeChange) + this.hide = function() { - var timeout = delayModeChange ? 500 : 0; - doc = wins.pop(); + if (!hintsGenerated) + return; + + doc = docs.pop(); if(doc); - removeHints(doc, timeout); - - vimperator.echo(" "); - vimperator.statusline.updateInputBuffer(""); - - linkNumString = ""; - hints = []; - valid_hints = []; - canUpdate = false; - - // only close this mode half a second later, so we don't trigger accidental actions so easily - setTimeout( function() { - if (vimperator.mode == vimperator.modes.HINTS) - vimperator.modes.reset(true); - }, timeout); + removeHints(doc, 0); }; this.onEvent = function(event) @@ -484,15 +498,34 @@ outer: break; default: + // pass any special or ctrl- etc. prefixed key back to the main vimperator loop + if (/^<./.test(key) || key == ":") + { + var map = null; + if ((map = vimperator.mappings.get(vimperator.modes.NORMAL, key)) || + (map = vimperator.mappings.get(vimperator.modes.HINTS, key))) + { + map.execute(null, -1); + return; + } + + vimperator.beep(); + return; + } + linkNumString += key; } vimperator.statusline.updateInputBuffer(linkNumString); if (canUpdate) { + if (!hintsGenerated && linkNumString.length > 0) + generate(); + showHints(null, linkNumString); processHints(followFirst); } + return false; } diff --git a/content/mappings.js b/content/mappings.js index 0d1886eb..6732decf 100644 --- a/content/mappings.js +++ b/content/mappings.js @@ -1027,25 +1027,40 @@ vimperator.Mappings = function() //{{{ usage: ["f{hint}"], help: "In QuickHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a unique number (FIXME: numbers shown, but not usable yet).
" + "You can now either type this number or type any part of the URL which you want to follow, and it is followed as soon as it can be uniquely identified. " + - //"If you write the hint in ALLCAPS, the hint is followed in a background tab.
" + "Often it is can be useful to combine these techniques to narrow down results with some letters, and then typing a single digit to make the match unique.
" + "<Esc> stops this mode at any time." } )); addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], ["F"], - function() { vimperator.echo("Always HINT mode not available anymore"); }, + function() { vimperator.hints.show(vimperator.modes.QUICK_HINT, "t"); }, { - short_help: "Start AlwaysHint mode (CURRENTLY DISABLED)", - help: "In AlwaysHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a label.
" + - "If you then press the keys for a label, it is followed as soon as it can be uniquely identified. Labels stay active after following a hint in this mode, press <Esc> to stop this mode.
" + - "This hint mode is especially useful for browsing large sites like Forums as hints are automatically regenerated when switching to a new document.
" + - "Also, most Ctrl-prefixed shortcut keys are available in this mode for navigation." + short_help: "Start QuickHint mode, but open link in a new tab", + usage: ["F{hint}"], + help: "Like normal QuickMode (activated with f) but open the link in a new tab." } )); +// addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], ["F"], +// function() { vimperator.echo("Always HINT mode not available anymore"); }, +// { +// short_help: "Start AlwaysHint mode (CURRENTLY DISABLED)", +// help: "In AlwaysHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a label.
" + +// "If you then press the keys for a label, it is followed as soon as it can be uniquely identified. Labels stay active after following a hint in this mode, press <Esc> to stop this mode.
" + +// "This hint mode is especially useful for browsing large sites like Forums as hints are automatically regenerated when switching to a new document.
" + +// "Also, most Ctrl-prefixed shortcut keys are available in this mode for navigation." +// } +// )); addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], [";"], - function(arg) { vimperator.hints.show(vimperator.modes.EXTENDED_HINT, arg); }, + function(arg) { - short_help: "Start ExtendedHint mode", + if (arg == "a") + vimperator.hints.show(vimperator.modes.ALWAYS_HINT, "o"); + else if (arg == "A") + vimperator.hints.show(vimperator.modes.ALWAYS_HINT, "t"); + else + vimperator.hints.show(vimperator.modes.EXTENDED_HINT, arg); + }, + { + short_help: "Start an extended Hint mode", usage: [";{mode}{hint}"], help: "ExtendedHint mode is useful, since in this mode you can yank link locations, open them in a new window or save images.
" + "If you want to yank the location of hint 24, press ;y to start this hint mode.
" +