function Map(mode, cmd, action, extra_info)
{
if (!mode || (!cmd || !cmd.length) || !action) return;
if (!extra_info) extra_info = {};
this.mode = mode;
this.cmd = cmd;
this.action = action;
this.flags = extra_info.flags || 0;
if (extra_info.usage)
this.usage = extra_info.usage;
else
{
var usage = "";
if (flags & vimperator.mappings.flags.COUNT)
usage = "{count}";
usage += cmd;
if (flags & vimperator.mappings.flags.ARGUMENT)
usage += " {arg}";
}
if (extra_info.help)
this.help = extra_info.help;
if (extra_info.short)
this.short = extra_info.short;
this.execute: function() {
this.cmd.call(this);
}
}
function Mappings()
{
this.main = [];
this.user = [];
this.flags = {
MOTION: 1 << 1;
COUNT: 1 << 2;
ARGUMENT: 1 << 3;
};
this.add: function(map)
{
if (!map) return;
if (!this.user[map.mode])
this.user[map.mode] = [];
this.user[map.mode].push(map);
return this;
}
this.remove: function(map)
{
var index;
if (!map || !(index = this.user[map.mode].indexOf(map)))
return;
this.user[map.mode].splice(index, 1);
return this;
}
this.get: function(mode, cmd)
{
if (!mode || !cmd) return;
var map = getFrom(mode, cmd, this.user);
if (!map) map = getFrom(mode, cmd, this.main);
return map;
}
function addDefaults(map)
{
if (!map) return;
if (!this.main[map.mode])
this.main[map.mode] = [];
this.main[map.mode].push(map);
return this;
}
function getFrom(mode, cmd, stack)
{
if (!stack || !stack[mode] || !stack[mode].length)
return;
var substack = stack[mode];
var stack_length = substack.length;
for (var i = 0; i < stack_length; i++)
{
for (var j = 0; j < substack[i].cmd.length; j++)
if (substack[i].cmd[j] == cmd)
return substack[i];
}
}
/* Default mappings
* Normal mode
* */
addDefaults(new Map(vimperator.mode.NORMAL, ["]f"], focusNextFrame, {short: "Focus next frame", help:
"Flashes the next frame in order with a red color, to quickly show where keyboard focus is.
"+
"This may not work correctly for frames with lots of CSS code."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["b"], function (args) { vimperator.commandline.open(":", "buffer ", vimperator.modes.EX); }, {
short: "Open a prompt to switch buffers", help:
"Typing the corresponding number opens switches to this buffer."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["B"], toggleBufferList, {short: "Toggle buffer list", help:
"Toggles the display of the buffer list which shows all opened tabs."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["d"], function(count) { vimperator.tabs.remove(getBrowser().mCurrentTab, count, false, 0); }, {
short: "Delete current buffer (=tab)", flags: this.flags.COUNT, help:
"Count WILL be supported in future releases, then 2d removes two tabs and the one the right is selected."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["D"], function(count) { vimperator.tabs.remove(getBrowser().mCurrentTab, count, true, 0); }, {
short: "Delete current buffer (=tab)", flags: this.flags.COUNT, help:
"Count WILL be supported in future releases, then 2d removes two tabs and the one the right is selected."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["gh"], BrowserHome, {short: "Go home", help:
"Opens the homepage in the current tab."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["gH"], BrowserHome, {short: "Go home in a new tab", help:
"Opens the homepage in a new tab."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["gP"], function(count) { openURLsInNewTab(readFromClipboard(), false); }, {
short: "Open (put) an URL based on the current clipboard contents in a new buffer",
help: "Works like P, but inverts the 'activate' setting."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["gt", "", ""],
function(count) { vimperator.tabs.select(count > 0 ? count -1: "+1", count > 0 ? false : true); }, {
short: "Go to the next tab", flags: this.flags.COUNT,
help: "Cycles to the first tab, when the last is selected.
Count is supported, 3gt goes to the third tab."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["gT", "", ""],
function(count) { vimperator.tabs.select(count > 0 ? count -1: "-1", count > 0 ? false : true); }, {
short: "Go to the previous tab", flags: this.flags.COUNT,
help: "Cycles to the last tab, when the first is selected.
Count is supported, 3gT goes to the third tab."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["m"], set_location_mark, {short: "Set mark at the cursor position", usage: "m{a-zA-Z}",
help: "Marks a-z are local to the buffer, whereas A-Z are valid between buffers", flags: this.flags.ARGUMENT
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["o"], function(count) { vimperator.commandline.open(":", "open ", vimperator.modes.EX) }, {
short: "Open one or more URLs in the current tab",
help: "See :open for more details."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["O"],
function(count) { vimperator.commandline.open(":", "open " + getCurrentLocation(), vimperator.modes.EX); }, {
short: "Open one ore more URLs in the current tab, based on current location",
help: "Works like o, but preselects current URL in the :open query."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["p", ""],
function(count) { openURLs(readFromClipboard()); }, {
short: "Open (put) an URL based on the current clipboard contents in the current buffer",
help: "You can also just select some non-URL text, and search for it with the default search engine or keyword (specified by the 'defsearch' setting) with p."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["P"],
function(count) { openURLsInNewTab(readFromClipboard(), true); }, {
short: "Open (put) an URL based on the current clipboard contents in a new buffer",
help: "Works like p, but opens a new tab.
" +
"Whether the new buffer is activated, depends on the 'activate' setting."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["r"], function(count) { reload(getBrowser().mCurrentTab, false); }, {
short: "Reload", help: "Forces reloading of the current page."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["R"], function(count) { reload(getBrowser().mCurrentTab, true); }, {
short: "Reload while skipping the cache", help: "Forces reloading of the current page skipping the cache."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["t"], function(count) { vimperator.commandline.open(":", "tabopen ", vimperator.modes.EX); }, {
short: "Open one or more URLs in a new tab",
help: "Like o but open URLs in a new tab.
"+
"See :tabopen for more details."
}));
addDefaults(new Map(vimperator.mode.NORMAL, ["T"],
function(count) { vimperator.commandline.open(":", "tabopen " + getCurrentLocation(), vimperator.modes.EX); }, {
short: "Open one ore more URLs in a new tab, based on current location",
help: "Works like t, but preselects current URL in the :tabopen query.",
}));
var normal_maps = [
[
["u"],
["{count}u"],
"Undo closing of a tab",
"If a count is given, don't close the last but the n'th last tab.",
function(count) { execute_command(count, 'undo', false, ''); },
this.flags.COUNT
],
[
["y"],
["y"],
"Yank current location to the clipboard",
"Under UNIX the location is also put into the selection, which can be pasted with the middle mouse button.",
yankCurrentLocation
],
[
["Y"],
["Y"],
"Copy selected text",
"The currently selected text is copied to the system clipboard.",
yankCurrentSelection,
null
],
[
["zi", "+"],
["zi", "+"],
"Zoom in current web page by 25%",
"Currently no count supported.",
function(count) { zoom_in(1); }
],
[
["zI"],
["zI"],
"Zoom in current web page by 100%",
"Currently no count supported.",
function(count) { zoom_in(4); }
],
[
["zo", "-"],
["zo", "-"],
"Zoom out current web page by 25%",
"Currently no count supported.",
function(count) { zoom_in(-1); }
],
[
["zO"],
["zO"],
"Zoom out current web page by 100%",
"Currently no count supported.",
function(count) { zoom_in(-4); }
],
[
["zz"],
["{count}zz"],
"Set zoom value of the webpage",
"Zoom value can be between 25 and 500%. If it is omitted, zoom is reset to 100%.",
zoom_to,
this.flags.COUNT
],
[
["ZQ"],
["ZQ"],
"Quit and don't save the session",
"Works like :qall.",
function(count) { quit(false); }
],
[
["ZZ"],
["ZZ"],
"Quit and save the session",
"Quit Vimperator, no matter how many tabs/windows are open. The session is stored.
" +
"Works like :xall.",
function(count) { quit(true); }
],
/* scrolling commands */
[
["0", "^"],
["0", "^"],
"Scroll to the absolute left of the document",
"Unlike in vim, 0 and ^ work exactly the same way.",
function(count) { scrollBufferAbsolute(0, -1); }
],
[
["$"],
["$"],
"Scroll to the absolute right of the document",
null,
function(count) { scrollBufferAbsolute(100, -1); }
],
[
["gg", ""],
["{count}gg", "{count}"],
"Goto the top of the document",
"Count is supported, 35gg vertically goes to 35% of the document.",
function(count) { scrollBufferAbsolute(-1, count > 0 ? count : 0); },
this.flags.COUNT
],
[
["G", ""],
["{count}G", "{count}"],
"Goto the end of the document",
"Count is supported, 35G vertically goes to 35% of the document.",
function(count) { scrollBufferAbsolute(-1, count >= 0 ? count : 100); },
this.flags.COUNT
],
[
["h", ""],
["{count}h", "{count}"],
"Scroll document to the left",
"Count is supported: 10h will move 10 times as much to the left.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(-1, 0); },
this.flags.COUNT
],
[
["j", "", ""],
["{count}j", "{count}", "{count}"],
"Scroll document down",
"Count is supported: 10j will move 10 times as much down.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(0, 1); },
this.flags.COUNT
],
[
["k", "", ""],
["{count}k", "{count}", "{count}"],
"Scroll document up",
"Count is supported: 10k will move 10 times as much up.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(0, -1); },
this.flags.COUNT
],
[
["l", ""],
["{count}l", "{count}"],
"Scroll document to the right",
"Count is supported: 10l will move 10 times as much to the right.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(1, 0); },
this.flags.COUNT
],
[
["", "", "", ""],
[""],
"Scroll up a full page of the current document",
"No count support for now.",
function(count) { goDoCommand('cmd_scrollPageUp'); }
],
[
["", "", "", ""],
[""],
"Scroll down a full page of the current document",
"No count support for now,",
function(count) { goDoCommand('cmd_scrollPageDown'); }
],
/* history manipulation and jumplist */
[
[""],
["{count}"],
"Go to an older position in the jump list",
"The jump list is just the browser history for now",
function(count) { stepInHistory(count > 0 ? -1 * count : -1); },
this.flags.COUNT
],
[
[""],
["{count}"],
"Go to a newer position in the jump list",
"The jump list is just the browser history for now",
function(count) { stepInHistory(count > 0 ? count : 1); },
this.flags.COUNT
],
[
["H", "", ""],
["{count}H", "{count}", "{count}"],
"Go back in the browser history",
"Count is supported, 3H goes back 3 steps.",
function(count) { stepInHistory(count > 0 ? -1 * count : -1); },
this.flags.COUNT
],
[
["L", "", ""],
["{count}L", "{count}", "{count}"],
"Go forward in the browser history",
"Count is supported, 3L goes forward 3 steps.",
function(count) { stepInHistory(count > 0 ? count : 1); },
this.flags.COUNT
],
[
["gu", ""],
["{count}gu", "{count}"],
"Go to parent directory",
"Count is supported, 2gu on http://www.example.com/dir1/dir2/file.htm would open http://www.example.com/dir1/.",
goUp,
this.flags.COUNT
],
[
["gU", ""],
["gU", ""],
"Go to the root of the website",
"gU on http://www.example.com/dir1/dir2/file.htm opens http://www.example.com/.
"+
"When browsing a local directory, it goes to the root document.",
function(count) { openURLs("..."); }
],
/* hint managment */
[
["f"],
["f"],
"Start QuickHint mode",
"In QuickHint 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 and this mode is stopped. Or press <Esc> to stop this mode.
"+
"If you write the hint in ALLCAPS, the hint is followed in a background tab.",
function(count) { hah.enableHahMode(vimperator.modes.QUICK_HINT); }
],
[
["F"],
["F"],
"Start AlwaysHint mode",
"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.",
function(count) { hah.enableHahMode(vimperator.modes.ALWAYS_HINT); }
],
[
[";"],
[";"],
"Start ExtendedHint mode",
"ExtendedHint mode is useful, since in this mode you can yank link locations, or open them in a new window.
"+
"E.g., if you want to yank the location of hint AB, press ; to start this hint mode.
"+
"Then press AB to select the hint. Now press y to yank its location.
"+
"Actions for selected hints in ExtendedHint mode are:
"+
"y to yank its location "+
" Y to yank its text description "+
" o to open its location in the current tab "+
" t to open its location in a new tab "+
" O to open its location in an :open query (not implemented yet) "+
" T to open its location in an :tabopen query (not implemented yet) "+
" s to save its destination (not implemented yet) "+
" <C-w> to open its destination in a new window "+
"
"+
"Multiple hints can be seperated by commas where it makes sense. ;ab,ac,adt opens AB, AC and AD in a new tab.
"+
"Hintable elements for this mode can be set in the 'extendedhinttags' XPath string.",
function(count) { hah.enableHahMode(vimperator.modes.EXTENDED_HINT); }
],
/* search managment */
[
["g/"],
["g/"],
"Search forward for a pattern",
"",
function(count) { vimperator.search.openSearchDialog(); }
],
[
["n"],
["n"],
"Find next",
"Repeat the last \"/\" 1 time (until count is supported).",
function(count) { vimperator.search.findNext(); }
],
[
["N"],
["N"],
"Find previous",
"Repeat the last \"/\" 1 time (until count is supported) in the opposite direction.",
function(count) { vimperator.search.findPrevious(); }
],
/* vimperator managment */
[
[""],
[""],
"Open help window",
"The default section is shown, if you need help for a specific topic, try :help <F1> (jumping to a specific section not implemented yet).",
function(count) { help(null); }
],
[
[":"],
[":"],
"Start command line mode",
"In command line mode, you can perform extended commands, which may require arguments.",
function(count) { vimperator.commandline.open(":", "", vimperator.modes.EX); }
],
[
["I"],
["I"],
"Disable vimperator keys",
"Starts an 'ignorekeys' mode, where all keys except <Esc> are passed to the next event handler.
"+
"This is especially useful, if JavaScript controlled forms like the RichEdit form fields of GMail don't work anymore.
" +
"To exit this mode, press <Esc>. If you also need to pass <Esc>"+
"in this mode to the webpage, prepend it with <C-v>.",
function(count) { vimperator.addMode(null, vimperator.modes.ESCAPE_ALL_KEYS);}
],
[
[""], // if you ever add/remove keys here, also check them in the onVimperatorKeypress() function
[""],
"Escape next key",
"If you need to pass a certain key to a javascript form field or another extension prefix the key with <C-v>.
"+
"Also works to unshadow Firefox shortcuts like <C-o> which are otherwise hidden in Vimperator.
"+
"When in 'ignorekeys' mode (activated by <I>), <C-v> will pass the next key to Vimperator instead of the webpage.",
function(count) { vimperator.addMode(null, vimperator.modes.ESCAPE_ONE_KEY); }
],
[
[""],
[""],
"Stop loading",
"Stops loading the current webpage.",
BrowserStop
],
[
["", ""], // if you ever add/remove keys here, also check them in the onVimperatorKeypress() function
["", ""],
"Cancel any operation",
"Exits any command line or hint mode and returns to browser mode.
"+
"Also focuses the web page, in case a form field has focus and eats our key presses.",
onEscape
]
];
var hint_maps = [
/* hint action keys */
["o", "hah.openHints(false, false);", true, false],
["t", "hah.openHints(true, false);", true, false],
["", "hah.openHints(false, true );", true, false],
["s", "vimperator.echoerr('Saving of links not yet implemented');", true, false],
["y", "hah.yankUrlHints();", true, false],
["Y", "hah.yankTextHints();", true, false],
[",", "g_inputbuffer+=','; hah.setCurrentState(0);", false, true],
[":", "vimperator.commandline.open(':', '', vimperator.modes.EX);", false, true],
/* movement keys */
["", "scrollBufferRelative(0, 1);", false, true],
["", "scrollBufferRelative(0, -1);", false, true],
["", "scrollBufferAbsolute(-1, 0);", false, true],
["", "scrollBufferAbsolute(-1, 100);", false, true],
["", "goDoCommand('cmd_scrollPageUp');", false, true],
["", "goDoCommand('cmd_scrollPageUp');", false, true],
["", "goDoCommand('cmd_scrollPageDown');", false, true],
["", "goDoCommand('cmd_scrollPageDown');", false, true],
["", "scrollBufferRelative(-1, 0);", false, true],
["", "scrollBufferRelative(0, 1);", false, true],
["", "scrollBufferRelative(0, -1);", false, true],
["", "scrollBufferRelative(1, 0);", false, true],
/* tab managment */
["", "vimperator.tabs.select('+1', true)", true, true], // same as gt, but no count supported
["", "vimperator.tabs.select('-1', true)", true, true],
/* navigation */
["", "stepInHistory(g_count > 0 ? -1 * g_count : -1);", false, true],
["", "stepInHistory(g_count > 0 ? g_count : 1);", false, true],
["", "stepInHistory(g_count > 0 ? -1 * g_count : -1);", false, true],
["", "stepInHistory(g_count > 0 ? g_count : 1);", false, true],
["", "vimperator.tabs.remove(getBrowser().mCurrentTab, g_count, false, 0);", true, true],
/* cancel hint mode keys */
["", "", true, true],
["", "", true, true],
["", "", true, true],
["", "", true, true]
];
}
// vim: set fdm=marker sw=4 ts=4 et: