1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-21 06:48:00 +01:00

imported patch groups

--HG--
branch : groups
This commit is contained in:
Kris Maglione
2011-02-05 03:02:36 -05:00
parent e9fd99dafa
commit 9b3ad1c7c6
16 changed files with 468 additions and 344 deletions

View File

@@ -241,7 +241,7 @@ var Abbreviations = Module("abbreviations", {
abbreviations.list(modes, lhs || ""); abbreviations.list(modes, lhs || "");
else { else {
if (args["-javascript"]) if (args["-javascript"])
rhs = Command.bindMacro({ literalArg: rhs }, "-javascript", ["editor"]); rhs = contexts.bindMacro({ literalArg: rhs }, "-javascript", ["editor"]);
abbreviations.add(modes, lhs, rhs); abbreviations.add(modes, lhs, rhs);
} }
}, { }, {

View File

@@ -156,7 +156,7 @@ var AutoCommands = Module("autocommands", {
if (args.length > 2) { // add new command, possibly removing all others with the same event/pattern if (args.length > 2) { // add new command, possibly removing all others with the same event/pattern
if (args.bang) if (args.bang)
autocommands.remove(event, regexp); autocommands.remove(event, regexp);
cmd = Command.bindMacro(args, "-ex", function (params) params); cmd = contexts.bindMacro(args, "-ex", function (params) params);
autocommands.add(events, regexp, cmd); autocommands.add(events, regexp, cmd);
} }
else { else {
@@ -245,7 +245,7 @@ var AutoCommands = Module("autocommands", {
}; };
}, },
javascript: function () { javascript: function () {
JavaScript.setCompleter(this.get, [function () Iterator(config.autocommands)]); JavaScript.setCompleter(autocommands.get, [function () Iterator(config.autocommands)]);
}, },
options: function () { options: function () {
options.add(["eventignore", "ei"], options.add(["eventignore", "ei"],

View File

@@ -262,7 +262,7 @@ var Buffer = Module("buffer", {
dactylLoadCount: 0, dactylLoadCount: 0,
// XXX: function may later be needed to detect a canceled synchronous openURL() // XXX: function may later be needed to detect a canceled synchronous openURL()
onStateChange: function onStateChange(webProgress, request, flags, status) { onStateChange: util.wrapCallback(function onStateChange(webProgress, request, flags, status) {
onStateChange.superapply(this, arguments); onStateChange.superapply(this, arguments);
// STATE_IS_DOCUMENT | STATE_IS_WINDOW is important, because we also // STATE_IS_DOCUMENT | STATE_IS_WINDOW is important, because we also
// receive statechange events for loading images and other parts of the web page // receive statechange events for loading images and other parts of the web page
@@ -286,9 +286,9 @@ var Buffer = Module("buffer", {
statusline.updateUrl(); statusline.updateUrl();
} }
} }
}, }),
// for notifying the user about secure web pages // for notifying the user about secure web pages
onSecurityChange: function onSecurityChange(webProgress, request, state) { onSecurityChange: util.wrapCallback(function onSecurityChange(webProgress, request, state) {
onSecurityChange.superapply(this, arguments); onSecurityChange.superapply(this, arguments);
if (state & Ci.nsIWebProgressListener.STATE_IS_BROKEN) if (state & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
statusline.security = "broken"; statusline.security = "broken";
@@ -300,22 +300,27 @@ var Buffer = Module("buffer", {
statusline.security = "insecure"; statusline.security = "insecure";
if (webProgress && webProgress.DOMWindow) if (webProgress && webProgress.DOMWindow)
webProgress.DOMWindow.document.dactylSecurity = statusline.security; webProgress.DOMWindow.document.dactylSecurity = statusline.security;
}, }),
onStatusChange: function onStatusChange(webProgress, request, status, message) { onStatusChange: util.wrapCallback(function onStatusChange(webProgress, request, status, message) {
onStatusChange.superapply(this, arguments); onStatusChange.superapply(this, arguments);
statusline.updateUrl(message); statusline.updateUrl(message);
}, }),
onProgressChange: function onProgressChange(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) { onProgressChange: util.wrapCallback(function onProgressChange(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) {
onProgressChange.superapply(this, arguments); try {
if (webProgress.DOMWindow) onProgressChange.superapply(this, arguments);
webProgress.DOMWindow.dactylProgress = curTotalProgress / maxTotalProgress; if (webProgress && webProgress.DOMWindow)
statusline.progress = curTotalProgress / maxTotalProgress; webProgress.DOMWindow.dactylProgress = curTotalProgress / maxTotalProgress;
}, statusline.progress = curTotalProgress / maxTotalProgress;
}
catch (e) {
util.reportError(e);
}
}),
// happens when the users switches tabs // happens when the users switches tabs
onLocationChange: function onLocationChange(webProgress, request, uri) { onLocationChange: util.wrapCallback(function onLocationChange(webProgress, request, uri) {
onLocationChange.superapply(this, arguments); onLocationChange.superapply(this, arguments);
delete mappings.hives; delete contexts.groups;
statusline.updateUrl(); statusline.updateUrl();
statusline.progress = ""; statusline.progress = "";
@@ -352,13 +357,13 @@ var Buffer = Module("buffer", {
if (loaded.commandline) if (loaded.commandline)
commandline.clear(); commandline.clear();
}, 500); }, 500);
}, }),
// called at the very end of a page load // called at the very end of a page load
asyncUpdateUI: function asyncUpdateUI() { asyncUpdateUI: util.wrapCallback(function asyncUpdateUI() {
asyncUpdateUI.superapply(this, arguments); asyncUpdateUI.superapply(this, arguments);
util.timeout(function () { statusline.updateUrl(); }, 100); util.timeout(function () { statusline.updateUrl(); }, 100);
}, }),
setOverLink: function setOverLink(link, b) { setOverLink: util.wrapCallback(function setOverLink(link, b) {
setOverLink.superapply(this, arguments); setOverLink.superapply(this, arguments);
switch (options["showstatuslinks"]) { switch (options["showstatuslinks"]) {
case "status": case "status":
@@ -371,7 +376,7 @@ var Buffer = Module("buffer", {
commandline.clear(); commandline.clear();
break; break;
} }
}, }),
}, },
/** /**

View File

@@ -352,8 +352,8 @@ var CommandMode = Class("CommandMode", {
if (this.history) if (this.history)
this.history.save(); this.history.save();
commandline.hideCompletions();
this.resetCompletions(); this.resetCompletions();
commandline.hideCompletions();
modes.delay(function () { modes.delay(function () {
if (!this.keepCommand || commandline.silent || commandline.quiet) if (!this.keepCommand || commandline.silent || commandline.quiet)
@@ -423,11 +423,13 @@ var CommandExMode = Class("CommandExMode", CommandMode, {
}, },
onSubmit: function onSubmit(command) { onSubmit: function onSubmit(command) {
io.withSavedValues(["readHeredoc", "sourcing"], function () { io.withSavedValues(["readHeredoc"], function () {
this.sourcing = { file: "[Command Line]", line: 1 };
this.readHeredoc = commandline.readHeredoc; this.readHeredoc = commandline.readHeredoc;
commands.repeat = command; contexts.withSavedValues(["context"], function () {
dactyl.execute(command); this.context = { file: "[Command Line]", line: 1 };
commands.repeat = command;
dactyl.execute(command);
});
}); });
} }
}); });
@@ -504,11 +506,6 @@ var CommandLine = Module("commandline", {
}, message)); }, message));
} }
}; //}}} }; //}}}
this._silent = false;
this._quiet = false;
this._lastEcho = null;
}, },
/** /**
@@ -546,12 +543,14 @@ var CommandLine = Module("commandline", {
get completionContext() this._completions.context, get completionContext() this._completions.context,
_silent: false,
get silent() this._silent, get silent() this._silent,
set silent(val) { set silent(val) {
this._silent = val; this._silent = val;
this.quiet = this.quiet; this.quiet = this.quiet;
}, },
_quite: false,
get quiet() this._quiet, get quiet() this._quiet,
set quiet(val) { set quiet(val) {
this._quiet = val; this._quiet = val;
@@ -665,6 +664,8 @@ var CommandLine = Module("commandline", {
} }
}, },
_lastEcho: null,
/** /**
* Output the given string onto the command line. With no flags, the * Output the given string onto the command line. With no flags, the
* message will be shown in the status line if it's short enough to * message will be shown in the status line if it's short enough to

View File

@@ -139,8 +139,9 @@ var Command = Class("Command", {
* @param {Object} modifiers Any modifiers to be passed to {@link #action}. * @param {Object} modifiers Any modifiers to be passed to {@link #action}.
*/ */
execute: function (args, modifiers) { execute: function (args, modifiers) {
if (this.deprecated && !set.add(this.complained, io.sourcing ? io.sourcing.file : "[Command Line]")) { let context = args.context;
let loc = io.sourcing ? io.sourcing.file + ":" + io.sourcing.line + ": " : ""; if (this.deprecated && !set.add(this.complained, context ? context.file : "[Command Line]")) {
let loc = contexts.context ? context.file + ":" + context.line + ": " : "";
dactyl.echoerr(loc + ":" + this.name + " is deprecated" + dactyl.echoerr(loc + ":" + this.name + " is deprecated" +
(isString(this.deprecated) ? ": " + this.deprecated : "")); (isString(this.deprecated) ? ": " + this.deprecated : ""));
} }
@@ -155,7 +156,7 @@ var Command = Class("Command", {
return !dactyl.trapErrors(function exec(command) { return !dactyl.trapErrors(function exec(command) {
if (this.always) if (this.always)
this.always(args, modifiers); this.always(args, modifiers);
if (!io.sourcing || !io.sourcing.noExecute) if (!contexts.context || !contexts.context.noExecute)
this.action(args, modifiers); this.action(args, modifiers);
}, this); }, this);
}, },
@@ -271,9 +272,15 @@ var Command = Class("Command", {
.toObject(), .toObject(),
{ {
__iterator__: function () array.iterItems(this), __iterator__: function () array.iterItems(this),
command: this, command: this,
get context() contexts.context,
explicitOpts: Class.memoize(function () ({})), explicitOpts: Class.memoize(function () ({})),
get literalArg() this.command.literal != null && this[this.command.literal] || "", get literalArg() this.command.literal != null && this[this.command.literal] || "",
// TODO: string: Class.memoize(function () { ... }), // TODO: string: Class.memoize(function () { ... }),
verify: function verify() { verify: function verify() {
if (this.command.argCount) { if (this.command.argCount) {
@@ -321,51 +328,6 @@ var Command = Class("Command", {
*/ */
replacementText: null replacementText: null
}, { }, {
bindMacro: function (args, default_, params) {
let process = util.identity;
if (callable(params))
var makeParams = function makeParams(self, args)
iter.toObject([k, process(v)]
for ([k, v] in iter(params.apply(self, args))));
else if (params)
makeParams = function makeParams(self, args)
iter.toObject([name, process(args[i])]
for ([i, name] in Iterator(params)));
let rhs = args.literalArg;
let type = ["-builtin", "-ex", "-javascript", "-keys"].reduce(function (a, b) args[b] ? b : a, default_);
switch (type) {
case "-builtin":
let noremap = true;
/* fallthrough */
case "-keys":
let silent = args["-silent"];
rhs = events.canonicalKeys(rhs, true);
var action = function action() events.feedkeys(action.macro(makeParams(this, arguments)),
noremap, silent);
action.macro = util.compileMacro(rhs, true);
break;
case "-ex":
action = function action() commands.execute(action.macro, makeParams(this, arguments),
false, null, action.sourcing);
action.macro = util.compileMacro(rhs, true);
action.sourcing = io.sourcing && update({}, io.sourcing);
break;
case "-javascript":
if (callable(params))
action = dactyl.userEval("(function action() { with (action.makeParams(this, arguments)) {" + args.literalArg + "} })");
else
action = dactyl.userFunc.apply(dactyl, params.concat(args.literalArg).array);
process = function (param) isObject(param) && param.valueOf ? param.valueOf() : param;
action.makeParams = makeParams;
break;
}
action.toString = function toString() (type === default_ ? "" : type + " ") + rhs;
args = null;
return action;
},
// TODO: do we really need more than longNames as a convenience anyway? // TODO: do we really need more than longNames as a convenience anyway?
/** /**
* Converts command name abbreviation specs of the form * Converts command name abbreviation specs of the form
@@ -576,60 +538,62 @@ var Commands = Module("commands", {
* interpolated into the command string. * interpolated into the command string.
* @param {object} args Optional arguments object to be passed to * @param {object} args Optional arguments object to be passed to
* command actions. * command actions.
* @param {object} sourcing An object containing information about * @param {object} context An object containing information about
* the file that is being or has been sourced to obtain the * the file that is being or has been sourced to obtain the
* command string. * command string.
*/ */
execute: function (string, tokens, silent, args, sourcing) { execute: function (string, tokens, silent, args, context) {
io.withSavedValues(["readHeredoc", "sourcing"], function () { contexts.withSavedValues(["context"], function () {
sourcing = sourcing || this.sourcing || { file: "[Command Line]", line: 1 }; context = update({}, context || this.context || { file: "[Command Line]", line: 1 });
this.sourcing = update({}, sourcing); this.context = context;
args = update({}, args || {}); io.withSavedValues(["readHeredoc"], function () {
this.readHeredoc = function (end) {
let res = [];
contexts.context.line++;
while (++i < lines.length) {
if (lines[i] === end)
return res.join("\n");
res.push(lines[i]);
}
dactyl.assert(false, "Unexpected end of file waiting for " + end);
};
if (tokens && !callable(string)) args = update({}, args || {});
string = util.compileMacro(string, true);
if (callable(string))
string = string(tokens || {});
let lines = string.split(/\r\n|[\r\n]/); if (tokens && !callable(string))
string = util.compileMacro(string, true);
if (callable(string))
string = string(tokens || {});
this.readHeredoc = function (end) { let lines = string.split(/\r\n|[\r\n]/);
let res = [];
this.sourcing.line++;
while (++i < lines.length) {
if (lines[i] === end)
return res.join("\n");
res.push(lines[i]);
}
dactyl.assert(false, "Unexpected end of file waiting for " + end);
};
for (var i = 0; i < lines.length && !this.sourcing.finished; i++) { for (var i = 0; i < lines.length && !context.finished; i++) {
// Deal with editors from Silly OSs. // Deal with editors from Silly OSs.
let line = lines[i].replace(/\r$/, ""); let line = lines[i].replace(/\r$/, "");
this.sourcing.line = sourcing.line + i; context.line = context.line + i;
// Process escaped new lines // Process escaped new lines
while (i < lines.length && /^\s*\\/.test(lines[i + 1])) while (i < lines.length && /^\s*\\/.test(lines[i + 1]))
line += "\n" + lines[++i].replace(/^\s*\\/, ""); line += "\n" + lines[++i].replace(/^\s*\\/, "");
try { try {
dactyl.execute(line, args); dactyl.execute(line, args);
} }
catch (e) { catch (e) {
if (!silent || silent === "loud") { if (!silent || silent === "loud") {
if (silent !== "loud") if (silent !== "loud")
e.message = this.sourcing.file + ":" + this.sourcing.line + ": " + e.message; e.message = context.file + ":" + context.line + ": " + e.message;
else { else {
dactyl.echoerr("Error detected while processing " + this.sourcing.file); dactyl.echoerr("Error detected while processing " + context.file);
dactyl.echomsg("line\t" + this.sourcing.line + ":"); dactyl.echomsg("line\t" + context.line + ":");
}
dactyl.reportError(e, true);
} }
dactyl.reportError(e, true);
} }
} }
} });
}); });
}, },
@@ -1172,12 +1136,12 @@ var Commands = Module("commands", {
* @param {nsIStackFrame} frame * @param {nsIStackFrame} frame
*/ */
getCaller: function (frame) { getCaller: function (frame) {
if (io.sourcing) if (contexts.context)
return { return {
__proto__: frame, __proto__: frame,
filename: io.sourcing.file[0] == "[" ? io.sourcing.file : filename: contexts.context.file[0] == "[" ? contexts.context.file :
services.io.newFileURI(File(io.sourcing.file)).spec, services.io.newFileURI(File(contexts.context.file)).spec,
lineNumber: io.sourcing.line lineNumber: contexts.context.line
}; };
return frame; return frame;
}, },
@@ -1302,11 +1266,11 @@ var Commands = Module("commands", {
if (/^custom,/.test(completer)) { if (/^custom,/.test(completer)) {
completer = completer.substr(7); completer = completer.substr(7);
let sourcing = update({}, io.sourcing || {}); let context = update({}, contexts.context || {});
completerFunc = function (context) { completerFunc = function (context) {
try { try {
var result = io.withSavedValues(["sourcing"], function () { var result = contextswithSavedValues(["context"], function () {
io.sourcing = sourcing; contexts.context = context;
return dactyl.userEval(completer); return dactyl.userEval(completer);
}); });
} }
@@ -1328,7 +1292,7 @@ var Commands = Module("commands", {
let added = commands.addUserCommand(cmd.split(","), let added = commands.addUserCommand(cmd.split(","),
args["-description"], args["-description"],
Command.bindMacro(args, "-ex", contexts.bindMacro(args, "-ex",
function makeParams(args, modifiers) ({ function makeParams(args, modifiers) ({
args: { args: {
__proto__: args, __proto__: args,
@@ -1345,7 +1309,7 @@ var Commands = Module("commands", {
literal: args["-literal"], literal: args["-literal"],
persist: !args["-nopersist"], persist: !args["-nopersist"],
replacementText: args.literalArg, replacementText: args.literalArg,
sourcing: io.sourcing && update({}, io.sourcing) context: contexts.context && update({}, contexts.context)
}, args.bang); }, args.bang);
if (!added) if (!added)
@@ -1484,62 +1448,6 @@ var Commands = Module("commands", {
} }
}); });
function checkStack(cmd) {
util.assert(io.sourcing && io.sourcing.stack &&
io.sourcing.stack[cmd] && io.sourcing.stack[cmd].length,
"Invalid use of conditional");
}
function pop(cmd) {
checkStack(cmd);
return io.sourcing.stack[cmd].pop();
}
function push(cmd, value) {
util.assert(io.sourcing, "Invalid use of conditional");
if (arguments.length < 2)
value = io.sourcing.noExecute;
io.sourcing.stack = io.sourcing.stack || {};
io.sourcing.stack[cmd] = (io.sourcing.stack[cmd] || []).concat([value]);
}
commands.add(["if"],
"Execute commands until the next :elseif, :else, or :endif only if the argument returns true",
function (args) { io.sourcing.noExecute = !dactyl.userEval(args[0]); },
{
always: function (args) { push("if"); },
argCount: "1",
literal: 0
});
commands.add(["elsei[f]", "elif"],
"Execute commands until the next :elseif, :else, or :endif only if the argument returns true",
function (args) {},
{
always: function (args) {
checkStack("if");
io.sourcing.noExecute = io.sourcing.stack.if.slice(-1)[0] ||
!io.sourcing.noExecute || !dactyl.userEval(args[0]);
},
argCount: "1",
literal: 0
});
commands.add(["el[se]"],
"Execute commands until the next :endif only if the previous conditionals were not executed",
function (args) {},
{
always: function (args) {
checkStack("if");
io.sourcing.noExecute = io.sourcing.stack.if.slice(-1)[0] ||
!io.sourcing.noExecute;
},
argCount: "0"
});
commands.add(["en[dif]", "fi"],
"End a string of :if/:elseif/:else conditionals",
function (args) {},
{
always: function (args) { io.sourcing.noExecute = pop("if"); },
argCount: "0"
});
commands.add(["y[ank]"], commands.add(["y[ank]"],
"Yank the output of the given command to the clipboard", "Yank the output of the given command to the clipboard",
function (args) { function (args) {

318
common/content/contexts.js Normal file
View File

@@ -0,0 +1,318 @@
// Copyright (c) 2010-2011 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"use strict";
var Group = Class("Group", {
init: function init(name, description, filter, persist) {
const self = this;
this.name = name;
this.description = description;
this.filter = filter || function (uri) true;
this.persist = persist || false;
this.subGroups = { __proto__: this.subGroups, owner: this };
this.subGroups.instance = this.subGroups;
},
get toStringParams() [this.name],
get builtin() dactyl.builtinGroups.indexOf(this) >= 0,
subGroups: {}
}, {
subGroup: {},
subGroups: {},
SubGroup: Class("SubGroup", Class.Property, {
init: function init(name, constructor) {
const self = this;
if (this.Group)
return {
enumerable: true,
get: function () array(contexts.groups[self.name])
};
this.Group = constructor;
this.name = name;
memoize(Group.prototype.subGroups, name,
function () constructor(this.owner.name, this.owner.description,
this.owner.filter, this.owner.persist));
memoize(Group.subGroup, name,
function () Object.create({ _subGroup: name, __proto__: contexts.subGroupProto }));
memoize(Group.subGroups, name,
function () [g.subGroups[name] for (g in values(this.groups)) if (set.has(g.subGroups, name))]);
}
})
});
var Contexts = Module("contexts", {
init: function () {
this.groupList = [];
this.groupMap = {};
this.subGroupProto = {};
this.builtinGroups = [this.addGroup("builtin", "Builtin items"),
this.addGroup("user", "User-defined items", null, true)];
},
context: null,
groups: Class.memoize(function () ({
__proto__: Group.subGroups,
groups: this.groupList.filter(function (g) g.filter(buffer.uri))
})),
allGroups: Class.memoize(function () ({
__proto__: Group.subGroups,
groups: this.groupList
})),
get subGroup() Group.subGroup,
addGroup: function addGroup(name, description, filter, persist) {
this.removeGroup(name);
let group = Group(name, description, filter, persist);
this.groupList.unshift(group);
this.groupMap[name] = group;
this.subGroupProto.__defineGetter__(name, function () group.subGroups[this._subGroup]);
return group;
},
removeGroup: function removeGroup(name, filter) {
let group = this.getGroup(name);
dactyl.assert(!group || !group.builtin, "Cannot remove builtin group");
if (group)
this.groupList.splice(this.groupList.indexOf(group), 1);
if (this.context && this.context.group === group)
this.context.group = null;
delete this.groupMap[name];
delete this.subGroupProto[name];
delete this.groups;
return group;
},
getGroup: function getGroup(name, subGroup) {
let group = array.nth(this.groupList, function (h) h.name == name, 0) || null;
if (group && subGroup)
return group.subGroups[subGroup];
return group;
},
bindMacro: function (args, default_, params) {
let process = util.identity;
if (callable(params))
var makeParams = function makeParams(self, args)
iter.toObject([k, process(v)]
for ([k, v] in iter(params.apply(self, args))));
else if (params)
makeParams = function makeParams(self, args)
iter.toObject([name, process(args[i])]
for ([i, name] in Iterator(params)));
let rhs = args.literalArg;
let type = ["-builtin", "-ex", "-javascript", "-keys"].reduce(function (a, b) args[b] ? b : a, default_);
switch (type) {
case "-builtin":
let noremap = true;
/* fallthrough */
case "-keys":
let silent = args["-silent"];
rhs = events.canonicalKeys(rhs, true);
var action = function action() events.feedkeys(action.macro(makeParams(this, arguments)),
noremap, silent);
action.macro = util.compileMacro(rhs, true);
break;
case "-ex":
action = function action() commands.execute(action.macro, makeParams(this, arguments),
false, null, action.context);
action.macro = util.compileMacro(rhs, true);
action.context = this.context && update({}, this.context);
break;
case "-javascript":
if (callable(params))
action = dactyl.userEval("(function action() { with (action.makeParams(this, arguments)) {" + args.literalArg + "} })");
else
action = dactyl.userFunc.apply(dactyl, params.concat(args.literalArg).array);
process = function (param) isObject(param) && param.valueOf ? param.valueOf() : param;
action.makeParams = makeParams;
break;
}
action.toString = function toString() (type === default_ ? "" : type + " ") + rhs;
args = null;
return action;
}
}, {
}, {
commands: function initCommands() {
commands.add(["gr[oup]", "mapg[roup]"],
"Create or select a group",
function (args) {
dactyl.assert(args.length <= 2, "Trailing characters");
if (args.length == 0)
return void completion.listCompleter("group", "");
let name = Option.dequote(args[0]);
dactyl.assert(commands.validName.test(name), "Invalid group name");
let group = contexts.getGroup(name);
if (args.length == 2) {
dactyl.assert(!group || args.bang, "Group exists");
let filter = function siteFilter(uri)
siteFilter.filters.every(function (f) f(uri) == f.result);
update(filter, {
toString: function () this.filters.join(","),
filters: Option.splitList(args[1], true).map(function (pattern) {
let [, res, filter] = /^(!?)(.*)/.exec(pattern);
return update(Styles.matchFilter(Option.dequote(filter)), {
result: !res,
toString: function () pattern
});
})
});
group = contexts.addGroup(name, args["-description"], filter, !args["-nopersist"]);
}
dactyl.assert(group, "No such group: " + name);
dactyl.assert(group.name != "builtin", "Cannot modify builtin group");
if (args.context)
args.context.group = group;
},
{
argCount: "*",
bang: true,
completer: function (context, args) {
if (args.length == 1)
completion.group(context);
else {
Option.splitList(context.filter);
context.advance(Option._splitAt);
context.compare = CompletionContext.Sort.unsorted;
context.completions = [
[buffer.uri.host, "Current Host"],
[buffer.uri.spec, "Current Page"]
];
}
},
keepQuotes: true,
options: [
{
names: ["-description", "-desc", "-d"],
description: "A description of this group",
type: CommandOption.STRING
},
{
names: ["-nopersist", "-n"],
description: "Do not save this group to an auto-generated RC file"
}
]
});
commands.add(["delg[roup]", "delmapg[roup]"],
"Delete a group",
function (args) {
dactyl.assert(contexts.getGroup(args[0]), "No such group: " + args[0]);
contexts.removeGroup(args[0]);
},
{
argCount: "1",
completer: function (context, args) {
completion.group(context);
context.filters.push(function ({ item }) !item.builtin);
}
});
commands.add(["fini[sh]"],
"Stop sourcing a script file",
function (args) {
dactyl.assert(args.context, "E168: :finish used outside of a sourced file");
args.context.finished = true;
},
{ argCount: "0" });
function checkStack(cmd) {
util.assert(contexts.context && contexts.context.stack &&
contexts.context.stack[cmd] && contexts.context.stack[cmd].length,
"Invalid use of conditional");
}
function pop(cmd) {
checkStack(cmd);
return contexts.context.stack[cmd].pop();
}
function push(cmd, value) {
util.assert(contexts.context, "Invalid use of conditional");
if (arguments.length < 2)
value = contexts.context.noExecute;
contexts.context.stack = contexts.context.stack || {};
contexts.context.stack[cmd] = (contexts.context.stack[cmd] || []).concat([value]);
}
commands.add(["if"],
"Execute commands until the next :elseif, :else, or :endif only if the argument returns true",
function (args) { args.context.noExecute = !dactyl.userEval(args[0]); },
{
always: function (args) { push("if"); },
argCount: "1",
literal: 0
});
commands.add(["elsei[f]", "elif"],
"Execute commands until the next :elseif, :else, or :endif only if the argument returns true",
function (args) {},
{
always: function (args) {
checkStack("if");
args.context.noExecute = args.context.stack.if.slice(-1)[0] ||
!args.context.noExecute || !dactyl.userEval(args[0]);
},
argCount: "1",
literal: 0
});
commands.add(["el[se]"],
"Execute commands until the next :endif only if the previous conditionals were not executed",
function (args) {},
{
always: function (args) {
checkStack("if");
args.context.noExecute = args.context.stack.if.slice(-1)[0] ||
!args.context.noExecute;
},
argCount: "0"
});
commands.add(["en[dif]", "fi"],
"End a string of :if/:elseif/:else conditionals",
function (args) {},
{
always: function (args) { args.context.noExecute = pop("if"); },
argCount: "0"
});
},
completion: function initCompletion() {
completion.group = function group(context, modes) {
context.title = ["Group"];
context.keys = { text: "name", description: function (h) h.description || h.filter };
context.completions = contexts.groupList.slice(0, -1);
};
}
});

View File

@@ -12,7 +12,6 @@ default xml namespace = XHTML;
XML.ignoreWhitespace = false; XML.ignoreWhitespace = false;
XML.prettyPrinting = false; XML.prettyPrinting = false;
var plugins = { __proto__: modules };
var userContext = { __proto__: modules }; var userContext = { __proto__: modules };
var _userContext = newContext(userContext); var _userContext = newContext(userContext);
@@ -53,7 +52,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
destroy: function () { destroy: function () {
autocommands.trigger("LeavePre", {}); autocommands.trigger("LeavePre", {});
storage.saveAll();
dactyl.triggerObserver("shutdown", null); dactyl.triggerObserver("shutdown", null);
util.dump("All dactyl modules destroyed\n"); util.dump("All dactyl modules destroyed\n");
autocommands.trigger("Leave", {}); autocommands.trigger("Leave", {});
@@ -337,7 +335,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
dactyl.reportError(str); dactyl.reportError(str);
if (typeof str == "object" && "echoerr" in str) if (typeof str == "object" && "echoerr" in str)
str = str.echoerr; str = str.echoerr;
else if (isinstance(str, ["Error"])) else if (isinstance(str, ["Error"]) && str.fileName)
str = <>{str.fileName.replace(/^.* -> /, "")}: {str.lineNumber}: {str}</>; str = <>{str.fileName.replace(/^.* -> /, "")}: {str.lineNumber}: {str}</>;
if (options["errorbells"]) if (options["errorbells"])
@@ -395,9 +393,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
if (jsmodules.__proto__ != window) if (jsmodules.__proto__ != window)
str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }"; str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }";
let info = contexts.context;
if (fileName == null) if (fileName == null)
if (io.sourcing && io.sourcing.file[0] !== "[") if (info && info.file[0] !== "[")
({ file: fileName, line: lineNumber, context: ctxt }) = io.sourcing; ({ file: fileName, line: lineNumber, context: ctxt }) = info;
else try { else try {
if (!context) if (!context)
context = userContext || ctxt; context = userContext || ctxt;
@@ -408,8 +407,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
this.loadScript("resource://dactyl-content/eval.js", context); this.loadScript("resource://dactyl-content/eval.js", context);
if (context[EVAL_ERROR]) { if (context[EVAL_ERROR]) {
try { try {
context[EVAL_ERROR].fileName = io.sourcing.file; context[EVAL_ERROR].fileName = context.file;
context[EVAL_ERROR].lineNumber += io.sourcing.line; context[EVAL_ERROR].lineNumber += context.line;
} }
catch (e) {} catch (e) {}
throw context[EVAL_ERROR]; throw context[EVAL_ERROR];
@@ -1356,7 +1355,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
reportError: function reportError(error, echo) { reportError: function reportError(error, echo) {
if (error instanceof FailedAssertion || error.message === "Interrupted") { if (error instanceof FailedAssertion || error.message === "Interrupted") {
let prefix = io.sourcing ? io.sourcing.file + ":" + io.sourcing.line + ": " : ""; let context = contexts.context;
let prefix = context ? context.file + ":" + context.line + ": " : "";
if (error.message && error.message.indexOf(prefix) !== 0) if (error.message && error.message.indexOf(prefix) !== 0)
error.message = prefix + error.message; error.message = prefix + error.message;

View File

@@ -107,6 +107,9 @@ var Map = Class("Map", {
.map(function ([i, prop]) [prop, this[i]], arguments) .map(function ([i, prop]) [prop, this[i]], arguments)
.toObject(); .toObject();
if (!args.context)
args.context = contexts.context;
let self = this; let self = this;
function repeat() self.action(args) function repeat() self.action(args)
if (this.names[0] != ".") // FIXME: Kludge. if (this.names[0] != ".") // FIXME: Kludge.
@@ -299,16 +302,15 @@ var MapHive = Class("MapHive", {
*/ */
var Mappings = Module("mappings", { var Mappings = Module("mappings", {
init: function () { init: function () {
this.user = MapHive("user", "User-defined mappings"); this.user = contexts.subGroup.mappings.user;
this.builtin = MapHive("builtin", "Builtin mappings"); this.builtin = contexts.subGroup.mappings.builtin;
this.builtinHives = array([this.user, this.builtin]);
this.allHives = [this.user, this.builtin];
}, },
repeat: Modes.boundProperty(), repeat: Modes.boundProperty(),
hives: Class.memoize(function () array(this.allHives.filter(function (h) h.filter(buffer.uri)))), hives: Group.SubGroup("mappings", MapHive),
get allHives() contexts.allGroups.mappings,
get userHives() this.allHives.filter(function (h) h !== this.builtin, this), get userHives() this.allHives.filter(function (h) h !== this.builtin, this),
@@ -365,29 +367,6 @@ var Mappings = Module("mappings", {
return map; return map;
}, },
addHive: function addHive(name, filter, description) {
this.removeHive(name);
let hive = MapHive(name, description, filter);
this.allHives.unshift(hive);
return hive;
},
removeHive: function removeHive(name, filter) {
let hive = this.getHive(name);
dactyl.assert(!hive || !hive.builtin, "Cannot remove builtin group");
if (hive)
this.allHives.splice(this.allHives.indexOf(hive), 1);
if (io.sourcing && io.sourcing.mapHive == hive)
io.sourcing.mapHive = null;
delete this.hives;
return hive;
},
getHive: function getHive(name) array.nth(this.allHives, function (h) h.name == name, 0) || null,
/** /**
* Returns the map from *mode* named *cmd*. * Returns the map from *mode* named *cmd*.
* *
@@ -482,7 +461,7 @@ var Mappings = Module("mappings", {
else { else {
args["-group"].add(mapmodes, [lhs], args["-group"].add(mapmodes, [lhs],
args["-description"], args["-description"],
Command.bindMacro(args, "-keys", function (params) params), contexts.bindMacro(args, "-keys", function (params) params),
{ {
arg: args["-arg"], arg: args["-arg"],
count: args["-count"], count: args["-count"],
@@ -650,96 +629,12 @@ var Mappings = Module("mappings", {
}); });
} }
commands.add(["mapg[roup]"],
"Create or select a mapping group",
function (args) {
dactyl.assert(args.length <= 2, "Trailing characters");
if (args.length == 0)
return void completion.listCompleter("mapGroup", "");
let name = Option.dequote(args[0]);
let hive = mappings.getHive(name);
if (args.length == 2) {
dactyl.assert(!hive || args.bang, "Group exists");
let filter = function siteFilter(uri)
siteFilter.filters.every(function (f) f(uri) == f.result);
update(filter, {
toString: function () this.filters.join(","),
filters: Option.splitList(args[1], true).map(function (pattern) {
let [, res, filter] = /^(!?)(.*)/.exec(pattern);
return update(Styles.matchFilter(Option.dequote(filter)), {
result: !res,
toString: function () pattern
});
})
});
hive = mappings.addHive(name, filter, args["-description"]);
if (args["-nopersist"])
hive.noPersist = true;
}
dactyl.assert(hive, "No mapping group: " + name);
dactyl.assert(hive.name != "builtin", "Can't map to builtin hive");
if (io.sourcing)
io.sourcing.mapHive = hive;
},
{
argCount: "*",
bang: true,
completer: function (context, args) {
if (args.length == 1)
completion.mapGroup(context);
else {
Option.splitList(context.filter);
context.advance(Option._splitAt);
context.compare = CompletionContext.Sort.unsorted;
context.completions = [
[buffer.uri.host, "Current Host"],
[buffer.uri.spec, "Current Page"]
];
}
},
keepQuotes: true,
options: [
{
names: ["-description", "-desc", "-d"],
description: "A description of this mapping group",
type: CommandOption.STRING
},
{
names: ["-nopersist", "-n"],
description: "Do not save this mapping group to an auto-generated RC file"
}
]
});
commands.add(["delmapg[roup]"],
"Delete a mapping group",
function (args) {
dactyl.assert(mappings.getHive(args[0]), "No mapping group: " + args[0]);
mappings.removeHive(args[0]);
},
{
argCount: "1",
completer: function (context, args) {
completion.mapGroup(context);
context.filters.push(function ({ item }) !item.builtin);
}
});
let groupFlag = { let groupFlag = {
names: ["-group", "-g"], names: ["-group", "-g"],
description: "Mapping group to which to add this mapping", description: "Mapping group to which to add this mapping",
type: ArgType("map-group", function (group) isString(group) ? mappings.getHive(group) : group), type: ArgType("map-group", function (group) isString(group) ? contexts.getGroup(group, "mappings") : group),
get default() io.sourcing && io.sourcing.mapHive || mappings.user, get default() (contexts.context && contexts.context.group || contexts.user).subGroups.mappings,
completer: function (context) completion.mapGroup(context) completer: function (context) completion.group(context)
}; };
let modeFlag = { let modeFlag = {
names: ["-mode", "-m"], names: ["-mode", "-m"],
@@ -848,11 +743,6 @@ var Mappings = Module("mappings", {
[mode.name.toLowerCase()]); [mode.name.toLowerCase()]);
}, },
completion: function () { completion: function () {
completion.mapGroup = function mapGroup(context, modes) {
context.title = ["Map group"];
context.keys = { text: "name", description: function (h) h.description || h.filter };
context.completions = mappings.userHives;
};
completion.userMapping = function userMapping(context, modes, hive) { completion.userMapping = function userMapping(context, modes, hive) {
// FIXME: have we decided on a 'standard' way to handle this clash? --djk // FIXME: have we decided on a 'standard' way to handle this clash? --djk
hive = hive || mappings.user; hive = hive || mappings.user;
@@ -862,7 +752,7 @@ var Mappings = Module("mappings", {
}; };
}, },
javascript: function () { javascript: function () {
JavaScript.setCompleter(this.get, JavaScript.setCompleter(mappings.get,
[ [
null, null,
function (context, obj, args) { function (context, obj, args) {

View File

@@ -4,6 +4,7 @@
// //
// This work is licensed for reuse under an MIT license. Details are // This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file. // given in the LICENSE.txt file included with this file.
"use strict";
var MOW = Module("mow", { var MOW = Module("mow", {
init: function () { init: function () {
@@ -71,7 +72,6 @@ var MOW = Module("mow", {
if (!commandline.commandVisible) if (!commandline.commandVisible)
commandline.hide(); commandline.hide();
this._startHints = false;
if (modes.main != modes.OUTPUT_MULTILINE) { if (modes.main != modes.OUTPUT_MULTILINE) {
modes.push(modes.OUTPUT_MULTILINE, null, { modes.push(modes.OUTPUT_MULTILINE, null, {
onKeyPress: this.closure.onKeyPress, onKeyPress: this.closure.onKeyPress,
@@ -170,6 +170,7 @@ var MOW = Module("mow", {
event.preventDefault(); event.preventDefault();
} }
}, },
contextEvents: { contextEvents: {
popupshowing: function (event) { popupshowing: function (event) {
let menu = commandline.widgets.contextMenu; let menu = commandline.widgets.contextMenu;
@@ -261,8 +262,7 @@ var MOW = Module("mow", {
if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow) if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow)
document.commandDispatcher.focusedWindow = content; document.commandDispatcher.focusedWindow = content;
} }
}), })
}, { }, {
}, { }, {
mappings: function () { mappings: function () {
@@ -277,7 +277,7 @@ var MOW = Module("mow", {
mow.echo(mow.lastOutput, "Normal"); mow.echo(mow.lastOutput, "Normal");
}); });
bind = function bind(keys, description, action, test, default_) { let bind = function bind(keys, description, action, test, default_) {
mappings.add([modes.OUTPUT_MULTILINE], mappings.add([modes.OUTPUT_MULTILINE],
keys, description, keys, description,
function (command) { function (command) {

View File

@@ -1295,7 +1295,7 @@ var Options = Module("options", {
}; };
}, },
javascript: function () { javascript: function () {
JavaScript.setCompleter(this.get, [function () ([o.name, o.description] for (o in options))]); JavaScript.setCompleter(options.get, [function () ([o.name, o.description] for (o in options))]);
}, },
sanitizer: function () { sanitizer: function () {
sanitizer.addItem("options", { sanitizer.addItem("options", {

View File

@@ -35,12 +35,12 @@ var AddonListener = Class("AddonListener", {
onExternalInstall: function (addon, existingAddon, needsRestart) {}, onExternalInstall: function (addon, existingAddon, needsRestart) {},
onDownloadStarted: listener("download", "started"), onDownloadStarted: listener("download", "started"),
onDownloadEnded: listener("download", "complete"), onDownloadEnded: listener("download", "complete"),
onDownloadCancelled: listener("download", "cancelled"), onDownloadCancelled: listener("download", "canceled"),
onDownloadFailed: listener("download", "failed"), onDownloadFailed: listener("download", "failed"),
onDownloadProgress: function (install) {}, onDownloadProgress: function (install) {},
onInstallStarted: function (install) {}, onInstallStarted: function (install) {},
onInstallEnded: listener("installation", "complete"), onInstallEnded: listener("installation", "complete"),
onInstallCancelled: listener("installation", "cancelled"), onInstallCancelled: listener("installation", "canceled"),
onInstallFailed: listener("installation", "failed") onInstallFailed: listener("installation", "failed")
}); });

View File

@@ -616,12 +616,12 @@ function update(target) {
if (desc.value instanceof Class.Property) if (desc.value instanceof Class.Property)
desc = desc.value.init(k) || desc.value; desc = desc.value.init(k) || desc.value;
if (typeof desc.value == "function" && Object.getPrototypeOf(target)) { if (typeof desc.value == "function" && Object.getPrototypeOf(target)) {
let func = desc.value; let func = desc.value.wrapped || desc.value;
desc.value.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]); func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]);
desc.value.superapply = function superapply(self, args) func.superapply = function superapply(self, args)
let (meth = Object.getPrototypeOf(target)[k]) let (meth = Object.getPrototypeOf(target)[k])
meth && meth.apply(self, args); meth && meth.apply(self, args);
desc.value.supercall = function supercall(self) func.supercall = function supercall(self)
func.superapply(self, Array.slice(arguments, 1)); func.superapply(self, Array.slice(arguments, 1));
} }
Object.defineProperty(target, k, desc); Object.defineProperty(target, k, desc);
@@ -663,7 +663,7 @@ function Class() {
superclass = args.shift(); superclass = args.shift();
var Constructor = eval(String.replace(<![CDATA[ var Constructor = eval(String.replace(<![CDATA[
(function constructor() { (function constructor(PARAMS) {
var self = Object.create(Constructor.prototype, { var self = Object.create(Constructor.prototype, {
constructor: { value: Constructor }, constructor: { value: Constructor },
}); });
@@ -671,7 +671,9 @@ function Class() {
var res = self.init.apply(self, arguments); var res = self.init.apply(self, arguments);
return res !== undefined ? res : self; return res !== undefined ? res : self;
})]]>, })]]>,
"constructor", (name || superclass.className).replace(/\W/g, "_"))); "constructor", (name || superclass.className).replace(/\W/g, "_"))
.replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1]));
Constructor.className = name || superclass.className || superclass.name; Constructor.className = name || superclass.className || superclass.name;
if ("init" in superclass.prototype) if ("init" in superclass.prototype)

View File

@@ -546,7 +546,7 @@ var IO = Module("io", {
PATH_SEP: deprecated("File.PATH_SEP", { get: function PATH_SEP() File.PATH_SEP }) PATH_SEP: deprecated("File.PATH_SEP", { get: function PATH_SEP() File.PATH_SEP })
}, { }, {
init: function init(dactyl, modules, window) { init: function init(dactyl, modules, window) {
modules.plugins.contexts = {}; Class.replaceProperty(modules.plugins, "contexts", {});
modules.Script = function Script(file) { modules.Script = function Script(file) {
const { io, plugins } = modules; const { io, plugins } = modules;
@@ -615,15 +615,6 @@ var IO = Module("io", {
literal: 0 literal: 0
}); });
// NOTE: this command is only used in :source
commands.add(["fini[sh]"],
"Stop sourcing a script file",
function () {
dactyl.assert(io.sourcing, "E168: :finish used outside of a sourced file");
io.sourcing.finished = true;
},
{ argCount: "0" });
commands.add(["pw[d]"], commands.add(["pw[d]"],
"Print the current directory name", "Print the current directory name",
function () { dactyl.echomsg(io.cwd.path); }, function () { dactyl.echomsg(io.cwd.path); },

View File

@@ -144,6 +144,7 @@ var Overlay = Module("Overlay", {
return sandbox; return sandbox;
} }
}); });
modules.plugins = create(modules);
modules.modules = modules; modules.modules = modules;
window.dactyl = { modules: modules }; window.dactyl = { modules: modules };
@@ -163,12 +164,13 @@ var Overlay = Module("Overlay", {
"util" "util"
].forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name)); ].forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name));
["dactyl", ["contexts",
"dactyl",
"modes", "modes",
"commandline",
"abbreviations", "abbreviations",
"autocommands", "autocommands",
"buffer", "buffer",
"commandline",
"commands", "commands",
"editor", "editor",
"events", "events",

View File

@@ -152,6 +152,8 @@ var Storage = Module("Storage", {
}, },
cleanup: function () { cleanup: function () {
this.saveAll();
for (let key in keys(this.keys)) { for (let key in keys(this.keys)) {
if (this[key].timer) if (this[key].timer)
this[key].timer.flush(); this[key].timer.flush();

View File

@@ -32,8 +32,8 @@ memoize(this, "Commands", function () {
var FailedAssertion = Class("FailedAssertion", ErrorBase); var FailedAssertion = Class("FailedAssertion", ErrorBase);
var Point = Struct("x", "y"); var Point = Struct("x", "y");
var wrapCallback = function wrapCallback(fn) var wrapCallback = function wrapCallback(fn) {
fn.wrapper = (function wrappedCallback () { fn.wrapper = function wrappedCallback () {
try { try {
return fn.apply(this, arguments); return fn.apply(this, arguments);
} }
@@ -41,7 +41,10 @@ var wrapCallback = function wrapCallback(fn)
util.reportError(e); util.reportError(e);
return undefined; return undefined;
} }
}) };
fn.wrapper.wrapped = fn;
return fn.wrapper;
}
var getAttr = function getAttr(elem, ns, name) var getAttr = function getAttr(elem, ns, name)
elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null; elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null;
@@ -1585,6 +1588,8 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
})(); })();
}, },
wrapCallback: wrapCallback,
/** /**
* Traps errors in the called function, possibly reporting them. * Traps errors in the called function, possibly reporting them.
* *