1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 18:07:58 +01:00
Files
pentadactyl-pm/common/content/autocommands.js
Kris Maglione 1557b70f45 Major documentation updates and formatting fixes, and many, many other changes thanks to an MQ glitch, including:
* Significant completion speed improvements
 * Significantly improve startup speed, in large part by lazily
   instantiating Options and Commands, lazily installing highlight
   stylesheets, etc.
 * Update logos and icons, fix atrocious about page
 * Fix Teledactyl
 * JavaScript completion now avoids accessing property values
 * Add Option#persist to define which options are saved with :mkp
 * Add new Dactyl component which holds add-on-specific configuration
   information and removes need for separate components for each dactyl
   host
 * Several fixes for latest nightlies
 * Significant code cleanup and many bug fixes

--HG--
rename : muttator/AUTHORS => teledactyl/AUTHORS
rename : muttator/Donors => teledactyl/Donors
rename : muttator/Makefile => teledactyl/Makefile
rename : muttator/NEWS => teledactyl/NEWS
rename : muttator/TODO => teledactyl/TODO
rename : muttator/chrome.manifest => teledactyl/chrome.manifest
rename : muttator/components/commandline-handler.js => teledactyl/components/commandline-handler.js
rename : muttator/components/protocols.js => teledactyl/components/protocols.js
rename : muttator/content/addressbook.js => teledactyl/content/addressbook.js
rename : muttator/content/compose/compose.js => teledactyl/content/compose/compose.js
rename : muttator/content/compose/compose.xul => teledactyl/content/compose/compose.xul
rename : muttator/content/compose/dactyl.dtd => teledactyl/content/compose/dactyl.dtd
rename : muttator/content/compose/dactyl.xul => teledactyl/content/compose/dactyl.xul
rename : muttator/content/config.js => teledactyl/content/config.js
rename : muttator/content/dactyl.dtd => teledactyl/content/dactyl.dtd
rename : muttator/content/logo.png => teledactyl/content/logo.png
rename : muttator/content/mail.js => teledactyl/content/mail.js
rename : muttator/content/muttator.xul => teledactyl/content/pentadactyl.xul
rename : muttator/contrib/vim/Makefile => teledactyl/contrib/vim/Makefile
rename : muttator/contrib/vim/ftdetect/muttator.vim => teledactyl/contrib/vim/ftdetect/muttator.vim
rename : muttator/contrib/vim/mkvimball.txt => teledactyl/contrib/vim/mkvimball.txt
rename : muttator/contrib/vim/syntax/muttator.vim => teledactyl/contrib/vim/syntax/muttator.vim
rename : muttator/install.rdf => teledactyl/install.rdf
rename : muttator/locale/en-US/Makefile => teledactyl/locale/en-US/Makefile
rename : muttator/locale/en-US/all.xml => teledactyl/locale/en-US/all.xml
rename : muttator/locale/en-US/autocommands.xml => teledactyl/locale/en-US/autocommands.xml
rename : muttator/locale/en-US/gui.xml => teledactyl/locale/en-US/gui.xml
rename : muttator/locale/en-US/intro.xml => teledactyl/locale/en-US/intro.xml
rename : muttator/skin/icon.png => teledactyl/skin/icon.png
2010-09-17 06:21:33 -04:00

287 lines
11 KiB
JavaScript

// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2010 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";
/** @scope modules */
const AutoCommand = Struct("event", "pattern", "command");
/**
* @instance autocommands
*/
const AutoCommands = Module("autocommands", {
init: function () {
this._store = [];
},
__iterator__: function () array.itervalues(this._store),
/**
* Adds a new autocommand. <b>cmd</b> will be executed when one of the
* specified <b>events</b> occurs and the URL of the applicable buffer
* matches <b>regex</b>.
*
* @param {Array} events The array of event names for which this
* autocommand should be executed.
* @param {string} regex The URL pattern to match against the buffer URL.
* @param {string} cmd The Ex command to run.
*/
add: function (events, regex, cmd) {
if (typeof events == "string") {
events = events.split(",");
dactyl.log("DEPRECATED: the events list arg to autocommands.add() should be an array of event names");
}
events.forEach(function (event) {
this._store.push(AutoCommand(event, RegExp(regex), cmd));
}, this);
},
/**
* Returns all autocommands with a matching <b>event</b> and
* <b>regex</b>.
*
* @param {string} event The event name filter.
* @param {string} regex The URL pattern filter.
* @returns {AutoCommand[]}
*/
get: function (event, regex) {
return this._store.filter(function (autoCmd) AutoCommands.matchAutoCmd(autoCmd, event, regex));
},
/**
* Deletes all autocommands with a matching <b>event</b> and
* <b>regex</b>.
*
* @param {string} event The event name filter.
* @param {string} regex The URL pattern filter.
*/
remove: function (event, regex) {
this._store = this._store.filter(function (autoCmd) !AutoCommands.matchAutoCmd(autoCmd, event, regex));
},
/**
* Lists all autocommands with a matching <b>event</b> and
* <b>regex</b>.
*
* @param {string} event The event name filter.
* @param {string} regex The URL pattern filter.
*/
list: function (event, regex) {
let cmds = {};
// XXX
this._store.forEach(function (autoCmd) {
if (AutoCommands.matchAutoCmd(autoCmd, event, regex)) {
cmds[autoCmd.event] = cmds[autoCmd.event] || [];
cmds[autoCmd.event].push(autoCmd);
}
});
commandline.commandOutput(
<table>
<tr highlight="Title">
<td colspan="2">----- Auto Commands -----</td>
</tr>
{
template.map(cmds, function ([event, items])
<tr highlight="Title">
<td colspan="2">{event}</td>
</tr>
+
template.map(items, function (item)
<tr>
<td>&#xa0;{item.pattern.source}</td>
<td>{item.command}</td>
</tr>))
}
</table>);
},
/**
* Triggers the execution of all autocommands registered for
* <b>event</b>. A map of <b>args</b> is passed to each autocommand
* when it is being executed.
*
* @param {string} event The event to fire.
* @param {Object} args The args to pass to each autocommand.
*/
trigger: function (event, args) {
if (options.get("eventignore").has("all", event))
return;
let autoCmds = this._store.filter(function (autoCmd) autoCmd.event == event);
dactyl.echomsg('Executing ' + event + ' Auto commands for "*"', 8);
let lastPattern = null;
let url = args.url || "";
for (let [, autoCmd] in Iterator(autoCmds)) {
if (autoCmd.pattern.test(url)) {
if (!lastPattern || lastPattern.source != autoCmd.pattern.source)
dactyl.echomsg("Executing " + event + " Auto commands for " + autoCmd.pattern.source.quote(), 8);
lastPattern = autoCmd.pattern;
dactyl.echomsg("autocommand " + autoCmd.command, 9);
if (typeof autoCmd.command == "function") {
try {
autoCmd.command.call(autoCmd, args);
}
catch (e) {
dactyl.echoerr(e);
}
}
else
dactyl.execute(commands.replaceTokens(autoCmd.command, args), null, true);
}
}
}
}, {
matchAutoCmd: function (autoCmd, event, regex) {
return (!event || autoCmd.event == event) && (!regex || autoCmd.pattern.source == regex);
}
}, {
commands: function () {
commands.add(["au[tocmd]"],
"Execute commands automatically on events",
function (args) {
let [event, regex, cmd] = args;
let events = [];
try {
RegExp(regex);
}
catch (e) {
dactyl.assert(false, "E475: Invalid argument: " + regex);
}
if (event) {
// NOTE: event can only be a comma separated list for |:au {event} {pat} {cmd}|
let validEvents = Object.keys(config.autocommands);
validEvents.push("*");
events = event.split(",");
dactyl.assert(events.every(function (event) validEvents.indexOf(event) >= 0),
"E216: No such group or event: " + event);
}
if (cmd) { // add new command, possibly removing all others with the same event/pattern
if (args.bang)
autocommands.remove(event, regex);
if (args["-javascript"])
cmd = dactyl.userfunc("args", "with(args) {" + cmd + "}");
autocommands.add(events, regex, cmd);
}
else {
if (event == "*")
event = null;
if (args.bang) {
// TODO: "*" only appears to work in Vim when there is a {group} specified
if (args[0] != "*" || regex)
autocommands.remove(event, regex); // remove all
}
else
autocommands.list(event, regex); // list all
}
}, {
bang: true,
completer: function (context, args) {
if (args.length == 1)
return completion.autocmdEvent(context);
if (args.length == 3)
return args["-javascript"] ? completion.javascript(context) : completion.ex(context);
},
literal: 2,
options: [
{
names: ["-javascript", "-js"],
description: "Interperate the action as JavaScript code rather than an ex command",
}
]
});
[
{
name: "do[autocmd]",
description: "Apply the autocommands matching the specified URL pattern to the current buffer"
}, {
name: "doautoa[ll]",
description: "Apply the autocommands matching the specified URL pattern to all buffers"
}
].forEach(function (command) {
commands.add([command.name],
command.description,
// TODO: Perhaps this should take -args to pass to the command?
function (args) {
// Vim compatible
if (args.length == 0) {
dactyl.echomsg("No matching autocommands");
return;
}
let [event, url] = args;
let defaultURL = url || buffer.URL;
let validEvents = Object.keys(config.autocommands);
// TODO: add command validators
dactyl.assert(event != "*",
"E217: Can't execute autocommands for ALL events");
dactyl.assert(validEvents.indexOf(event) >= 0,
"E216: No such group or event: " + args);
dactyl.assert(autocommands.get(event).some(function (c) c.pattern.test(defaultURL)),
"No matching autocommands");
if (this.name == "doautoall" && dactyl.has("tabs")) {
let current = tabs.index();
for (let i = 0; i < tabs.count; i++) {
tabs.select(i);
// if no url arg is specified use the current buffer's URL
autocommands.trigger(event, { url: url || buffer.URL });
}
tabs.select(current);
}
else
autocommands.trigger(event, { url: defaultURL });
}, {
argCount: "*", // FIXME: kludged for proper error message should be "1".
completer: function (context) completion.autocmdEvent(context)
});
});
},
completion: function () {
completion.autocmdEvent = function autocmdEvent(context) {
context.completions = Iterator(config.autocommands);
};
completion.macro = function macro(context) {
context.title = ["Macro", "Keys"];
context.completions = [item for (item in events.getMacros())];
};
},
javascript: function () {
JavaScript.setCompleter(this.get, [function () Iterator(config.autocommands)]);
},
options: function () {
options.add(["eventignore", "ei"],
"List of autocommand event names which should be ignored",
"stringlist", "",
{
completer: function () Iterator(update({ all: "All Events" }, config.autocommands))
});
options.add(["strictfocus", "sf"],
"Prevent scripts from focusing input elements without user intervention",
"boolean", true);
}
});
// vim: set fdm=marker sw=4 ts=4 et: