mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 20:27:57 +01:00
2589 lines
94 KiB
JavaScript
2589 lines
94 KiB
JavaScript
/***** BEGIN LICENSE BLOCK ***** {{{
|
|
Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
The contents of this file are subject to the Mozilla Public License Version
|
|
1.1 (the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
for the specific language governing rights and limitations under the
|
|
License.
|
|
|
|
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net>
|
|
|
|
Alternatively, the contents of this file may be used under the terms of
|
|
either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
in which case the provisions of the GPL or the LGPL are applicable instead
|
|
of those above. If you wish to allow use of your version of this file only
|
|
under the terms of either the GPL or the LGPL, and not to allow others to
|
|
use your version of this file under the terms of the MPL, indicate your
|
|
decision by deleting the provisions above and replace them with the notice
|
|
and other provisions required by the GPL or the LGPL. If you do not delete
|
|
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) //{{{
|
|
{
|
|
if (!specs || !action)
|
|
return null;
|
|
|
|
// convert command name abbreviation specs of the form
|
|
// 'shortname[optional-tail]' to short and long versions Eg. 'abc[def]' ->
|
|
// 'abc', 'abcdef'
|
|
var parseSpecs = function (specs)
|
|
{
|
|
var shortNames = [];
|
|
var longNames = [];
|
|
var names = [];
|
|
for (var i = 0; i < specs.length; i++)
|
|
{
|
|
var match;
|
|
if (match = specs[i].match(/(\w+|!)\[(\w+)\]/))
|
|
{
|
|
shortNames.push(match[1]);
|
|
longNames.push(match[1] + match[2]);
|
|
// order as long1, short1, long2, short2
|
|
names.push(match[1] + match[2]);
|
|
names.push(match[1]);
|
|
}
|
|
else
|
|
{
|
|
longNames.push(specs[i]);
|
|
names.push(specs[i]);
|
|
}
|
|
}
|
|
return { names: names, longNames: longNames, shortNames: shortNames };
|
|
};
|
|
|
|
this.specs = specs;
|
|
var expandedSpecs = parseSpecs(specs);
|
|
this.shortNames = expandedSpecs.shortNames;
|
|
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;
|
|
}
|
|
|
|
};
|
|
|
|
vimperator.Command.prototype = {
|
|
|
|
execute: function (args, special, count, modifiers)
|
|
{
|
|
return this.action.call(this, args, special, count, modifiers);
|
|
},
|
|
|
|
// return true if the candidate name matches one of the command's aliases
|
|
// (including all acceptable abbreviations)
|
|
hasName: function (name)
|
|
{
|
|
// match a candidate name against a command name abbreviation spec - returning
|
|
// true if the candidate matches unambiguously
|
|
function matchAbbreviation(name, format)
|
|
{
|
|
var minimum = format.indexOf("["); // minumum number of characters for a command name match
|
|
var fullname = format.replace(/\[(\w+)\]$/, "$1"); // full command name
|
|
if (fullname.indexOf(name) == 0 && name.length >= minimum)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < this.specs.length; i++)
|
|
{
|
|
if (this.specs[i] == name) // literal command name
|
|
{
|
|
return true;
|
|
}
|
|
else if (/^(\w+|!)\[\w+\]$/.test(this.specs[i])) // abbreviation spec
|
|
{
|
|
if (matchAbbreviation(name, this.specs[i]))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
};
|
|
//}}}
|
|
|
|
vimperator.Commands = function () //{{{
|
|
{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////// PRIVATE SECTION /////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////{{{
|
|
|
|
const OPTION_ANY = 0; // can be given no argument or an argument of any type, user is responsible
|
|
// for parsing the return value
|
|
const OPTION_NOARG = 1;
|
|
const OPTION_BOOL = 2;
|
|
const OPTION_STRING = 3;
|
|
const OPTION_INT = 4;
|
|
const OPTION_FLOAT = 5;
|
|
const OPTION_LIST = 6;
|
|
|
|
var exCommands = [];
|
|
var lastRunCommand = ""; // updated whenever the users runs a command with :!
|
|
|
|
// in '-quoted strings, only ' and \ itself are escaped
|
|
// in "-quoted strings, also ", \n and \t are translated
|
|
// in non-quoted strings everything is taken literally apart from "\ " and "\\"
|
|
//
|
|
// "options" is an array [name, type, validator, completions] and could look like:
|
|
// options = [[["-force"], OPTION_NOARG],
|
|
// [["-fullscreen"], OPTION_BOOL],
|
|
// [["-language"], OPTION_STRING, validateFunc, ["perl", "ruby"]],
|
|
// [["-speed"], OPTION_INT],
|
|
// [["-acceleration"], OPTION_FLOAT],
|
|
// [["-accessories"], OPTION_LIST, null, ["foo", "bar"]],
|
|
// [["-other"], OPTION_ANY]];
|
|
// TODO: should it handle comments?
|
|
// TODO: should it return an error, if it contains arguments which look like options (beginning with -)?
|
|
function parseArgs(str, options)
|
|
{
|
|
// returns [count, parsed_argument]
|
|
function getNextArg(str)
|
|
{
|
|
var inSingleString = false;
|
|
var inDoubleString = false;
|
|
var inEscapeKey = false;
|
|
|
|
var arg = "";
|
|
|
|
outer:
|
|
for (var i = 0; i < str.length; i++)
|
|
{
|
|
switch (str[i])
|
|
{
|
|
case "\"":
|
|
if (inEscapeKey)
|
|
{
|
|
inEscapeKey = false;
|
|
break;
|
|
}
|
|
if (!inSingleString)
|
|
{
|
|
inDoubleString = !inDoubleString;
|
|
continue outer;
|
|
}
|
|
break;
|
|
|
|
case "'":
|
|
if (inEscapeKey)
|
|
{
|
|
inEscapeKey = false;
|
|
break;
|
|
}
|
|
if (!inDoubleString)
|
|
{
|
|
inSingleString = !inSingleString;
|
|
continue outer;
|
|
}
|
|
break;
|
|
|
|
// \ is an escape key for non quoted or "-quoted strings
|
|
// for '-quoted strings it is taken literally, apart from \' and \\
|
|
case "\\":
|
|
if (inEscapeKey)
|
|
{
|
|
inEscapeKey = false;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// only escape "\\" and "\ " in non quoted strings
|
|
if (!inSingleString && !inDoubleString && str[i + 1] != "\\" && str[i + 1] != " ")
|
|
continue outer;
|
|
// only escape "\\" and "\'" in single quoted strings
|
|
else if (inSingleString && str[i + 1] != "\\" && str[i + 1] != "'")
|
|
break;
|
|
else
|
|
{
|
|
inEscapeKey = true;
|
|
continue outer;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (inSingleString)
|
|
{
|
|
inEscapeKey = false;
|
|
break;
|
|
}
|
|
else if (inEscapeKey)
|
|
{
|
|
inEscapeKey = false;
|
|
switch (str[i])
|
|
{
|
|
case "n": arg += "\n"; continue outer;
|
|
case "t": arg += "\t"; continue outer;
|
|
default:
|
|
break; // this makes "a\fb" -> afb; wanted or should we return ab? --mst
|
|
}
|
|
}
|
|
else if (!inDoubleString && /\s/.test(str[i]))
|
|
{
|
|
return [i, arg];
|
|
}
|
|
else // a normal charcter
|
|
break;
|
|
}
|
|
arg += str[i];
|
|
}
|
|
|
|
// TODO: add parsing of a " comment here:
|
|
if (inDoubleString || inSingleString)
|
|
return [-1, "E114: Missing quote"];
|
|
if (inEscapeKey)
|
|
return [-1, "trailing \\"];
|
|
else
|
|
return [str.length, arg];
|
|
}
|
|
|
|
var args = []; // parsed arguments
|
|
var opts = []; // parsed options
|
|
if (!options)
|
|
options = [];
|
|
|
|
var invalid = false;
|
|
var arg = null;
|
|
var count = 0; // the length of the argument
|
|
var i = 0;
|
|
outer:
|
|
while (i < str.length)
|
|
{
|
|
// skip whitespace
|
|
if (/\s/.test(str[i]))
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
var sub = str.substr(i);
|
|
var optname = "";
|
|
for (var opt = 0; opt < options.length; opt++)
|
|
{
|
|
for (var name = 0; name < options[opt][0].length; name++)
|
|
{
|
|
optname = options[opt][0][name];
|
|
if (sub.indexOf(optname) == 0)
|
|
{
|
|
invalid = false;
|
|
arg = null;
|
|
// no value to the option
|
|
if (optname.length >= sub.length)
|
|
{
|
|
count = 0;
|
|
}
|
|
else if (sub[optname.length] == "=")
|
|
{
|
|
[count, arg] = getNextArg(sub.substr(optname.length + 1));
|
|
if (count == -1)
|
|
{
|
|
vimperator.echoerr("Invalid argument for option " + optname);
|
|
return null;
|
|
}
|
|
|
|
count++; // to compensate the "=" character
|
|
}
|
|
else if (options[opt][1] != OPTION_NOARG && /\s/.test(sub[optname.length]))
|
|
{
|
|
[count, arg] = getNextArg(sub.substr(optname.length + 1));
|
|
if (count == -1)
|
|
{
|
|
vimperator.echoerr("Invalid argument for option " + optname);
|
|
return null;
|
|
}
|
|
|
|
// if we add the argument to an option after a space, it MUST not be empty
|
|
if (arg.length == 0)
|
|
arg = null;
|
|
|
|
count++; // to compensate the " " character
|
|
}
|
|
else
|
|
{
|
|
// this isn't really an option as it has trailing characters, parse it as an argument
|
|
invalid = true;
|
|
}
|
|
|
|
if (!invalid)
|
|
{
|
|
switch (options[opt][1]) // type
|
|
{
|
|
case OPTION_NOARG:
|
|
if (arg != null)
|
|
{
|
|
vimperator.echoerr("No argument allowed for option: " + optname);
|
|
return null;
|
|
}
|
|
break;
|
|
case OPTION_BOOL:
|
|
if (arg == "true" || arg == "1" || arg == "on")
|
|
arg = true;
|
|
else if (arg == "false" || arg == "0" || arg == "off")
|
|
arg = false;
|
|
else
|
|
{
|
|
vimperator.echoerr("Invalid argument for boolean option: " + optname);
|
|
return null;
|
|
}
|
|
break;
|
|
case OPTION_STRING:
|
|
if (arg == null)
|
|
{
|
|
vimperator.echoerr("Argument required for string option: " + optname);
|
|
return null;
|
|
}
|
|
break;
|
|
case OPTION_INT:
|
|
arg = parseInt(arg, 10);
|
|
if (isNaN(arg))
|
|
{
|
|
vimperator.echoerr("Numeric argument required for integer option: " + optname);
|
|
return null;
|
|
}
|
|
break;
|
|
case OPTION_FLOAT:
|
|
arg = parseFloat(arg);
|
|
if (isNaN(arg))
|
|
{
|
|
vimperator.echoerr("Numeric argument required for float option: " + optname);
|
|
return null;
|
|
}
|
|
break;
|
|
case OPTION_LIST:
|
|
if (arg == null)
|
|
{
|
|
vimperator.echoerr("Argument required for list option: " + optname);
|
|
return null;
|
|
}
|
|
arg = arg.split(/\s*,\s*/);
|
|
break;
|
|
}
|
|
|
|
// we have a validator function
|
|
if (typeof options[opt][2] == "function")
|
|
{
|
|
if (options[opt][2].call(this, arg) == false)
|
|
{
|
|
vimperator.echoerr("Invalid argument for option: " + optname);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
opts.push([options[opt][0][0], arg]); // always use the first name of the option
|
|
i += optname.length + count;
|
|
continue outer;
|
|
}
|
|
// if it is invalid, just fall through and try the next argument
|
|
}
|
|
}
|
|
}
|
|
|
|
// if not an option, treat this token as an argument
|
|
var [count, arg] = getNextArg(sub);
|
|
if (count == -1)
|
|
{
|
|
vimperator.echoerr("Error parsing arguments: " + arg);
|
|
return null;
|
|
}
|
|
|
|
if (arg != null)
|
|
args.push(arg);
|
|
|
|
i += count; // hopefully count is always >0, otherwise we get an endless loop
|
|
}
|
|
|
|
return { opts: opts, args: args };
|
|
}
|
|
|
|
function getOption(opts, option, def)
|
|
{
|
|
for (var i = 0; i < opts.length; i++)
|
|
{
|
|
if (opts[i][0] == option)
|
|
return opts[i][1];
|
|
}
|
|
|
|
// no match found, return default
|
|
return def;
|
|
}
|
|
|
|
function commandsIterator()
|
|
{
|
|
for (var i = 0; i < exCommands.length; i++)
|
|
yield exCommands[i];
|
|
|
|
throw StopIteration;
|
|
}
|
|
|
|
function getUserCommands(name)
|
|
{
|
|
var matches = [];
|
|
for (var i = 0; i < exCommands.length; i++)
|
|
{
|
|
if (exCommands[i].isUserCommand)
|
|
{
|
|
if (name)
|
|
{
|
|
if (exCommands[i].name.match("^"+name))
|
|
matches.push(exCommands[i]);
|
|
}
|
|
else
|
|
{
|
|
matches.push(exCommands[i]);
|
|
}
|
|
}
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////}}}
|
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////{{{
|
|
|
|
var commandManager = {
|
|
|
|
__iterator__: function ()
|
|
{
|
|
return commandsIterator();
|
|
},
|
|
|
|
add: function (command, replace)
|
|
{
|
|
for (var i = 0; i < exCommands.length; i++)
|
|
{
|
|
if (exCommands[i].name == command.name)
|
|
{
|
|
if (!replace)
|
|
return false;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
},
|
|
|
|
get: function (name)
|
|
{
|
|
for (var i = 0; i < exCommands.length; i++)
|
|
{
|
|
if (exCommands[i].hasName(name))
|
|
return exCommands[i];
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
// TODO: generalized 0 count handling -> "Zero count"
|
|
// FIXME: doesn't really belong here...
|
|
// return [null, null, null, null, heredoc_tag || false];
|
|
// [count, cmd, special, args] = match;
|
|
parseCommand: function (str, tag)
|
|
{
|
|
// remove comments
|
|
str.replace(/\s*".*$/, "");
|
|
|
|
if (tag) // we already have a multiline heredoc construct
|
|
{
|
|
if (str == tag)
|
|
return [null, null, null, null, false];
|
|
else
|
|
return [null, null, null, str, tag];
|
|
}
|
|
|
|
// 0 - count, 1 - cmd, 2 - special, 3 - args, 4 - heredoc tag
|
|
var matches = str.match(/^:*(\d+)?([a-zA-Z]+|!)(!)?(?:\s*(.*?)\s*)?$/);
|
|
if (!matches)
|
|
return [null, null, null, null, null];
|
|
matches.shift();
|
|
|
|
// parse count
|
|
if (matches[0])
|
|
matches[0] = parseInt(matches[0], 10);
|
|
else
|
|
matches[0] = -1;
|
|
|
|
matches[2] = !!matches[2];
|
|
matches.push(null);
|
|
if (matches[3])
|
|
{
|
|
tag = matches[3].match(/<<\s*(\w+)\s*$/);
|
|
if (tag && tag[1])
|
|
matches[4] = tag[1];
|
|
}
|
|
else
|
|
matches[3] = "";
|
|
|
|
return matches;
|
|
}
|
|
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////}}}
|
|
////////////////////// DEFAULT COMMANDS ////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////{{{
|
|
|
|
commandManager.add(new vimperator.Command(["addo[ns]"],
|
|
function () { vimperator.open("chrome://mozapps/content/extensions/extensions.xul", vimperator.NEW_TAB); },
|
|
{
|
|
shortHelp: "Show available Browser Extensions and Themes"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["ba[ck]"],
|
|
function (args, special, count)
|
|
{
|
|
if (special)
|
|
vimperator.history.goToStart();
|
|
else
|
|
{
|
|
if (args)
|
|
{
|
|
var sh = getWebNavigation().sessionHistory;
|
|
for (var i = sh.index - 1; i >= 0; i--)
|
|
{
|
|
if (sh.getEntryAtIndex(i, false).URI.spec == args)
|
|
{
|
|
getWebNavigation().gotoIndex(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
vimperator.history.stepTo(count > 0 ? -1 * count : -1);
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Go back in the browser history",
|
|
completer: function (filter)
|
|
{
|
|
var sh = getWebNavigation().sessionHistory;
|
|
var completions = [];
|
|
for (var i = sh.index - 1; i >= 0; i--)
|
|
{
|
|
var entry = sh.getEntryAtIndex(i, false);
|
|
var url = entry.URI.spec;
|
|
var title = entry.title;
|
|
if (vimperator.completion.match([url, title], filter, false))
|
|
completions.push([url, title]);
|
|
}
|
|
return [0, completions];
|
|
}
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["bd[elete]", "bw[ipeout]", "bun[load]", "tabc[lose]"],
|
|
function (args, special, count) { vimperator.tabs.remove(getBrowser().mCurrentTab, count > 0 ? count : 1, special, 0); },
|
|
{
|
|
shortHelp: "Delete current buffer (=tab)"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["beep"],
|
|
function () { vimperator.beep(); },
|
|
{
|
|
shortHelp: "Play a system beep"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["bma[rk]"],
|
|
function (args)
|
|
{
|
|
var res = parseArgs(args, this.args);
|
|
if (!res)
|
|
return;
|
|
|
|
var url = res.args.length == 0 ? vimperator.buffer.URL : res.args[0];
|
|
var title = getOption(res.opts, "-title", res.args.length == 0 ? vimperator.buffer.title : null);
|
|
if (!title)
|
|
title = url;
|
|
var keyword = getOption(res.opts, "-keyword", null);
|
|
var tags = getOption(res.opts, "-tags", []);
|
|
|
|
if (vimperator.bookmarks.add(false, title, url, keyword, tags))
|
|
{
|
|
var extra = "";
|
|
if (title != url)
|
|
extra = " (" + title + ")";
|
|
vimperator.echo("Added bookmark: " + url + extra, vimperator.commandline.FORCE_SINGLELINE);
|
|
}
|
|
else
|
|
vimperator.echoerr("Exxx: Could not add bookmark `" + title + "'", vimperator.commandline.FORCE_SINGLELINE);
|
|
},
|
|
{
|
|
shortHelp: "Add a bookmark",
|
|
args: [[["-title", "-t"], OPTION_STRING],
|
|
[["-tags", "-T"], OPTION_LIST],
|
|
[["-keyword", "-k"], OPTION_STRING, function (arg) { return /\w/.test(arg); }]]
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["bmarks"],
|
|
function (args, special)
|
|
{
|
|
var res = parseArgs(args, this.args);
|
|
if (!res)
|
|
return;
|
|
|
|
var tags = getOption(res.opts, "-tags", []);
|
|
vimperator.bookmarks.list(res.args.join(" "), tags, special);
|
|
},
|
|
{
|
|
shortHelp: "List or open multiple bookmarks",
|
|
completer: function (filter) { return [0, vimperator.bookmarks.get(filter)]; },
|
|
args: [[["-tags", "-T"], OPTION_LIST]]
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["b[uffer]"],
|
|
function (args, special) { vimperator.buffer.switchTo(args, special); },
|
|
{
|
|
shortHelp: "Go to buffer from buffer list",
|
|
completer: function (filter) { return vimperator.completion.buffer(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["dia[log]"],
|
|
function (args, special)
|
|
{
|
|
function viewPartialSource()
|
|
{
|
|
// copied (and tuned somebit) from browser.jar -> nsContextMenu.js
|
|
var focusedWindow = document.commandDispatcher.focusedWindow;
|
|
if (focusedWindow == window)
|
|
focusedWindow = content;
|
|
|
|
var docCharset = null;
|
|
if (focusedWindow)
|
|
docCharset = "charset=" + focusedWindow.document.characterSet;
|
|
|
|
var reference = null;
|
|
reference = focusedWindow.getSelection();
|
|
|
|
var docUrl = null;
|
|
window.openDialog("chrome://global/content/viewPartialSource.xul",
|
|
"_blank", "scrollbars,resizable,chrome,dialog=no",
|
|
docUrl, docCharset, reference, "selection");
|
|
}
|
|
|
|
try
|
|
{
|
|
switch (args)
|
|
{
|
|
case "about": openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); break;
|
|
case "addbookmark": PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksRootId); break;
|
|
case "addons": BrowserOpenAddonsMgr(); break;
|
|
case "bookmarks": openDialog("chrome://browser/content/bookmarks/bookmarksPanel.xul", "Bookmarks", "dialog,centerscreen,width=600,height=600"); break;
|
|
case "checkupdates": checkForUpdates(); break;
|
|
case "cleardata": Cc[GLUE_CID].getService(Ci.nsIBrowserGlue).sanitize(window || null); break;
|
|
case "console": toJavaScriptConsole(); break;
|
|
case "customizetoolbar": BrowserCustomizeToolbar(); break;
|
|
case "dominspector": inspectDOMDocument(content.document); break;
|
|
case "downloads": toOpenWindowByType('Download:Manager', 'chrome://mozapps/content/downloads/downloads.xul', 'chrome,dialog=no,resizable'); break;
|
|
case "history": openDialog("chrome://browser/content/history/history-panel.xul", "History", "dialog,centerscreen,width=600,height=600"); break;
|
|
case "import": BrowserImport(); break;
|
|
case "openfile": BrowserOpenFileWindow(); break;
|
|
case "pageinfo": BrowserPageInfo(); break;
|
|
case "pagesource": BrowserViewSourceOfDocument(content.document); break;
|
|
case "places": PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); break;
|
|
case "preferences": openPreferences(); break;
|
|
case "printpreview": PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); break;
|
|
case "print": PrintUtils.print(); break;
|
|
case "printsetup": PrintUtils.showPageSetup(); break;
|
|
case "saveframe": saveFrameDocument(); break;
|
|
case "savepage": saveDocument(window.content.document); break;
|
|
case "searchengines": openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); break;
|
|
case "selectionsource": viewPartialSource(); break;
|
|
case "": vimperator.echoerr("E474: Invalid argument"); break;
|
|
default: vimperator.echoerr("Dialog '" + args + "' not available");
|
|
}
|
|
}
|
|
catch (e)
|
|
{
|
|
vimperator.echoerr("Error opening '" + args + "': " + e);
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Open a Firefox dialog",
|
|
completer: function (filter) { return vimperator.completion.dialog(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["buffers", "files", "ls", "tabs"],
|
|
function (args, special)
|
|
{
|
|
if (args)
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
return;
|
|
}
|
|
|
|
vimperator.buffer.list(special);
|
|
},
|
|
{
|
|
shortHelp: "Show a list of all buffers (=tabs)"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["delbm[arks]"],
|
|
function (args, special)
|
|
{
|
|
var url = args;
|
|
if (!url)
|
|
url = vimperator.buffer.URL;
|
|
|
|
var deletedCount = vimperator.bookmarks.remove(url);
|
|
vimperator.echo(deletedCount + " bookmark(s) with url `" + url + "' deleted", vimperator.commandline.FORCE_SINGLELINE);
|
|
},
|
|
{
|
|
shortHelp: "Delete a bookmark",
|
|
completer: function (filter) { return [0, vimperator.bookmarks.get(filter)]; }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["cd", "chd[ir]"],
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
args = "~";
|
|
|
|
if (vimperator.io.setCurrentDirectory(args))
|
|
vimperator.echo(vimperator.io.getCurrentDirectory());
|
|
},
|
|
{
|
|
shortHelp: "Change the current directory",
|
|
completer: function (filter) { return vimperator.completion.file(filter, true); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["pw[d]"],
|
|
function (args)
|
|
{
|
|
if (args)
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
else
|
|
vimperator.echo(vimperator.io.getCurrentDirectory());
|
|
},
|
|
{
|
|
shortHelp: "Print the current directory name"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["com[mand]"],
|
|
function (args, special)
|
|
{
|
|
if (args)
|
|
{
|
|
var res = args.match(/^(\w+)(?:\s+(.+))?$/);
|
|
if (!res)
|
|
{
|
|
vimperator.echoerr("E182: Invalid command name");
|
|
return false;
|
|
}
|
|
var [cmd, rep] = [res[1], res[2]]
|
|
}
|
|
|
|
if (rep)
|
|
{
|
|
if (!vimperator.commands.add(new vimperator.Command([cmd], function (args, special, count, modifiers) { eval(rep) }, { isUserCommand: rep } ), special))
|
|
vimperator.echoerr("E174: Command already exists: add ! to replace it");
|
|
}
|
|
else
|
|
{
|
|
var cmdlist = getUserCommands(cmd);
|
|
if (cmdlist.length > 0)
|
|
{
|
|
var str = ":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) + "<br/>" +
|
|
"<table><tr align=\"left\" class=\"hl-Title\"><th>Name</th><th>Args</th><th>Definition</th></tr>";
|
|
for (var i = 0; i < cmdlist.length; i++)
|
|
str += "<tr><td>" + cmdlist[i].name + "</td><td>" + "*" + "</td><td>" + cmdlist[i].isUserCommand + "</td></tr>";
|
|
str += "</table>"
|
|
vimperator.commandline.echo(str, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE);
|
|
}
|
|
else
|
|
vimperator.echo("No user-defined commands found");
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Lists and defines commands" /*,
|
|
args: [[["-nargs"], OPTION_STRING, function (arg) { return /^(0|1|\*|\?|\+)$/.test(arg); }],
|
|
[["-bang"], OPTION_NOARG],
|
|
[["-bar"], OPTION_NOARG]] */
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["delm[arks]"],
|
|
function (args, special)
|
|
{
|
|
if (!special && !args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
if (special && args)
|
|
{
|
|
vimperator.echoerr("E474: Invalid argument");
|
|
return;
|
|
}
|
|
var matches;
|
|
if (matches = args.match(/(?:(?:^|[^a-zA-Z0-9])-|-(?:$|[^a-zA-Z0-9])|[^a-zA-Z0-9 -]).*/))
|
|
{
|
|
// TODO: this currently differs from Vim's behaviour which
|
|
// deletes any valid marks in the arg list, up to the first
|
|
// invalid arg, as well as giving the error message. Do we want
|
|
// to match this behaviour?
|
|
vimperator.echoerr("E475: Invalid argument: " + matches[0]);
|
|
return;
|
|
}
|
|
// check for illegal ranges - only allow a-z A-Z 0-9
|
|
if (matches = args.match(/[a-zA-Z0-9]-[a-zA-Z0-9]/g))
|
|
{
|
|
for (var i = 0; i < matches.length; i++)
|
|
{
|
|
var start = matches[i][0];
|
|
var end = matches[i][2];
|
|
if (/[a-z]/.test(start) != /[a-z]/.test(end) ||
|
|
/[A-Z]/.test(start) != /[A-Z]/.test(end) ||
|
|
/[0-9]/.test(start) != /[0-9]/.test(end) ||
|
|
start > end)
|
|
{
|
|
vimperator.echoerr("E475: Invalid argument: " + args.match(new RegExp(matches[i] + ".*"))[0]);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
vimperator.marks.remove(args, special);
|
|
},
|
|
{
|
|
shortHelp: "Delete the specified marks"
|
|
}
|
|
|
|
));
|
|
commandManager.add(new vimperator.Command(["delqm[arks]"],
|
|
function (args, special)
|
|
{
|
|
// TODO: finish arg parsing - we really need a proper way to do this. :)
|
|
if (!special && !args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
if (special && args)
|
|
{
|
|
vimperator.echoerr("E474: Invalid argument");
|
|
return;
|
|
}
|
|
|
|
if (special)
|
|
vimperator.quickmarks.removeAll();
|
|
else
|
|
vimperator.quickmarks.remove(args);
|
|
},
|
|
{
|
|
shortHelp: "Delete the specified QuickMarks"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["downl[oads]", "dl"],
|
|
function () { vimperator.open("chrome://mozapps/content/downloads/downloads.xul", vimperator.NEW_TAB); },
|
|
{
|
|
shortHelp: "Show progress of current downloads"
|
|
}
|
|
));
|
|
|
|
// TODO: move helper function somewhere else?
|
|
function argToString(arg, color)
|
|
{
|
|
if (!arg)
|
|
return "";
|
|
|
|
try
|
|
{
|
|
// TODO: move to vimperator.eval()?
|
|
// with (vimperator) means, vimperator is the default namespace "inside" eval
|
|
arg = eval("with(vimperator){" + arg + "}");
|
|
}
|
|
catch (e)
|
|
{
|
|
vimperator.echoerr(e.toString());
|
|
return null;
|
|
}
|
|
|
|
if (typeof arg === "object")
|
|
arg = vimperator.util.objectToString(arg, color);
|
|
else if (typeof arg === "function")
|
|
arg = vimperator.util.escapeHTML(arg.toString());
|
|
else if (typeof arg === "number" || typeof arg === "boolean")
|
|
arg = "" + arg;
|
|
else if (typeof arg === "undefined")
|
|
arg = "undefined";
|
|
|
|
return arg;
|
|
}
|
|
commandManager.add(new vimperator.Command(["ec[ho]"],
|
|
function (args)
|
|
{
|
|
var res = argToString(args, true);
|
|
if (res != null)
|
|
vimperator.echo(res);
|
|
},
|
|
{
|
|
shortHelp: "Display a string at the bottom of the window",
|
|
completer: function (filter) { return vimperator.completion.javascript(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["echoe[rr]"],
|
|
function (args)
|
|
{
|
|
var res = argToString(args, false);
|
|
if (res != null)
|
|
vimperator.echoerr(res);
|
|
},
|
|
{
|
|
shortHelp: "Display an error string at the bottom of the window",
|
|
completer: function (filter) { return vimperator.completion.javascript(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["exe[cute]"],
|
|
function (args)
|
|
{
|
|
// TODO: :exec has some difficult semantics -> later
|
|
// var res = parseArgs(args, this.args);
|
|
// if (!res)
|
|
// return;
|
|
//
|
|
// vimperator.execute(res.args);
|
|
|
|
vimperator.execute(args);
|
|
},
|
|
{
|
|
shortHelp: "Execute the string that results from the evaluation of {expr1} as an Ex command."
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["exu[sage]"],
|
|
function (args, special, count, modifiers)
|
|
{
|
|
var usage = "<table>";
|
|
for (let command in vimperator.commands)
|
|
{
|
|
usage += "<tr><td style='color: magenta; padding-right: 20px'> :" +
|
|
vimperator.util.escapeHTML(command.name) + "</td><td>" +
|
|
vimperator.util.escapeHTML(command.shortHelp) + "</td></tr>";
|
|
}
|
|
usage += "</table>";
|
|
|
|
vimperator.echo(usage, vimperator.commandline.FORCE_MULTILINE);
|
|
},
|
|
{
|
|
shortHelp: "Show help for Ex commands"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["fo[rward]", "fw"],
|
|
function (args, special, count)
|
|
{
|
|
if (special)
|
|
vimperator.history.goToEnd();
|
|
else
|
|
{
|
|
if (args)
|
|
{
|
|
var sh = getWebNavigation().sessionHistory;
|
|
for (var i = sh.index + 1; i < sh.count; i++)
|
|
{
|
|
if (sh.getEntryAtIndex(i, false).URI.spec == args)
|
|
{
|
|
getWebNavigation().gotoIndex(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
vimperator.history.stepTo(count > 0 ? count : 1);
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Go forward in the browser history",
|
|
completer: function (filter)
|
|
{
|
|
var sh = getWebNavigation().sessionHistory;
|
|
var completions = [];
|
|
for (var i = sh.index + 1; i < sh.count; i++)
|
|
{
|
|
var entry = sh.getEntryAtIndex(i, false);
|
|
var url = entry.URI.spec;
|
|
var title = entry.title;
|
|
if (vimperator.completion.match([url, title], filter, false))
|
|
completions.push([url, title]);
|
|
}
|
|
return [0, completions];
|
|
}
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["ha[rdcopy]"],
|
|
function () { getBrowser().contentWindow.print(); },
|
|
{
|
|
shortHelp: "Print current document"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["h[elp]"],
|
|
function (args, special, count, modifiers)
|
|
{
|
|
function jumpToTag(file, tag)
|
|
{
|
|
vimperator.open("chrome://vimperator/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/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);
|
|
},
|
|
{
|
|
shortHelp: "Display help",
|
|
completer: function (filter) { return vimperator.completion.help(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["hist[ory]", "hs"],
|
|
function (args, special) { vimperator.history.list(args, special); },
|
|
{
|
|
shortHelp: "Show recently visited URLs",
|
|
completer: function (filter) { return [0, vimperator.history.get(filter)]; }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["javas[cript]", "js"],
|
|
function (args, special)
|
|
{
|
|
if (special) // open javascript console
|
|
vimperator.open("chrome://global/content/console.xul", vimperator.NEW_TAB);
|
|
else
|
|
{
|
|
// check for a heredoc
|
|
var matches = args.match(/(.*)<<\s*([^\s]+)$/);
|
|
if (matches && matches[2])
|
|
{
|
|
vimperator.commandline.inputMultiline(new RegExp("^" + matches[2] + "$", "m"),
|
|
function (code)
|
|
{
|
|
try
|
|
{
|
|
eval(matches[1] + "\n" + code);
|
|
}
|
|
catch (e)
|
|
{
|
|
vimperator.echoerr(e.name + ": " + e.message);
|
|
}
|
|
});
|
|
}
|
|
else // single line javascript code
|
|
{
|
|
try
|
|
{
|
|
eval("with(vimperator){" + args + "}");
|
|
}
|
|
catch (e)
|
|
{
|
|
vimperator.echoerr(e.name + ": " + e.message);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Run any JavaScript command through eval()",
|
|
completer: function (filter) { return vimperator.completion.javascript(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["let"],
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
{
|
|
var str = "";
|
|
for (var i in vimperator.globalVariables)
|
|
{
|
|
var value = vimperator.globalVariables[i];
|
|
if (typeof value == "number")
|
|
var prefix = "#";
|
|
else if (typeof value == "function")
|
|
var prefix = "*";
|
|
else
|
|
var prefix = "";
|
|
|
|
str += "<tr><td style=\"width: 200px;\">" + i + "</td><td>" + prefix + value + "</td>\n";
|
|
}
|
|
if (str)
|
|
vimperator.echo("<table>" + str + "</table>", vimperator.commandline.FORCE_MULTILINE);
|
|
else
|
|
vimperator.echo("No variables found");
|
|
return;
|
|
}
|
|
|
|
var matches;
|
|
// 1 - type, 2 - name, 3 - +-., 4 - expr
|
|
if (matches = args.match(/([$@&])?([\w:]+)\s*([+-.])?=\s*(.+)/))
|
|
{
|
|
if (!matches[1])
|
|
{
|
|
var reference = vimperator.variableReference(matches[2]);
|
|
if (!reference[0] && matches[3])
|
|
{
|
|
vimperator.echoerr("E121: Undefined variable: " + matches[2]);
|
|
return;
|
|
}
|
|
|
|
var expr = vimperator.eval(matches[4]);
|
|
if (typeof expr === undefined)
|
|
{
|
|
vimperator.echoerr("E15: Invalid expression: " + matches[4]);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (!reference[0])
|
|
{
|
|
if (reference[2] == "g")
|
|
reference[0] = vimperator.globalVariables;
|
|
else
|
|
return; // for now
|
|
}
|
|
|
|
if (matches[3])
|
|
{
|
|
if (matches[3] == "+")
|
|
reference[0][reference[1]] += expr;
|
|
else if (matches[3] == "-")
|
|
reference[0][reference[1]] -= expr;
|
|
else if (matches[3] == ".")
|
|
reference[0][reference[1]] += expr.toString();
|
|
}
|
|
else
|
|
reference[0][reference[1]] = expr;
|
|
}
|
|
}
|
|
}
|
|
// 1 - name
|
|
else if (matches = args.match(/^\s*([\w:]+)\s*$/))
|
|
{
|
|
var reference = vimperator.variableReference(matches[1]);
|
|
if (!reference[0])
|
|
{
|
|
vimperator.echoerr("E121: Undefined variable: " + matches[1]);
|
|
return;
|
|
}
|
|
|
|
var value = reference[0][reference[1]];
|
|
if (typeof value == "number")
|
|
var prefix = "#";
|
|
else if (typeof value == "function")
|
|
var prefix = "*";
|
|
else
|
|
var prefix = "";
|
|
vimperator.echo(reference[1] + "\t\t" + prefix + value);
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Sets or lists a variable"
|
|
}
|
|
));
|
|
// code for abbreviations
|
|
commandManager.add(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.add(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.add(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.add(new vimperator.Command(["una[bbreviate]"],
|
|
function (args) { vimperator.editor.removeAbbreviation("!", args); },
|
|
{ shortHelp: "Remove an abbreviation" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["cuna[bbrev]"],
|
|
function (args) { vimperator.editor.removeAbbreviation("c", args); },
|
|
{ shortHelp: "Remove an abbreviation for Command-line mode" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["iuna[bbrev]"],
|
|
function (args) { vimperator.editor.removeAbbreviation("i", args); },
|
|
{ shortHelp: "Remove an abbreviation for Insert mode" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["abc[lear]"],
|
|
function (args) { vimperator.editor.removeAllAbbreviations("!"); },
|
|
{ shortHelp: "Remove all abbreviations" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["cabc[lear]"],
|
|
function (args) { vimperator.editor.removeAllAbbreviations("c"); },
|
|
{ shortHelp: "Remove all abbreviations for Command-line mode" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["iabc[lear]"],
|
|
function (args) { vimperator.editor.removeAllAbbreviations("i"); },
|
|
{ shortHelp: "Remove all abbreviations for Insert mode" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["au[tocmd]"],
|
|
function (args, special)
|
|
{
|
|
if (!args)
|
|
{
|
|
if (special) // :au!
|
|
vimperator.autocommands.remove(null, null);
|
|
else // :au
|
|
vimperator.autocommands.list(null, null);
|
|
}
|
|
else
|
|
{
|
|
// (?: ) means don't store; (....)? <-> exclamation marks makes the group optional
|
|
var [all, asterix, auEvent, regex, cmds] = args.match(/^(\*)?(?:\s+)?(\S+)(?:\s+)?(\S+)?(?:\s+)?(.+)?$/);
|
|
|
|
if (cmds)
|
|
{
|
|
vimperator.autocommands.add(auEvent, regex, cmds);
|
|
}
|
|
else if (regex) // e.g. no cmds provided
|
|
{
|
|
if (special)
|
|
vimperator.autocommands.remove(auEvent, regex);
|
|
else
|
|
vimperator.autocommands.list(auEvent, regex);
|
|
}
|
|
else if (auEvent)
|
|
{
|
|
if (asterix)
|
|
if (special)
|
|
vimperator.autocommands.remove(null, auEvent); // ':au! * auEvent'
|
|
else
|
|
vimperator.autocommands.list(null, auEvent);
|
|
else
|
|
if (special)
|
|
vimperator.autocommands.remove(auEvent, null);
|
|
else
|
|
vimperator.autocommands.list(auEvent, null);
|
|
}
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Execute commands automatically on events",
|
|
completer: function (filter) { return vimperator.completion.autocommands(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["macros"],
|
|
function (arg)
|
|
{
|
|
var str = "<table>";
|
|
var macroRef = vimperator.events.getMacros(arg);
|
|
for (var item in macroRef)
|
|
str += "<tr><td> " + item + " </td><td>" +
|
|
vimperator.util.escapeHTML(macroRef[item]) + "</td></tr>";
|
|
|
|
str += "</table>";
|
|
|
|
vimperator.echo(str, vimperator.commandline.FORCE_MULTILINE);
|
|
},
|
|
{
|
|
shortHelp: "List macros matching a regex"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["delmac[ros]"],
|
|
function (arg)
|
|
{
|
|
if (!arg)
|
|
vimperator.echoerr("E474: Invalid argument");
|
|
else
|
|
vimperator.events.deleteMacros(arg);
|
|
},
|
|
{
|
|
shortHelp: "Delete macros matching a regex"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["pl[ay]"],
|
|
function (arg)
|
|
{
|
|
if (!arg)
|
|
vimperator.echoerr("E474: Invalid argument");
|
|
else
|
|
vimperator.events.playMacro(arg);
|
|
},
|
|
{
|
|
shortHelp: "Play a macro",
|
|
completer: function (filter) { return vimperator.completion.macros(filter); }
|
|
}
|
|
));
|
|
// 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 = /<Leader>/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.add(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.add(new vimperator.Command(["map"],
|
|
function (args) { map(args, [vimperator.modes.NORMAL], false); },
|
|
{ shortHelp: "Map the key sequence {lhs} to {rhs}" }
|
|
));
|
|
commandManager.add(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.add(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.add(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.add(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.add(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)"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["ma[rk]"],
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
if (args.length > 1)
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
return;
|
|
}
|
|
if (!/[a-zA-Z]/.test(args))
|
|
{
|
|
vimperator.echoerr("E191: Argument must be a letter or forward/backward quote");
|
|
return;
|
|
}
|
|
|
|
vimperator.marks.add(args);
|
|
},
|
|
{
|
|
shortHelp: "Mark current location within the web page"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["marks"],
|
|
function (args)
|
|
{
|
|
// ignore invalid mark characters unless there are no valid mark chars
|
|
if (args && !/[a-zA-Z]/.test(args))
|
|
{
|
|
vimperator.echoerr("E283: No marks matching \"" + args + "\"");
|
|
return;
|
|
}
|
|
|
|
var filter = args.replace(/[^a-zA-Z]/g, "");
|
|
vimperator.marks.list(filter);
|
|
},
|
|
{
|
|
shortHelp: "Show all location marks of current web page"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["mkv[imperatorrc]"],
|
|
function (args, special)
|
|
{
|
|
// TODO: "E172: Only one file name allowed"
|
|
var filename;
|
|
if (args)
|
|
filename = args;
|
|
else
|
|
filename = (navigator.platform == "Win32") ? "~/_vimperatorrc" : "~/.vimperatorrc";
|
|
|
|
var file = vimperator.io.getFile(filename);
|
|
if (file.exists() && !special)
|
|
{
|
|
vimperator.echoerr("E189: \".vimperatorrc\" exists (add ! to override)");
|
|
return;
|
|
}
|
|
|
|
var line = "\" " + vimperator.version + "\n";
|
|
line += "\" Mappings\n";
|
|
|
|
var mode = [[[vimperator.modes.NORMAL], ""], [[vimperator.modes.COMMAND_LINE], "c"],
|
|
[[vimperator.modes.INSERT, vimperator.modes.TEXTAREA], "i"]];
|
|
for (var y = 0; y < mode.length; y++)
|
|
{
|
|
// NOTE: names.length is always 1 on user maps. If that changes, also fix getUserIterator and v.m.list
|
|
for (var map in vimperator.mappings.getUserIterator(mode[y][0]))
|
|
line += mode[y][1] + (map.noremap ? "nore" : "") + "map " + map.names[0] + " " + map.rhs + "\n";
|
|
}
|
|
|
|
line += "\n\" Options\n";
|
|
for (var option in vimperator.options)
|
|
{
|
|
// TODO: options should be queried for this info
|
|
// TODO: string/list options might need escaping in future
|
|
if (!/fullscreen|usermode/.test(option.name) && option.value != option.defaultValue)
|
|
{
|
|
if (option.type == "boolean")
|
|
line += "set " + (option.value ? option.name : "no" + option.name) + "\n";
|
|
else
|
|
line += "set " + option.name + "=" + option.value + "\n";
|
|
}
|
|
}
|
|
|
|
// :mkvimrc doesn't save autocommands, so we don't either - remove this code at some point
|
|
// line += "\n\" Auto-Commands\n";
|
|
// for (var item in vimperator.autocommands)
|
|
// line += "autocmd " + item + "\n";
|
|
|
|
line += "\n\" Abbreviations\n";
|
|
for (var abbrCmd in vimperator.editor.abbreviations)
|
|
line += abbrCmd;
|
|
|
|
// if (vimperator.events.getMapLeader() != "\\")
|
|
// line += "\nlet mapleader = \"" + vimperator.events.getMapLeader() + "\"\n";
|
|
|
|
// source a user .vimperatorrc file
|
|
line += "\nsource! " + filename + ".local\n";
|
|
line += "\n\" vim: set ft=vimperator:";
|
|
|
|
vimperator.io.writeFile(file, line);
|
|
},
|
|
{
|
|
shortHelp: "Write current key mappings and changed options to [file]"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["noh[lsearch]"],
|
|
function (args) { vimperator.search.clear(); },
|
|
{ shortHelp: "Remove the search highlighting" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["norm[al]"],
|
|
function (args, special)
|
|
{
|
|
if (!args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
|
|
vimperator.events.feedkeys(args, special);
|
|
},
|
|
{
|
|
shortHelp: "Execute Normal mode commands"
|
|
}
|
|
));
|
|
// TODO: remove duplication in :map
|
|
commandManager.add(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.add(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.add(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.add(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); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["pa[geinfo]"],
|
|
function () { vimperator.buffer.showPageInfo(true); },
|
|
{ shortHelp: "Show various page information" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["pc[lose]"],
|
|
function () { vimperator.previewwindow.hide(); },
|
|
{ shortHelp: "Close preview window on bottom of screen" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["pref[erences]", "prefs"],
|
|
function (args, special, count, modifiers)
|
|
{
|
|
if (!args)
|
|
{
|
|
// TODO: copy these snippets to more function which should work with :tab xxx
|
|
if (modifiers && modifiers.inTab)
|
|
{
|
|
vimperator.open(special ? "about:config" :
|
|
"chrome://browser/content/preferences/preferences.xul", vimperator.NEW_TAB);
|
|
}
|
|
else
|
|
{
|
|
if (special) // open firefox settings gui dialog
|
|
vimperator.open("about:config", vimperator.CURRENT_TAB);
|
|
else
|
|
openPreferences();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Show Browser Preferences"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["qma[rk]"],
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
|
|
var matches = args.match(/^([a-zA-Z0-9])(?:\s+(.+))?$/);
|
|
if (!matches)
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
else if (!matches[2])
|
|
vimperator.quickmarks.add(matches[1], vimperator.buffer.URL);
|
|
else
|
|
vimperator.quickmarks.add(matches[1], matches[2]);
|
|
},
|
|
{
|
|
shortHelp: "Mark a URL with a letter for quick access"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["qmarks"],
|
|
function (args)
|
|
{
|
|
// ignore invalid mark characters unless there are no valid mark chars
|
|
if (args && !/[a-zA-Z0-9]/.test(args))
|
|
{
|
|
vimperator.echoerr("E283: No QuickMarks matching \"" + args + "\"");
|
|
return;
|
|
}
|
|
|
|
var filter = args.replace(/[^a-zA-Z0-9]/g, "");
|
|
vimperator.quickmarks.list(filter);
|
|
},
|
|
{
|
|
shortHelp: "Show all QuickMarks"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["q[uit]"],
|
|
function () { vimperator.tabs.remove(getBrowser().mCurrentTab, 1, false, 1); },
|
|
{ shortHelp: "Quit current tab" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["quita[ll]", "qa[ll]"],
|
|
function () { vimperator.quit(false); },
|
|
{ shortHelp: "Quit Vimperator", }
|
|
));
|
|
commandManager.add(new vimperator.Command(["redr[aw]"],
|
|
function ()
|
|
{
|
|
var wu = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
|
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
|
wu.redraw();
|
|
},
|
|
{ shortHelp: "Redraw the screen", }
|
|
));
|
|
commandManager.add(new vimperator.Command(["re[load]"],
|
|
function (args, special) { vimperator.tabs.reload(getBrowser().mCurrentTab, special); },
|
|
{ shortHelp: "Reload current page" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["reloada[ll]"],
|
|
function (args, special) { vimperator.tabs.reloadAll(special); },
|
|
{ shortHelp: "Reload all pages" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["res[tart]"],
|
|
function () { vimperator.restart(); },
|
|
{ shortHelp: "Force the browser to restart" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["sav[eas]", "w[rite]"],
|
|
function (args, special)
|
|
{
|
|
var file = vimperator.io.getFile(args || "");
|
|
// we always want to save that link relative to the current working directory
|
|
vimperator.options.setPref("browser.download.lastDir", vimperator.io.getCurrentDirectory());
|
|
//if (args)
|
|
//{
|
|
// saveURL(vimperator.buffer.URL, args, null, true, special, // special == skipPrompt
|
|
// makeURI(vimperator.buffer.URL, content.document.characterSet));
|
|
//}
|
|
//else
|
|
saveDocument(window.content.document, special);
|
|
},
|
|
{
|
|
shortHelp: "Save current web page to disk"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["se[t]"],
|
|
// TODO: support setting multiple options at once
|
|
function (args, special, count, modifiers)
|
|
{
|
|
if (special)
|
|
{
|
|
var onlyNonDefault = false;
|
|
if (!args)
|
|
{
|
|
args = "all";
|
|
onlyNonDefault = true;
|
|
}
|
|
// 1 2 3 4 5
|
|
var matches = args.match(/^\s*?([a-zA-Z0-9\.\-_{}]+)([?&!])?\s*(([+-^]?)=(.*))?\s*$/);
|
|
var name = matches[1];
|
|
var reset = false;
|
|
var invertBoolean = false;
|
|
|
|
if (matches[2] == "&")
|
|
reset = true;
|
|
else if (matches[2] == "!")
|
|
invertBoolean = true;
|
|
|
|
if (name == "all" && reset)
|
|
vimperator.echoerr("You can't reset all the firefox options, it could make your browser unusable.");
|
|
else if (name == "all")
|
|
vimperator.options.listPrefs(onlyNonDefault, "");
|
|
else if (reset)
|
|
vimperator.options.resetPref(name);
|
|
else if (invertBoolean)
|
|
vimperator.options.invertPref(name);
|
|
else if (matches[3])
|
|
{
|
|
var value = matches[5];
|
|
switch (value)
|
|
{
|
|
case undefined:
|
|
value = "";
|
|
break;
|
|
case "true":
|
|
value = true;
|
|
break;
|
|
case "false":
|
|
value = false;
|
|
break;
|
|
default:
|
|
var valueInt = parseInt(value, 10);
|
|
if (!isNaN(valueInt))
|
|
value = valueInt;
|
|
}
|
|
vimperator.options.setPref(name, value);
|
|
}
|
|
else
|
|
{
|
|
vimperator.options.listPrefs(onlyNonDefault, name);
|
|
}
|
|
return;
|
|
}
|
|
|
|
var onlyNonDefault = false; // used for :set to print non-default options
|
|
if (!args)
|
|
{
|
|
args = "all";
|
|
onlyNonDefault = true;
|
|
}
|
|
|
|
// 1 2 3 4 5 6
|
|
var matches = args.match(/^\s*(no|inv)?([a-z]+)([?&!])?\s*(([+-^]?)=(.*))?\s*$/);
|
|
if (!matches)
|
|
{
|
|
vimperator.echoerr("E518: Unknown option: " + args);
|
|
return;
|
|
}
|
|
|
|
var unsetBoolean = false;
|
|
if (matches[1] == "no")
|
|
unsetBoolean = true;
|
|
|
|
var name = matches[2];
|
|
var all = false;
|
|
if (name == "all")
|
|
all = true;
|
|
|
|
var option = vimperator.options.get(name);
|
|
if (!option && !all)
|
|
{
|
|
vimperator.echoerr("E518: Unknown option: " + args);
|
|
return;
|
|
}
|
|
|
|
var valueGiven = !!matches[4];
|
|
|
|
var get = false;
|
|
if (all || matches[3] == "?" || (option.type != "boolean" && !valueGiven))
|
|
get = true;
|
|
|
|
var reset = false;
|
|
if (matches[3] == "&")
|
|
reset = true;
|
|
|
|
var invertBoolean = false;
|
|
if (matches[1] == "inv" || matches[3] == "!")
|
|
invertBoolean = true;
|
|
|
|
var operator = matches[5];
|
|
|
|
var value = matches[6];
|
|
if (value === undefined)
|
|
value = "";
|
|
|
|
// reset a variable to its default value
|
|
if (reset)
|
|
{
|
|
if (all)
|
|
{
|
|
for (let option in vimperator.options)
|
|
option.reset();
|
|
}
|
|
else
|
|
{
|
|
option.reset();
|
|
}
|
|
}
|
|
// read access
|
|
else if (get)
|
|
{
|
|
if (all)
|
|
{
|
|
vimperator.options.list(onlyNonDefault);
|
|
}
|
|
else
|
|
{
|
|
if (option.type == "boolean")
|
|
vimperator.echo((option.value ? " " : "no") + option.name);
|
|
else
|
|
vimperator.echo(" " + option.name + "=" + option.value);
|
|
}
|
|
}
|
|
// write access
|
|
// NOTE: the behaviour is generally Vim compatible but could be
|
|
// improved. i.e. Vim's behaviour is pretty sloppy to no real
|
|
// benefit
|
|
else
|
|
{
|
|
var currentValue = option.value;
|
|
var newValue;
|
|
|
|
switch (option.type)
|
|
{
|
|
case "boolean":
|
|
if (valueGiven)
|
|
{
|
|
vimperator.echoerr("E474: Invalid argument: " + args);
|
|
return;
|
|
}
|
|
|
|
if (invertBoolean)
|
|
newValue = !option.value;
|
|
else
|
|
newValue = !unsetBoolean;
|
|
|
|
break;
|
|
|
|
case "number":
|
|
value = parseInt(value);
|
|
|
|
if (isNaN(value))
|
|
{
|
|
vimperator.echoerr("E521: Number required after =: " + args);
|
|
return;
|
|
}
|
|
|
|
if (operator == "+")
|
|
newValue = currentValue + value;
|
|
else if (operator == "-")
|
|
newValue = currentValue - value;
|
|
else if (operator == "^")
|
|
newValue = currentValue * value;
|
|
else
|
|
newValue = value;
|
|
|
|
break;
|
|
|
|
case "charlist":
|
|
if (operator == "+")
|
|
newValue = currentValue.replace(new RegExp("[" + value + "]", "g"), "") + value;
|
|
else if (operator == "-")
|
|
newValue = currentValue.replace(value, "");
|
|
else if (operator == "^")
|
|
// NOTE: Vim doesn't prepend if there's a match in the current value
|
|
newValue = value + currentValue.replace(new RegExp("[" + value + "]", "g"), "");
|
|
else
|
|
newValue = value;
|
|
|
|
break;
|
|
|
|
case "stringlist":
|
|
if (operator == "+")
|
|
{
|
|
if (!currentValue.match(value))
|
|
newValue = (currentValue ? currentValue + "," : "") + value;
|
|
else
|
|
newValue = currentValue;
|
|
}
|
|
else if (operator == "-")
|
|
{
|
|
newValue = currentValue.replace(new RegExp("^" + value + ",?|," + value), "");
|
|
}
|
|
else if (operator == "^")
|
|
{
|
|
if (!currentValue.match(value))
|
|
newValue = value + (currentValue ? "," : "") + currentValue;
|
|
else
|
|
newValue = currentValue;
|
|
}
|
|
else
|
|
{
|
|
newValue = value;
|
|
}
|
|
|
|
break;
|
|
|
|
case "string":
|
|
if (operator == "+")
|
|
newValue = currentValue + value;
|
|
else if (operator == "-")
|
|
newValue = currentValue.replace(value, "");
|
|
else if (operator == "^")
|
|
newValue = value + currentValue;
|
|
else
|
|
newValue = value;
|
|
|
|
break;
|
|
|
|
default:
|
|
vimperator.echoerr("E685: Internal error: option type `" + option.type + "' not supported");
|
|
}
|
|
|
|
if (option.isValidValue(newValue))
|
|
option.value = newValue;
|
|
else
|
|
// FIXME: need to be able to specify more specific errors
|
|
vimperator.echoerr("E474: Invalid argument: " + args);
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Set an option",
|
|
completer: function (filter, special) { return vimperator.completion.option(filter, special); }
|
|
}
|
|
));
|
|
// TODO: sclose instead?
|
|
commandManager.add(new vimperator.Command(["sbcl[ose]"],
|
|
function (args)
|
|
{
|
|
if (args)
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
return;
|
|
}
|
|
|
|
if (document.getElementById("sidebar-box").hidden == false)
|
|
toggleSidebar();
|
|
},
|
|
{
|
|
shortHelp: "Close the sidebar window"
|
|
}
|
|
));
|
|
// TODO: sopen instead? Separate :sidebar from :sbopen and make them behave
|
|
// more like :cw, :cope etc
|
|
commandManager.add(new vimperator.Command(["sideb[ar]", "sb[ar]", "sbope[n]"],
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
|
|
// do nothing if the requested sidebar is already open
|
|
if (document.getElementById("sidebar-title").value == args)
|
|
{
|
|
document.getElementById("sidebar-box").contentWindow.focus();
|
|
return;
|
|
}
|
|
|
|
var menu = document.getElementById("viewSidebarMenu");
|
|
|
|
for (var i = 0; i < menu.childNodes.length; i++)
|
|
{
|
|
if (menu.childNodes[i].label == args)
|
|
{
|
|
eval(menu.childNodes[i].getAttribute("oncommand"));
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Open the sidebar window",
|
|
completer: function (filter) { return vimperator.completion.sidebar(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["so[urce]"],
|
|
function (args, special)
|
|
{
|
|
// FIXME: implement proper filename quoting
|
|
//if (/[^\\]\s/.test(args))
|
|
//{
|
|
// vimperator.echoerr("E172: Only one file name allowed");
|
|
// return;
|
|
//}
|
|
|
|
vimperator.io.source(args, special);
|
|
},
|
|
{
|
|
shortHelp: "Read Ex commands from {file}",
|
|
completer: function (filter) { return vimperator.completion.file(filter, true); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["st[op]"],
|
|
BrowserStop,
|
|
{ shortHelp: "Stop loading" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["tab"],
|
|
function (args) { vimperator.execute(args, { inTab: true }); },
|
|
{
|
|
shortHelp: "Execute {cmd} and tell it to output in a new tab",
|
|
completer: function (filter) { return vimperator.completion.command(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabl[ast]"],
|
|
function () { vimperator.tabs.select("$", false); },
|
|
{ shortHelp: "Switch to the last tab" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabm[ove]"],
|
|
function (args, special)
|
|
{
|
|
// FIXME: tabmove! N should probably produce an error
|
|
if (!/^([+-]?\d+|)$/.test(args))
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
return;
|
|
}
|
|
|
|
if (!args)
|
|
args = "$"; // if not specified, move to the last tab
|
|
|
|
vimperator.tabs.move(getBrowser().mCurrentTab, args, special);
|
|
},
|
|
{
|
|
shortHelp: "Move the current tab after tab N"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabn[ext]", "tn[ext]"],
|
|
// TODO: count support
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
{
|
|
vimperator.tabs.select("+1", true);
|
|
}
|
|
else if (/^\d+$/.test(args))
|
|
{
|
|
var index = parseInt(args, 10) - 1;
|
|
if (index < vimperator.tabs.count)
|
|
vimperator.tabs.select(index, true);
|
|
else
|
|
vimperator.beep();
|
|
}
|
|
else
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Switch to the next or [count]th tab"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabo[nly]"],
|
|
function () { vimperator.tabs.keepOnly(getBrowser().mCurrentTab); },
|
|
{ shortHelp: "Close all other tabs" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabopen", "t[open]", "tabnew", "tabe[dit]"],
|
|
function (args, special)
|
|
{
|
|
var where = special ? vimperator.NEW_TAB : vimperator.NEW_BACKGROUND_TAB;
|
|
if (/\btabopen\b/.test(vimperator.options["activate"]))
|
|
where = special ? vimperator.NEW_BACKGROUND_TAB : vimperator.NEW_TAB;
|
|
|
|
if (args)
|
|
vimperator.open(args, where);
|
|
else
|
|
vimperator.open("about:blank", where);
|
|
},
|
|
{
|
|
shortHelp: "Open one or more URLs in a new tab",
|
|
completer: function (filter) { return vimperator.completion.url(filter); }
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabp[revious]", "tp[revious]", "tabN[ext]", "tN[ext]"],
|
|
// TODO: count support
|
|
function (args)
|
|
{
|
|
if (!args)
|
|
vimperator.tabs.select("-1", true);
|
|
else if (/^\d+$/.test(args))
|
|
vimperator.tabs.select("-" + args, true); // FIXME: urgh!
|
|
else
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
},
|
|
{
|
|
shortHelp: "Switch to the previous tab or go [count] tabs back"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["tabr[ewind]", "tabfir[st]"],
|
|
function () { vimperator.tabs.select(0, false); },
|
|
{ shortHelp: "Switch to the first tab" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["time"],
|
|
function (args, special, count)
|
|
{
|
|
try
|
|
{
|
|
if (count > 1)
|
|
{
|
|
var i = count;
|
|
var beforeTime = Date.now();
|
|
|
|
if (args && args[0] == ":")
|
|
{
|
|
while (i--)
|
|
vimperator.execute(args);
|
|
}
|
|
else
|
|
{
|
|
while (i--)
|
|
eval("with(vimperator){" + args + "}");
|
|
}
|
|
|
|
if (special)
|
|
return;
|
|
|
|
var afterTime = Date.now();
|
|
|
|
if ((afterTime - beforeTime) / count >= 100)
|
|
{
|
|
var each = ((afterTime - beforeTime) / 1000.0 / count);
|
|
var eachUnits = "sec";
|
|
}
|
|
else
|
|
{
|
|
var each = ((afterTime - beforeTime) / count);
|
|
var eachUnits = "msec";
|
|
}
|
|
|
|
if (afterTime - beforeTime >= 100)
|
|
{
|
|
var total = ((afterTime - beforeTime) / 1000.0);
|
|
var totalUnits = "sec";
|
|
}
|
|
else
|
|
{
|
|
var total = (afterTime - beforeTime);
|
|
var totalUnits = "msec";
|
|
}
|
|
|
|
var str = ":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) + "<br/>" +
|
|
"<table>" +
|
|
"<tr align=\"left\" class=\"hl-Title\"><th colspan=\"3\">Code execution summary</th></tr>" +
|
|
"<tr><td> Executed:</td><td align=\"right\"><span style=\"color: green\">" + count + "</span></td><td>times</td></tr>" +
|
|
"<tr><td> Average time:</td><td align=\"right\"><span style=\"color: green\">" + each.toFixed(2) + "</span></td><td>" + eachUnits + "</td></tr>" +
|
|
"<tr><td> Total time:</td><td align=\"right\"><span style=\"color: red\">" + total.toFixed(2) + "</span></td><td>" + totalUnits + "</td></tr>" +
|
|
"</table>";
|
|
|
|
vimperator.commandline.echo(str, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE);
|
|
}
|
|
else
|
|
{
|
|
var beforeTime = Date.now();
|
|
if (args && args[0] == ":")
|
|
vimperator.execute(args);
|
|
else
|
|
eval("with(vimperator){" + args + "}");
|
|
|
|
if (special)
|
|
return;
|
|
|
|
var afterTime = Date.now();
|
|
|
|
if (afterTime - beforeTime >= 100)
|
|
vimperator.echo("Total time: " + ((afterTime - beforeTime) / 1000.0).toFixed(2) + " sec");
|
|
else
|
|
vimperator.echo("Total time: " + (afterTime - beforeTime) + " msec");
|
|
}
|
|
}
|
|
catch (e)
|
|
{
|
|
vimperator.echoerr(e);
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Profile a piece of code or a command"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["u[ndo]"],
|
|
function (args, special, count)
|
|
{
|
|
if (count < 1)
|
|
count = 1;
|
|
|
|
if (args)
|
|
{
|
|
var ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
|
|
getService(Components.interfaces.nsISessionStore);
|
|
var undoItems = eval("(" + ss.getClosedTabData(window) + ")");
|
|
for (var i = 0; i < undoItems.length; i++)
|
|
{
|
|
if (undoItems[i].state.entries[0].url == args)
|
|
{
|
|
count = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
undoCloseTab(count - 1);
|
|
},
|
|
{
|
|
shortHelp: "Undo closing of a tab",
|
|
completer: function (filter)
|
|
{
|
|
// get closed-tabs from nsSessionStore
|
|
var ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
|
|
getService(Components.interfaces.nsISessionStore);
|
|
var undoItems = eval("(" + ss.getClosedTabData(window) + ")");
|
|
var completions = [];
|
|
for (var i = 0; i < undoItems.length; i++)
|
|
{
|
|
// undoItems[i].image is also available if need for favicons
|
|
var url = undoItems[i].state.entries[0].url;
|
|
var title = undoItems[i].title;
|
|
if (vimperator.completion.match([url, title], filter, false))
|
|
completions.push([url, title]);
|
|
}
|
|
return [0, completions];
|
|
}
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["undoa[ll]"],
|
|
function (args, special, count)
|
|
{
|
|
if (count > -1)
|
|
{
|
|
vimperator.echoerr("E481: No range allowed");
|
|
return;
|
|
}
|
|
if (special)
|
|
{
|
|
vimperator.echoerr("E477: No ! allowed");
|
|
return;
|
|
}
|
|
|
|
var ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
|
|
getService(Components.interfaces.nsISessionStore);
|
|
var undoItems = eval("(" + ss.getClosedTabData(window) + ")");
|
|
for (var i = 0; i < undoItems.length; i++)
|
|
undoCloseTab(); // doesn't work with i as the index to undoCloseTab
|
|
},
|
|
{
|
|
shortHelp: "Undo closing of all closed tabs"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["unl[et]"],
|
|
function (args, special)
|
|
{
|
|
if (!args)
|
|
{
|
|
vimperator.echoerr("E471: Argument required");
|
|
return;
|
|
}
|
|
|
|
var names = args.split(/ /);
|
|
if (typeof names == "string") names = [names];
|
|
var length = names.length;
|
|
for (var i = 0, name = names[i]; i < length; name = names[++i])
|
|
{
|
|
var reference = vimperator.variableReference(name);
|
|
if (!reference[0])
|
|
{
|
|
if (!special)
|
|
vimperator.echoerr("E108: No such variable: " + name);
|
|
return;
|
|
}
|
|
|
|
delete reference[0][reference[1]];
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "Deletes a variable."
|
|
}
|
|
));
|
|
commandManager.add(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.add(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.add(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)"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["ve[rsion]"],
|
|
function (args, special)
|
|
{
|
|
if (special)
|
|
vimperator.open("about:");
|
|
else
|
|
vimperator.echo(":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) +
|
|
"\nVimperator " + vimperator.version + " running on:\n" + navigator.userAgent);
|
|
},
|
|
{
|
|
shortHelp: "Show version information"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["vie[wsource]"],
|
|
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)
|
|
}
|
|
},
|
|
{
|
|
shortHelp: "View source code of current document"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["viu[sage]"],
|
|
function (args, special, count, modifiers)
|
|
{
|
|
var usage = "<table>";
|
|
for (let mapping in vimperator.mappings)
|
|
{
|
|
usage += "<tr><td style='color: magenta; padding-right: 20px'> " +
|
|
vimperator.util.escapeHTML(mapping.names[0]) + "</td><td>" +
|
|
vimperator.util.escapeHTML(mapping.shortHelp || "") + "</td></tr>";
|
|
}
|
|
usage += "</table>";
|
|
|
|
vimperator.echo(usage, vimperator.commandline.FORCE_MULTILINE);
|
|
},
|
|
{
|
|
shortHelp: "Show help for normal mode commands"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["winc[lose]", "wc[lose]"],
|
|
function (args) { window.close(); },
|
|
{ shortHelp: "Close window" }
|
|
));
|
|
commandManager.add(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"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["wqa[ll]", "wq", "xa[ll]"],
|
|
function () { vimperator.quit(true); },
|
|
{ shortHelp: "Save the session and quit" }
|
|
));
|
|
commandManager.add(new vimperator.Command(["zo[om]"],
|
|
function (args, special)
|
|
{
|
|
var level;
|
|
|
|
if (!args)
|
|
{
|
|
level = 100;
|
|
}
|
|
else if (/^\d+$/.test(args))
|
|
{
|
|
level = parseInt(args, 10);
|
|
}
|
|
else if (/^[+-]\d+$/.test(args))
|
|
{
|
|
if (special)
|
|
level = vimperator.buffer.fullZoom + parseInt(args, 10);
|
|
else
|
|
level = vimperator.buffer.textZoom + parseInt(args, 10);
|
|
|
|
// relative args shouldn't take us out of range
|
|
if (level < 1)
|
|
level = 1;
|
|
if (level > 2000)
|
|
level = 2000;
|
|
}
|
|
else
|
|
{
|
|
vimperator.echoerr("E488: Trailing characters");
|
|
return;
|
|
}
|
|
|
|
if (special)
|
|
vimperator.buffer.fullZoom = level;
|
|
else
|
|
vimperator.buffer.textZoom = level;
|
|
},
|
|
{
|
|
shortHelp: "Set zoom value of current web page"
|
|
}
|
|
));
|
|
commandManager.add(new vimperator.Command(["!", "run"],
|
|
function (args, special)
|
|
{
|
|
// :!! needs to be treated specially as the command parser sets the special flag but removes the ! from args
|
|
if (special)
|
|
args = "!" + (args || "");
|
|
|
|
// TODO: better escaping of ! to also substitute \\! correctly
|
|
args = args.replace(/(^|[^\\])!/g, "$1" + lastRunCommand);
|
|
lastRunCommand = args;
|
|
|
|
var output = vimperator.io.system(args);
|
|
if (output)
|
|
vimperator.echo(vimperator.util.escapeHTML(output));
|
|
},
|
|
{
|
|
shortHelp: "Run a command"
|
|
}
|
|
));
|
|
//}}}
|
|
|
|
return commandManager;
|
|
}; //}}}
|
|
|
|
// vim: set fdm=marker sw=4 ts=4 et:
|