From 57debc00e052a1830176e4945a2e132d2c0ab234 Mon Sep 17 00:00:00 2001 From: Martin Stubenschrott Date: Fri, 29 Feb 2008 14:46:33 +0000 Subject: [PATCH] * renamed shortHelp -> decription * refactored abbreviation and mapping commands (actually 200 LOC less now :) --- content/buffer.js | 61 +++--- content/commands.js | 420 +++++------------------------------------- content/completion.js | 10 +- content/editor.js | 42 +++++ content/hints.js | 4 +- content/mail.js | 1 + content/mappings.js | 142 +++++++++++--- content/muttator.js | 7 +- content/options.js | 2 +- content/tabs.js | 12 +- content/util.js | 4 +- content/vim.js | 102 +++++----- content/vimperator.js | 43 ++++- 13 files changed, 357 insertions(+), 493 deletions(-) diff --git a/content/buffer.js b/content/buffer.js index 431b90c6..c15cdca0 100644 --- a/content/buffer.js +++ b/content/buffer.js @@ -140,6 +140,7 @@ vimperator.Buffer = function () //{{{ } + /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// OPTIONS ///////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ @@ -279,11 +280,11 @@ vimperator.Buffer = function () //{{{ vimperator.mappings.add(modes, ["gf"], "View source", - function () { vimperator.commands.viewsource(); }); + function () { vimperator.buffer.viewSource(null, false); }); vimperator.mappings.add(modes, ["gF"], "View source with an external editor", - function () { vimperator.commands.viewsource(null, true); }); + function () { vimperator.buffer.viewSource(null, true); }); vimperator.mappings.add(modes, ["gi"], "Focus last used input field", @@ -446,32 +447,7 @@ vimperator.Buffer = function () //{{{ vimperator.commands.add(["vie[wsource]"], "View source code of current document", - function (args, special) - { - var url = args || vimperator.buffer.URL; - if (special) // external editor - { - // TODO: make that a helper function - // TODO: save return value in v:shell_error - var newThread = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0); - var editor = vimperator.options["editor"]; - var args = editor.split(" "); // FIXME: too simple - if (args.length < 1) - { - vimperator.open("view-source:" + url) - vimperator.echoerr("no editor specified"); - return; - } - - var prog = args.shift(); - args.push(url) - vimperator.callFunctionInThread(newThread, vimperator.io.run, [prog, args, true]); - } - else - { - vimperator.open("view-source:" + url) - } - }); + function (args, special) { vimperator.buffer.viewSource(args, special) }); vimperator.commands.add(["zo[om]"], "Set zoom value of current web page", @@ -1320,7 +1296,7 @@ vimperator.Buffer = function () //{{{ vimperator.beep(); }, - viewSelectionSource: function() + viewSelectionSource: function () { // copied (and tuned somebit) from browser.jar -> nsContextMenu.js var focusedWindow = document.commandDispatcher.focusedWindow; @@ -1338,6 +1314,33 @@ vimperator.Buffer = function () //{{{ window.openDialog("chrome://global/content/viewPartialSource.xul", "_blank", "scrollbars,resizable,chrome,dialog=no", docUrl, docCharset, reference, "selection"); + }, + + // url is optional + viewSource: function (url, useExternalEditor) + { + var url = url || vimperator.buffer.URL; + if (useExternalEditor) + { + // TODO: make that a helper function + // TODO: save return value in v:shell_error + var newThread = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0); + var editor = vimperator.options["editor"]; + var args = editor.split(" "); // FIXME: too simple + if (args.length < 1) + { + vimperator.echoerr("no editor specified"); + return; + } + + var prog = args.shift(); + args.push(url) + vimperator.callFunctionInThread(newThread, vimperator.io.run, [prog, args, true]); + } + else + { + vimperator.open("view-source:" + url) + } } }; //}}} diff --git a/content/commands.js b/content/commands.js index be8bb32a..56817b92 100644 --- a/content/commands.js +++ b/content/commands.js @@ -26,11 +26,16 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ -vimperator.Command = function (specs, action, extraInfo) //{{{ +// Do NOT create instances of this class yourself, use the helper method +// vimperator.commands.add() instead +vimperator.Command = function (specs, description, action, extraInfo) //{{{ { if (!specs || !action) return null; + if (!extraInfo) + extraInfo = {}; + // convert command name abbreviation specs of the form // 'shortname[optional-tail]' to short and long versions Eg. 'abc[def]' -> // 'abc', 'abcdef' @@ -59,28 +64,19 @@ vimperator.Command = function (specs, action, extraInfo) //{{{ return { names: names, longNames: longNames, shortNames: shortNames }; }; - this.specs = specs; var expandedSpecs = parseSpecs(specs); + this.specs = specs; this.shortNames = expandedSpecs.shortNames; - this.longNames = expandedSpecs.longNames; + this.longNames = expandedSpecs.longNames; // return the primary command name (the long name of the first spec listed) - this.name = this.longNames[0]; - - // return all command name aliases - this.names = expandedSpecs.names; - - this.action = action; - - if (extraInfo) - { - this.help = extraInfo.help || null; - this.shortHelp = extraInfo.shortHelp || null; - this.completer = extraInfo.completer || null; - this.args = extraInfo.args || []; - this.isUserCommand = extraInfo.isUserCommand || false; - } - + this.name = this.longNames[0]; + this.names = expandedSpecs.names; // return all command name aliases + this.description = extraInfo.description || ""; + this.action = action; + this.completer = extraInfo.completer || null; + this.args = extraInfo.args || []; + this.isUserCommand = extraInfo.isUserCommand || false; }; vimperator.Command.prototype = { @@ -475,15 +471,9 @@ vimperator.Commands = function () //{{{ return commandsIterator(); }, - // FIXME - // TODO: should commands added this way replace existing commands? add: function (names, description, action, extra) { - var extra = extra || {}; - if (!extra.shortHelp) - extra.shortHelp = description; - - var command = new vimperator.Command(names, action, extra); + var command = new vimperator.Command(names, description, action, extra); if (!command) return false; @@ -491,28 +481,26 @@ vimperator.Commands = function () //{{{ { if (exCommands[i].name == command.name) { - //if (!replace) - return false; // never replace for now - //else - // break; + // never replace for now + vimperator.log("Warning: :" + names[0] + " already exists, NOT replacing existing command.", 2); + return false; } } - - // add an alias, so that commands can be accessed with - // vimperator.commands.zoom("130") - this[command.name] = function (args, special, count, modifiers) - { - command.execute(args, special, count, modifiers); - }; - exCommands.push(command); return true; }, - // TODO: will change it's interface/semantics later! - addUserCommand: function (command, replace) + addUserCommand: function (names, description, action, extra, replace) { + var extra = extra || {}; + extra.isUserCommand = true; + description = description || "User defined command"; + + var command = new vimperator.Command(names, description, action, extra); + if (!command) + return false; + for (var i = 0; i < exCommands.length; i++) { if (exCommands[i].name == command.name) @@ -524,13 +512,6 @@ vimperator.Commands = function () //{{{ } } - // add an alias, so that commands can be accessed with - // vimperator.commands.zoom("130") - this[command.name] = function (args, special, count, modifiers) - { - command.execute(args, special, count, modifiers); - }; - exCommands.push(command); return true; }, @@ -591,24 +572,11 @@ vimperator.Commands = function () //{{{ }; /////////////////////////////////////////////////////////////////////////////}}} - ////////////////////// DEFAULT COMMANDS //////////////////////////////////////// + ////////////////////// COMMANDS //////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - // move to vim.js: - - commandManager.addUserCommand(new vimperator.Command(["q[uit]"], - function () { vimperator.tabs.remove(getBrowser().mCurrentTab, 1, false, 1); }, - { shortHelp: "Quit current tab" } - )); - // TODO: check for "tabs" feature - commandManager.addUserCommand(new vimperator.Command(["quita[ll]", "qa[ll]"], - function () { vimperator.quit(false); }, - { shortHelp: "Quit Vimperator", } - )); - - - // TODO: move where? (commands.js would be fine, but timing issue) - commandManager.addUserCommand(new vimperator.Command(["com[mand]"], + commandManager.add(["com[mand]"], + "List and define commands", function (args, special) { if (args) @@ -624,8 +592,13 @@ vimperator.Commands = function () //{{{ if (rep) { - if (!vimperator.commands.addUserCommand(new vimperator.Command([cmd], function (args, special, count, modifiers) { eval(rep) }, { isUserCommand: rep } ), special)) + if (!vimperator.commands.addUserCommand([cmd], + "User defined command", + function (args, special, count, modifiers) { eval(rep) }), + special); + { vimperator.echoerr("E174: Command already exists: add ! to replace it"); + } } else { @@ -644,323 +617,16 @@ vimperator.Commands = function () //{{{ } }, { - shortHelp: "Lists and defines commands" /*, - args: [[["-nargs"], OPTION_STRING, function (arg) { return /^(0|1|\*|\?|\+)$/.test(arg); }], + /*args: [[["-nargs"], OPTION_STRING, function (arg) { return /^(0|1|\*|\?|\+)$/.test(arg); }], [["-bang"], OPTION_NOARG], [["-bar"], OPTION_NOARG]] */ - } - )); + }); - // TODO: part of vimperator.js or vim.js? - commandManager.addUserCommand(new vimperator.Command(["o[pen]", "e[dit]"], - function (args, special) - { - if (args) - { - vimperator.open(args); - } - else - { - if (special) - BrowserReloadSkipCache(); - else - BrowserReload(); - } - }, - { - shortHelp: "Open one or more URLs in the current tab", - completer: function (filter) { return vimperator.completion.url(filter); } - } - )); + // TODO: remove preview window, or change it at least + commandManager.add(["pc[lose]"], + "Close preview window on bottom of screen", + function () { vimperator.previewwindow.hide(); }); - // move to editor.js: - TODO: unify - commandManager.addUserCommand(new vimperator.Command(["ab[breviate]"], - function (args) - { - if (!args) - { - vimperator.editor.listAbbreviations("!", ""); - return; - } - - var matches = args.match(/^([^\s]+)(?:\s+(.+))?$/); - var [lhs, rhs] = [matches[1], matches[2]]; - if (rhs) - vimperator.editor.addAbbreviation("!", lhs, rhs); - else - vimperator.editor.listAbbreviations("!", lhs); - }, - { - shortHelp: "Abbreviate a key sequence" - } - )); - commandManager.addUserCommand(new vimperator.Command(["ca[bbrev]"], - function (args) - { - if (!args) - { - vimperator.editor.listAbbreviations("c", ""); - return; - } - - var matches = args.match(/^([^\s]+)(?:\s+(.+))?$/); - var [lhs, rhs] = [matches[1], matches[2]]; - if (rhs) - vimperator.editor.addAbbreviation("c", lhs, rhs); - else - vimperator.editor.listAbbreviations("c", lhs); - }, - { - shortHelp: "Abbreviate a key sequence for Command-line mode" - } - )); - commandManager.addUserCommand(new vimperator.Command(["ia[bbrev]"], - function (args) - { - if (!args) - { - vimperator.editor.listAbbreviations("i", ""); - return; - } - - var matches = args.match(/^([^\s]+)(?:\s+(.+))?$/); - var [lhs, rhs] = [matches[1], matches[2]]; - if (rhs) - vimperator.editor.addAbbreviation("i", lhs, rhs); - else - vimperator.editor.listAbbreviations("i", lhs); - }, - { shortHelp: "Abbreviate a key sequence for Insert mode" } - )); - commandManager.addUserCommand(new vimperator.Command(["una[bbreviate]"], - function (args) { vimperator.editor.removeAbbreviation("!", args); }, - { shortHelp: "Remove an abbreviation" } - )); - commandManager.addUserCommand(new vimperator.Command(["cuna[bbrev]"], - function (args) { vimperator.editor.removeAbbreviation("c", args); }, - { shortHelp: "Remove an abbreviation for Command-line mode" } - )); - commandManager.addUserCommand(new vimperator.Command(["iuna[bbrev]"], - function (args) { vimperator.editor.removeAbbreviation("i", args); }, - { shortHelp: "Remove an abbreviation for Insert mode" } - )); - commandManager.addUserCommand(new vimperator.Command(["abc[lear]"], - function (args) { vimperator.editor.removeAllAbbreviations("!"); }, - { shortHelp: "Remove all abbreviations" } - )); - commandManager.addUserCommand(new vimperator.Command(["cabc[lear]"], - function (args) { vimperator.editor.removeAllAbbreviations("c"); }, - { shortHelp: "Remove all abbreviations for Command-line mode" } - )); - commandManager.addUserCommand(new vimperator.Command(["iabc[lear]"], - function (args) { vimperator.editor.removeAllAbbreviations("i"); }, - { shortHelp: "Remove all abbreviations for Insert mode" } - )); - - // TODO: add helper method: addMappingCommand - // 0 args -> list all maps - // 1 arg -> list the maps starting with args - // 2 args -> map arg1 to arg* - function map(args, mode, noremap) - { - if (!args) - { - vimperator.mappings.list(mode); - return; - } - - // ?:\s+ <- don't remember; (...)? optional = rhs - var [, lhs, rhs] = args.match(/(\S+)(?:\s+(.+))?/); - var leaderRegexp = //i; - - if (leaderRegexp.test(lhs)) - lhs = lhs.replace(leaderRegexp, vimperator.events.getMapLeader()); - - if (!rhs) // list the mapping - { - vimperator.mappings.list(mode, lhs); - } - else - { - for (var index = 0; index < mode.length; index++) - { - vimperator.mappings.addUserMap(new vimperator.Map([mode[index]], [lhs], - function (count) { vimperator.events.feedkeys((count > 1 ? count : "") + rhs, noremap); }, - { flags: vimperator.Mappings.flags.COUNT, rhs: rhs, noremap: noremap} - )); - } - } - } - commandManager.addUserCommand(new vimperator.Command(["map"], - function (args) { map(args, [vimperator.modes.NORMAL], false); }, - { shortHelp: "Map the key sequence {lhs} to {rhs}" } - )); - commandManager.addUserCommand(new vimperator.Command(["cm[ap]"], - function (args) { map(args, [vimperator.modes.COMMAND_LINE], false); }, - { shortHelp: "Map the key sequence {lhs} to {rhs} (in command-line mode)" } - )); - commandManager.addUserCommand(new vimperator.Command(["im[ap]"], - function (args) { map(args, [vimperator.modes.INSERT, vimperator.modes.TEXTAREA], false); }, - { shortHelp: "Map the key sequence {lhs} to {rhs} (in insert mode)" } - )); - commandManager.addUserCommand(new vimperator.Command(["mapc[lear]"], - function (args) - { - if (args) - { - vimperator.echoerr("E474: Invalid argument"); - return; - } - - vimperator.mappings.removeAll(vimperator.modes.NORMAL); - }, - { - shortHelp: "Remove all mappings" - } - )); - commandManager.addUserCommand(new vimperator.Command(["cmapc[lear]"], - function (args) - { - if (args) - { - vimperator.echoerr("E474: Invalid argument"); - return; - } - - vimperator.mappings.removeAll(vimperator.modes.COMMAND_LINE); - }, - { - shortHelp: "Remove all mappings (in command-line mode)" - } - )); - commandManager.addUserCommand(new vimperator.Command(["imapc[lear]"], - function (args) - { - if (args) - { - vimperator.echoerr("E474: Invalid argument"); - return; - } - - vimperator.mappings.removeAll(vimperator.modes.INSERT); - vimperator.mappings.removeAll(vimperator.modes.TEXTAREA); - }, - { - shortHelp: "Remove all mappings (in insert mode)" - } - )); - // TODO: remove duplication in :map - commandManager.addUserCommand(new vimperator.Command(["no[remap]"], - function (args) { map(args, [vimperator.modes.NORMAL], true); }, - { shortHelp: "Map the key sequence {lhs} to {rhs}" } - )); - // XXX: TODO: remove duplication in :cmap - commandManager.addUserCommand(new vimperator.Command(["cno[remap]"], - function (args) { map(args, [vimperator.modes.COMMAND_LINE], true); }, - { shortHelp: "Map the key sequence {lhs} to {rhs} (in command-line mode)" } - )); - commandManager.addUserCommand(new vimperator.Command(["ino[remap]"], - function (args) { map(args, [vimperator.modes.INSERT, vimperator.modes.TEXTAREA], true); }, - { shortHelp: "Map the key sequence {lhs} to {rhs} (in insert mode)" } - )); - commandManager.addUserCommand(new vimperator.Command(["unm[ap]"], - function (args) - { - if (!args) - { - vimperator.echoerr("E474: Invalid argument"); - return; - } - - var lhs = args; - - if (vimperator.mappings.hasMap(vimperator.modes.NORMAL, lhs)) - vimperator.mappings.remove(vimperator.modes.NORMAL, lhs); - else - vimperator.echoerr("E31: No such mapping"); - }, - { - shortHelp: "Remove the mapping of {lhs}" - } - )); - commandManager.addUserCommand(new vimperator.Command(["cunm[ap]"], - function (args) - { - if (!args) - { - vimperator.echoerr("E474: Invalid argument"); - return; - } - - var lhs = args; - - if (vimperator.mappings.hasMap(vimperator.modes.COMMAND_LINE, lhs)) - vimperator.mappings.remove(vimperator.modes.COMMAND_LINE, lhs); - else - vimperator.echoerr("E31: No such mapping"); - }, - { - shortHelp: "Remove the mapping of {lhs} (in command-line mode)" - } - )); - commandManager.addUserCommand(new vimperator.Command(["iunm[ap]"], - function (args) - { - if (!args) - { - vimperator.echoerr("E474: Invalid argument"); - return; - } - - var lhs = args; - var flag = false; - - if (vimperator.mappings.hasMap(vimperator.modes.INSERT, lhs)) - { - vimperator.mappings.remove(vimperator.modes.INSERT, lhs); - flag = true; - } - if (vimperator.mappings.hasMap(vimperator.modes.TEXTAREA, lhs)) - { - vimperator.mappings.remove(vimperator.modes.TEXTAREA, lhs); - flag = true; - } - if (!flag) - vimperator.echoerr("E31: No such mapping"); - }, - { - shortHelp: "Remove the mapping of {lhs} (in insert mode)" - } - )); - - // TODO: remove/change preview window - commandManager.addUserCommand(new vimperator.Command(["pc[lose]"], - function () { vimperator.previewwindow.hide(); }, - { shortHelp: "Close preview window on bottom of screen" } - )); - - // TODO: check for v.has("windows") - commandManager.addUserCommand(new vimperator.Command(["winc[lose]", "wc[lose]"], - function (args) { window.close(); }, - { shortHelp: "Close window" } - )); - commandManager.addUserCommand(new vimperator.Command(["wino[pen]", "wo[pen]", "wine[dit]"], - function (args) - { - if (args) - vimperator.open(args, vimperator.NEW_WINDOW); - else - vimperator.open("about:blank", vimperator.NEW_WINDOW); - }, - { - shortHelp: "Open one or more URLs in a new window" - } - )); - // TODO: check for v.has("session")? - commandManager.addUserCommand(new vimperator.Command(["wqa[ll]", "wq", "xa[ll]"], - function () { vimperator.quit(true); }, - { shortHelp: "Save the session and quit" } - )); //}}} return commandManager; diff --git a/content/completion.js b/content/completion.js index 4f965ddc..27ea486b 100644 --- a/content/completion.js +++ b/content/completion.js @@ -305,12 +305,12 @@ vimperator.Completion = function () //{{{ if (!filter) { for (var command in vimperator.commands) - completions.push([command.name, command.shortHelp]); + completions.push([command.name, command.description]); return [0, completions]; } for (var command in vimperator.commands) - completions.push([command.longNames, command.shortHelp]); + completions.push([command.longNames, command.description]); return [0, buildLongestStartingSubstring(completions, filter)]; }, @@ -333,7 +333,7 @@ vimperator.Completion = function () //{{{ { if (prefix && option.type != "boolean") continue; - options.push([option.names, option.shortHelp]); + options.push([option.names, option.description]); } return options; } @@ -381,7 +381,7 @@ vimperator.Completion = function () //{{{ { if (prefix && option.type != "boolean") continue; - options.push([prefix + option.name, option.shortHelp]); + options.push([prefix + option.name, option.description]); } return [0, options]; } @@ -421,7 +421,7 @@ vimperator.Completion = function () //{{{ return option.names[j].indexOf($_) == 0; }); } - optionCompletions.push([prefix + option.names[j], option.shortHelp]); + optionCompletions.push([prefix + option.names[j], option.description]); break; } } diff --git a/content/editor.js b/content/editor.js index e14c6b3f..12e9e7ad 100644 --- a/content/editor.js +++ b/content/editor.js @@ -148,6 +148,39 @@ vimperator.Editor = function () //{{{ { flags: vimperator.Mappings.flags.MOTION | vimperator.Mappings.flags.COUNT }); } + // mode = "i" -> add :iabbrev, :iabclear and :iunabbrev commands + function addAbbreviationCommands(char, modeDescription) + { + var modeDescription = modeDescription ? " in " + modeDescription + " mode" : ""; + var mode = char || "!"; + + vimperator.commands.add([char ? char + "a[bbrev]" : "ab[breviate]"], + "Abbreviate a key sequence" + modeDescription, + function (args) + { + if (!args) + { + vimperator.editor.listAbbreviations(mode, ""); + return; + } + + var matches = args.match(/^([^\s]+)(?:\s+(.+))?$/); + var [lhs, rhs] = [matches[1], matches[2]]; + if (rhs) + vimperator.editor.addAbbreviation(mode, lhs, rhs); + else + vimperator.editor.listAbbreviations(mode, lhs); + }); + + vimperator.commands.add([char ? char + "una[bbrev]" : "una[bbreviate]"], + "Remove an abbreviation" + modeDescription, + function (args) { vimperator.editor.removeAbbreviation(mode, args); }); + + vimperator.commands.add([char + "abc[lear]"], + "Remove all abbreviations" + modeDescription, + function (args) { vimperator.editor.removeAllAbbreviations(mode); }); + } + /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// OPTIONS ///////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ @@ -163,6 +196,7 @@ vimperator.Editor = function () //{{{ /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// MAPPINGS //////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ + var modes = [vimperator.modes.INSERT, vimperator.modes.COMMAND_LINE]; /* KEYS COUNT CARET TEXTAREA VISUAL_TEXTAREA */ @@ -400,6 +434,14 @@ vimperator.Editor = function () //{{{ }, { flags: vimperator.Mappings.flags.ARGUMENT | vimperator.Mappings.flags.COUNT}); + /////////////////////////////////////////////////////////////////////////////}}} + ////////////////////// COMMANDS //////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + addAbbreviationCommands("", ""); + addAbbreviationCommands("i", "insert"); + addAbbreviationCommands("c", "command line"); + /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// PUBLIC SECTION ////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ diff --git a/content/hints.js b/content/hints.js index 7d7c9a4b..e90ba520 100644 --- a/content/hints.js +++ b/content/hints.js @@ -350,8 +350,8 @@ vimperator.Hints = function () //{{{ case "O": vimperator.commandline.open(":", "open " + loc, vimperator.modes.EX); break; case "t": vimperator.buffer.followLink(elem, vimperator.NEW_TAB); break; case "T": vimperator.commandline.open(":", "tabopen " + loc, vimperator.modes.EX); break; - case "v": vimperator.commands.viewsource(loc); break; - case "V": vimperator.commands.viewsource(loc, true); break; + case "v": vimperator.buffer.viewSource(loc, false); break; + case "V": vimperator.buffer.viewSource(loc, true); break; case "w": vimperator.buffer.followLink(elem, vimperator.NEW_WINDOW); break; case "W": vimperator.commandline.open(":", "winopen " + loc, vimperator.modes.EX); break; case "y": setTimeout(function(){vimperator.copyToClipboard(loc, true)}, timeout + 50); break; diff --git a/content/mail.js b/content/mail.js index f4c91656..c22950c7 100644 --- a/content/mail.js +++ b/content/mail.js @@ -46,6 +46,7 @@ vimperator.Mail = function () /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// MAPPINGS //////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ + var modes = vimperator.config.mailModes || [vimperator.modes.NORMAL]; vimperator.mappings.add(modes, ["", "i"], diff --git a/content/mappings.js b/content/mappings.js index 027feaf0..ca43084f 100644 --- a/content/mappings.js +++ b/content/mappings.js @@ -26,24 +26,25 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ -vimperator.Map = function (modes, cmds, action, extraInfo) //{{{ +// Do NOT create instances of this class yourself, use the helper method +// vimperator.mappings.add() instead +vimperator.Map = function (modes, cmds, description, action, extraInfo) //{{{ { if (!modes || (!cmds || !cmds.length) || !action) return null; + if (!extraInfo) + extraInfo = {}; + this.modes = modes; - this.names = cmds; + // only store keysyms with uppercase modifier strings + this.names = cmds.map(function (cmd) { return cmd.replace(/[casm]-/g, function (name) { return name.toUpperCase(); });}); this.action = action; - if (extraInfo) - { - this.flags = extraInfo.flags || 0; - - this.shortHelp = extraInfo.shortHelp || ""; - - this.rhs = extraInfo.rhs || null; - this.noremap = extraInfo.noremap || false; - } + this.flags = extraInfo.flags || 0; + this.description = extraInfo.description || ""; + this.rhs = extraInfo.rhs || null; + this.noremap = extraInfo.noremap || false; }; vimperator.Map.prototype = { @@ -85,11 +86,6 @@ vimperator.Mappings = function () //{{{ user[mode] = []; } - function addDefaultMap(map) - { - map.modes.forEach(function (mode) { main[mode].push(map); }); - } - function addMap(map, userMap) { var where = userMap ? user : main; @@ -161,6 +157,104 @@ vimperator.Mappings = function () //{{{ throw StopIteration; } + function addMapCommands(char, modes, modeDescription) + { + // 0 args -> list all maps + // 1 arg -> list the maps starting with args + // 2 args -> map arg1 to arg* + function map(args, mode, noremap) + { + if (!args) + { + vimperator.mappings.list(mode); + return; + } + + // ?:\s+ <- don't remember; (...)? optional = rhs + var [, lhs, rhs] = args.match(/(\S+)(?:\s+(.+))?/); + var leaderRegexp = //i; + + if (leaderRegexp.test(lhs)) + lhs = lhs.replace(leaderRegexp, vimperator.events.getMapLeader()); + + if (!rhs) // list the mapping + { + vimperator.mappings.list(mode, lhs); + } + else + { + for (var index = 0; index < mode.length; index++) + { + vimperator.mappings.addUserMap([mode[index]], [lhs], + "User defined mapping", + function (count) { vimperator.events.feedkeys((count > 1 ? count : "") + rhs, noremap); }, + { + flags: vimperator.Mappings.flags.COUNT, + rhs: rhs, + noremap: noremap + }); + } + } + } + + var modeDescription = modeDescription ? " in " + modeDescription + " mode" : ""; + + vimperator.commands.add([char ? char + "m[ap]" : "map"], + "Map a key sequence" + modeDescription, + function (args) { map(args, modes, false); }); + + vimperator.commands.add([char + "no[remap]"], + "Map a key sequence without remapping keys" + modeDescription, + function (args) { map(args, modes, true); }); + + vimperator.commands.add([char + "mapc[lear]"], + "Remove all mappings" + modeDescription, + function (args) + { + if (args) + { + vimperator.echoerr("E474: Invalid argument"); + return; + } + + for (let i = 0; i < modes.length; i++) + vimperator.mappings.removeAll(modes[i]); + }); + + vimperator.commands.add([char + "unm[ap]"], + "Remove a mapping" + modeDescription, + function (args) + { + if (!args) + { + vimperator.echoerr("E474: Invalid argument"); + return; + } + + var flag = false; + for (let i = 0; i < modes.length; i++) + { + if (vimperator.mappings.hasMap(modes[i], args)) + { + vimperator.mappings.remove(modes[i], args); + flag = true; + } + } + if (!flag) + vimperator.echoerr("E31: No such mapping"); + }); + } + + /////////////////////////////////////////////////////////////////////////////}}} + ////////////////////// COMMANDS //////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + addMapCommands("", [vimperator.modes.NORMAL], ""); + addMapCommands("c", [vimperator.modes.COMMAND_LINE], "command line"); + addMapCommands("i", [vimperator.modes.INSERT, vimperator.modes.TEXTAREA], "insert"); + if (vimperator.has("mail")) + addMapCommands("m", [vimperator.modes.MESSAGE], "message"); + /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// PUBLIC SECTION ////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ @@ -189,25 +283,21 @@ vimperator.Mappings = function () //{{{ add: function (modes, keys, description, action, extra) { - addMap (new vimperator.Map(modes, keys, - action, { shortHelp: description, flags: (extra && extra.flags) ? extra.flags : 0 }), false); + addMap (new vimperator.Map(modes, keys, description, action, extra), false); }, - // TODO: change map to "easier" arguments - addUserMap: function (map) + addUserMap: function (modes, keys, description, action, extra) { - // a map can have multiple names + var map = new vimperator.Map(modes, keys, description || "User defined mapping", action, extra); + + // remove all old mappings to this key sequence for (var i = 0; i < map.names.length; i++) { - // only store keysyms with uppercase modifier strings - map.names[i] = map.names[i].replace(/[casm]-/g, function (name) { return name.toUpperCase(); }); for (var j = 0; j < map.modes.length; j++) removeMap(map.modes[j], map.names[i]); } - // all maps got removed (matching names = lhs), and added newly here - for (var k = 0; k < map.modes.length; k++) - user[map.modes[k]].push(map); + addMap (map, true); }, get: function (mode, cmd) diff --git a/content/muttator.js b/content/muttator.js index d6db5700..d797ead6 100644 --- a/content/muttator.js +++ b/content/muttator.js @@ -33,10 +33,12 @@ vimperator.config = { /*** optional options, there are checked for existance and a fallback provided ***/ features: ["hints", "mail", "marks"], + guioptions: { m: ["mail-toolbar-menubar2"], T: ["mail-bar2"], f: ["folderPaneBox", "folderpane_splitter"], F: ["folderPaneHeader"] }, + get browserModes() { return [vimperator.modes.MESSAGE]; }, get mainWidget() { return GetThreadTree(); }, // focusContent() focuses this widget mainWindowID: "messengerWindow", // used for :set titlestring - guioptions: { m: ["mail-toolbar-menubar2"], T: ["mail-bar2"], f: ["folderPaneBox", "folderpane_splitter"], F: ["folderPaneHeader"] }, + dialogs: [ /*["about", "About Firefox", function() { openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); }], @@ -83,9 +85,8 @@ vimperator.config = { init: function() { vimperator.mappings.add([vimperator.modes.NORMAL], - ["o"], "Open one or more URLs", + ["o"], "Open a message", function () { vimperator.commandline.open(":", "open ", vimperator.modes.EX); }); - } } diff --git a/content/options.js b/content/options.js index cff6dfed..f05abb52 100644 --- a/content/options.js +++ b/content/options.js @@ -38,7 +38,7 @@ vimperator.Option = function (names, description, type, defaultValue, getter, se this.name = names[0]; this.names = names; this.type = type; - this.shortHelp = description || ""; + this.description = description || ""; // "", 0 are valid default values this.defaultValue = (defaultValue === undefined) ? null : defaultValue; diff --git a/content/tabs.js b/content/tabs.js index 14eff3ac..992fd749 100644 --- a/content/tabs.js +++ b/content/tabs.js @@ -182,7 +182,7 @@ vimperator.Tabs = function () //{{{ vimperator.mappings.add([vimperator.modes.NORMAL], ["u"], "Undo closing of a tab", - function (count) { vimperator.commands.undo("", false, count); }, + function (count) { vimperator.commands.get("undo").execute("", false, count); }, { flags: vimperator.Mappings.flags.COUNT }); vimperator.mappings.add([vimperator.modes.NORMAL], ["", ""], @@ -238,6 +238,10 @@ vimperator.Tabs = function () //{{{ vimperator.buffer.list(special); }); + vimperator.commands.add(["quita[ll]", "qa[ll]"], + "Quit " + vimperator.config.appName, + function () { vimperator.quit(false); }); + vimperator.commands.add(["reloada[ll]"], "Reload all tab pages", function (args, special) { vimperator.tabs.reloadAll(special); }); @@ -394,6 +398,12 @@ vimperator.Tabs = function () //{{{ undoCloseTab(); // doesn't work with i as the index to undoCloseTab }); + if (vimperator.has("session")) + { + vimperator.commands.add(["wqa[ll]", "wq", "xa[ll]"], + "Save the session and quit", + function () { vimperator.quit(true); }); + } /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// PUBLIC SECTION ////////////////////////////////////////// diff --git a/content/util.js b/content/util.js index dde6bfe3..59eba5c1 100644 --- a/content/util.js +++ b/content/util.js @@ -134,7 +134,7 @@ vimperator.util = { //{{{ var ret = ""; var longHelp = false; - if ((command.help && command.shortHelp) && (command.help.length + command.shortHelp.length) > 50) + if ((command.help && command.description) && (command.help.length + command.description.length) > 50) longHelp = true; // the tags which are printed on the top right @@ -162,7 +162,7 @@ vimperator.util = { //{{{ // the actual help text if (command.shortHelp) { - ret += command.shortHelp + "."; // the help description + ret += command.description + "."; // the help description if (extraHelp) ret += " +\n" + extraHelp; } diff --git a/content/vim.js b/content/vim.js index bcd063cd..579cf287 100644 --- a/content/vim.js +++ b/content/vim.js @@ -103,7 +103,7 @@ const vimperator = (function () //{{{ { vimperator.mappings.add(vimperator.modes.all, [""], "Open help window", - function () { vimperator.commands.help(); }); + function () { vimperator.help(); }); vimperator.mappings.add([vimperator.modes.NORMAL], ["ZQ"], "Quit and don't save the session", @@ -160,7 +160,7 @@ const vimperator = (function () //{{{ { usage += " :" + vimperator.util.escapeHTML(command.name) + "" + - vimperator.util.escapeHTML(command.shortHelp) + ""; + vimperator.util.escapeHTML(command.description) + ""; } usage += ""; @@ -169,46 +169,7 @@ const vimperator = (function () //{{{ vimperator.commands.add(["h[elp]"], "Display help", - function (args, special, count, modifiers) - { - function jumpToTag(file, tag) - { - vimperator.open("chrome://" + vimperator.config.name.toLowerCase() + "/locale/" + file); - setTimeout(function() { - var elem = vimperator.buffer.getElement('@class="tag" and text()="' + tag + '"'); - if (elem) - window.content.scrollTo(0, elem.getBoundingClientRect().top - 10); // 10px context - else - dump('no element: ' + '@class="tag" and text()="' + tag + '"\n' ); - }, 200); - } - - if (!args) - { - vimperator.open("chrome://" + vimperator.config.name.toLowerCase() + "/locale/intro.html"); - return; - } - - var [, items] = vimperator.completion.help(args); - var partialMatch = -1; - for (var i = 0; i < items.length; i++) - { - if (items[i][0] == args) - { - jumpToTag(items[i][1], items[i][0]); - return; - } - else if (partialMatch == -1 && items[i][0].indexOf(args) > -1) - { - partialMatch = i; - } - } - - if (partialMatch > -1) - jumpToTag(items[partialMatch][1], items[partialMatch][0]); - else - vimperator.echoerr("E149: Sorry, no help for " + args); - }, + function (args) { vimperator.help(args); }, { completer: function (filter) { return vimperator.completion.help(filter); } }); @@ -268,6 +229,16 @@ const vimperator = (function () //{{{ vimperator.events.feedkeys(args, special); }); + vimperator.commands.add(["q[uit]"], + vimperator.has("tabs") ? "Quit current tab" : "Quit application", + function () + { + if (vimperator.has("tabs")) + vimperator.tabs.remove(getBrowser().mCurrentTab, 1, false, 1); + else + vimperator.quit(false); + }); + vimperator.commands.add(["res[tart]"], "Force " + vimperator.config.appName + " to restart", function () { vimperator.restart(); }); @@ -364,7 +335,7 @@ const vimperator = (function () //{{{ vimperator.open("about:"); else vimperator.echo(":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) + "\n" + - vimperator.config.appName + " " + vimperator.version + + vimperator.config.hostApplication + " " + vimperator.version + " running on:\n" + navigator.userAgent); }); @@ -377,7 +348,7 @@ const vimperator = (function () //{{{ { usage += " " + vimperator.util.escapeHTML(mapping.names[0]) + "" + - vimperator.util.escapeHTML(mapping.shortHelp || "") + ""; + vimperator.util.escapeHTML(mapping.description) + ""; } usage += ""; @@ -616,6 +587,47 @@ const vimperator = (function () //{{{ return features.some (function(feat) { return feat == feature; }); }, + help: function(topic) + { + function jumpToTag(file, tag) + { + vimperator.open("chrome://" + vimperator.config.name.toLowerCase() + "/locale/" + file); + setTimeout(function() { + var elem = vimperator.buffer.getElement('@class="tag" and text()="' + tag + '"'); + if (elem) + window.content.scrollTo(0, elem.getBoundingClientRect().top - 10); // 10px context + else + dump('no element: ' + '@class="tag" and text()="' + tag + '"\n' ); + }, 200); + } + + if (!topic) + { + vimperator.open("chrome://" + vimperator.config.name.toLowerCase() + "/locale/intro.html"); + return; + } + + var [, items] = vimperator.completion.help(topic); + var partialMatch = -1; + for (var i = 0; i < items.length; i++) + { + if (items[i][0] == topic) + { + jumpToTag(items[i][1], items[i][0]); + return; + } + else if (partialMatch == -1 && items[i][0].indexOf(topic) > -1) + { + partialMatch = i; + } + } + + if (partialMatch > -1) + jumpToTag(items[partialMatch][1], items[partialMatch][0]); + else + vimperator.echoerr("E149: Sorry, no help for " + topic); + }, + // logs a message to the javascript error console // if msg is an object, it is beautified log: function (msg, level) @@ -807,7 +819,7 @@ const vimperator = (function () //{{{ if (vimperator.options.getPref("extensions." + vimperator.config.name.toLowerCase() + ".firsttime", true)) { setTimeout(function () { - vimperator.commands.help(); + vimperator.help(); vimperator.options.setPref("extensions." + vimperator.config.name.toLowerCase() + ".firsttime", false); }, 1000); } diff --git a/content/vimperator.js b/content/vimperator.js index 2c8c425e..0430aa93 100644 --- a/content/vimperator.js +++ b/content/vimperator.js @@ -32,8 +32,9 @@ vimperator.config = { hostApplication: "Firefox", /*** optional options, there are checked for existance and a fallback provided ***/ - features: ["bookmarks", "history", "marks", "quickmarks", "hints", "tabs", "windows"], + features: ["bookmarks", "hints", "history", "marks", "quickmarks", "session", "tabs", "windows"], guioptions: { m: ["toolbar-menubar"], T: ["nav-bar"], b: ["PersonalToolbar"] }, + dialogs: [ ["about", "About Firefox", function() { openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); }], @@ -229,6 +230,26 @@ vimperator.config = { "Show progress of current downloads", function () { vimperator.open("chrome://mozapps/content/downloads/downloads.xul", vimperator.NEW_TAB); }); + vimperator.commands.add(["o[pen]", "e[dit]"], + "Open one or more URLs in the current tab", + function (args, special) + { + if (args) + { + vimperator.open(args); + } + else + { + if (special) + BrowserReloadSkipCache(); + else + BrowserReload(); + } + }, + { + completer: function (filter) { return vimperator.completion.url(filter); } + }); + vimperator.commands.add(["redr[aw]"], "Redraw the screen", function () @@ -281,8 +302,26 @@ vimperator.config = { } } }, - { completer: function (filter) { return vimperator.completion.sidebar(filter); } }); + { + completer: function (filter) { return vimperator.completion.sidebar(filter); } + }); + vimperator.commands.add(["winc[lose]", "wc[lose]"], + "Close window", + function (args) { window.close(); }); + + vimperator.commands.add(["wino[pen]", "wo[pen]", "wine[dit]"], + "Open one or more URLs in a new window", + function (args) + { + if (args) + vimperator.open(args, vimperator.NEW_WINDOW); + else + vimperator.open("about:blank", vimperator.NEW_WINDOW); + }, + { + completer: function (filter) { return vimperator.completion.url(filter); } + }); } }