summaryrefslogtreecommitdiff
path: root/common/content
diff options
context:
space:
mode:
Diffstat (limited to 'common/content')
-rw-r--r--common/content/autocommands.js6
-rw-r--r--common/content/bookmarks.js40
-rw-r--r--common/content/browser.js2
-rw-r--r--common/content/buffer.js108
-rw-r--r--common/content/commandline.js149
-rw-r--r--common/content/commands.js95
-rw-r--r--common/content/completion.js191
-rw-r--r--common/content/configbase.js280
-rw-r--r--common/content/dactyl-overlay.js7
-rw-r--r--common/content/dactyl.js334
-rw-r--r--common/content/dactyl.xul13
-rw-r--r--common/content/editor.js2
-rw-r--r--common/content/eval.js2
-rw-r--r--common/content/events.js4
-rw-r--r--common/content/finder.js37
-rw-r--r--common/content/help-single.xsl36
-rw-r--r--common/content/help.js7
-rw-r--r--common/content/help.xsl375
-rw-r--r--common/content/hints.js22
-rw-r--r--common/content/history.js16
-rw-r--r--common/content/io.js65
-rw-r--r--common/content/javascript.js121
-rw-r--r--common/content/mappings.js9
-rw-r--r--common/content/marks.js16
-rw-r--r--common/content/modes.js7
-rw-r--r--common/content/modules.js44
-rw-r--r--common/content/options.js244
-rw-r--r--common/content/quickmarks.js4
-rw-r--r--common/content/statusline.js21
-rw-r--r--common/content/tabs.js29
-rw-r--r--common/content/x-click-but21.pngbin1861 -> 0 bytes
31 files changed, 1306 insertions, 980 deletions
diff --git a/common/content/autocommands.js b/common/content/autocommands.js
index 8acf6c36..a9675f42 100644
--- a/common/content/autocommands.js
+++ b/common/content/autocommands.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -18,7 +18,7 @@ const AutoCommands = Module("autocommands", {
this._store = [];
},
- __iterator__: function () util.Array.itervalues(this._store),
+ __iterator__: function () array.itervalues(this._store),
/**
* Adds a new autocommand. <b>cmd</b> will be executed when one of the
@@ -94,7 +94,7 @@ const AutoCommands = Module("autocommands", {
+
template.map(items, function (item)
<tr>
- <td>&#160;{item.pattern.source}</td>
+ <td>&#xa0;{item.pattern.source}</td>
<td>{item.command}</td>
</tr>))
}
diff --git a/common/content/bookmarks.js b/common/content/bookmarks.js
index ca83d81e..45c3ae8c 100644
--- a/common/content/bookmarks.js
+++ b/common/content/bookmarks.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -11,13 +11,11 @@ const DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png";
// also includes methods for dealing with keywords and search engines
const Bookmarks = Module("bookmarks", {
init: function () {
- let bookmarkObserver = function (key, event, arg) {
+ storage.addObserver("bookmark-cache", function (key, event, arg) {
if (event == "add")
autocommands.trigger("BookmarkAdd", arg);
statusline.updateUrl();
- };
-
- storage.addObserver("bookmark-cache", bookmarkObserver, window);
+ }, window);
},
get format() ({
@@ -36,7 +34,8 @@ const Bookmarks = Module("bookmarks", {
add: function add(starOnly, title, url, keyword, tags, force) {
try {
let uri = util.createURI(url);
- if (!force) {
+ if (!force && bookmarks.isBookmarked(uri.spec)) {
+ // WTF? This seems wrong... --Kris
for (let bmark in bookmarkcache) {
if (bmark[0] == uri.spec) {
var id = bmark[5];
@@ -74,21 +73,22 @@ const Bookmarks = Module("bookmarks", {
let count = this.remove(url);
if (count > 0)
- commandline.echo("Removed bookmark: " + url, commandline.HL_NORMAL, commandline.FORCE_SINGLELINE);
+ dactyl.echomsg({ domains: [util.getHost(url)], message: "Removed bookmark: " + url });
else {
let title = buffer.title || url;
let extra = "";
if (title != url)
extra = " (" + title + ")";
this.add(true, title, url);
- commandline.echo("Added bookmark: " + url + extra, commandline.HL_NORMAL, commandline.FORCE_SINGLELINE);
+ dactyl.echomsg({ domains: [util.getHost(url)], message: "Added bookmark: " + url + extra });
}
},
isBookmarked: function isBookmarked(url) {
try {
- return services.get("bookmarks").getBookmarkIdsForURI(makeURI(url), {})
- .some(bookmarkcache.isRegularBookmark);
+ return services.get("bookmarks")
+ .getBookmarkIdsForURI(makeURI(url), {})
+ .some(bookmarkcache.closure.isRegularBookmark);
}
catch (e) {
return false;
@@ -99,13 +99,14 @@ const Bookmarks = Module("bookmarks", {
remove: function remove(url) {
try {
let uri = util.newURI(url);
- let bmarks = services.get("bookmarks").getBookmarkIdsForURI(uri, {})
- .filter(bookmarkcache.isRegularBookmark);
+ let bmarks = services.get("bookmarks")
+ .getBookmarkIdsForURI(uri, {})
+ .filter(bookmarkcache.closure.isRegularBookmark);
bmarks.forEach(services.get("bookmarks").removeItem);
return bmarks.length;
}
catch (e) {
- dactyl.log(e, 0);
+ dactyl.reportError(e);
return 0;
}
},
@@ -287,7 +288,7 @@ const Bookmarks = Module("bookmarks", {
args.completeFilter = have.pop();
let prefix = filter.substr(0, filter.length - args.completeFilter.length);
- let tags = array.uniq(util.Array.flatten([b.tags for ([k, b] in Iterator(bookmarkcache.bookmarks))]));
+ let tags = array.uniq(array.flatten([b.tags for ([k, b] in Iterator(bookmarkcache.bookmarks))]));
return [[prefix + tag, tag] for ([i, tag] in Iterator(tags)) if (have.indexOf(tag) < 0)];
},
@@ -330,7 +331,8 @@ const Bookmarks = Module("bookmarks", {
if (bookmarks.add(false, title, url, keyword, tags, args.bang)) {
let extra = (title == url) ? "" : " (" + title + ")";
- dactyl.echomsg("Added bookmark: " + url + extra, 1, commandline.FORCE_SINGLELINE);
+ dactyl.echomsg({ domains: [util.getHost(url)], message: "Added bookmark: " + url + extra },
+ 1, commandline.FORCE_SINGLELINE);
}
else
dactyl.echoerr("Exxx: Could not add bookmark " + title.quote(), commandline.FORCE_SINGLELINE);
@@ -385,7 +387,8 @@ const Bookmarks = Module("bookmarks", {
let url = args.string || buffer.URL;
let deletedCount = bookmarks.remove(url);
- dactyl.echomsg(deletedCount + " bookmark(s) with url " + url.quote() + " deleted", 1, commandline.FORCE_SINGLELINE);
+ dactyl.echomsg({ domains: [util.getHost(url)], message: deletedCount + " bookmark(s) with url " + url.quote() + " deleted" },
+ 1, commandline.FORCE_SINGLELINE);
}
},
@@ -493,13 +496,12 @@ const Bookmarks = Module("bookmarks", {
return history.get({ uri: window.makeURI(begin), uriIsPrefix: true }).map(function (item) {
let rest = item.url.length - end.length;
let query = item.url.substring(begin.length, rest);
- if (item.url.substr(rest) == end && query.indexOf("&") == -1) {
+ if (item.url.substr(rest) == end && query.indexOf("&") == -1)
try {
- item.url = decodeURIComponent(query.replace(/#.*/, ""));
+ item.url = decodeURIComponent(query.replace(/#.*/, "").replace(/\+/g, " "));
return item;
}
catch (e) {}
- }
return null;
}).filter(util.identity);
};
diff --git a/common/content/browser.js b/common/content/browser.js
index 4334ffc6..e709cca7 100644
--- a/common/content/browser.js
+++ b/common/content/browser.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
diff --git a/common/content/buffer.js b/common/content/buffer.js
index 4cc84adb..3000d059 100644
--- a/common/content/buffer.js
+++ b/common/content/buffer.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -84,7 +84,7 @@ const Buffer = Module("buffer", {
const ACCESS_READ = Ci.nsICache.ACCESS_READ;
let cacheKey = doc.location.toString().replace(/#.*$/, "");
- for (let proto in util.Array.itervalues(["HTTP", "FTP"])) {
+ for (let proto in array.itervalues(["HTTP", "FTP"])) {
try {
var cacheEntryDescriptor = services.get("cache").createSession(proto, 0, true)
.openCacheEntry(cacheKey, ACCESS_READ, false);
@@ -174,9 +174,11 @@ const Buffer = Module("buffer", {
// event listener which is is called on each page load, even if the
// page is loaded in a background tab
onPageLoad: function onPageLoad(event) {
- if (!dactyl.helpInitialized && event.originalTarget instanceof Document)
- if (/^dactyl:/.test(event.originalTarget.location.href))
+ if (event.originalTarget instanceof Document)
+ if (/^dactyl:/.test(event.originalTarget.location.href)) {
dactyl.initHelp();
+ config.styleHelp();
+ }
if (event.originalTarget instanceof HTMLDocument) {
let doc = event.originalTarget;
@@ -197,7 +199,7 @@ const Buffer = Module("buffer", {
doc.pageIsFullyLoaded = 1;
if (doc != config.browser.contentDocument)
- dactyl.echomsg("Background tab loaded: " + doc.title || doc.location.href, 3);
+ dactyl.echomsg({ domains: [util.getHost(doc.location.href)], message: "Background tab loaded: " + doc.title || doc.location.href }, 3);
this._triggerLoadAutocmd("PageLoad", doc);
}
@@ -206,7 +208,11 @@ const Buffer = Module("buffer", {
/**
* @property {Object} The document loading progress listener.
*/
- progressListener: update({ __proto__: window.XULBrowserWindow }, {
+ progressListener: update(Object.create(window.XULBrowserWindow), {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIWebProgressListener]),
+
+ loadCount: 0,
+
// XXX: function may later be needed to detect a canceled synchronous openURL()
onStateChange: function onStateChange(webProgress, request, flags, status) {
onStateChange.superapply(this, arguments);
@@ -223,7 +229,7 @@ const Buffer = Module("buffer", {
// don't reset mode if a frame of the frameset gets reloaded which
// is not the focused frame
- if (document.commandDispatcher.focusedWindow == webProgress.DOMWindow) {
+ if (document.commandDispatcher.focusedWindow == webProgress.DOMWindow && this.loadCount++) {
util.timeout(function () { modes.reset(false); },
dactyl.mode == modes.HINTS ? 500 : 0);
}
@@ -1012,7 +1018,7 @@ const Buffer = Module("buffer", {
if (win.scrollMaxX > 0 || win.scrollMaxY > 0)
return win;
- for (let frame in util.Array.itervalues(win.frames))
+ for (let frame in array.itervalues(win.frames))
if (frame.scrollMaxX > 0 || frame.scrollMaxY > 0)
return frame;
@@ -1314,39 +1320,39 @@ const Buffer = Module("buffer", {
group[1].push([i, tab.linkedBrowser]);
});
- let orig = context;
- for (let [id, [name, browsers]] in Iterator(tabGroups)) {
- context = orig.fork(id, 0);
- context.anchored = false;
- context.title = [name || "Buffers"];
- context.keys = { text: "text", description: "url", icon: "icon" };
- context.compare = CompletionContext.Sort.number;
- let process = context.process[0];
- context.process = [function (item, text)
- <>
- <span highlight="Indicator" style="display: inline-block;">{item.item.indicator}</span>
- { process.call(this, item, text) }
- </>];
-
- context.completions = util.map(util.Array.itervalues(browsers), function ([i, browser]) {
- let indicator = " ";
- if (i == tabs.index())
- indicator = "%"
- else if (i == tabs.index(tabs.alternate))
- indicator = "#";
-
- let tab = tabs.getTab(i);
- let url = browser.contentDocument.location.href;
- i = i + 1;
-
- return {
- text: [i + ": " + (tab.label || "(Untitled)"), i + ": " + url],
- url: template.highlightURL(url),
- indicator: indicator,
- icon: tab.image || DEFAULT_FAVICON
- };
- });
- }
+ context.pushProcessor(0, function (item, text, next) <>
+ <span highlight="Indicator" style="display: inline-block;">{item.item.indicator}</span>
+ { next.call(this, item, text) }
+ </>);
+ context.process[1] = function (item, text) template.highlightURL(text);
+
+ context.anchored = false;
+ context.keys = { text: "text", description: "url", icon: "icon" };
+ context.compare = CompletionContext.Sort.number;
+
+ for (let [id, vals] in Iterator(tabGroups))
+ context.fork(id, 0, this, function (context, [name, browsers]) {
+ context.title = [name || "Buffers"];
+ context.generate = function ()
+ util.map(array.itervalues(browsers), function ([i, browser]) {
+ let indicator = " ";
+ if (i == tabs.index())
+ indicator = "%"
+ else if (i == tabs.index(tabs.alternate))
+ indicator = "#";
+
+ let tab = tabs.getTab(i);
+ let url = browser.contentDocument.location.href;
+ i = i + 1;
+
+ return {
+ text: [i + ": " + (tab.label || "(Untitled)"), i + ": " + url],
+ url: url,
+ indicator: indicator,
+ icon: tab.image || DEFAULT_FAVICON
+ };
+ });
+ }, vals);
};
},
events: function () {
@@ -1354,6 +1360,15 @@ const Buffer = Module("buffer", {
config.browser.removeProgressListener(window.XULBrowserWindow);
}
catch (e) {} // Why? --djk
+
+ // I hate this whole hack. --Kris
+ let obj = window.XULBrowserWindow, getter;
+ for (let p in properties(obj))
+ if ((getter = obj.__lookupGetter__(p)) && !obj.__lookupSetter__(p)) {
+ this.progressListener.__defineGetter__(p, getter);
+ delete obj[p];
+ }
+
config.browser.addProgressListener(this.progressListener, Ci.nsIWebProgress.NOTIFY_ALL);
window.XULBrowserWindow = this.progressListener;
window.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -1503,7 +1518,8 @@ const Buffer = Module("buffer", {
if (elem.readOnly || elem instanceof HTMLInputElement && !set.has(Events.editableInputs, elem.type))
return false;
let computedStyle = util.computedStyle(elem);
- return computedStyle.visibility != "hidden" && computedStyle.display != "none";
+ return computedStyle.visibility != "hidden" && computedStyle.display != "none" &&
+ computedStyle.MozUserFocus != "ignore";
});
dactyl.assert(elements.length > 0);
@@ -1617,13 +1633,13 @@ const Buffer = Module("buffer", {
function () { buffer.showPageInfo(true); });
},
options: function () {
- options.add(["nextpattern"], // \u00BB is » (>> in a single char)
+ options.add(["nextpattern"],
"Patterns to use when guessing the 'next' page in a document sequence",
- "stringlist", "\\bnext\\b,^>$,^(>>|\u00BB)$,^(>|\u00BB),(>|\u00BB)$,\\bmore\\b");
+ "stringlist", UTF8("\\bnext\\b,^>$,^(>>|»)$,^(>|»),(>|»)$,\\bmore\\b"));
- options.add(["previouspattern"], // \u00AB is « (<< in a single char)
+ options.add(["previouspattern"],
"Patterns to use when guessing the 'previous' page in a document sequence",
- "stringlist", "\\bprev|previous\\b,^<$,^(<<|\u00AB)$,^(<|\u00AB),(<|\u00AB)$");
+ "stringlist", UTF8("\\bprev|previous\\b,^<$,^(<<|«)$,^(<|«),(<|«)$"));
options.add(["pageinfo", "pa"],
"Desired info in the :pageinfo output",
diff --git a/common/content/commandline.js b/common/content/commandline.js
index c7552aaf..9039b7b1 100644
--- a/common/content/commandline.js
+++ b/common/content/commandline.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -103,31 +103,32 @@ const CommandLine = Module("commandline", {
////////////////////// VARIABLES ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
- this._completionList = ItemList("dactyl-completions");
+ memoize(this, "_completionList", function () ItemList("dactyl-completions"));
this._completions = null;
this._history = null;
this._startHints = false; // whether we're waiting to start hints mode
this._lastSubstring = "";
- this.widgets = {
- commandline: document.getElementById("dactyl-commandline"),
- prompt: document.getElementById("dactyl-commandline-prompt"),
- command: document.getElementById("dactyl-commandline-command"),
+ memoize(this, "widgets", function () {
+ let widgets = {
+ commandline: document.getElementById("dactyl-commandline"),
+ prompt: document.getElementById("dactyl-commandline-prompt"),
+ command: document.getElementById("dactyl-commandline-command"),
- message: document.getElementById("dactyl-message"),
+ message: document.getElementById("dactyl-message"),
- multilineOutput: document.getElementById("dactyl-multiline-output"),
- multilineInput: document.getElementById("dactyl-multiline-input"),
- };
-
- this.widgets.command.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
- this.widgets.message.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
+ multilineOutput: document.getElementById("dactyl-multiline-output"),
+ multilineInput: document.getElementById("dactyl-multiline-input"),
+ };
- // the widget used for multiline output
- this._outputContainer = this.widgets.multilineOutput.parentNode;
+ widgets.command.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
+ widgets.message.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
+ widgets.mowContainer = widgets.multilineOutput.parentNode;
- this.widgets.multilineOutput.contentDocument.body.id = "dactyl-multiline-output-content";
+ widgets.multilineOutput.contentDocument.body.id = "dactyl-multiline-output-content";
+ return widgets;
+ });
// we need to save the mode which were in before opening the command line
// this is then used if we focus the command line again without the "official"
@@ -181,12 +182,14 @@ const CommandLine = Module("commandline", {
}
},
+
/**
* Highlight the messageBox according to <b>group</b>.
*/
- _setHighlightGroup: function (group) {
- this.widgets.message.setAttributeNS(NS.uri, "highlight", group);
+ set highlightGroup(group) {
+ highlight.highlightNode(this.widgets.message, group);
},
+ get highlightGroup() this.widgets.message.getAttributeNS(NS.uri, "highlight"),
/**
* Determines whether the command line should be visible.
@@ -206,7 +209,7 @@ const CommandLine = Module("commandline", {
this.widgets.prompt.value = val;
this.widgets.prompt.size = val.length;
this.widgets.prompt.collapsed = (val == "");
- this.widgets.prompt.setAttributeNS(NS.uri, "highlight", highlightGroup || commandline.HL_NORMAL);
+ highlight.highlightNode(this.widgets.prompt, highlightGroup || commandline.HL_NORMAL);
},
/**
@@ -229,8 +232,8 @@ const CommandLine = Module("commandline", {
* @param {boolean} forceSingle If provided, don't let over-long
* messages move to the MOW.
*/
- _echoLine: function (str, highlightGroup, forceSingle) {
- this._setHighlightGroup(highlightGroup);
+ _echoLine: function echoLine(str, highlightGroup, forceSingle) {
+ this.highlightGroup = highlightGroup;
this.widgets.message.value = str;
dactyl.triggerObserver("echoLine", str, highlightGroup, forceSingle);
@@ -250,7 +253,7 @@ const CommandLine = Module("commandline", {
* @param {string} highlightGroup
*/
// TODO: resize upon a window resize
- _echoMultiline: function (str, highlightGroup) {
+ _echoMultiline: function echoMultiline(str, highlightGroup) {
let doc = this.widgets.multilineOutput.contentDocument;
let win = this.widgets.multilineOutput.contentWindow;
@@ -260,14 +263,15 @@ const CommandLine = Module("commandline", {
// Otherwise, white space is significant.
// The problem elsewhere is that E4X tends to insert new lines
// after interpolated data.
- XML.ignoreWhitespace = typeof str != "xml";
- this._lastMowOutput = <div class="ex-command-output" style="white-space: nowrap" highlight={highlightGroup}>{template.maybeXML(str)}</div>;
+ XML.ignoreWhitespace = false;
+ XML.prettyPrinting = false;
+ let style = typeof str === "string" ? "pre" : "nowrap";
+ this._lastMowOutput = <div class="ex-command-output" style={"white-space: " + style} highlight={highlightGroup}>{str}</div>;
let output = util.xmlToDom(this._lastMowOutput, doc);
- XML.ignoreWhitespace = true;
// FIXME: need to make sure an open MOW is closed when commands
// that don't generate output are executed
- if (this._outputContainer.collapsed)
+ if (this.widgets.mowContainer.collapsed)
doc.body.innerHTML = "";
doc.body.appendChild(output);
@@ -417,6 +421,8 @@ const CommandLine = Module("commandline", {
this._currentExtendedMode = null;
commandline.triggerCallback("cancel", mode);
+ if (this._completions)
+ this._completions.previewClear();
if (this._history)
this._history.save();
@@ -431,11 +437,11 @@ const CommandLine = Module("commandline", {
this._completionList.hide();
if (!this._keepCommand || this._silent || this._quiet) {
- this._outputContainer.collapsed = true;
+ this.widgets.mowContainer.collapsed = true;
commandline.updateMorePrompt();
this.hide();
}
- if (!this._outputContainer.collapsed) {
+ if (!this.widgets.mowContainer.collapsed) {
modes.set(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
commandline.updateMorePrompt();
}
@@ -492,23 +498,35 @@ const CommandLine = Module("commandline", {
if (flags & this.APPEND_TO_MESSAGES) {
let message = isobject(str) ? str : { message: str };
- this._messageHistory.add(update({ highlight: highlightGroup }, str));
+ this._messageHistory.add(update({ highlight: highlightGroup }, message));
str = message.message;
}
+
if ((flags & this.ACTIVE_WINDOW) &&
window != services.get("windowWatcher").activeWindow &&
services.get("windowWatcher").activeWindow.dactyl)
return;
- if ((flags & this.DISALLOW_MULTILINE) && !this._outputContainer.collapsed)
+ if ((flags & this.DISALLOW_MULTILINE) && !this.widgets.mowContainer.collapsed)
return;
let single = flags & (this.FORCE_SINGLELINE | this.DISALLOW_MULTILINE);
let action = this._echoLine;
+ if (single)
+ this._lastEcho = null;
+ else {
+ if (this.widgets.message.value == this._lastEcho)
+ this._echoMultiline(<span highlight="Message">{this._lastEcho}</span>,
+ this.highlightGroup);
+ this._lastEcho = (action == this._echoLine) && str;
+ }
+
// TODO: this is all a bit convoluted - clean up.
// assume that FORCE_MULTILINE output is fully styled
- if (!(flags & this.FORCE_MULTILINE) && !single && (!this._outputContainer.collapsed || this.widgets.message.value == this._lastEcho)) {
+ if (!(flags & this.FORCE_MULTILINE) && !single
+ && (!this.widgets.mowContainer.collapsed || this.widgets.message.value == this._lastEcho)) {
+
highlightGroup += " Message";
action = this._echoMultiline;
}
@@ -516,15 +534,6 @@ const CommandLine = Module("commandline", {
if ((flags & this.FORCE_MULTILINE) || (/\n/.test(str) || typeof str == "xml") && !(flags & this.FORCE_SINGLELINE))
action = this._echoMultiline;
- if (single)
- this._lastEcho = null;
- else {
- if (this.widgets.message.value == this._lastEcho)
- this._echoMultiline(<span highlight="Message">{this._lastEcho}</span>,
- this.widgets.message.getAttributeNS(NS.uri, "highlight"));
- this._lastEcho = (action == this._echoLine) && str;
- }
-
if (action)
action.call(this, str, highlightGroup, single);
}),
@@ -937,7 +946,7 @@ const CommandLine = Module("commandline", {
* and what they do.
*/
updateMorePrompt: function updateMorePrompt(force, showHelp) {
- if (this._outputContainer.collapsed) {
+ if (this.widgets.mowContainer.collapsed) {
this._echoLine("", this.HL_NORMAL);
return;
}
@@ -960,19 +969,25 @@ const CommandLine = Module("commandline", {
* @param {boolean} open If true, the widget will be opened if it's not
* already so.
*/
- updateOutputHeight: function updateOutputHeight(open) {
- if (!open && this._outputContainer.collapsed)
+ updateOutputHeight: function updateOutputHeight(open, extra) {
+ if (!open && this.widgets.mowContainer.collapsed)
return;
let doc = this.widgets.multilineOutput.contentDocument;
let availableHeight = config.outputHeight;
- if (!this._outputContainer.collapsed)
- availableHeight += parseFloat(this._outputContainer.height);
+ if (!this.widgets.mowContainer.collapsed)
+ availableHeight += parseFloat(this.widgets.mowContainer.height);
+ availableHeight -= extra || 0;
+
doc.body.style.minWidth = this.widgets.commandline.scrollWidth + "px";
- this._outputContainer.height = Math.min(doc.height, availableHeight) + "px";
+ this.widgets.mowContainer.height = Math.min(doc.height, availableHeight) + "px";
+ this.timeout(function ()
+ this.widgets.mowContainer.height = Math.min(doc.height, availableHeight) + "px",
+ 0);
+
doc.body.style.minWidth = "";
- this._outputContainer.collapsed = false;
+ this.widgets.mowContainer.collapsed = false;
},
resetCompletions: function resetCompletions() {
@@ -1015,7 +1030,12 @@ const CommandLine = Module("commandline", {
if (/^\s*$/.test(str))
return;
this.store.mutate("filter", function (line) (line.value || line) != str);
- this.store.push({ value: str, timestamp: Date.now()*1000, privateData: this.checkPrivate(str) });
+ try {
+ this.store.push({ value: str, timestamp: Date.now()*1000, privateData: this.checkPrivate(str) });
+ }
+ catch (e) {
+ dactyl.reportError(e);
+ }
this.store.truncate(options["history"], true);
},
/**
@@ -1142,6 +1162,8 @@ const CommandLine = Module("commandline", {
get wildtype() this.wildtypes[this.wildIndex] || "",
+ get wildtypes() this.wildmode.values,
+
complete: function complete(show, tabPressed) {
this.context.reset();
this.context.tabPressed = tabPressed;
@@ -1162,7 +1184,7 @@ const CommandLine = Module("commandline", {
let substring = "";
switch (this.wildtype.replace(/.*:/, "")) {
case "":
- substring = this.items[0].text;
+ substring = this.items[0].result;
break;
case "longest":
if (this.items.length > 1) {
@@ -1173,7 +1195,7 @@ const CommandLine = Module("commandline", {
case "full":
let item = this.items[this.selected != null ? this.selected + 1 : 0];
if (item)
- substring = item.text;
+ substring = item.result;
break;
}
@@ -1227,14 +1249,14 @@ const CommandLine = Module("commandline", {
this.wildIndex = 0;
}
- this.wildtypes = this.wildmode.values;
this.preview();
},
_reset: function _reset() {
- this.prefix = this.context.value.substring(0, this.start);
- this.value = this.context.value.substring(this.start, this.caret);
- this.suffix = this.context.value.substring(this.caret);
+ let value = this.editor.selection.focusNode.textContent;
+ this.prefix = value.substring(0, this.start);
+ this.value = value.substring(this.start, this.caret);
+ this.suffix = value.substring(this.caret);
this.itemList.reset();
this.itemList.selectItem(this.selected);
@@ -1301,7 +1323,7 @@ const CommandLine = Module("commandline", {
return;
this.selected = idx;
- this.completion = this.items[idx].text;
+ this.completion = this.items[idx].result;
}
this.itemList.selectItem(idx);
@@ -1320,6 +1342,8 @@ const CommandLine = Module("commandline", {
return;
while (this.tabs.length) {
+ this.wildIndex = Math.min(this.wildIndex, this.wildtypes.length - 1);
+
reverse = this.tabs.shift();
switch (this.wildtype.replace(/.*:/, "")) {
case "":
@@ -1340,7 +1364,7 @@ const CommandLine = Module("commandline", {
if (this.haveType("list"))
this.itemList.show();
- this.wildIndex = Math.constrain(this.wildIndex + 1, 0, this.wildtypes.length - 1);
+ this.wildIndex++;
this.preview();
commandline._statusTimer.tell();
@@ -1373,7 +1397,7 @@ const CommandLine = Module("commandline", {
if (typeof arg === "object")
arg = util.objectToString(arg, useColor);
- else if (typeof arg == "string" && /\n/.test(arg))
+ else if (typeof arg === "string" && /\n/.test(arg))
arg = <span highlight="CmdOutput">{arg}</span>;
else
arg = String(arg);
@@ -1533,7 +1557,7 @@ const CommandLine = Module("commandline", {
styles: function () {
let fontSize = util.computedStyle(document.getElementById(config.mainWindowId)).fontSize;
styles.registerSheet("chrome://dactyl/skin/dactyl.css");
- let error = styles.addSheet(true, "font-size", "chrome://dactyl/content/buffer.xhtml",
+ styles.addSheet(true, "font-size", "chrome://dactyl/content/buffer.xhtml",
"body { font-size: " + fontSize + "; }");
}
});
@@ -1542,7 +1566,7 @@ const CommandLine = Module("commandline", {
* The list which is used for the completion box (and QuickFix window in
* future).
*
- * @param {string} id The id of the <iframe> which will display the list. It
+ * @param {string} id The id of the iframe which will display the list. It
* must be in its own container element, whose height it will update as
* necessary.
*/
@@ -1579,12 +1603,15 @@ const ItemList = Class("ItemList", {
this._minHeight = Math.max(this._minHeight,
this._win.scrollY + this._divNodes.completions.getBoundingClientRect().bottom);
- this._container.height = this._minHeight;
if (this._container.collapsed)
this._div.style.minWidth = "";
// FIXME: Belongs elsewhere.
+ commandline.updateOutputHeight(false, Math.max(0, this._minHeight - this._container.height));
+
+ this._container.height = this._minHeight;
+ this._container.height -= commandline.getSpaceNeeded()
commandline.updateOutputHeight(false);
this.timeout(function () { this._container.height -= commandline.getSpaceNeeded(); }, 0);
},
@@ -1678,7 +1705,7 @@ const ItemList = Class("ItemList", {
for (let [i, row] in Iterator(context.getRows(start, end, this._doc)))
nodes[i] = row;
- for (let [i, row] in util.Array.iteritems(nodes)) {
+ for (let [i, row] in array.iteritems(nodes)) {
if (!row)
continue;
let display = (i >= start && i < end);
diff --git a/common/content/commands.js b/common/content/commands.js
index b19653f3..1dd25d93 100644
--- a/common/content/commands.js
+++ b/common/content/commands.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -171,16 +171,10 @@ const Command = Class("Command", {
* @returns {boolean}
*/
hasName: function (name) {
- for (let [, spec] in Iterator(this.specs)) {
- let fullName = spec.replace(/\[(\w+)]$/, "$1");
- let index = spec.indexOf("[");
- let min = index == -1 ? fullName.length : index;
-
- if (fullName.indexOf(name) == 0 && name.length >= min)
- return true;
- }
-
- return false;
+ return this.specs.some(function (spec) {
+ let [, head, tail] = spec.match(/([^[]+)(?:\[(.*)])?/);
+ return name.indexOf(head) == 0 && (head + (tail || "")).indexOf(name) == 0;
+ });
},
/**
@@ -340,25 +334,29 @@ const Commands = Module("commands", {
/** @property {Iterator(Command)} @private */
__iterator__: function () {
let sorted = this._exCommands.sort(function (a, b) a.name > b.name);
- return util.Array.itervalues(sorted);
+ return array.itervalues(sorted);
},
/** @property {string} The last executed Ex command line. */
repeat: null,
- _addCommand: function (command, replace) {
- if (command.name in this._exMap) {
- if (command.user && replace)
- commands.removeUserCommand(command.name);
- else {
- dactyl.log("Warning: :" + command.name + " already exists, NOT replacing existing command.", 1);
- return false;
- }
- }
-
- this._exCommands.push(command);
- for (let [,name] in Iterator(command.names))
- this._exMap[name] = command;
+ _addCommand: function (args, replace) {
+ let names = array.flatten(Command.parseSpecs(args[0]));
+ dactyl.assert(!names.some(function (name) name in this._exMap && !this._exMap[name].user, this),
+ "E182: Can't replace non-user command: " + args[0]);
+ if (!replace && args[3] && args[3].user)
+ dactyl.assert(!names.some(function (name) name in this._exMap, this),
+ "Not replacing command " + args[0]);
+ for (let name in names)
+ if (name in this._exMap)
+ commands.removeUserCommand(name);
+
+ let name = names[0];
+ let closure = function () commands._exMap[name];
+ memoize(this._exMap, name, function () Command.apply(null, args));
+ memoize(this._exCommands, this._exCommands.length, closure);
+ for (let alias in values(names.slice(1)))
+ memoize(this._exMap, alias, closure);
return true;
},
@@ -375,7 +373,7 @@ const Commands = Module("commands", {
* @optional
*/
add: function (names, description, action, extra) {
- return this._addCommand(Command(names, description, action, extra), false);
+ return this._addCommand([names, description, action, extra], false);
},
/**
@@ -395,7 +393,7 @@ const Commands = Module("commands", {
extra.user = true;
description = description || "User defined command";
- return this._addCommand(Command(names, description, action, extra), replace);
+ return this._addCommand([names, description, action, extra], replace);
},
/**
@@ -407,7 +405,7 @@ const Commands = Module("commands", {
*/
commandToString: function (args) {
let res = [args.command + (args.bang ? "!" : "")];
- function quote(str) Commands.quoteArg[/[\s"'\\]|^$/.test(str) ? '"' : ""](str);
+ function quote(str) Commands.quoteArg[/[\s"'\\]|^$/.test(str) ? "'" : ""](str);
for (let [opt, val] in Iterator(args.options || {})) {
let chr = /^-.$/.test(opt) ? " " : "=";
@@ -431,8 +429,8 @@ const Commands = Module("commands", {
* any of the command's names.
* @returns {Command}
*/
- get: function (name) {
- return this._exMap[name] || this._exCommands.filter(function (cmd) cmd.hasName(name))[0] || null;
+ get: function (name, full) {
+ return this._exMap[name] || !full && this._exCommands.filter(function (cmd) cmd.hasName(name))[0] || null;
},
/**
@@ -573,7 +571,7 @@ const Commands = Module("commands", {
argCount = "*";
var args = []; // parsed options
- args.__iterator__ = function () util.Array.iteritems(this);
+ args.__iterator__ = function () array.iteritems(this);
args.string = str; // for access to the unparsed string
args.literalArg = "";
@@ -833,11 +831,11 @@ const Commands = Module("commands", {
* any of the command's names.
*/
removeUserCommand: function (name) {
- for (let [,cmd] in Iterator(this._exCommands))
- if (cmd.user && cmd.hasName(name))
- for (let [,name] in Iterator(cmd.names))
- delete this._exMap[name];
- this._exCommands = this._exCommands.filter(function (cmd) !(cmd.user && cmd.hasName(name)));
+ let cmd = this.get(name);
+ dactyl.assert(cmd.user, "E184: No such user-defined command: " + name);
+ for (let name in values(cmd.names))
+ delete this._exMap[name];
+ this._exCommands = this._exCommands.filter(function (c) c != cmd);
},
// FIXME: still belong here? Also used for autocommand parameters.
@@ -867,8 +865,6 @@ const Commands = Module("commands", {
});
}
}, {
- QUOTE_STYLE: "rc-ish",
-
// returns [count, parsed_argument]
parseArg: function (str) {
let arg = "";
@@ -918,7 +914,7 @@ const Commands = Module("commands", {
// dynamically get completions as specified with the command's completer function
let command = commands.get(cmd);
if (!command) {
- context.highlight(0, cmd.length, "SPELLCHECK");
+ context.highlight(0, cmd && cmd.length, "SPELLCHECK");
return;
}
@@ -936,7 +932,8 @@ const Commands = Module("commands", {
cmdContext.filter = args.completeFilter;
try {
let compObject = command.completer.call(command, cmdContext, args);
- if (compObject instanceof Array) // for now at least, let completion functions return arrays instead of objects
+
+ if (isarray(compObject)) // for now at least, let completion functions return arrays instead of objects
compObject = { start: compObject[0], items: compObject[1] };
if (compObject != null) {
cmdContext.advance(compObject.start);
@@ -1041,14 +1038,13 @@ const Commands = Module("commands", {
function completerToString(completer) {
if (completer)
return [k for ([k, v] in Iterator(completeOptionMap)) if (completer == completion[v])][0] || "custom";
- else
- return "";
+ return "";
}
// TODO: using an array comprehension here generates flakey results across repeated calls
// : perhaps we shouldn't allow options in a list call but just ignore them for now
// : No, array comprehensions are fine, generator statements aren't. --Kris
- let cmds = this._exCommands.filter(function (c) c.user && (!cmd || c.name.match("^" + cmd)));
+ let cmds = commands._exCommands.filter(function (c) c.user && (!cmd || c.name.match("^" + cmd)));
if (cmds.length > 0)
commandline.commandOutput(
@@ -1101,7 +1097,7 @@ const Commands = Module("commands", {
serialize: function () [ {
command: this.name,
bang: true,
- options: util.Array.toObject(
+ options: array.toObject(
[[v, typeof cmd[k] == "boolean" ? null : cmd[k]]
// FIXME: this map is expressed multiple times
for ([k, v] in Iterator({ argCount: "-nargs", bang: "-bang", count: "-count", description: "-description" }))
@@ -1162,17 +1158,20 @@ const Commands = Module("commands", {
};
function quote(q, list) {
let re = RegExp("[" + list + "]", "g");
- return function (str) q + String.replace(str, re, function ($0) $0 in Commands.quoteMap ? Commands.quoteMap[$0] : ("\\" + $0)) + q;
+ let res = function (str) q + String.replace(str, re, function ($0) $0 in Commands.quoteMap ? Commands.quoteMap[$0] : ("\\" + $0)) + q;
+ res.list = list;
+ return res;
};
- Commands.complQuote = { // FIXME
+ Commands.complQuote = {
'"': ['"', quote("", '\n\t"\\\\'), '"'],
"'": ["'", quote("", "\\\\'"), "'"],
- "": ["", quote("", "\\\\ "), ""]
+ "": ["", quote("", "\\\\ '\""), ""]
};
+
Commands.quoteArg = {
'"': quote('"', '\n\t"\\\\'),
"'": quote("'", "\\\\'"),
- "": quote("", "\\\\ ")
+ "": quote("", "\\\\ '\"")
};
Commands.parseBool = function (arg) {
diff --git a/common/content/completion.js b/common/content/completion.js
index be2a5ab6..68a5dc89 100644
--- a/common/content/completion.js
+++ b/common/content/completion.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -54,7 +54,7 @@ const CompletionContext = Class("CompletionContext", {
["filters", "keys", "title", "quote"].forEach(function (key)
self[key] = parent[key] && util.cloneObject(parent[key]));
- ["anchored", "compare", "editor", "_filter", "filterFunc", "keys", "_process", "top"].forEach(function (key)
+ ["anchored", "compare", "editor", "_filter", "filterFunc", "keys", "process", "top"].forEach(function (key)
self[key] = parent[key]);
self.__defineGetter__("value", function () this.top.value);
@@ -90,8 +90,14 @@ const CompletionContext = Class("CompletionContext", {
this._value = editor;
else
this.editor = editor;
- this.compare = function (a, b) String.localeCompare(a.text, b.text);
+ /**
+ * @property {boolean} Specifies whether this context results must
+ * match the filter at the beginning of the string.
+ * @default true
+ */
+ this.anchored = true;
+ this.compare = function (a, b) String.localeCompare(a.text, b.text);
/**
* @property {function} This function is called when we close
* a completion window with Esc or Ctrl-c. Usually this callback
@@ -99,6 +105,20 @@ const CompletionContext = Class("CompletionContext", {
*/
this.cancel = null;
/**
+ * @property {[CompletionContext]} A list of active
+ * completion contexts, in the order in which they were
+ * instantiated.
+ */
+ this.contextList = [];
+ /**
+ * @property {Object} A map of all contexts, keyed on their names.
+ * Names are assigned when a context is forked, with its specified
+ * name appended, after a '/', to its parent's name. May
+ * contain inactive contexts. For active contexts, see
+ * {@link #contextList}.
+ */
+ this.contexts = { "": this };
+ /**
* @property {function} The function used to filter the results.
* @default Selects all results which match every predicate in the
* {@link #filters} array.
@@ -115,20 +135,6 @@ const CompletionContext = Class("CompletionContext", {
*/
this.filters = [CompletionContext.Filter.text];
/**
- * @property {boolean} Specifies whether this context results must
- * match the filter at the beginning of the string.
- * @default true
- */
- this.anchored = true;
- /**
- * @property {Object} A map of all contexts, keyed on their names.
- * Names are assigned when a context is forked, with its specified
- * name appended, after a '/', to its parent's name. May
- * contain inactive contexts. For active contexts, see
- * {@link #contextList}.
- */
- this.contexts = { "": this };
- /**
* @property {Object} A mapping of keys, for {@link #getKey}. Given
* { key: value }, getKey(item, key) will return values as such:
* if value is a string, it will return item.item[value]. If it's a
@@ -146,6 +152,9 @@ const CompletionContext = Class("CompletionContext", {
* {@link #updateAsync} is true.
*/
this.onUpdate = function () true;
+
+ this.runCount = 0;
+
/**
* @property {CompletionContext} The top-level completion context.
*/
@@ -190,6 +199,7 @@ const CompletionContext = Class("CompletionContext", {
: item.item[key];
return this;
},
+
// Temporary
/**
* @property {Object}
@@ -202,7 +212,7 @@ const CompletionContext = Class("CompletionContext", {
get allItems() {
try {
let self = this;
- let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.items.length && context.hasItems)]);
+ let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.hasItems && context.items.length)]);
if (minStart == Infinity)
minStart = 0;
let items = this.contextList.map(function (context) {
@@ -214,7 +224,7 @@ const CompletionContext = Class("CompletionContext", {
__proto__: item
}));
});
- return { start: minStart, items: util.Array.flatten(items), longestSubstring: this.longestAllSubstring };
+ return { start: minStart, items: array.flatten(items), longestSubstring: this.longestAllSubstring };
}
catch (e) {
dactyl.reportError(e);
@@ -235,7 +245,7 @@ const CompletionContext = Class("CompletionContext", {
lists.pop());
if (!substrings) // FIXME: How is this undefined?
return [];
- return util.Array.uniq(Array.slice(substrings));
+ return array.uniq(Array.slice(substrings));
},
// Temporary
get longestAllSubstring() {
@@ -253,14 +263,16 @@ const CompletionContext = Class("CompletionContext", {
// Accept a generator
if (!isarray(items))
items = [x for (x in Iterator(items))];
- delete this.cache.filtered;
- delete this.cache.filter;
- this.cache.rows = [];
- this.hasItems = items.length > 0;
- this._completions = items;
- let self = this;
+ if (this._completions !== items) {
+ delete this.cache.filtered;
+ delete this.cache.filter;
+ this.cache.rows = [];
+ this.hasItems = items.length > 0;
+ this._completions = items;
+ this.itemCache[this.key] = items;
+ }
if (this.updateAsync && !this.noUpdate)
- util.callInMainThread(function () { self.onUpdate.call(self); });
+ util.callInMainThread(function () { this.onUpdate(); }, this);
},
get createRow() this._createRow || template.completionRow, // XXX
@@ -293,14 +305,18 @@ const CompletionContext = Class("CompletionContext", {
get proto() {
let res = {};
- for (let i in Iterator(this.keys)) {
+ function result(quote) {
+ yield ["result", quote ? function () quote[0] + quote[1](this.text) + quote[2]
+ : function () this.text]
+ };
+ for (let i in iterall(this.keys, result(this.quote))) {
let [k, v] = i;
if (typeof v == "string" && /^[.[]/.test(v))
// This is only allowed to be a simple accessor, and shouldn't
// reference any variables. Don't bother with eval context.
v = Function("i", "return i" + v);
if (typeof v == "function")
- res.__defineGetter__(k, function () Class.replaceProperty(this, k, v(this.item)));
+ res.__defineGetter__(k, function () Class.replaceProperty(this, k, v.call(this, this.item)));
else
res.__defineGetter__(k, function () Class.replaceProperty(this, k, this.item[v]));
res.__defineSetter__(k, function (val) Class.replaceProperty(this, k, val));
@@ -312,11 +328,16 @@ const CompletionContext = Class("CompletionContext", {
set regenerate(val) { if (val) delete this.itemCache[this.key]; },
get generate() !this._generate ? null : function () {
- if (this.offset != this.cache.offset)
+ if (this.offset != this.cache.offset || this.lastActivated != this.top.runCount) {
this.itemCache = {};
- this.cache.offset = this.offset;
- if (!this.itemCache[this.key])
- this.itemCache[this.key] = this._generate.call(this) || [];
+ this.cache.offset = this.offset;
+ this.lastActivated = this.top.runCount;
+ }
+ if (!this.itemCache[this.key]) {
+ let res = this._generate.call(this) || [];
+ if (res != null)
+ this.itemCache[this.key] = res;
+ }
return this.itemCache[this.key];
},
set generate(arg) {
@@ -354,16 +375,27 @@ const CompletionContext = Class("CompletionContext", {
get items() {
if (!this.hasItems || this.backgroundLock)
return [];
- if (this.cache.filtered && this.cache.filter == this.filter)
- return this.cache.filtered;
- this.cache.rows = [];
- let items = this.completions;
+
+ // Regenerate completions if we must
if (this.generate && !this.background) {
// XXX
this.noUpdate = true;
- this.completions = items = this.generate();
+ this.completions = this.generate();
this.noUpdate = false;
}
+ let items = this.completions;
+
+ // Check for cache miss
+ if (this.cache.completions !== this.completions) {
+ this.cache.completions = this.completions;
+ this.cache.constructed = null;
+ this.cache.filtered = null;
+ }
+
+ if (this.cache.filtered && this.cache.filter == this.filter)
+ return this.cache.filtered;
+
+ this.cache.rows = [];
this.cache.filter = this.filter;
if (items == null)
return items;
@@ -371,6 +403,7 @@ const CompletionContext = Class("CompletionContext", {
let self = this;
delete this._substrings;
+ // Item matchers
if (this.ignoreCase)
this.matchString = this.anchored ?
function (filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) == 0 :
@@ -380,36 +413,28 @@ const CompletionContext = Class("CompletionContext", {
function (filter, str) String.indexOf(str, filter) == 0 :
function (filter, str) String.indexOf(str, filter) >= 0;
+ // Item formatters
+ this.processor = Array.slice(this.process);
+ if (!this.anchored)
+ this.processor[0] = function (item, text) self.process[0].call(self, item,
+ template.highlightFilter(item.text, self.filter));
+
+ // Item prototypes
let proto = this.proto;
- let filtered = this.filterFunc(items.map(function (item) ({ __proto__: proto, item: item })));
+ if (!this.cache.constructed)
+ this.cache.constructed = items.map(function (item) Object.create(proto, { item: { value: item, enumerable: true } }));
+
+ // Filters
+ let filtered = this.filterFunc(this.cache.constructed);
if (this.maxItems)
filtered = filtered.slice(0, this.maxItems);
+ // Sorting
if (this.sortResults && this.compare)
filtered.sort(this.compare);
- let quote = this.quote;
- if (quote)
- filtered.forEach(function (item) {
- item.unquoted = item.text;
- item.text = quote[0] + quote[1](item.text) + quote[2];
- });
return this.cache.filtered = filtered;
},
- get process() { // FIXME
- let self = this;
- let process = this._process;
- process = [process[0] || template.icon, process[1] || function (item, k) k];
- let first = process[0];
- let filter = this.filter;
- if (!this.anchored)
- process[0] = function (item, text) first.call(self, item, template.highlightFilter(item.text, filter));
- return process;
- },
- set process(process) {
- this._process = process;
- },
-
get substrings() {
let items = this.items;
if (items.length == 0 || !this.hasItems)
@@ -418,7 +443,10 @@ const CompletionContext = Class("CompletionContext", {
return this._substrings;
let fixCase = this.ignoreCase ? String.toLowerCase : util.identity;
- let text = fixCase(items[0].unquoted || items[0].text);
+ let text = fixCase(items[0].text);
+ // Exceedingly long substrings cause Gecko to go into convulsions
+ if (text.length > 100)
+ text = text.substr(0, 100);
let filter = fixCase(this.filter);
if (this.anchored) {
var compare = function compare(text, s) text.substr(0, s.length) == s;
@@ -521,7 +549,6 @@ const CompletionContext = Class("CompletionContext", {
context.waitingForTab = true;
else if (completer)
return completer.apply(self || this, [context].concat(Array.slice(arguments, fork.length)));
-
if (completer)
return null;
return context;
@@ -535,20 +562,24 @@ const CompletionContext = Class("CompletionContext", {
},
highlight: function highlight(start, length, type) {
- try { // Gecko < 1.9.1 doesn't have repaintSelection
- this.selectionTypes[type] = null;
+ if (arguments.length == 0) {
+ for (let type in this.selectionTypes)
+ this.highlight(0, 0, type);
+ this.selectionTypes = {};
+ }
+ try {
+ // Requires Gecko >= 1.9.1
+ this.selectionTypes[type] = true;
const selType = Ci.nsISelectionController["SELECTION_" + type];
- const editor = this.editor;
- let sel = editor.selectionController.getSelection(selType);
+ let sel = this.editor.selectionController.getSelection(selType);
if (length == 0)
sel.removeAllRanges();
else {
- let range = editor.selection.getRangeAt(0).cloneRange();
+ let range = this.editor.selection.getRangeAt(0).cloneRange();
range.setStart(range.startContainer, this.offset + start);
range.setEnd(range.startContainer, this.offset + start + length);
sel.addRange(range);
}
- editor.selectionController.repaintSelection(selType);
}
catch (e) {}
},
@@ -557,23 +588,19 @@ const CompletionContext = Class("CompletionContext", {
return this.matchString(this.filter, str);
},
+ pushProcessor: function pushProcess(i, fn) {
+ let next = this.process[i];
+ this.process[i] = function (item, text) fn(item, text, next);
+ },
+
reset: function reset() {
let self = this;
if (this.parent)
throw Error();
- // Not ideal.
- for (let type in this.selectionTypes)
- this.highlight(0, 0, type);
- /**
- * @property {[CompletionContext]} A list of active
- * completion contexts, in the order in which they were
- * instantiated.
- */
- this.contextList = [];
this.offset = 0;
- this.process = [];
- this.selectionTypes = {};
+ this.process = [template.icon, function (item, k) k];
+ this.filters = [CompletionContext.Filter.text];
this.tabPressed = false;
this.title = ["Completions"];
this.updateAsync = false;
@@ -595,6 +622,10 @@ const CompletionContext = Class("CompletionContext", {
if (context != context.top)
context.incomplete = false;
}
+ this.runCount++;
+ for each (let context in this.contextList)
+ context.lastActivated = this.runCount;
+ this.contextList = [];
},
/**
@@ -668,7 +699,7 @@ const Completion = Module("completion", {
commandline.commandOutput(
<div highlight="Completions">
- { template.map(context.contextList.filter(function (c) c.hasItems),
+ { template.map(context.contextList.filter(function (c) c.hasItems && c.items.length),
function (context)
template.completionRow(context.title, "CompTitle") +
template.map(context.items, function (item) context.createRow(item), null, 100)) }
@@ -747,7 +778,7 @@ const Completion = Module("completion", {
let re = RegExp(tokens.filter(util.identity).map(util.escapeRegex).join("|"), "g");
function highlight(item, text, i) process[i].call(this, item, template.highlightRegexp(text, re));
- let process = [template.icon, function (item, k) k];
+ let process = context.process;
context.process = [
function (item, text) highlight.call(this, item, item.text, 0),
function (item, text) highlight.call(this, item, text, 1)
diff --git a/common/content/configbase.js b/common/content/configbase.js
index a8a79847..03fd84b0 100644
--- a/common/content/configbase.js
+++ b/common/content/configbase.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -12,8 +12,33 @@ const ConfigBase = Class(ModuleBase, {
* initialization code. Must call superclass's init function.
*/
init: function () {
+ this.name = services.get("dactyl:").name;
+ this.appname = services.get("dactyl:").appname;
+ this.host = services.get("dactyl:").host;
+
highlight.styleableChrome = this.styleableChrome;
highlight.loadCSS(this.CSS);
+ highlight.loadCSS(this.helpCSS);
+
+ let img = Image();
+ img.src = this.logo || "chrome://" + this.name + "/content/logo.png";
+ img.onload = function () {
+ highlight.set("Logo", String(<>
+ display: inline-block;
+ background: url({img.src});
+ width: {img.width}px;
+ height: {img.height}px;
+ </>));
+ img = null;
+ }
+ },
+
+ styleHelp: function () {
+ if (!this.helpStyled)
+ for (let k in keys(highlight.loaded))
+ if (/^(Help|StatusLine)|^(Boolean|Indicator|MoreMsg|Number|Logo|Key(word)?|String)$/.test(k))
+ highlight.loaded[k] = true;
+ this.helpCSS = true;
},
/**
@@ -92,7 +117,7 @@ const ConfigBase = Class(ModuleBase, {
* @property {number} The height (px) that is available to the output
* window.
*/
- get outputHeight() config.browser.mPanelContainer.boxObject.height,
+ get outputHeight() this.browser.mPanelContainer.boxObject.height,
/**
* @property {[string]} A list of extra scripts in the dactyl or
@@ -105,45 +130,41 @@ const ConfigBase = Class(ModuleBase, {
* @property {string} The leaf name of any temp files created by
* {@link io.createTempFile}.
*/
- get tempFile() this.name.toLowerCase() + ".tmp",
+ get tempFile() this.name + ".tmp",
/**
* @constant
- * @property {string} The default highlighting rules. They have the
- * form:
- * rule ::= selector space space+ css
- * selector ::= group
- * | group "," css-selector
- * | group "," css-selector "," scope
- * group ::= groupname
- * | groupname css-selector
+ * @property {string} The default highlighting rules.
+ * See {@link Highlights#loadCSS} for details.
*/
- // <css>
- CSS: <![CDATA[
- Boolean color: red;
- Function color: navy;
- Null color: blue;
- Number color: blue;
- Object color: maroon;
- String color: green;
-
- Key font-weight: bold;
-
- Enabled color: blue;
- Disabled color: red;
-
- Normal color: black; background: white;
- ErrorMsg color: white; background: red; font-weight: bold;
- InfoMsg color: black; background: white;
- ModeMsg color: black; background: white;
- MoreMsg color: green; background: white;
- WarningMsg color: red; background: white;
- Message white-space: normal; min-width: 100%; padding-left: 2em; text-indent: -2em; display: block;
- NonText color: blue; min-height: 16px; padding-left: 2px;
- Preview color: gray;
-
- CmdLine,>* font-family: monospace; padding: 1px;
- CmdOutput white-space: pre;
+ CSS: UTF8(<><![CDATA[
+ // <css>
+ Boolean color: red;
+ Function color: navy;
+ Null color: blue;
+ Number color: blue;
+ Object color: maroon;
+ String color: green;
+
+ Key font-weight: bold;
+
+ Enabled color: blue;
+ Disabled color: red;
+
+ !Normal color: black !important; background: white !important;
+ ErrorMsg color: white !important; background: red !important; font-weight: bold !important;
+ InfoMsg color: black !important; background: white !important;
+ LineNr color: orange !important; background: white !important;
+ ModeMsg color: black !important; background: white !important;
+ MoreMsg color: green !important; background: white !important;
+ Message white-space: normal; min-width: 100%; padding-left: 2em; text-indent: -2em; display: block;
+ NonText color: blue; min-height: 16px; padding-left: 2px;
+ *Preview color: gray;
+ Question color: green !important; background: white !important; font-weight: bold !important;
+ WarningMsg color: red !important; background: white !important;
+
+ !CmdLine;>* font-family: monospace !important; padding: 1px !important;
+ CmdOutput white-space: pre;
CompGroup
CompGroup:not(:first-of-type) margin-top: .5em;
@@ -158,9 +179,10 @@ const ConfigBase = Class(ModuleBase, {
CompResult width: 45%; overflow: hidden;
CompDesc color: gray; width: 50%;
CompLess text-align: center; height: 0; line-height: .5ex; padding-top: 1ex;
- CompLess::after content: "\2303" /* Unicode up arrowhead */
+ CompLess::after content: "⌃";
CompMore text-align: center; height: .5ex; line-height: .5ex; margin-bottom: -.5ex;
- CompMore::after content: "\2304" /* Unicode down arrowhead */
+ CompMore::after content: "⌄";
+ CompGroup:last-of-type padding-bottom: 1.5ex;
Gradient height: 1px; margin-bottom: -1px; margin-top: -1px;
GradientLeft background-color: magenta;
@@ -172,19 +194,16 @@ const ConfigBase = Class(ModuleBase, {
Keyword color: red;
Tag color: blue;
- LineNr color: orange; background: white;
- Question color: green; background: white; font-weight: bold;
-
- StatusLine color: white; background: black;
- StatusLineBroken color: black; background: #FFa0a0 /* light-red */
- StatusLineSecure color: black; background: #a0a0FF /* light-blue */
- StatusLineExtended color: black; background: #a0FFa0 /* light-green */
+ !StatusLine color: white !important; background: black !important
+ StatusLineBroken color: black !important; background: #FFa0a0 !important /* light-red */
+ StatusLineSecure color: black !important; background: #a0a0FF !important /* light-blue */
+ StatusLineExtended color: black !important; background: #a0FFa0 !important /* light-green */
- TabClose,.tab-close-button
- TabIcon,.tab-icon
- TabText,.tab-text
- TabNumber font-weight: bold; margin: 0px; padding-right: .3ex;
- TabIconNumber {
+ TabClose;.tab-close-button
+ TabIcon;.tab-icon
+ TabText;.tab-text
+ !TabNumber font-weight: bold; margin: 0px; padding-right: .3ex;
+ !TabIconNumber {
font-weight: bold;
color: white;
text-align: center;
@@ -195,47 +214,52 @@ const ConfigBase = Class(ModuleBase, {
URL text-decoration: none; color: green; background: inherit;
URL:hover text-decoration: underline; cursor: pointer;
- FrameIndicator,,* {
- background-color: red;
- opacity: 0.5;
- z-index: 999;
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
+ FrameIndicator;;* {
+ /* This gets released into the wild, so everything is important */
+ background-color: red !important;
+ opacity: 0.5 !important;
+ z-index: 999999 !important;
+ position: fixed !important;
+ top: 0 !important;
+ bottom: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
}
- Bell border: none; background-color: black;
- Hint,,* {
- font-family: monospace;
- font-size: 10px;
- font-weight: bold;
- color: white;
- background-color: red;
- border-color: ButtonShadow;
- border-width: 0px;
- border-style: solid;
- padding: 0px 1px 0px 1px;
+ !Bell border: none; background-color: black;
+ Hint;;* {
+ /* This gets released into the wild, so everything is important */
+ font: bold 10px monospace !important;
+ background-color: red !important;
+ color: white !important;
+ border: 0px solid ButtonShadow !important;
+ padding: 0px 1px !important;
}
- Hint::after,,* content: attr(number);
- HintElem,,* background-color: yellow; color: black;
- HintActive,,* background-color: #88FF00; color: black;
- HintImage,,* opacity: .5;
+ !Hint::after;;* content: attr(number) !important;
+ !HintElem;;* background-color: yellow !important; color: black !important;
+ !HintActive;;* background-color: #88FF00 !important; color: black !important;
+ !HintImage;;* opacity: .5 !important;
- Help font-size: 8pt; line-height: 1.4em; font-family: -moz-fixed;
+ !Logo
+ // </css>
+ ]]></>),
+
+ helpCSS: UTF8(<><![CDATA[
+ // <css>
+ Help font-size: 8pt; line-height: 1.4em; font-family: -moz-fixed, monospace;
HelpArg color: #6A97D4;
HelpOptionalArg color: #6A97D4;
- HelpBody display: block; margin: 1em auto; max-width: 100ex;
- HelpBorder,*,dactyl://help/* border-color: silver; border-width: 0px; border-style: solid;
- HelpCode display: block; white-space: pre; margin-left: 2em; font-family: Terminus, Fixed, monospace;
+ HelpBody display: block; margin: 1em auto; max-width: 100ex; padding-bottom: 1em; margin-bottom: 4em; border-bottom-width: 1px;
+ HelpBorder;*;dactyl://help/* border-color: silver; border-width: 0px; border-style: solid;
+ HelpCode display: block; white-space: pre; margin-left: 2em; font-family: monospace;
- HelpDefault margin-right: 1ex; white-space: pre;
+ HelpDefault display: inline-block; margin-right: 1ex; white-space: pre;
- HelpDescription display: block;
- HelpEm,html|em,dactyl://help/* font-weight: bold; font-style: normal;
+ HelpDescription display: block; clear: right;
+ HelpDescription[short] clear: none;
+ HelpEm;html|em;dactyl://help/* font-weight: bold; font-style: normal;
HelpEx display: inline-block; color: #527BBD; font-weight: bold;
@@ -249,32 +273,42 @@ const ConfigBase = Class(ModuleBase, {
HelpItem display: block; margin: 1em 1em 1em 10em; clear: both;
HelpKey color: #102663;
+ HelpKeyword font-weight: bold; color: navy;
+
+ HelpLink;html|a;dactyl://help/* text-decoration: none !important;
+ HelpLink[href]:hover text-decoration: underline !important;
+ HelpLink[href^="mailto:"]::after content: "✉"; padding-left: .2em;
+ HelpLink[rel=external] {
+ /* Thanks, Wikipedia */
+ background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAFVBMVEVmmcwzmcyZzP8AZswAZv////////9E6giVAAAAB3RSTlP///////8AGksDRgAAADhJREFUGFcly0ESAEAEA0Ei6/9P3sEcVB8kmrwFyni0bOeyyDpy9JTLEaOhQq7Ongf5FeMhHS/4AVnsAZubxDVmAAAAAElFTkSuQmCC) no-repeat scroll right center;
+ padding-right: 13px;
+ }
- HelpLink,html|a,dactyl://help/* text-decoration: none;
- HelpLink[href]:hover text-decoration: underline;
-
- HelpList,html|ul,dactyl://help/* display: block; list-style: outside disc;
- HelpOrderedList,html|ol,dactyl://help/* display: block; list-style: outside decimal;
- HelpListItem,html|li,dactyl://help/* display: list-item;
+ HelpOrderedList;ol[level="1"],ol;dactyl://help/* display: block; list-style: outside decimal;
+ HelpOrderedList2;ol[level="2"],ol ol;dactyl://help/* list-style: outside upper-alpha;
+ HelpOrderedList3;ol[level="3"],ol ol ol;dactyl://help/* list-style: outside lower-roman;
+ HelpList;html|ul;dactyl://help/* display: block; list-style: outside disc;
+ HelpListItem;html|li;dactyl://help/* display: list-item;
HelpNote color: red; font-weight: bold;
HelpOpt color: #106326;
- HelpOptInfo display: inline-block; margin-bottom: 1ex;
+ HelpOptInfo display: block; margin-bottom: 1ex; padding-left: 4em;
- HelpParagraph,html|p,dactyl://help/* display: block; margin: 1em 0em;
+ HelpParagraph;html|p;dactyl://help/* display: block; margin: 1em 0em;
HelpParagraph:first-child margin-top: 0;
- HelpSpec display: block; margin-left: -10em; float: left; clear: left; color: #527BBD; margin-right: 2em;
+ HelpParagraph:last-child margin-bottom: 0;
+ HelpSpec display: block; margin-left: -10em; float: left; clear: left; color: #527BBD; margin-right: 1em;
- HelpString display: inline-block; color: green; font-weight: normal; vertical-align: text-top;
+ HelpString color: green; font-weight: normal;
HelpString::before content: '"';
HelpString::after content: '"';
HelpString[delim]::before content: attr(delim);
HelpString[delim]::after content: attr(delim);
- HelpHead,html|h1,dactyl://help/* {
+ HelpHead;html|h1;dactyl://help/* {
display: block;
- margin: 1em 0;
+ margin: 2em 0 1em;
padding-bottom: .2ex;
border-bottom-width: 1px;
font-size: 2em;
@@ -282,9 +316,9 @@ const ConfigBase = Class(ModuleBase, {
color: #527BBD;
clear: both;
}
- HelpSubhead,html|h2,dactyl://help/* {
+ HelpSubhead;html|h2;dactyl://help/* {
display: block;
- margin: 1em 0;
+ margin: 2em 0 1em;
padding-bottom: .2ex;
border-bottom-width: 1px;
font-size: 1.2em;
@@ -292,7 +326,7 @@ const ConfigBase = Class(ModuleBase, {
color: #527BBD;
clear: both;
}
- HelpSubsubhead,html|h3,dactyl://help/* {
+ HelpSubsubhead;html|h3;dactyl://help/* {
display: block;
margin: 1em 0;
padding-bottom: .2ex;
@@ -305,12 +339,20 @@ const ConfigBase = Class(ModuleBase, {
HelpTOC
HelpTOC>ol ol margin-left: -1em;
- HelpTab,html|dl,dactyl://help/* display: table; width: 100%; margin: 1em 0; border-bottom-width: 1px; border-top-width: 1px; padding: .5ex 0; table-layout: fixed;
- HelpTabColumn,html|column,dactyl://help/* display: table-column;
- HelpTabColumn:first-child width: 25%;
- HelpTabTitle,html|dt,dactyl://help/* display: table-cell; padding: .1ex 1ex; font-weight: bold;
- HelpTabDescription,html|dd,dactyl://help/* display: table-cell; padding: .1ex 1ex; border-width: 0px;
- HelpTabRow,html|dl>html|tr,dactyl://help/* display: table-row;
+ HelpTab;html|dl;dactyl://help/* {
+ display: table;
+ width: 100%;
+ margin: 1em 0;
+ border-bottom-width: 1px;
+ border-top-width: 1px;
+ padding: .5ex 0;
+ table-layout: fixed;
+ }
+ HelpTabColumn;html|column;dactyl://help/* display: table-column;
+ HelpTabColumn:first-child width: 25%;
+ HelpTabTitle;html|dt;dactyl://help/* display: table-cell; padding: .1ex 1ex; font-weight: bold;
+ HelpTabDescription;html|dd;dactyl://help/* display: table-cell; padding: .1ex 1ex; border-width: 0px;
+ HelpTabRow;html|dl>html|tr;dactyl://help/* display: table-row;
HelpTag display: inline-block; color: #527BBD; margin-left: 1ex; font-size: 8pt; font-weight: bold;
HelpTags display: block; float: right; clear: right;
@@ -319,15 +361,31 @@ const ConfigBase = Class(ModuleBase, {
HelpWarning color: red; font-weight: bold;
- Logo
-
- Search,,* {
- font-size: inherit;
- padding: 0;
- color: black;
- background-color: yellow;
+ HelpXML color: #C5F779; background-color: #444444; font-family: Terminus, Fixed, monospace;
+ HelpXMLBlock { white-space: pre; color: #C5F779; background-color: #444444;
+ border: 1px dashed #aaaaaa;
+ display: block;
+ margin-left: 2em;
+ font-family: Terminus, Fixed, monospace;
}
- ]]>.toString()
+ HelpXMLAttribute color: #C5F779;
+ HelpXMLAttribute::after color: #E5E5E5; content: "=";
+ HelpXMLComment color: #444444;
+ HelpXMLComment::before content: "<!--";
+ HelpXMLComment::after content: "-->";
+ HelpXMLProcessing color: #C5F779;
+ HelpXMLProcessing::before color: #444444; content: "<?";
+ HelpXMLProcessing::after color: #444444; content: "?>";
+ HelpXMLString color: #C5F779; white-space: pre;
+ HelpXMLString::before content: '"';
+ HelpXMLString::after content: '"';
+ HelpXMLNamespace color: #FFF796;
+ HelpXMLNamespace::after color: #777777; content: ":";
+ HelpXMLTagStart color: #FFF796; white-space: normal; display: inline-block; text-indent: -1.5em; padding-left: 1.5em;
+ HelpXMLTagEnd color: #71BEBE;
+ HelpXMLText color: #E5E5E5;
+ // </css>
+ ]]></>)
});
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/dactyl-overlay.js b/common/content/dactyl-overlay.js
index af0cc3be..219da375 100644
--- a/common/content/dactyl-overlay.js
+++ b/common/content/dactyl-overlay.js
@@ -20,8 +20,10 @@
return;
}
catch (e) {
- if (e !== "Error opening input stream (invalid filename?)")
+ if (e !== "Error opening input stream (invalid filename?)") {
dump("dactyl: Trying: " + (base + script + ".js") + ": " + e + "\n" + e.stack);
+ Components.utils.reportError(e);
+ }
}
}
try {
@@ -30,6 +32,7 @@
catch (e) {
dump("dactyl: Loading script " + script + ": " + e.result + " " + e + "\n");
dump(Error().stack + "\n");
+ Components.utils.reportError(e);
}
};
@@ -64,7 +67,7 @@
"template",
].forEach(modules.load);
- prefix.unshift("chrome://" + modules.Config.prototype.name.toLowerCase() + "/content/");
+ prefix.unshift("chrome://" + modules.services.get("dactyl:").name + "/content/");
modules.Config.prototype.scripts.forEach(modules.load);
})();
diff --git a/common/content/dactyl.js b/common/content/dactyl.js
index 93608912..2c96ac96 100644
--- a/common/content/dactyl.js
+++ b/common/content/dactyl.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -204,14 +204,14 @@ const Dactyl = Module("dactyl", {
*
* @param {string|Object} msg The message to print.
*/
- dump: function () {
+ dump: function dump() {
let msg = Array.map(arguments, function (msg) {
if (typeof msg == "object")
msg = util.objectToString(msg);
return msg;
}).join(", ");
msg = String.replace(msg, /\n?$/, "\n");
- window.dump(msg.replace(/^./gm, ("config" in modules && config.name.toLowerCase()) + ": $&"));
+ window.dump(msg.replace(/^./gm, ("config" in modules && config.name) + ": $&"));
},
/**
@@ -220,7 +220,7 @@ const Dactyl = Module("dactyl", {
* @param {string} msg The trace message.
* @param {number} frames The number of frames to print.
*/
- dumpStack: function (msg, frames) {
+ dumpStack: function dumpStack(msg, frames) {
let stack = Error().stack.replace(/(?:.*\n){2}/, "");
if (frames != null)
[stack] = stack.match(RegExp("(?:.*\n){0," + frames + "}"));
@@ -234,7 +234,7 @@ const Dactyl = Module("dactyl", {
* @param {number} flags These control the multiline message behaviour.
* See {@link CommandLine#echo}.
*/
- echo: function (str, flags) {
+ echo: function echo(str, flags) {
commandline.echo(str, commandline.HL_NORMAL, flags);
},
@@ -246,7 +246,7 @@ const Dactyl = Module("dactyl", {
* @param {number} flags These control the multiline message behaviour.
* See {@link CommandLine#echo}.
*/
- echoerr: function (str, flags) {
+ echoerr: function echoerr(str, flags) {
flags |= commandline.APPEND_TO_MESSAGES;
if (isinstance(str, ["Error", "Exception"]))
@@ -293,8 +293,6 @@ const Dactyl = Module("dactyl", {
* should be loaded.
*/
loadScript: function (uri, context) {
- XML.ignoreWhiteSpace = false;
- XML.prettyPrinting = false;
services.get("subscriptLoader").loadSubScript(uri, context);
},
@@ -395,7 +393,7 @@ const Dactyl = Module("dactyl", {
let command = commands.get(cmd);
if (command === null) {
- err = "E492: Not a " + config.name.toLowerCase() + " command: " + str;
+ err = "E492: Not a " + config.name + " command: " + str;
dactyl.focusContent();
}
else if (command.action === null)
@@ -486,27 +484,19 @@ const Dactyl = Module("dactyl", {
* Initialize the help system.
*/
initHelp: function () {
- if ("noscriptOverlay" in window) {
- noscriptOverlay.safeAllow("chrome-data:", true, false);
- noscriptOverlay.safeAllow("dactyl:", true, false);
- }
+ if (!this.helpInitialized) {
+ if ("noscriptOverlay" in window) {
+ noscriptOverlay.safeAllow("chrome-data:", true, false);
+ noscriptOverlay.safeAllow("dactyl:", true, false);
+ }
- if(!this.helpInitialized) {
- let namespaces = [config.name.toLowerCase(), "dactyl"];
+ let namespaces = [config.name, "dactyl"];
services.get("dactyl:").init({});
let tagMap = services.get("dactyl:").HELP_TAGS;
let fileMap = services.get("dactyl:").FILE_MAP;
let overlayMap = services.get("dactyl:").OVERLAY_MAP;
- // Left as an XPCOM instantiation so it can easilly be moved
- // into XPCOM code.
- function XSLTProcessor(sheet) {
- let xslt = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
- xslt.importStylesheet(util.httpGet(sheet).responseXML);
- return xslt;
- }
-
// Find help and overlay files with the given name.
function findHelpFile(file) {
let result = [];
@@ -525,23 +515,20 @@ const Dactyl = Module("dactyl", {
}
// Find the tags in the document.
function addTags(file, doc) {
- doc = XSLT.transformToDocument(doc);
- for (let elem in util.evaluateXPath("//xhtml:a/@id", doc))
- tagMap[elem.value] = file;
+ for (let elem in util.evaluateXPath("//@tag|//dactyl:tags/text()|//dactyl:tag/text()", doc))
+ for (let tag in array((elem.value || elem.textContent).split(/\s+/)).compact().itervalues())
+ tagMap[tag] = file;
}
- const XSLT = XSLTProcessor("chrome://dactyl/content/help-single.xsl");
-
// Scrape the list of help files from all.xml
- // Always process main and overlay files, since XSLTProcessor and
+ // Manually process main and overlay files, since XSLTProcessor and
// XMLHttpRequest don't allow access to chrome documents.
tagMap.all = "all";
let files = findHelpFile("all").map(function (doc)
- [f.value for (f in util.evaluateXPath(
- "//dactyl:include/@href", doc))]);
+ [f.value for (f in util.evaluateXPath("//dactyl:include/@href", doc))]);
// Scrape the tags from the rest of the help files.
- util.Array.flatten(files).forEach(function (file) {
+ array.flatten(files).forEach(function (file) {
findHelpFile(file).forEach(function (doc) {
addTags(file, doc);
});
@@ -550,7 +537,6 @@ const Dactyl = Module("dactyl", {
// Process plugin help entries.
XML.ignoreWhiteSpace = false;
XML.prettyPrinting = false;
- XML.prettyIndent = 4;
let body = XML();
for (let [, context] in Iterator(plugins.contexts))
@@ -558,11 +544,12 @@ const Dactyl = Module("dactyl", {
body += <h2 xmlns={NS.uri} tag={context.INFO.@name + '-plugin'}>{context.INFO.@summary}</h2> +
context.INFO;
- let help = '<?xml version="1.0"?>\n' +
- '<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>\n' +
- '<!DOCTYPE document SYSTEM "chrome://dactyl/content/dactyl.dtd">' +
+ let help =
+ '<?xml version="1.0"?>\n' +
+ '<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>\n' +
+ '<!DOCTYPE document SYSTEM "chrome://dactyl/content/dactyl.dtd">\n' +
<document xmlns={NS}
- name="plugins" title={config.name + " Plugins"}>
+ name="plugins" title={config.appname + " Plugins"}>
<h1 tag="using-plugins">Using Plugins</h1>
<toc start="2"/>
@@ -589,11 +576,11 @@ const Dactyl = Module("dactyl", {
function addDataEntry(file, data) // Inideal to an extreme.
addURIEntry(file, "data:text/plain;charset=UTF-8," + encodeURI(data));
- let empty = util.Array.toObject(
- "area base basefont br col frame hr img input isindex link meta param"
- .split(" ").map(Array.concat));
+ let empty = set("area base basefont br col frame hr img input isindex link meta param"
+ .split(" "));
let chrome = {};
+ let styles = {};
for (let [file,] in Iterator(services.get("dactyl:").FILE_MAP)) {
dactyl.open("dactyl://help/" + file);
dactyl.modules.events.waitForPageLoad();
@@ -612,10 +599,11 @@ const Dactyl = Module("dactyl", {
if (node instanceof HTMLHtmlElement)
data.push(" xmlns=" + XHTML.uri.quote());
- for (let { name: name, value: value } in util.Array.itervalues(node.attributes)) {
+ for (let { name, value } in array.itervalues(node.attributes)) {
if (name == "dactyl:highlight") {
name = "class";
value = "hl-" + value;
+ set.add(styles, value);
}
if (name == "href") {
if (value.indexOf("dactyl://help-tag/") == 0)
@@ -651,11 +639,11 @@ const Dactyl = Module("dactyl", {
addDataEntry(file + ".xhtml", data.join(""));
}
- let data = [h.selector.replace(/^\[.*?=(.*?)\]/, ".hl-$1").replace(/html\|/, "") +
- "\t{" + h.value + "}"
- for (h in highlight) if (/^Help|^Logo/.test(h.class))];
-
- data = data.join("\n");
+ let data = [h for (h in highlight) if (set.has(styles, h.class) || /^Help/.test(h.class))]
+ .map(function (h)
+ h.selector.replace(/^\[.*?=(.*?)\]/, ".hl-$1").replace(/html\|/, "") + "\t" +
+ "{" + h.value + "}")
+ .join("\n");
addDataEntry("help.css", data.replace(/chrome:[^ ")]+\//g, ""));
let re = /(chrome:[^ ");]+\/)([^ ");]+)/g;
@@ -669,6 +657,49 @@ const Dactyl = Module("dactyl", {
},
/**
+ * Generates a help entry.
+ *
+ * @param {Command|Map|Option} obj A dactyl <b>Command</b>,
+ * <b>Map</b> or <b>Option</b> object
+ * @param {XMLList} extraHelp Extra help text beyond the description.
+ * @returns {string}
+ */
+ generateHelp: function generateHelp(obj, extraHelp)
+ {
+ default xml namespace = "";
+ let spec = util.identity;
+ let tag = util.identity;
+ if (obj instanceof Command)
+ tag = spec = function (cmd) <>:{cmd}</>;
+ else if (obj instanceof Map && obj.count)
+ spec = function (map) <><oa>count</oa>{map}</>;
+ else if (obj instanceof Option)
+ tag = spec = function (opt) <>'{opt}'</>;
+
+ XML.prettyPrinting = false;
+ XML.ignoreWhitespace = false;
+
+ // E4X has its warts.
+ let br = <>
+ </>;
+
+ return <>
+ <item>
+ <tags>{template.map(obj.names, tag, " ")}</tags>
+ <spec>{spec((obj.specs || obj.names)[0])}</spec>{
+ !obj.type ? "" : <>
+ <type>{obj.type}</type>
+ <default>{obj.defaultValue}</default></>}
+ <description>{
+ obj.description ? br+<p>{obj.description.replace(/\.?$/, ".")}</p> : "" }{
+ extraHelp ? br+extraHelp : "" }{
+ !(extraHelp || obj.description) ? br+<p>Sorry, no help available.</p> : "" }
+ </description>
+ </item></>.toXMLString();
+ },
+
+
+ /**
* Opens the help page containing the specified <b>topic</b> if it
* exists.
*
@@ -692,8 +723,6 @@ const Dactyl = Module("dactyl", {
dactyl.assert(page != null, "E149: Sorry, no help for " + topic);
dactyl.open("dactyl://help/" + page, { from: "help" });
- if (options.get("activate").has("all", "help"))
- content.postMessage("fragmentChange", "*");
},
/**
@@ -723,15 +752,15 @@ const Dactyl = Module("dactyl", {
});
}
- let dirs = io.getRuntimeDirectories("plugin");
+ let dirs = io.getRuntimeDirectories("plugins");
if (dirs.length == 0) {
dactyl.log("No user plugin directory found", 3);
return;
}
- dactyl.echomsg('Searching for "plugin/**/*.{js,vimp}" in '
- + [dir.path.replace(/.plugin$/, "") for ([, dir] in Iterator(dirs))]
+ dactyl.echomsg('Searching for "plugins/**/*.{js,vimp}" in '
+ + [dir.path.replace(/.plugins$/, "") for ([, dir] in Iterator(dirs))]
.join(",").quote(), 2);
dirs.forEach(function (dir) {
@@ -765,20 +794,33 @@ const Dactyl = Module("dactyl", {
if (typeof msg == "object")
msg = util.objectToString(msg, false);
- services.get("console").logStringMessage(config.name.toLowerCase() + ": " + msg);
+ services.get("console").logStringMessage(config.name + ": " + msg);
},
/**
* Opens one or more URLs. Returns true when load was initiated, or
* false on error.
*
- * @param {string|string[]} urls Either a URL string or an array of URLs.
- * The array can look like this:
- * ["url1", "url2", "url3", ...]
- * or:
- * [["url1", postdata1], ["url2", postdata2], ...]
- * @param {number|Object} where If ommited, CURRENT_TAB is assumed but NEW_TAB
- * is set when dactyl.forceNewTab is true.
+ * @param {string|Array} urls A representation of the URLs to open. May be
+ * either a string, which will be bassed to
+ * {@see Dactyl#stringToURLArray}, or an array in the same format as
+ * would be returned by the same.
+ * @param {object} params A set of parameters specifing to open the
+ * URLs. The following properties are recognized:
+ *
+ * • background If true, new tabs are opened in the background.
+ *
+ * • from The desgination of the opener, as appears in
+ * 'activate' and 'newtab' options. If present,
+ * the newtab option provides the default 'where'
+ * parameter, and the value of the 'activate'
+ * parameter is inverted if 'background' is true.
+ *
+ * • where One of CURRENT_TAB, NEW_TAB, or NEW_WINDOW
+ *
+ * As a deprecated special case, the where paramater may be provided
+ * by itself, in which case it is transformed into { where: params }.
+ *
* @param {boolean} force Don't prompt whether to open more than 20
* tabs.
* @returns {boolean}
@@ -787,30 +829,29 @@ const Dactyl = Module("dactyl", {
if (typeof urls == "string")
urls = dactyl.stringToURLArray(urls);
- if (urls.length > 20 && !force) {
- commandline.input("This will open " + urls.length + " new tabs. Would you like to continue? (yes/[no]) ",
+ if (urls.length > 20 && !force)
+ return commandline.input("This will open " + urls.length + " new tabs. Would you like to continue? (yes/[no]) ",
function (resp) {
if (resp && resp.match(/^y(es)?$/i))
dactyl.open(urls, params, true);
});
- return;
- }
- let flags = 0;
params = params || {};
if (isarray(params))
params = { where: params };
+ let flags = 0;
for (let [opt, flag] in Iterator({ replace: "REPLACE_HISTORY", hide: "BYPASS_HISTORY" }))
- if (params[opt])
- flags |= Ci.nsIWebNavigation["LOAD_FLAGS_" + flag];
+ flags |= params[opt] && Ci.nsIWebNavigation["LOAD_FLAGS_" + flag];
let where = params.where || dactyl.CURRENT_TAB;
- let background = ("background" in params) ? params.background : params.where == dactyl.NEW_BACKGROUND_TAB;
- if ("from" in params && dactyl.has("tabs")) {
- if (!('where' in params) && options.get("newtab").has("all", params.from))
+ let background = ("background" in params) ? params.background
+ : params.where == dactyl.NEW_BACKGROUND_TAB;
+
+ if (params.from && dactyl.has("tabs")) {
+ if (!params.where && options.get("newtab").has("all", params.from))
where = dactyl.NEW_TAB;
- background = !options.get("activate").has("all", params.from);
+ background ^= !options.get("activate").has("all", params.from);
}
if (urls.length == 0)
@@ -829,10 +870,8 @@ const Dactyl = Module("dactyl", {
break;
case dactyl.NEW_TAB:
- if (!dactyl.has("tabs")) {
- open(urls, dactyl.NEW_WINDOW);
- return;
- }
+ if (!dactyl.has("tabs"))
+ return open(urls, dactyl.NEW_WINDOW);
options.withContext(function () {
options.setPref("browser.tabs.loadInBackground", true);
@@ -849,6 +888,9 @@ const Dactyl = Module("dactyl", {
}
}
catch(e) {}
+ // Unfortunately, failed page loads throw exceptions and
+ // cause a lot of unwanted noise. This solution means that
+ // any genuine errors go unreported.
}
if (dactyl.forceNewTab)
@@ -860,6 +902,7 @@ const Dactyl = Module("dactyl", {
for (let [, url] in Iterator(urls)) {
open(url, where);
+ where = dactyl.NEW_TAB;
background = true;
}
},
@@ -1037,12 +1080,10 @@ const Dactyl = Module("dactyl", {
services.get("observer").notifyObservers(null, "quit-application-granted", null);
// enumerate all windows and call shutdown handlers
- let windows = services.get("windowMediator").getEnumerator(null);
- while (windows.hasMoreElements()) {
- let win = windows.getNext();
+ for (let win in iter(services.get("windowMediator").getEnumerator(null)))
if (("tryToClose" in win) && !win.tryToClose())
return;
- }
+
services.get("appStartup").quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
},
@@ -1092,14 +1133,7 @@ const Dactyl = Module("dactyl", {
* @property {Window[]} Returns an array of all the host application's
* open windows.
*/
- get windows() {
- let windows = [];
- let enumerator = services.get("windowMediator").getEnumerator("navigator:browser");
- while (enumerator.hasMoreElements())
- windows.push(enumerator.getNext());
-
- return windows;
- }
+ get windows() [win for (win in iter(services.get("windowMediator").getEnumerator("navigator:browser")))],
}, {
// initially hide all GUI elements, they are later restored unless the user
@@ -1193,26 +1227,27 @@ const Dactyl = Module("dactyl", {
this);
let class_ = dir.map(function (dir) "html|html > xul|scrollbar[orient=" + dir + "]");
- if (class_.length)
- styles.addSheet(true, "scrollbar", "*", class_.join(", ") + " { visibility: collapse !important; }", true);
- else
- styles.removeSheet(true, "scrollbar");
+ styles.addSheet(true, "scrollbar", "*",
+ class_.length ? class_.join(", ") + " { visibility: collapse !important; }" : "");
+
options.safeSetPref("layout.scrollbar.side", opts.indexOf("l") >= 0 ? 3 : 2,
"See 'guioptions' scrollbar flags.");
},
validator: function (opts) (opts.indexOf("l") < 0 || opts.indexOf("r") < 0)
},
tab: {
+ feature: "tabs",
opts: {
n: ["Tab number", highlight.selector("TabNumber")],
N: ["Tab number over icon", highlight.selector("TabIconNumber")]
},
setter: function (opts) {
- const self = this;
let classes = [v[1] for ([k, v] in Iterator(this.opts)) if (opts.indexOf(k) < 0)];
- let css = classes.length ? classes.join(",") + "{ display: none; }" : "";
- styles.addSheet(true, "taboptions", "chrome://*", css);
- tabs.tabsBound = Array.some(opts, function (k) k in self.opts);
+
+ styles.addSheet(true, "taboptions", "chrome://*",
+ classes.length ? classes.join(",") + "{ display: none; }" : "");
+
+ tabs.tabBinding.enabled = Array.some(opts, function (k) k in this.opts, this);
statusline.updateTabCount();
}
}
@@ -1230,13 +1265,14 @@ const Dactyl = Module("dactyl", {
"charlist", config.defaults.guioptions || "", {
setter: function (value) {
for (let [, group] in Iterator(groups))
- group.setter(value);
+ if (!group.feature || dactyl.has(group.feature))
+ group.setter(value);
return value;
},
completer: function (context) {
- let opts = [v.opts for ([k, v] in Iterator(groups))];
+ let opts = [v.opts for ([k, v] in Iterator(groups)) if (!v.feature || dactyl.has(v.feature))];
opts = opts.map(function (opt) [[k, v[0]] for ([k, v] in Iterator(opt))]);
- return util.Array.flatten(opts);
+ return array.flatten(opts);
},
validator: function (val) Option.validateCompleter.call(this, val) &&
[v for ([k, v] in Iterator(groups))].every(function (g) !g.validator || g.validator(val))
@@ -1252,7 +1288,7 @@ const Dactyl = Module("dactyl", {
options.add(["titlestring"],
"Change the title of the window",
- "string", config.defaults.titlestring || config.hostApplication,
+ "string", config.defaults.titlestring || config.host,
{
setter: function (value) {
let win = document.documentElement;
@@ -1330,13 +1366,13 @@ const Dactyl = Module("dactyl", {
{ argCount: "0" });
commands.add(["dia[log]"],
- "Open a " + config.name + " dialog",
+ "Open a " + config.appname + " dialog",
function (args) {
- let arg = args[0];
+ let dialog = args[0];
+ dactyl.assert(dialog in config.dialogs, "E475: Invalid argument: " + dialog);
try {
- dactyl.assert(args[0] in config.dialogs, "E475: Invalid argument: " + arg);
- config.dialogs[args[0]][1]();
+ config.dialogs[dialog][1]();
}
catch (e) {
dactyl.echoerr("Error opening " + arg.quote() + ": " + e);
@@ -1383,15 +1419,8 @@ const Dactyl = Module("dactyl", {
///////////////////////////////////////////////////////////////////////////
- if (typeof AddonManager == "undefined") {
+ if (typeof AddonManager == "undefined")
modules.AddonManager = {
- getInstallForFile: function (file, callback, mimetype) {
- callback({
- install: function () {
- services.get("extensionManager").installItemFromFile(file, "app-profile");
- }
- });
- },
getAddonById: function (id, callback) {
let addon = id;
if (!isobject(addon))
@@ -1438,11 +1467,19 @@ const Dactyl = Module("dactyl", {
.getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {})))
res.append(this.getAddonById(item));
return res;
- }
+ },
+ getInstallForFile: function (file, callback, mimetype) {
+ callback({
+ install: function () {
+ services.get("extensionManager").installItemFromFile(file, "app-profile");
+ }
+ });
+ },
+ getInstallForURL: function (url, callback, mimetype) {
+ dactyl.assert(false, "Install by URL not implimented");
+ },
};
- }
-
///////////////////////////////////////////////////////////////////////////
function callResult(method) {
@@ -1467,7 +1504,7 @@ const Dactyl = Module("dactyl", {
}, {
argCount: "1",
completer: function (context) {
- context.filters.push(function ({ item: f }) f.isDirectory() || /\.xpi$/.test(f.leafName));
+ context.filters.push(function ({ item }) item.isDirectory() || /\.xpi$/.test(item.leafName));
completion.file(context);
}
});
@@ -1483,13 +1520,13 @@ const Dactyl = Module("dactyl", {
name: "exte[nable]",
description: "Enable an extension",
action: function (addon) addon.userDisabled = false,
- filter: function ({ item: e }) e.userDisabled
+ filter: function ({ item }) item.userDisabled
},
{
name: "extd[isable]",
description: "Disable an extension",
action: function (addon) addon.userDisabled = true,
- filter: function ({ item: e }) !e.userDisabled
+ filter: function ({ item }) !item.userDisabled
}
].forEach(function (command) {
commands.add([command.name],
@@ -1535,7 +1572,7 @@ const Dactyl = Module("dactyl", {
bang: true,
completer: function (context) {
completion.extension(context);
- context.filters.push(function ({ item: e }) e.isActive && e.optionsURL);
+ context.filters.push(function ({ item }) item.isActive && item.optionsURL);
},
literal: 0
});
@@ -1543,6 +1580,23 @@ const Dactyl = Module("dactyl", {
commands.add(["extens[ions]", "exts"],
"List available extensions",
function (args) {
+ function addonExtra(e) {
+ let extra;
+ if (e.pendingOperations & AddonManager.PENDING_UNINSTALL)
+ extra = ["Disabled", "uninstalled"];
+ else if (e.pendingOperations & AddonManager.PENDING_DISABLE)
+ extra = ["Disabled", "disabled"];
+ else if (e.pendingOperations & AddonManager.PENDING_INSTALL)
+ extra = ["Enabled", "installed"];
+ else if (e.pendingOperations & AddonManager.PENDING_ENABLE)
+ extra = ["Enabled", "enabled"];
+ else if (e.pendingOperations & AddonManager.PENDING_UPGRADE)
+ extra = ["Enabled", "upgraded"];
+ if (extra)
+ return <>&#xa0;(<span highlight={extra[0]}>{extra[1]}</span>
+ &#xa0;on restart)</>;
+ return <></>;
+ }
AddonManager.getAddonsByTypes(["extension"], function (extensions) {
if (args[0])
extensions = extensions.filter(function (extension) extension.name.indexOf(args[0]) >= 0);
@@ -1555,12 +1609,7 @@ const Dactyl = Module("dactyl", {
e.version,
(e.isActive ? <span highlight="Enabled">enabled</span>
: <span highlight="Disabled">disabled</span>) +
- ((e.userDisabled || e.appDisabled) == !e.isActive ? XML() :
- <>&#xa0;({e.userDisabled || e.appDisabled
- ? <span highlight="Disabled">disabled</span>
- : <span highlight="Enabled">enabled</span>}
- on restart)
- </>),
+ addonExtra(e),
e.description]
for ([, e] in Iterator(extensions)))));
else if (filter)
@@ -1658,7 +1707,7 @@ const Dactyl = Module("dactyl", {
});
commands.add(["res[tart]"],
- "Force " + config.name + " to restart",
+ "Force " + config.appname + " to restart",
function () { dactyl.restart(); },
{ argCount: "0" });
@@ -1810,7 +1859,7 @@ const Dactyl = Module("dactyl", {
dactyl.open("about:");
else
commandline.commandOutput(<>
- {config.name} {dactyl.version} running on:<br/>{navigator.userAgent}
+ {config.appname} {dactyl.version} running on:<br/>{navigator.userAgent}
</>);
}, {
argCount: "0",
@@ -1836,11 +1885,13 @@ const Dactyl = Module("dactyl", {
context.title = ["Extension"];
context.anchored = false;
context.keys = { text: "name", description: "description", icon: "iconURL" },
- context.incomplete = true;
- AddonManager.getAddonsByTypes(["extension"], function (addons) {
- context.incomplete = false;
- context.completions = addons;
- });
+ context.generate = function () {
+ context.incomplete = true;
+ AddonManager.getAddonsByTypes(["extension"], function (addons) {
+ context.incomplete = false;
+ context.completions = addons;
+ });
+ };
};
completion.help = function help(context, unchunked) {
@@ -1877,7 +1928,7 @@ const Dactyl = Module("dactyl", {
dactyl.log("All modules loaded", 3);
- services.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=" + config.name.toLowerCase());
+ services.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=" + config.name);
let commandline = services.get("commandLineHandler").optionValue;
if (commandline) {
@@ -1892,7 +1943,7 @@ const Dactyl = Module("dactyl", {
dactyl.log("Command-line options: " + util.objectToString(dactyl.commandLineOptions), 3);
// first time intro message
- const firstTime = "extensions." + config.name.toLowerCase() + ".firsttime";
+ const firstTime = "extensions." + config.name + ".firsttime";
if (options.getPref(firstTime, true)) {
util.timeout(function () {
dactyl.help();
@@ -1904,7 +1955,7 @@ const Dactyl = Module("dactyl", {
modes.reset();
// TODO: we should have some class where all this guioptions stuff fits well
- Dactyl.hideGUI();
+ // Dactyl.hideGUI();
if (dactyl.commandLineOptions.preCommands)
dactyl.commandLineOptions.preCommands.forEach(function (cmd) {
@@ -1914,7 +1965,7 @@ const Dactyl = Module("dactyl", {
// finally, read the RC file and source plugins
// make sourcing asynchronous, otherwise commands that open new tabs won't work
util.timeout(function () {
- let extensionName = config.name.toUpperCase();
+ let extensionName = config.idname;
let init = services.get("environment").get(extensionName + "_INIT");
let rcFile = io.getRCFile("~");
@@ -1951,13 +2002,18 @@ const Dactyl = Module("dactyl", {
// after sourcing the initialization files, this function will set
// all gui options to their default values, if they have not been
// set before by any RC file
- for (let option in options) {
+ for (let option in values(options.needInit))
+ // FIXME:
// 'encoding' option should not be set at this timing.
// Probably a wrong value is set into the option,
// if current page's encoging is not UTF-8.
- if (option.name != "encoding" && option.setter)
- option.value = option.value;
- }
+ try {
+ if (option.name != "encoding");
+ option.value = option.value;
+ }
+ catch (e) {
+ dactyl.reportError(e);
+ }
if (dactyl.commandLineOptions.postCommands)
dactyl.commandLineOptions.postCommands.forEach(function (cmd) {
@@ -1969,7 +2025,7 @@ const Dactyl = Module("dactyl", {
}, 0);
statusline.update();
- dactyl.log(config.name + " fully initialized", 0);
+ dactyl.log(config.appname + " fully initialized", 0);
dactyl.initialized = true;
}
});
diff --git a/common/content/dactyl.xul b/common/content/dactyl.xul
index 1483e7cc..49e15ff5 100644
--- a/common/content/dactyl.xul
+++ b/common/content/dactyl.xul
@@ -23,11 +23,6 @@
<script type="application/x-javascript;version=1.8" src="&dactyl.content;dactyl-overlay.js"/>
<window id="&dactyl.mainWindow;">
- <stringbundleset id="dactyl-stringbundles">
- <stringbundle id="dactyl-charset-bundle"
- src="chrome://global/locale/charsetTitles.properties"/>
- </stringbundleset>
-
<keyset id="mainKeyset">
<key id="key_open_vimbar" key=":" oncommand="window.dactyl &and; dactyl.modules.commandline.open(':', '', dactyl.modules.modes.EX);" modifiers=""/>
<key id="key_stop" keycode="VK_ESCAPE" oncommand="window.dactyl &and; dactyl.modules.events.onEscape();"/>
@@ -43,13 +38,13 @@
<commandset id="onPentadactylFocus"
commandupdater="true"
events="focus"
- oncommandupdate="if (window.dactyl &and; dactyl.modules.events != undefined) dactyl.modules.events.onFocusChange(event);"/>
+ oncommandupdate="if (window.dactyl &and; dactyl.modules.loaded.events) dactyl.modules.events.onFocusChange(event);"/>
<commandset id="onPentadactylSelect"
commandupdater="true"
events="select"
- oncommandupdate="if (window.dactyl &and; dactyl.modules.events != undefined) dactyl.modules.events.onSelectionChange(event);"/>
+ oncommandupdate="if (window.dactyl &and; dactyl.modules.loaded.events) dactyl.modules.events.onSelectionChange(event);"/>
- <!-- As of Firefox 3.1pre, <iframe>.height changes do not seem to have immediate effect,
+ <!-- As of Firefox 3.1pre, iframe.height changes do not seem to have immediate effect,
therefore we need to put them into a <vbox> for which that works just fine -->
<vbox class="dactyl-container" hidden="false" collapsed="true">
<iframe id="dactyl-multiline-output" src="chrome://dactyl/content/buffer.xhtml"
@@ -81,7 +76,6 @@
oninput="window.dactyl &and; dactyl.modules.commandline.onMultilineInputEvent(event);"
onblur="window.dactyl &and; dactyl.modules.commandline.onMultilineInputEvent(event);"/>
</vbox>
-
</window>
<statusbar id="status-bar" dactyl:highlight="StatusLine">
@@ -98,7 +92,6 @@
<statusbarpanel id="statusbar-display" hidden="true"/>
<statusbarpanel id="statusbar-progresspanel" hidden="true"/>
</statusbar>
-
</overlay>
<!-- vim: set fdm=marker sw=4 ts=4 et: -->
diff --git a/common/content/editor.js b/common/content/editor.js
index 25b4f461..2dc6844c 100644
--- a/common/content/editor.js
+++ b/common/content/editor.js
@@ -569,7 +569,7 @@ const Editor = Module("editor", {
let list = this.getAbbreviations(filter, lhs);
if (!list.length)
- dactyl.echomsg("No this._abbreviations found");
+ dactyl.echomsg("No abbreviations found");
else if (list.length == 1) {
let [mode, lhs, rhs] = list[0];
diff --git a/common/content/eval.js b/common/content/eval.js
index 7fc899f4..49298d92 100644
--- a/common/content/eval.js
+++ b/common/content/eval.js
@@ -4,7 +4,7 @@ catch (e) { __dactyl_eval_error = e; }
// IMPORTANT: The eval statement *must* remain on the first line
// in order for line numbering in any errors to remain correct.
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
diff --git a/common/content/events.js b/common/content/events.js
index ddfd4697..81fdb5f1 100644
--- a/common/content/events.js
+++ b/common/content/events.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -1173,7 +1173,7 @@ const Events = Module("events", {
function () { document.commandDispatcher.rewindFocus(); });
mappings.add(modes.all,
- ["<C-z>"], "Temporarily ignore all " + config.name + " key bindings",
+ ["<C-z>"], "Temporarily ignore all " + config.appname + " key bindings",
function () { modes.passAllKeys = true; });
mappings.add(modes.all,
diff --git a/common/content/finder.js b/common/content/finder.js
index 95c2356d..dbbe38b1 100644
--- a/common/content/finder.js
+++ b/common/content/finder.js
@@ -27,20 +27,25 @@ const RangeFinder = Module("rangefinder", {
let highlighted = this.rangeFind && this.rangeFind.highlighted;
let selections = this.rangeFind && this.rangeFind.selections;
+ let regex = false;
let matchCase = !(options["ignorecase"] || options["smartcase"] && !/[A-Z]/.test(str));
let linksOnly = options["linksearch"];
str = str.replace(/\\(.|$)/g, function (m, n1) {
- if (n1 == "l")
- linksOnly = true;
- else if (n1 == "L")
- linksOnly = false;
- else if (n1 == "c")
+ if (n1 == "c")
matchCase = false;
else if (n1 == "C")
matchCase = true;
+ else if (n1 == "l")
+ linksOnly = true;
+ else if (n1 == "L")
+ linksOnly = false;
+ else if (n1 == "r")
+ regex = true;
+ else if (n1 == "R")
+ regex = false;
else
- return n1;
+ return m;
return "";
});
@@ -49,12 +54,13 @@ const RangeFinder = Module("rangefinder", {
if (!this.rangeFind
|| this.rangeFind.window.get() != window
|| linksOnly != !!this.rangeFind.elementPath
+ || regex != this.rangeFind.regex
|| matchCase != this.rangeFind.matchCase
|| !!backward != this.rangeFind.reverse) {
if (this.rangeFind)
this.rangeFind.cancel();
- this.rangeFind = RangeFind(matchCase, backward, linksOnly && options["hinttags"]);
+ this.rangeFind = RangeFind(matchCase, backward, linksOnly && options["hinttags"], regex);
this.rangeFind.highlighted = highlighted;
this.rangeFind.selections = selections;
}
@@ -201,7 +207,7 @@ const RangeFinder = Module("rangefinder", {
},
options: function () {
- options.safeSetPref("accessibility.typeaheadfind.autostart", false);
+ // options.safeSetPref("accessibility.typeaheadfind.autostart", false);
// The above should be sufficient, but: https://bugzilla.mozilla.org/show_bug.cgi?id=348187
options.safeSetPref("accessibility.typeaheadfind", false);
@@ -262,13 +268,14 @@ const RangeFinder = Module("rangefinder", {
* large amounts of data are concerned (e.g., for API documents).
*/
const RangeFind = Class("RangeFind", {
- init: function (matchCase, backward, elementPath) {
+ init: function (matchCase, backward, elementPath, regex) {
this.window = Cu.getWeakReference(window);
this.elementPath = elementPath || null;
- this.matchCase = Boolean(matchCase);
this.reverse = Boolean(backward);
+
this.finder = services.create("find");
- this.finder.caseSensitive = this.matchCase;
+ this.matchCase = Boolean(matchCase);
+ this.regex = Boolean(regex);
this.ranges = this.makeFrameList(content);
@@ -281,6 +288,12 @@ const RangeFind = Class("RangeFind", {
get backward() this.finder.findBackwards,
+ get matchCase() this.finder.caseSensitive,
+ set matchCase(val) this.finder.caseSensitive = Boolean(val),
+
+ get regex() this.finder.regularExpression,
+ set regex(val) this.finder.regularExpression = Boolean(val),
+
get searchString() this.lastString,
get selectedRange() {
@@ -437,7 +450,7 @@ const RangeFind = Class("RangeFind", {
let pageStart = RangeFind.endpoint(pageRange, true);
let pageEnd = RangeFind.endpoint(pageRange, false);
- for (let frame in util.Array.itervalues(win.frames)) {
+ for (let frame in array.itervalues(win.frames)) {
let range = doc.createRange();
if (util.computedStyle(frame.frameElement).visibility == "visible") {
range.selectNode(frame.frameElement);
diff --git a/common/content/help-single.xsl b/common/content/help-single.xsl
deleted file mode 100644
index 7367a6f2..00000000
--- a/common/content/help-single.xsl
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE document SYSTEM "chrome://dactyl/content/dactyl.dtd">
-
-<xsl:stylesheet version="1.0"
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:dactyl="http://vimperator.org/namespaces/liberator"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:str="http://exslt.org/strings"
- xmlns:exsl="http://exslt.org/common"
- extension-element-prefixes="exsl str">
-
- <xsl:output method="xml" indent="no"/>
-
- <xsl:variable name="root" select="/dactyl:document"/>
- <xsl:variable name="tags">
- <xsl:text> </xsl:text>
- <xsl:for-each select="$root//@tag|$root//dactyl:tags/text()|$root//dactyl:tag/text()">
- <xsl:value-of select="concat(., ' ')"/>
- </xsl:for-each>
- </xsl:variable>
-
- <xsl:template name="parse-tags">
- <xsl:param name="text"/>
- <div dactyl:highlight="HelpTags">
- <xsl:for-each select="str:tokenize($text)">
- <a id="{.}" dactyl:highlight="HelpTag"><xsl:value-of select="."/></a>
- </xsl:for-each>
- </div>
- </xsl:template>
-
- <xsl:template match="/">
- <xsl:call-template name="parse-tags">
- <xsl:with-param name="text" select="$tags"/>
- </xsl:call-template>
- </xsl:template>
-</xsl:stylesheet>
diff --git a/common/content/help.js b/common/content/help.js
index ed1dd22a..092678aa 100644
--- a/common/content/help.js
+++ b/common/content/help.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 by Kris Maglione <kris@vimperator.org>
+// Copyright (c) 2009-2010 by Kris Maglione <kris@vimperator.org>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -13,9 +13,6 @@ function checkFragment() {
}
document.addEventListener("load", checkFragment, true);
-window.addEventListener("message", function (event) {
- if (event.data == "fragmentChange")
- checkFragment();
-}, true);
+document.addEventListener("hashChange", checkFragment, true);
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/help.xsl b/common/content/help.xsl
index 0fe24524..ff03cf20 100644
--- a/common/content/help.xsl
+++ b/common/content/help.xsl
@@ -6,40 +6,27 @@
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:dactyl="http://vimperator.org/namespaces/liberator"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:str="http://exslt.org/strings"
xmlns:exsl="http://exslt.org/common"
- extension-element-prefixes="exsl str">
+ xmlns:regexp="http://exslt.org/regular-expressions"
+ xmlns:str="http://exslt.org/strings"
+ extension-element-prefixes="exsl regexp str">
<xsl:output method="xml" indent="no"/>
<!-- Variable Definitions {{{1 -->
- <xsl:variable name="doc">
- <xsl:apply-templates select="/dactyl:document" mode="overlay"/>
- </xsl:variable>
- <xsl:variable name="root" select="exsl:node-set($doc)"/>
-
- <xsl:variable name="tags">
- <xsl:text> </xsl:text>
- <xsl:for-each select="$root//@tag|$root//dactyl:tags/text()|$root//dactyl:tag/text()">
- <xsl:value-of select="concat(., ' ')"/>
- </xsl:for-each>
- </xsl:variable>
<!-- Process Overlays {{{1 -->
- <xsl:variable name="overlay" select="concat('dactyl://help-overlay/', /dactyl:document/@name)"/>
- <xsl:variable name="overlaydoc" select="document($overlay)/dactyl:overlay"/>
-
<xsl:template name="splice-overlays">
<xsl:param name="elem"/>
<xsl:param name="tag"/>
- <xsl:for-each select="$overlaydoc/*[@insertbefore=$tag]">
+ <xsl:for-each select="ancestor::*/dactyl:overlay/*[@insertbefore=$tag]">
<xsl:apply-templates select="." mode="overlay"/>
</xsl:for-each>
<xsl:choose>
- <xsl:when test="$overlaydoc/*[@replace=$tag] and not($elem[@replace])">
- <xsl:for-each select="$overlaydoc/*[@replace=$tag]">
+ <xsl:when test="ancestor::*/dactyl:overlay/*[@replace=$tag] and not($elem[@replace])">
+ <xsl:for-each select="ancestor::*/dactyl:overlay/*[@replace=$tag]">
<xsl:apply-templates select="." mode="overlay-2"/>
</xsl:for-each>
</xsl:when>
@@ -49,7 +36,7 @@
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
- <xsl:for-each select="$overlaydoc/*[@insertafter=$tag]">
+ <xsl:for-each select="ancestor::*/dactyl:overlay/*[@insertafter=$tag]">
<xsl:apply-templates select="." mode="overlay"/>
</xsl:for-each>
</xsl:template>
@@ -75,9 +62,32 @@
<!-- Process Inclusions {{{1 -->
+ <xsl:template name="include">
+ <xsl:param name="root-node" select="."/>
+ <xsl:param name="overlay" select="concat('dactyl://help-overlay/', $root-node/@name)"/>
+
+ <!-- Ridiculous three-pass processing is needed to deal with
+ - lack of dynamic variable scope in XSL 1.0. -->
+
+ <!-- Store a copy of the overlay for the current document. -->
+ <xsl:variable name="doc">
+ <dactyl:document>
+ <xsl:copy-of select="document($overlay)/dactyl:overlay"/>
+ <xsl:copy-of select="$root-node/node()"/>
+ </dactyl:document>
+ </xsl:variable>
+
+ <xsl:call-template name="parse-tags">
+ <xsl:with-param name="text" select="concat($root-node/@name, '.xml')"/>
+ </xsl:call-template>
+ <xsl:apply-templates select="exsl:node-set($doc)/dactyl:document/node()[position() != 1]" mode="overlay"/>
+ </xsl:template>
+
<xsl:template match="dactyl:include" mode="overlay-2">
<div dactyl:highlight="HelpInclude">
- <xsl:apply-templates select="document(@href)/dactyl:document/node()" mode="overlay"/>
+ <xsl:call-template name="include">
+ <xsl:with-param name="root-node" select="document(@href)/dactyl:document"/>
+ </xsl:call-template>
</div>
</xsl:template>
@@ -93,22 +103,39 @@
<!-- Root {{{1 -->
<xsl:template match="/">
- <xsl:for-each select="$root/dactyl:document">
- <html dactyl:highlight="Help">
- <head>
- <title><xsl:value-of select="@title"/></title>
- <script type="text/javascript"
- src="chrome://dactyl/content/help.js"/>
- </head>
- <body dactyl:highlight="HelpBody">
- <div dactyl:highlight="Logo"/>
- <xsl:call-template name="parse-tags">
- <xsl:with-param name="text" select="concat(@name, '.html')"/>
- </xsl:call-template>
- <xsl:apply-templates/>
- </body>
- </html>
- </xsl:for-each>
+
+ <!-- Ridiculous three-pass processing is needed to deal with
+ - lack of dynamic variable scope in XSL 1.0. -->
+
+ <xsl:variable name="doc1">
+ <xsl:call-template name="include">
+ <xsl:with-param name="root-node" select="dactyl:document"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="root" select="exsl:node-set($doc1)"/>
+
+ <!-- Store a cache of all tags defined -->
+ <xsl:variable name="doc2">
+ <dactyl:document>
+ <xsl:attribute name="document-tags">
+ <xsl:text> </xsl:text>
+ <xsl:for-each select="$root//@tag|$root//dactyl:tags/text()|$root//dactyl:tag/text()">
+ <xsl:value-of select="concat(., ' ')"/>
+ </xsl:for-each>
+ </xsl:attribute>
+ <xsl:copy-of select="$root/node()"/>
+ </dactyl:document>
+ </xsl:variable>
+
+ <html dactyl:highlight="Help">
+ <head>
+ <title><xsl:value-of select="@title"/></title>
+ <script type="text/javascript" src="chrome://dactyl/content/help.js"/>
+ </head>
+ <body dactyl:highlight="HelpBody">
+ <xsl:apply-templates select="exsl:node-set($doc2)/dactyl:document/node()" mode="help-1"/>
+ </body>
+ </html>
</xsl:template>
<!-- Table of Contents {{{1 -->
@@ -125,14 +152,14 @@
local-name() = $tag and not(preceding::*[local-name() = $lasttag][position() = 1 and not(.=$context)])]"/>
<xsl:if test="$nodes">
- <ol dactyl:highlight="HelpOrderedList">
+ <ol level="{$level}" dactyl:highlight="HelpOrderedList">
<xsl:for-each select="$nodes">
<li>
<a>
<xsl:if test="@tag">
<xsl:attribute name="href"><xsl:value-of select="concat('#', substring-before(concat(@tag, ' '), ' '))"/></xsl:attribute>
</xsl:if>
- <xsl:apply-templates select="node()"/>
+ <xsl:apply-templates select="node()" mode="help-1"/>
</a>
<xsl:call-template name="toc">
<xsl:with-param name="level" select="$level + 1"/>
@@ -144,7 +171,7 @@
</ol>
</xsl:if>
</xsl:template>
- <xsl:template match="dactyl:toc" mode="pass-2">
+ <xsl:template match="dactyl:toc" mode="help-2">
<xsl:variable name="TOC">
<context/>
<xsl:for-each
@@ -174,36 +201,38 @@
<!-- Items {{{1 -->
- <xsl:template match="dactyl:strut" mode="pass-2">
+ <xsl:template match="dactyl:strut" mode="help-2">
<div style="clear: both"/>
</xsl:template>
- <xsl:template match="dactyl:item" mode="pass-2">
+ <xsl:template match="dactyl:item" mode="help-2">
<div dactyl:highlight="HelpItem">
- <xsl:apply-templates select="dactyl:tags|dactyl:spec|dactyl:strut"/>
+ <xsl:apply-templates select="dactyl:tags|dactyl:spec|dactyl:strut" mode="help-1"/>
<xsl:if test="not(dactyl:description/@short)">
<hr style="border: 0; height: 0; margin: 0; width: 100%; float: right;"/>
- <div dactyl:highlight="HelpOptInfo">
- <xsl:apply-templates select="dactyl:type|dactyl:default"/>
- <div style="clear: both;"/>
- </div>
+ <xsl:if test="dactyl:type|dactyl:default">
+ <div dactyl:highlight="HelpOptInfo">
+ <xsl:apply-templates select="dactyl:type|dactyl:default" mode="help-1"/>
+ <div style="clear: both;"/>
+ </div>
+ </xsl:if>
</xsl:if>
- <xsl:apply-templates select="dactyl:description"/>
+ <xsl:apply-templates select="dactyl:description" mode="help-1"/>
<div style="clear: both;"/>
</div>
</xsl:template>
- <xsl:template match="dactyl:spec[preceding-sibling::dactyl:spec]" mode="pass-2">
+ <!--
+ <xsl:template match="dactyl:item/dactyl:spec[position() = last()]" mode="help-2">
<div style="clear: both;"/>
- <div dactyl:highlight="HelpSpec">
- <xsl:apply-templates/>
- </div>
+ <div dactyl:highlight="HelpSpec"><xsl:apply-templates mode="help-1"/></div>
</xsl:template>
+ -->
- <xsl:template match="dactyl:default[not(@type='plain')]" mode="pass-2">
+ <xsl:template match="dactyl:default[not(@type='plain')]" mode="help-2">
<xsl:variable name="type" select="preceding-sibling::dactyl:type[1] | following-sibling::dactyl:type[1]"/>
<span dactyl:highlight="HelpDefault">(default:<xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="starts-with($type, 'string') or starts-with($type, 'regex')">
- <span dactyl:highlight="HelpString"><xsl:apply-templates/></span>
+ <span dactyl:highlight="HelpString"><xsl:apply-templates mode="help-1"/></span>
</xsl:when>
<xsl:otherwise>
<span>
@@ -214,22 +243,32 @@
<xsl:when test="$type = 'charlist'">String</xsl:when>
</xsl:choose>
</xsl:attribute>
- <xsl:apply-templates/>
+ <xsl:apply-templates select="node()" mode="help-1"/>
</span>
</xsl:otherwise>
- </xsl:choose>)
- </span>
+ </xsl:choose>)</span>
</xsl:template>
<!-- Tag Definitions {{{1 -->
- <xsl:template match="dactyl:tags" mode="pass-2">
+ <xsl:template match="dactyl:item/dactyl:tags[position() = last()]" mode="help-2">
<div style="clear: right"/>
<xsl:call-template name="parse-tags">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:template>
- <xsl:template match="dactyl:tag|@tag" mode="pass-2">
+ <xsl:template match="dactyl:tags" mode="help-2">
+ <xsl:call-template name="parse-tags">
+ <xsl:with-param name="text" select="."/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="@tag[parent::dactyl:p]" mode="help-2">
+ <xsl:call-template name="parse-tags">
+ <xsl:with-param name="text" select="."/>
+ </xsl:call-template>
+ <div style="clear: right"/>
+ </xsl:template>
+ <xsl:template match="dactyl:tag|@tag" mode="help-2">
<xsl:call-template name="parse-tags">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
@@ -249,31 +288,40 @@
<xsl:param name="contents" select="text()"/>
<xsl:variable name="tag" select="str:tokenize($contents, ' [!')[1]"/>
<a href="dactyl://help-tag/{$tag}" style="color: inherit;">
- <xsl:if test="contains($tags, concat(' ', $tag, ' '))">
+ <xsl:if test="contains(ancestor::*/@document-tags, concat(' ', $tag, ' '))">
<xsl:attribute name="href">#<xsl:value-of select="$tag"/></xsl:attribute>
</xsl:if>
<xsl:value-of select="$contents"/>
</a>
</xsl:template>
- <xsl:template match="dactyl:o" mode="pass-2">
- <span dactyl:highlight="HelpOption">
+ <xsl:template match="dactyl:o" mode="help-2">
+ <span dactyl:highlight="HelpOpt">
<xsl:call-template name="linkify-tag">
<xsl:with-param name="contents" select='concat("&#39;", text(), "&#39;")'/>
</xsl:call-template>
</span>
</xsl:template>
- <xsl:template match="dactyl:t" mode="pass-2">
+ <xsl:template match="dactyl:pref" mode="help-2">
+ <a href="http://kb.mozillazine.org/{text()}" dactyl:highlight="HelpOpt"
+ >'<xsl:apply-templates select="@*|node()" mode="help-1"/>'</a>
+ </xsl:template>
+ <xsl:template match="dactyl:t" mode="help-2">
<span dactyl:highlight="HelpTopic">
<xsl:call-template name="linkify-tag"/>
</span>
</xsl:template>
- <xsl:template match="dactyl:k" mode="pass-2">
+ <xsl:template match="dactyl:k" mode="help-2">
<span dactyl:highlight="HelpKey">
<xsl:call-template name="linkify-tag"/>
</span>
</xsl:template>
- <xsl:template match="dactyl:k[@name]" mode="pass-2">
+ <xsl:template match="dactyl:kwd" mode="help-2">
+ <span dactyl:highlight="HelpKeyword">
+ <xsl:apply-templates select="@*|node()" mode="help-1"/>
+ </span>
+ </xsl:template>
+ <xsl:template match="dactyl:k[@name]" mode="help-2">
<span dactyl:highlight="HelpKey">
<xsl:call-template name="linkify-tag">
<xsl:with-param name="contents" select="concat('&lt;', @name, '>', .)"/>
@@ -283,100 +331,117 @@
<!-- HTML-ish elements {{{1 -->
- <xsl:template match="dactyl:dl" mode="pass-2">
+ <xsl:template match="dactyl:dl" mode="help-2">
<dl>
<column/>
<column/>
<xsl:for-each select="dactyl:dt">
<tr>
- <xsl:apply-templates select="."/>
- <xsl:apply-templates select="following-sibling::dactyl:dd[1]"/>
+ <xsl:apply-templates select="." mode="help-1"/>
+ <xsl:apply-templates select="following-sibling::dactyl:dd[1]" mode="help-1"/>
</tr>
</xsl:for-each>
</dl>
</xsl:template>
- <xsl:template match="dactyl:link" mode="pass-2">
- <a href="{@topic}"><xsl:apply-templates select="@*|node()"/></a>
+ <xsl:template match="dactyl:link" mode="help-2">
+ <a href="{@topic}">
+ <xsl:if test="regexp:match(@topic, '^[a-zA-Z]*:', '')
+ and not(starts-with(@topic, 'mailto:'))">
+ <xsl:attribute name="rel">external</xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates select="@*|node()" mode="help-1"/>
+ </a>
</xsl:template>
+ <xsl:template match="dactyl:hl" mode="help-2">
+ <span dactyl:highlight="{@key}"><xsl:apply-templates select="@*|node()" mode="help-1"/></span>
+ </xsl:template>
+ <xsl:template match="dactyl:h" mode="help-2">
+ <em><xsl:apply-templates select="@*|node()" mode="help-1"/></em>
+ </xsl:template>
<xsl:template match="dactyl:em | dactyl:tt | dactyl:p |
dactyl:dt | dactyl:dd |
dactyl:ol | dactyl:ul | dactyl:li |
dactyl:h1 | dactyl:h2 | dactyl:h3"
- mode="pass-2">
- <xsl:element name="html:{local-name()}">
- <xsl:apply-templates select="@*|node()"/>
+ mode="help-2">
+ <xsl:element name="{local-name()}">
+ <xsl:apply-templates select="@*|node()" mode="help-1"/>
</xsl:element>
</xsl:template>
- <xsl:template match="dactyl:code" mode="pass-2">
- <pre dactyl:highlight="HelpCode"><xsl:apply-templates select="@*|node()"/></pre>
+ <xsl:template match="dactyl:code" mode="help-2">
+ <pre dactyl:highlight="HelpCode"><xsl:apply-templates select="@*|node()" mode="help-1"/></pre>
</xsl:template>
<!-- Help elements {{{1 -->
- <xsl:template match="dactyl:a" mode="pass-2">
- <span dactyl:highlight="HelpArg">{<xsl:apply-templates select="@*|node()"/>}</span>
+ <xsl:template match="dactyl:a" mode="help-2">
+ <span dactyl:highlight="HelpArg">{<xsl:apply-templates select="@*|node()" mode="help-1"/>}</span>
</xsl:template>
- <xsl:template match="dactyl:oa" mode="pass-2">
- <span dactyl:highlight="HelpOptionalArg">[<xsl:apply-templates select="@*|node()"/>]</span>
+ <xsl:template match="dactyl:oa" mode="help-2">
+ <span dactyl:highlight="HelpOptionalArg">[<xsl:apply-templates select="@*|node()" mode="help-1"/>]</span>
</xsl:template>
- <xsl:template match="dactyl:note" mode="pass-2">
+ <xsl:template match="dactyl:note" mode="help-2">
<p style="clear: both;">
- <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="@*" mode="help-1"/>
<div style="clear: both;"/>
<span dactyl:highlight="HelpNote">Note:</span>
<xsl:text> </xsl:text>
- <xsl:apply-templates select="node()"/>
+ <xsl:apply-templates select="node()" mode="help-1"/>
</p>
</xsl:template>
- <xsl:template match="dactyl:warning" mode="pass-2">
+ <xsl:template match="dactyl:warning" mode="help-2">
<p style="clear: both;">
- <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="@*" mode="help-1"/>
<div style="clear: both;"/>
<span dactyl:highlight="HelpWarning">Warning:</span>
<xsl:text> </xsl:text>
- <xsl:apply-templates select="node()"/>
+ <xsl:apply-templates select="node()" mode="help-1"/>
</p>
</xsl:template>
- <xsl:template match="dactyl:default" mode="pass-2">
- <span dactyl:highlight="HelpDefault">
- (default:<xsl:text> </xsl:text><xsl:apply-templates select="@*|node()"/>)
- </span>
+ <xsl:template match="dactyl:default" mode="help-2">
+ <span dactyl:highlight="HelpDefault">(default:<xsl:text> </xsl:text><xsl:apply-templates select="@*|node()" mode="help-1"/>)</span>
</xsl:template>
<!-- HTML-ify other elements {{{1 -->
- <xsl:template match="dactyl:ex" mode="pass-2">
+ <xsl:template match="dactyl:ex" mode="help-2">
<span dactyl:highlight="HelpEx">
<xsl:variable name="tag" select="str:tokenize(text(), ' [!')[1]"/>
<a href="dactyl://help-tag/{$tag}" style="color: inherit;">
- <xsl:if test="contains($tags, concat(' ', $tag, ' '))">
+ <xsl:if test="contains(ancestor::*/@document-tags, concat(' ', $tag, ' '))">
<xsl:attribute name="href">#<xsl:value-of select="$tag"/></xsl:attribute>
</xsl:if>
- <xsl:apply-templates/>
+ <xsl:apply-templates mode="help-1"/>
</a>
</span>
</xsl:template>
- <xsl:template match="dactyl:description | dactyl:example | dactyl:spec" mode="pass-2">
+ <xsl:template match="dactyl:description | dactyl:example | dactyl:spec" mode="help-2">
<div>
<xsl:if test="self::dactyl:description"><xsl:attribute name="dactyl:highlight">HelpDescription</xsl:attribute></xsl:if>
<xsl:if test="self::dactyl:example"><xsl:attribute name="dactyl:highlight">HelpExample</xsl:attribute></xsl:if>
<xsl:if test="self::dactyl:spec"><xsl:attribute name="dactyl:highlight">HelpSpec</xsl:attribute></xsl:if>
- <xsl:apply-templates select="@*|node()"/>
+ <xsl:apply-templates select="@*|node()" mode="help-1"/>
</div>
</xsl:template>
- <xsl:template match="dactyl:str | dactyl:t | dactyl:type" mode="pass-2">
+ <xsl:template match="dactyl:str | dactyl:type" mode="help-2">
<span>
<xsl:if test="self::dactyl:str"><xsl:attribute name="dactyl:highlight">HelpString</xsl:attribute></xsl:if>
- <xsl:if test="self::dactyl:t"><xsl:attribute name="dactyl:highlight">HelpTopic</xsl:attribute></xsl:if>
<xsl:if test="self::dactyl:type"><xsl:attribute name="dactyl:highlight">HelpType</xsl:attribute></xsl:if>
- <xsl:apply-templates select="@*|node()"/>
+ <xsl:apply-templates select="@*|node()" mode="help-1"/>
</span>
</xsl:template>
+ <xsl:template match="dactyl:xml-block" mode="help-2">
+ <div dactyl:highlight="HelpXMLBlock">
+ <xsl:call-template name="xml-highlight"/>
+ </div>
+ </xsl:template>
+ <xsl:template match="dactyl:xml-highlight" mode="help-2">
+ <xsl:call-template name="xml-highlight"/>
+ </xsl:template>
<!-- Plugins {{{1 -->
@@ -400,59 +465,133 @@
</span>
</div>
</xsl:template>
- <xsl:template match="dactyl:author[@email]" mode="pass-2">
+ <xsl:template match="dactyl:author[@email]" mode="help-2">
<xsl:call-template name="info">
<xsl:with-param name="label" select="'Author'"/>
<xsl:with-param name="extra">
- <xsl:text> </xsl:text><a href="mailto:{@email}">✉</a>
+ <xsl:text> </xsl:text><a href="mailto:{@email}"></a>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
- <xsl:template match="dactyl:author" mode="pass-2">
+ <xsl:template match="dactyl:author" mode="help-2">
<xsl:call-template name="info">
<xsl:with-param name="label" select="'Author'"/>
</xsl:call-template>
</xsl:template>
- <xsl:template match="dactyl:license" mode="pass-2">
+ <xsl:template match="dactyl:license" mode="help-2">
<xsl:call-template name="info">
<xsl:with-param name="label" select="'License'"/>
</xsl:call-template>
</xsl:template>
- <xsl:template match="dactyl:plugin" mode="pass-2">
+ <xsl:template match="dactyl:plugin" mode="help-2">
<xsl:call-template name="info">
<xsl:with-param name="label" select="'Plugin'"/>
<xsl:with-param name="nodes">
<span><xsl:value-of select="@name"/></span>
</xsl:with-param>
</xsl:call-template>
- <xsl:apply-templates/>
+ <xsl:if test="@version">
+ <xsl:call-template name="info">
+ <xsl:with-param name="label" select="'Version'"/>
+ <xsl:with-param name="link" select="''"/>
+ <xsl:with-param name="nodes">
+ <span><xsl:value-of select="@version"/></span>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates mode="help-1"/>
</xsl:template>
<!-- Special Element Templates {{{1 -->
- <xsl:template match="dactyl:logo">
+ <xsl:template match="dactyl:logo" mode="help-1">
<span dactyl:highlight="Logo"/>
</xsl:template>
- <xsl:template match="dactyl:pan[dactyl:handle]">
- <form style="text-align:center" xmlns="http://www.w3.org/1999/xhtml"
- action="https://www.paypal.com/cgi-bin/webscr" method="post">
- <input type="hidden" name="cmd" value="_s-xclick"/>
- <input type="image" src="chrome://dactyl/content/x-click-but21.png" border="0" name="submit" alt="Donate with PayPal"/>
- <input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHPwYJKoZIhvcNAQcEoIIHMDCCBywCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYAUOJADCwiik68MpIUKcMAtNfs4Cx6RY7604ZujgKj7WVaiELWyhUUDSaq8+iLYaNkRUq+dDld96KwhfodqP3MEmIzpQ/qKvh5+4JzTWSBU5G1lHzc4NJQw6TpXKloPxxXhuGKzZ84/asKZIZpLfkP5i8VtqVFecu7qYc0q1U2KoDELMAkGBSsOAwIaBQAwgbwGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIWR7nX4WwgcqAgZgO41g/NtgfBwI14LlJx3p5Hc4nHsQD2wyu5l4BMndkc3mc0uRTXvzutcfPBxYC4aGV5UDn6c+XPzsne+OAdSs4/0a2DJe85SBDOlVyOekz3rRhy5+6XKpKQ7qfiMpKROladi4opfMac/aDUPhGeVsY0jtQCtelIE199iaVKhlbiDvfE7nzV5dLU4d3VZwSDuWBIrIIi9GMtKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA4MDYwNTE0NDk1OFowIwYJKoZIhvcNAQkEMRYEFBpY8FafLq7i3V0czWS9TbR/RjyQMA0GCSqGSIb3DQEBAQUABIGAPvYR9EC2ynooWAvX0iw9aZYTrpX2XrTl6lYkZaLrhM1zKn4RuaiL33sPtq0o0uSKm98gQHzh4P6wmzES0jzHucZjCU4VlpW0fC+/pJxswbW7Qux+ObsNx3f45OcvprqMMZyJiEOULcNhxkm9pCeXQMUGwlHoRRtAxYK2T8L/rQQ=-----END PKCS7-----
- "/>
- </form>
- </xsl:template>
-
<!-- Process Tree {{{1 -->
- <xsl:template match="@*|node()" mode="pass-2">
+ <xsl:template match="@*|node()" mode="help-2">
<xsl:copy>
- <xsl:apply-templates select="@*|node()"/>
+ <xsl:apply-templates select="@*|node()" mode="help-1"/>
</xsl:copy>
</xsl:template>
- <xsl:template match="@*|node()">
- <xsl:apply-templates select="." mode="pass-2"/>
+ <xsl:template match="@*|node()" mode="help-1">
+ <xsl:apply-templates select="." mode="help-2"/>
+ </xsl:template>
+
+ <!-- XML Highlighting (xsl:import doesn't work in Firefox 3.x) {{{1 -->
+ <xsl:template name="xml-highlight">
+ <div dactyl:highlight="HelpXML">
+ <xsl:apply-templates mode="xml-highlight"/>
+ </div>
+ </xsl:template>
+
+ <xsl:template name="xml-namespace">
+ <xsl:param name="node" select="."/>
+ <xsl:if test="name($node) != local-name($node)">
+ <span dactyl:highlight="HelpXMLNamespace">
+ <xsl:value-of select="substring-before(name($node), ':')"/>
+ </span>
+ </xsl:if>
+ <xsl:value-of select="local-name($node)"/>
+ </xsl:template>
+
+ <xsl:template match="*" mode="xml-highlight">
+ <span dactyl:highlight="HelpXMLTagStart">
+ <xsl:text>&lt;</xsl:text>
+ <xsl:call-template name="xml-namespace"/>
+ <xsl:apply-templates select="@*" mode="xml-highlight"/>
+ <xsl:text>/></xsl:text>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="*[node()]" mode="xml-highlight">
+ <span dactyl:highlight="HelpXMLTagStart">
+ <xsl:text>&lt;</xsl:text>
+ <xsl:call-template name="xml-namespace"/>
+ <xsl:apply-templates select="@*" mode="xml-highlight"/>
+ <xsl:text>></xsl:text>
+ </span>
+ <xsl:apply-templates select="node()" mode="xml-highlight"/>
+ <span dactyl:highlight="HelpXMLTagEnd">
+ <xsl:text>&lt;/</xsl:text>
+ <xsl:call-template name="xml-namespace"/>
+ <xsl:text>></xsl:text>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="dactyl:escape | dactyl:escape[node()]" mode="xml-highlight">
+ <span dactyl:highlight="HelpXMLText">
+ <xsl:apply-templates mode="help-1"/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="@*" mode="xml-highlight">
+ <xsl:text> </xsl:text>
+ <span dactyl:highlight="HelpXMLAttribute">
+ <xsl:call-template name="xml-namespace"/>
+ </span>
+ <span dactyl:highlight="HelpXMLString">
+ <xsl:value-of select="regexp:replace(., '&quot;', 'g', '&amp;quot;')"/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="comment()" mode="xml-highlight">
+ <span dactyl:highlight="HelpXMLComment">
+ <xsl:value-of select="."/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="processing-instruction()" mode="xml-highlight">
+ <span dactyl:highlight="HelpXMLProcessing">
+ <xsl:value-of select="."/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="text()" mode="xml-highlight">
+ <span dactyl:highlight="HelpXMLText">
+ <xsl:value-of select="regexp:replace(., '&lt;', 'g', '&amp;lt;')"/>
+ </span>
</xsl:template>
</xsl:stylesheet>
diff --git a/common/content/hints.js b/common/content/hints.js
index 5bb503a7..4095eddd 100644
--- a/common/content/hints.js
+++ b/common/content/hints.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -36,26 +36,26 @@ const Hints = Module("hints", {
function images() util.makeXPath(["img"]);
this._hintModes = {
- ";": Mode("Focus hint", function (elem) buffer.focusElement(elem), extended),
- "?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended),
+ ";": Mode("Focus hint", function (elem) buffer.focusElement(elem), extended),
+ "?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended),
s: Mode("Save hint", function (elem) buffer.saveLink(elem, true)),
a: Mode("Save hint with prompt", function (elem) buffer.saveLink(elem, false)),
f: Mode("Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () ["body"]),
o: Mode("Follow hint", function (elem) buffer.followLink(elem, dactyl.CURRENT_TAB)),
t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB)),
b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB)),
- w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW), extended),
+ w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW), extended),
F: Mode("Open multiple hints in tabs", function (elem) { buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB); hints.show("F") }),
O: Mode("Generate an ':open URL' using hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)),
T: Mode("Generate a ':tabopen URL' using hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)),
W: Mode("Generate a ':winopen URL' using hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)),
- v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended),
- V: Mode("View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true), extended),
+ v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended),
+ V: Mode("View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true), extended),
y: Mode("Yank hint location", function (elem, loc) dactyl.clipboardWrite(loc, true)),
Y: Mode("Yank hint description", function (elem) dactyl.clipboardWrite(elem.textContent || "", true), extended),
- c: Mode("Open context menu", function (elem) buffer.openContextMenu(elem), extended),
- i: Mode("Show image", function (elem) dactyl.open(elem.src), images),
- I: Mode("Show image in a new tab", function (elem) dactyl.open(elem.src, dactyl.NEW_TAB), images)
+ c: Mode("Open context menu", function (elem) buffer.openContextMenu(elem), extended),
+ i: Mode("Show image", function (elem) dactyl.open(elem.src), images),
+ I: Mode("Show image in a new tab", function (elem) dactyl.open(elem.src, dactyl.NEW_TAB), images)
};
},
@@ -351,7 +351,7 @@ const Hints = Module("hints", {
if (hint.text == "" && hint.elem.firstChild && hint.elem.firstChild instanceof HTMLImageElement) {
if (!hint.imgSpan) {
- var rect = hint.elem.firstChild.getBoundingClientRect();
+ let rect = hint.elem.firstChild.getBoundingClientRect();
if (!rect)
continue;
@@ -1054,7 +1054,7 @@ const Hints = Module("hints", {
["wordstartswith", "The typed characters are split on whitespace. The resulting groups must all match the beginings of words, in order."],
["firstletters", "Behaves like wordstartswith, but all groups much match a sequence of words."],
["custom", "Delegate to a custom function: dactyl.plugins.customHintMatcher(hintString)"],
- ["transliterated", "When true, special latin characters are translated to their ascii equivalent (e.g., \u00e9 -> e)"]
+ ["transliterated", UTF8("When true, special latin characters are translated to their ascii equivalent (e.g., é -> e)")]
]
});
diff --git a/common/content/history.js b/common/content/history.js
index 691810ed..a8c28ff6 100644
--- a/common/content/history.js
+++ b/common/content/history.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -45,11 +45,12 @@ const History = Module("history", {
let sh = window.getWebNavigation().sessionHistory;
let obj = [];
obj.index = sh.index;
- obj.__iterator__ = function () util.Array.iteritems(this);
+ obj.__iterator__ = function () array.iteritems(this);
for (let i in util.range(0, sh.count)) {
- obj[i] = { index: i, __proto__: sh.getEntryAtIndex(i, false) };
- util.memoize(obj[i], "icon",
- function (obj) services.get("favicon").getFaviconImageForPage(obj.URI).spec);
+ obj[i] = update(Object.create(sh.getEntryAtIndex(i, false)),
+ { index: i });
+ memoize(obj[i], "icon",
+ function () services.get("favicon").getFaviconImageForPage(this.URI).spec);
}
return obj;
},
@@ -64,7 +65,10 @@ const History = Module("history", {
dactyl.beep();
else {
let index = Math.constrain(current + steps, start, end);
- window.getWebNavigation().gotoIndex(index);
+ try {
+ window.getWebNavigation().gotoIndex(index);
+ }
+ catch (e) {} // We get NS_ERROR_FILE_NOT_FOUND if files in history don't exist
}
},
diff --git a/common/content/io.js b/common/content/io.js
index ce092f87..9f114e5a 100644
--- a/common/content/io.js
+++ b/common/content/io.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k@gmail.com>
// Some code based on Venkman
//
// This work is licensed for reuse under an MIT license. Details are
@@ -19,16 +19,15 @@ function Script(file) {
}
self = { __proto__: plugins };
plugins.contexts[file.path] = self;
+ plugins[file.path] = self;
self.NAME = file.leafName.replace(/\..*/, "").replace(/-([a-z])/g, function (m, n1) n1.toUpperCase());
self.PATH = file.path;
self.__context__ = self;
- self.__proto__ = plugins;
// This belongs elsewhere
- for (let [, dir] in Iterator(io.getRuntimeDirectories("plugin"))) {
- if (dir.contains(file, false))
- plugins[self.NAME] = self;
- }
+ if (io.getRuntimeDirectories("plugins").some(
+ function (dir) dir.contains(file, false)))
+ plugins[self.NAME] = self;
return self;
}
@@ -54,7 +53,8 @@ const IO = Module("io", {
let file = download.targetFile.path;
let size = download.size;
- dactyl.echomsg("Download of " + title + " to " + file + " finished", 1, commandline.ACTIVE_WINDOW);
+ dactyl.echomsg({ domains: [util.getHost(url)], message: "Download of " + title + " to " + file + " finished" },
+ 1, commandline.ACTIVE_WINDOW);
autocommands.trigger("DownloadPost", { url: url, title: title, file: file, size: size });
}
},
@@ -179,8 +179,8 @@ const IO = Module("io", {
getRCFile: function (dir, always) {
dir = dir || "~";
- let rcFile1 = File.joinPaths(dir, "." + config.name.toLowerCase() + "rc");
- let rcFile2 = File.joinPaths(dir, "_" + config.name.toLowerCase() + "rc");
+ let rcFile1 = File.joinPaths(dir, "." + config.name + "rc");
+ let rcFile2 = File.joinPaths(dir, "_" + config.name + "rc");
if (dactyl.has("Win32"))
[rcFile1, rcFile2] = [rcFile2, rcFile1];
@@ -346,6 +346,8 @@ lookup:
dactyl.helpInitialized = false;
}
catch (e) {
+ if (isstring(e))
+ e = { message: e };
let err = new Error();
for (let [k, v] in Iterator(e))
err[k] = v;
@@ -508,10 +510,10 @@ lookup:
* variable.
*/
get runtimePath() {
- const rtpvar = config.name.toUpperCase() + "_RUNTIME";
+ const rtpvar = config.idname + "_RUNTIME";
let rtp = services.get("environment").get(rtpvar);
if (!rtp) {
- rtp = "~/" + (dactyl.has("Win32") ? "" : ".") + config.name.toLowerCase();
+ rtp = "~/" + (dactyl.has("Win32") ? "" : ".") + config.name;
services.get("environment").set(rtpvar, rtp);
}
return rtp;
@@ -582,7 +584,7 @@ lookup:
{ argCount: "0" });
// "mkv[imperatorrc]" or "mkm[uttatorrc]"
- commands.add([config.name.toLowerCase().replace(/(.)(.*)/, "mk$1[$2rc]")],
+ commands.add([config.name.replace(/(.)(.*)/, "mk$1[$2rc]")],
"Write current key mappings and changed options to the config file",
function (args) {
dactyl.assert(args.length <= 1, "E172: Only one file name allowed");
@@ -595,7 +597,7 @@ lookup:
// TODO: Use a set/specifiable list here:
let lines = [cmd.serialize().map(commands.commandToString) for (cmd in commands) if (cmd.serialize)];
- lines = util.Array.flatten(lines);
+ lines = array.flatten(lines);
// source a user .pentadactylrc file
lines.unshift('"' + dactyl.version + "\n");
@@ -608,7 +610,7 @@ lookup:
arguments: [filename + ".local"]
}));
- lines.push("\n\" vim: set ft=" + config.name.toLowerCase() + ":");
+ lines.push("\n\" vim: set ft=" + config.name + ":");
try {
file.write(lines.join("\n"));
@@ -669,9 +671,13 @@ lookup:
// NOTE: Vim doesn't replace ! preceded by 2 or more backslashes and documents it - desirable?
// pass through a raw bang when escaped or substitute the last command
- arg = arg.replace(/(\\)*!/g,
- function (m) /^\\(\\\\)*!$/.test(m) ? m.replace("\\!", "!") : m.replace("!", io._lastRunCommand)
- );
+
+ // This is an asinine and irritating feature when we have searchable
+ // command-line history. --Kris
+ if (options["banghist"])
+ arg = arg.replace(/(\\)*!/g,
+ function (m) /^\\(\\\\)*!$/.test(m) ? m.replace("\\!", "!") : m.replace("!", io._lastRunCommand)
+ );
io._lastRunCommand = arg;
@@ -691,19 +697,20 @@ lookup:
completion: function () {
completion.charset = function (context) {
context.anchored = false;
- context.generate = function () {
- let names = util.Array(
- "more1 more2 more3 more4 more5 unicode".split(" ").map(function (key)
- options.getPref("intl.charsetmenu.browser." + key).split(', '))
- ).flatten().uniq();
- let bundle = document.getElementById("dactyl-charset-bundle");
- return names.map(function (name) [name, bundle.getString(name.toLowerCase() + ".title")]);
+ let bundle = services.get("stringBundle").createBundle(
+ "chrome://global/locale/charsetTitles.properties");
+ context.keys = {
+ text: util.identity,
+ description: function (charset) bundle.GetStringFromName(charset.toLowerCase() + ".title")
};
+ context.generate = function () array("more1 more2 more3 more4 more5 unicode".split(" "))
+ .map(function (key) options.getPref("intl.charsetmenu.browser." + key).split(', '))
+ .flatten().uniq().array;
};
completion.directory = function directory(context, full) {
this.file(context, full);
- context.filters.push(function ({ item: f }) f.isDirectory());
+ context.filters.push(function ({ item }) item.isDirectory());
};
completion.environment = function environment(context) {
@@ -737,7 +744,7 @@ lookup:
if (options["wildignore"]) {
let wig = options.get("wildignore");
- context.filters.push(function ({item: f}) f.isDirectory() || !wig.getKey(this.name));
+ context.filters.push(function ({ item }) item.isDirectory() || !wig.getKey(this.name));
}
// context.background = true;
@@ -765,7 +772,7 @@ lookup:
}
}
- return util.Array.flatten(commands);
+ return array.flatten(commands);
};
};
@@ -795,6 +802,10 @@ lookup:
shellcmdflag = "-c";
}
+ options.add(["banghist", "bh"],
+ "Replace occurances of ! with the previous command when executing external commands",
+ "banghist", true);
+
options.add(["fileencoding", "fenc"],
"Sets the character encoding of read and written files",
"string", "UTF-8", {
diff --git a/common/content/javascript.js b/common/content/javascript.js
index 18fa2719..349e438d 100644
--- a/common/content/javascript.js
+++ b/common/content/javascript.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -41,11 +41,13 @@ const JavaScript = Module("javascript", {
let seen = {};
for (let key in properties(obj, !toplevel)) {
set.add(seen, key);
- yield [key, this.getKey(obj, key)];
+ yield key;
}
+ // Properties aren't visible in an XPCNativeWrapper until
+ // they're accessed.
for (let key in properties(this.getKey(obj, "wrappedJSObject"), !toplevel))
- if (!set.has(seen, key))
- yield [key, this.getKey(obj, key)];
+ if (key in obj && !set.has(seen, key))
+ yield key;
},
objectKeys: function objectKeys(obj, toplevel) {
@@ -110,15 +112,14 @@ const JavaScript = Module("javascript", {
},
_pop: function pop(arg) {
+ if (this._i == this.context.caret - 1)
+ this.context.highlight(this._top.offset, 1, "FIND");
+
if (this._top.char != arg) {
this.context.highlight(this._top.offset, this._i - this._top.offset, "SPELLCHECK");
- this.context.highlight(this._top.offset, 1, "FIND");
- throw new Error("Invalid JS");
+ throw Error("Invalid JS");
}
- if (this._i == this.context.caret - 1)
- this.context.highlight(this._top.offset, 1, "FIND");
-
// The closing character of this stack frame will have pushed a new
// statement, leaving us with an empty statement. This doesn't matter,
// now, as we simply throw away the frame when we pop it, but it may later.
@@ -139,11 +140,13 @@ const JavaScript = Module("javascript", {
// Reuse the old stack.
if (this._str && filter.substr(0, this._str.length) == this._str) {
+ this.context.highlight(0, 0, "FIND");
this._i = this._str.length;
if (this.popStatement)
this._top.statements.pop();
}
else {
+ this.context.highlight();
this._stack = [];
this._functions = [];
this._push("#root");
@@ -239,7 +242,7 @@ const JavaScript = Module("javascript", {
_getObj: function (frame, stop) {
let statement = this._get(frame, 0, "statements") || 0; // Current statement.
let prev = statement;
- let obj;
+ let obj = null;
let cacheKey;
for (let [, dot] in Iterator(this._get(frame).dots.concat(stop))) {
if (dot < statement)
@@ -285,19 +288,19 @@ const JavaScript = Module("javascript", {
return [dot + 1 + space.length, obj, key];
},
- _fill: function (context, obj, name, compl, anchored, key, last, offset) {
- context.title = [name];
- context.anchored = anchored;
- context.filter = key;
+ _fill: function (context, args) {
+ context.title = [args.name];
+ context.anchored = args.anchored;
+ context.filter = args.filter;
context.itemCache = context.parent.itemCache;
- context.key = name + last;
+ context.key = args.name + args.last;
- if (last != null)
- context.quote = [last, function (text) util.escapeString(text.substr(offset), ""), last];
+ if (args.last != null)
+ context.quote = [args.last, function (text) util.escapeString(text.substr(args.offset), ""), args.last];
else // We're not looking for a quoted string, so filter out anything that's not a valid identifier
context.filters.push(function (item) /^[a-zA-Z_$][\w$]*$/.test(item.text));
- compl.call(self, context, obj);
+ args.completer.call(self, context, args.obj);
},
_complete: function (objects, key, compl, string, last) {
@@ -309,7 +312,10 @@ const JavaScript = Module("javascript", {
let orig = compl;
if (!compl) {
compl = function (context, obj, recurse) {
- context.process = [null, function highlight(item, v) template.highlight(typeof v == "xml" ? new String(v.toXMLString()) : v, true)];
+
+ context.process[1] = function highlight(item, v)
+ template.highlight(typeof v == "xml" ? new String(v.toXMLString()) : v, true);
+
// Sort in a logical fashion for object keys:
// Numbers are sorted as numbers, rather than strings, and appear first.
// Constants are unsorted, and appear before other non-null strings.
@@ -321,14 +327,15 @@ const JavaScript = Module("javascript", {
return a.key - b.key;
return isnan(b.key) - isnan(a.key) || compare(a, b);
};
- context.keys = { text: 0, description: 1,
+ context.keys = {
+ text: util.identity,
+ description: function (item) self.getKey(obj, item),
key: function (item) {
- let key = item[0];
if (!isNaN(key))
return parseInt(key);
- else if (/^[A-Z_][A-Z0-9_]*$/.test(key))
+ if (/^[A-Z_][A-Z0-9_]*$/.test(key))
return ""
- return key;
+ return item;
}
};
@@ -339,37 +346,51 @@ const JavaScript = Module("javascript", {
context.generate = function () self.objectKeys(obj, !recurse);
};
}
+
+ let args = {
+ completer: compl,
+ anchored: true,
+ filter: key + (string || ""),
+ last: last,
+ offset: key.length
+ };
+
// TODO: Make this a generic completion helper function.
- let filter = key + (string || "");
- for (let [, obj] in Iterator(objects)) {
+ for (let [, obj] in Iterator(objects))
this.context.fork(obj[1], this._top.offset, this, this._fill,
- obj[0], obj[1], compl,
- true, filter, last, key.length);
- }
+ update(args, {
+ obj: obj[0],
+ name: obj[1],
+ }));
if (orig)
return;
- for (let [, obj] in Iterator(objects)) {
- let name = obj[1] + " (prototypes)";
- this.context.fork(name, this._top.offset, this, this._fill,
- obj[0], name, function (a, b) compl(a, b, true),
- true, filter, last, key.length);
- }
-
- for (let [, obj] in Iterator(objects)) {
- let name = obj[1] + " (substrings)";
- this.context.fork(name, this._top.offset, this, this._fill,
- obj[0], name, compl,
- false, filter, last, key.length);
- }
-
- for (let [, obj] in Iterator(objects)) {
- let name = obj[1] + " (prototype substrings)";
- this.context.fork(name, this._top.offset, this, this._fill,
- obj[0], name, function (a, b) compl(a, b, true),
- false, filter, last, key.length);
- }
+ for (let [, obj] in Iterator(objects))
+ this.context.fork(obj[1] + "/prototypes", this._top.offset, this, this._fill,
+ update(args, {
+ obj: obj[0],
+ name: obj[1] + " (prototypes)",
+ completer: function (a, b) compl(a, b, true)
+ }));
+
+ for (let [, obj] in Iterator(objects))
+ this.context.fork(obj[1] + "/substrings", this._top.offset, this, this._fill,
+ update(args, {
+ obj: obj[0],
+ name: obj[1] + " (substrings)",
+ anchored: false,
+ completer: compl
+ }));
+
+ for (let [, obj] in Iterator(objects))
+ this.context.fork(obj[1] + "/prototypes/substrings", this._top.offset, this, this._fill,
+ update(args, {
+ obj: obj[0],
+ name: obj[1] + " (prototype substrings)",
+ anchored: false,
+ completer: function (a, b) compl(a, b, true)
+ }));
},
_getKey: function () {
@@ -398,7 +419,7 @@ const JavaScript = Module("javascript", {
}
this.context.getCache("evalled", Object);
- this.context.getCache("evalContext", function () ({ __proto__: userContext }));;
+ this.context.getCache("evalContext", function () ({ __proto__: userContext }));
// Okay, have parse stack. Figure out what we're completing.
@@ -478,7 +499,7 @@ const JavaScript = Module("javascript", {
for (let [i, idx] in Iterator(this._get(-2).comma)) {
let arg = this._str.substring(prev + 1, idx);
prev = idx;
- util.memoize(args, i, function () self.evalled(arg));
+ memoize(args, i, function () self.evalled(arg));
}
let key = this._getKey();
args.push(key + string);
diff --git a/common/content/mappings.js b/common/content/mappings.js
index a8cfebe1..74489a17 100644
--- a/common/content/mappings.js
+++ b/common/content/mappings.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -383,7 +383,7 @@ const Mappings = Module("mappings", {
let [lhs, rhs] = args;
if (!rhs) // list the mapping
- mappings.list(modes, this._expandLeader(lhs));
+ mappings.list(modes, mappings._expandLeader(lhs));
else {
// this matches Vim's behaviour
if (/^<Nop>$/i.test(rhs))
@@ -467,7 +467,7 @@ const Mappings = Module("mappings", {
addMapCommands("", [modes.NORMAL, modes.VISUAL], "");
for (let mode in modes.mainModes)
- if (mode.char && !commands.get(mode.char + "map"))
+ if (mode.char && !commands.get(mode.char + "map", true))
addMapCommands(mode.char,
[m.mask for (m in modes.mainModes) if (m.char == mode.char)],
[mode.disp.toLowerCase()]);
@@ -489,8 +489,7 @@ const Mappings = Module("mappings", {
null,
function (context, obj, args) {
let mode = args[0];
- return util.Array.flatten(
- [
+ return array.flatten([
[[name, map.description] for ([i, name] in Iterator(map.names))]
for ([i, map] in Iterator(mappings._user[mode].concat(mappings._main[mode])))
]);
diff --git a/common/content/marks.js b/common/content/marks.js
index eeea047b..e2c5a9e1 100644
--- a/common/content/marks.js
+++ b/common/content/marks.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -17,7 +17,7 @@ const Marks = Module("marks", {
this._urlMarks = storage.newMap("url-marks", { privateData: true, replacer: replacer, store: true });
try {
- if(isarray(Iterator(this._localMarks).next()));
+ if(isarray(Iterator(this._localMarks).next()[1]))
this._localMarks.clear();
}
catch(e) {}
@@ -31,7 +31,7 @@ const Marks = Module("marks", {
*/
get all() {
let lmarks = array(Iterator(this._localMarks.get(this.localURI) || {}));
- let umarks = array(Iterator(this._urlMarks)).__proto__;
+ let umarks = array(Iterator(this._urlMarks)).array;
return lmarks.concat(umarks).sort(function (a, b) String.localeCompare(a[0], b[0]));
},
@@ -54,9 +54,7 @@ const Marks = Module("marks", {
let win = window.content;
let doc = win.document;
- if (!doc.body)
- return;
- if (doc.body instanceof HTMLFrameSetElement) {
+ if (doc.body && doc.body instanceof HTMLFrameSetElement) {
if (!silent)
dactyl.echoerr("Marks support for frameset pages not implemented yet");
return;
@@ -72,8 +70,8 @@ const Marks = Module("marks", {
dactyl.log("Adding URL mark: " + Marks.markToString(mark, res), 5);
}
else if (Marks.isLocalMark(mark)) {
- let marks = this._localMarks.get(doc.URL, {});
- marks[mark] = { location: doc.URL, position: position, timestamp: Date.now()*1000 };
+ let marks = this._localMarks.get(doc.documentURI, {});
+ marks[mark] = { location: doc.documentURI, position: position, timestamp: Date.now()*1000 };
this._localMarks.changed();
if (!silent)
dactyl.log("Adding local mark: " + Marks.markToString(mark, marks[mark]), 5);
@@ -237,7 +235,7 @@ const Marks = Module("marks", {
// NOTE: this currently differs from Vim's behavior which
// deletes any valid marks in the arg list, up to the first
// invalid arg, as well as giving the error message.
- dactyl.assert(!matches, "E475: Invalid argument: " + matches[0]);
+ dactyl.assert(!matches, "E475: Invalid argument: " + (matches && matches[0]));
// 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))) {
diff --git a/common/content/modes.js b/common/content/modes.js
index d9aa994b..52fe6911 100644
--- a/common/content/modes.js
+++ b/common/content/modes.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -120,7 +120,7 @@ const Modes = Module("modes", {
NONE: 0,
- __iterator__: function () util.Array.itervalues(this.all),
+ __iterator__: function () array.itervalues(this.all),
get all() this._mainModes.slice(),
@@ -155,7 +155,8 @@ const Modes = Module("modes", {
getCharModes: function (chr) [m for (m in values(this._modeMap)) if (m.char == chr)],
- matchModes: function (obj) [m for (m in values(this._modeMap)) if (Object.keys(obj).every(function (k) obj[k] == (m[k] || false)))],
+ matchModes: function (obj)
+ [m for (m in values(this._modeMap)) if (Object.keys(obj).every(function (k) obj[k] == (m[k] || false)))],
// show the current mode string in the command line
show: function () {
diff --git a/common/content/modules.js b/common/content/modules.js
index 5f9594a4..cfc58511 100644
--- a/common/content/modules.js
+++ b/common/content/modules.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-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.
@@ -15,7 +15,7 @@ const ModuleBase = Class("ModuleBase", {
*/
requires: [],
- toString: function () "[module " + this.constructor.name + "]"
+ toString: function () "[module " + this.constructor.classname + "]"
});
/**
@@ -76,26 +76,29 @@ window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad, false);
Module.list.forEach(function(module) {
- modules.__defineGetter__(module.name, function() {
- delete modules[module.name];
- return load(module.name, null, Components.stack.caller);
+ modules.__defineGetter__(module.classname, function() {
+ delete modules[module.classname];
+ return load(module.classname, null, Components.stack.caller);
});
});
- function dump(str) window.dump(String.replace(str, /\n?$/, "\n").replace(/^/m, Config.prototype.name.toLowerCase() + ": "));
+ function dump(str) window.dump(String.replace(str, /\n?$/, "\n").replace(/^/m, services.get("dactyl:").name + ": "));
const start = Date.now();
const deferredInit = { load: [] };
const seen = set();
const loaded = set(["init"]);
+ modules.loaded = loaded;
function init(module) {
function init(func, mod)
- function () defmodule.time(module.name || module.constructor.name, mod, func, module, dactyl, modules, window);
+ function () defmodule.time(module.classname || module.constructor.classname, mod,
+ func, module,
+ dactyl, modules, window);
- set.add(loaded, module.constructor.name);
+ set.add(loaded, module.constructor.classname);
for (let [mod, func] in Iterator(module.INIT)) {
if (mod in loaded)
- init(func)();
+ init(func, mod)();
else {
deferredInit[mod] = deferredInit[mod] || [];
deferredInit[mod].push(init(func, mod));
@@ -112,34 +115,35 @@ window.addEventListener("load", function onLoad() {
}
try {
- if (module.name in loaded)
+ if (module.classname in loaded)
return;
- if (module.name in seen)
+ if (module.classname in seen)
throw Error("Module dependency loop.");
- set.add(seen, module.name);
+ set.add(seen, module.classname);
for (let dep in values(module.requires))
- load(Module.constructors[dep], module.name);
+ load(Module.constructors[dep], module.classname);
- defmodule.loadLog.push("Load" + (isstring(prereq) ? " " + prereq + " dependency: " : ": ") + module.name);
+ defmodule.loadLog.push("Load" + (isstring(prereq) ? " " + prereq + " dependency: " : ": ") + module.classname);
if (frame && frame.filename)
defmodule.loadLog.push(" from: " + frame.filename + ":" + frame.lineNumber);
- delete modules[module.name];
- modules[module.name] = defmodule.time(module.name, "init", module);
+ delete modules[module.classname];
+ modules[module.classname] = defmodule.time(module.classname, "init", module);
- init(modules[module.name]);
- for (let [, fn] in iter(deferredInit[module.name] || []))
+ init(modules[module.classname]);
+ for (let [, fn] in iter(deferredInit[module.classname] || []))
fn();
}
catch (e) {
- dump("Loading " + (module && module.name) + ": " + e + "\n" + (e.stack || ""));
+ dump("Loading " + (module && module.classname) + ": " + e + "\n" + (e.stack || ""));
}
- return modules[module.name];
+ return modules[module.classname];
}
Module.list.forEach(load);
deferredInit["load"].forEach(call);
+ modules.times = update({}, defmodule.times);
dump("Loaded in " + (Date.now() - start) + "ms");
}, false);
diff --git a/common/content/options.js b/common/content/options.js
index b925787a..6346cf3d 100644
--- a/common/content/options.js
+++ b/common/content/options.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -23,6 +23,8 @@
* completer - see {@link Option#completer}
* domains - see {@link Option#domains}
* getter - see {@link Option#getter}
+ * initialValue - Initial value is loaded from getter
+ * persist - see {@link Option#persist}
* privateData - see {@link Option#privateData}
* scope - see {@link Option#scope}
* setter - see {@link Option#setter}
@@ -56,9 +58,9 @@ const Option = Class("Option", {
// add no{option} variant of boolean {option} to this.names
if (this.type == "boolean")
- this.names = array([name, "no" + name] for (name in values(names))).flatten().__proto__;
+ this.names = array([name, "no" + name] for (name in values(names))).flatten().array;
- if (this.globalValue == undefined)
+ if (this.globalValue == undefined && !this.initialValue)
this.globalValue = this.parseValues(this.defaultValue);
},
@@ -296,6 +298,13 @@ const Option = Class("Option", {
getter: null,
/**
+ * @property {boolean} When true, this options values will be saved
+ * when generating a configuration file.
+ * @default true
+ */
+ persist: true,
+
+ /**
* @property {boolean|function(values)} When true, values of this
* option may contain private data which should be purged from
* saved histories when clearing private data. If a function, it
@@ -363,18 +372,23 @@ const Option = Class("Option", {
let re = RegExp(val);
re.bang = bang;
re.result = arguments.length == 2 ? result : !bang;
+ re.toString = function () Option.unparseRegex(this);
return re;
},
- unparseRegex: function (re) re.bang + re.source + (typeof re.result == "string" ? ":" + re.result : ""),
+ unparseRegex: function (re) re.bang + re.source.replace(/\\(.)/g, function (m, n1) n1 == "/" ? n1 : m) +
+ (typeof re.result == "string" ? ":" + re.result : ""),
getKey: {
stringlist: function (k) this.values.indexOf(k) >= 0,
+ get charlist() this.stringlist,
+
regexlist: function (k) {
for (let re in values(this.values))
if (re.test(k))
return re.result;
return null;
- }
+ },
+ get regexmap() this.regexlist
},
joinValues: {
@@ -382,6 +396,7 @@ const Option = Class("Option", {
stringlist: function (vals) vals.join(","),
stringmap: function (vals) [k + ":" + v for ([k, v] in Iterator(vals))].join(","),
regexlist: function (vals) vals.map(Option.unparseRegex).join(","),
+ get regexmap() this.regexlist
},
parseValues: {
@@ -430,10 +445,10 @@ const Option = Class("Option", {
switch (operator) {
case "+":
- return util.Array.uniq(Array.concat(orig, values), true);
+ return array.uniq(Array.concat(orig, values), true);
case "^":
// NOTE: Vim doesn't prepend if there's a match in the current value
- return util.Array.uniq(Array.concat(values, orig), true);
+ return array.uniq(Array.concat(values, orig), true);
case "-":
return orig.filter(function (item) values.indexOf(item) == -1);
case "=":
@@ -452,10 +467,10 @@ const Option = Class("Option", {
values = Array.concat(values);
switch (operator) {
case "+":
- return util.Array.uniq(Array.concat(this.values, values), true);
+ return array.uniq(Array.concat(this.values, values), true);
case "^":
// NOTE: Vim doesn't prepend if there's a match in the current value
- return util.Array.uniq(Array.concat(values, this.values), true);
+ return array.uniq(Array.concat(values, this.values), true);
case "-":
return this.values.filter(function (item) values.indexOf(item) == -1);
case "=":
@@ -468,6 +483,9 @@ const Option = Class("Option", {
}
return null;
},
+ get charlist() this.stringlist,
+ get regexlist() this.stringlist,
+ get regexmap() this.stringlist,
string: function (operator, values, scope, invert) {
switch (operator) {
@@ -503,21 +521,14 @@ const Option = Class("Option", {
}
});
-Option.joinValues["regexmap"] = Option.joinValues["regexlist"];
-
-Option.getKey["charlist"] = Option.getKey["stringlist"];
-Option.getKey["regexmap"] = Option.getKey["regexlist"];
-
-Option.ops["charlist"] = Option.ops["stringlist"];
-Option.ops["regexlist"] = Option.ops["stringlist"];
-Option.ops["regexmap"] = Option.ops["stringlist"];
-
/**
* @instance options
*/
const Options = Module("options", {
init: function () {
- this._optionHash = {};
+ this.needInit = [];
+ this._options = [];
+ this._optionMap = {};
this._prefContexts = [];
for (let [, pref] in Iterator(this.allPrefs(Options.OLD_SAVED))) {
@@ -541,45 +552,28 @@ const Options = Module("options", {
});
}
- function optionObserver(key, event, option) {
+ storage.newMap("options", { store: false });
+ storage.addObserver("options", function optionObserver(key, event, option) {
// Trigger any setters.
let opt = options.get(option);
if (event == "change" && opt)
opt.setValues(opt.globalValue, Option.SCOPE_GLOBAL, true);
- }
-
- storage.newMap("options", { store: false });
- storage.addObserver("options", optionObserver, window);
+ }, window);
- this.prefObserver.register();
+ this._branch = services.get("pref").getBranch("").QueryInterface(Ci.nsIPrefBranch2);
+ this._branch.addObserver("", this, false);
},
destroy: function () {
- this.prefObserver.unregister();
+ this._branch.removeObserver("", this);
},
/** @property {Iterator(Option)} @private */
__iterator__: function ()
- array(values(this._optionHash)).sort(function (a, b) String.localeCompare(a.name, b.name))
- .itervalues(),
-
- /** @property {Object} Observes preference value changes. */
- prefObserver: {
- register: function () {
- // better way to monitor all changes?
- this._branch = services.get("pref").getBranch("").QueryInterface(Ci.nsIPrefBranch2);
- this._branch.addObserver("", this, false);
- },
-
- unregister: function () {
- if (this._branch)
- this._branch.removeObserver("", this);
- },
-
- observe: function (subject, topic, data) {
- if (topic != "nsPref:changed")
- return;
+ values(this._options.sort(function (a, b) String.localeCompare(a.name, b.name))),
+ observe: function (subject, topic, data) {
+ if (topic == "nsPref:changed") {
// subject is the nsIPrefBranch we're observing (after appropriate QI)
// data is the name of the pref that's been changed (relative to subject)
switch (data) {
@@ -588,7 +582,7 @@ const Options = Module("options", {
dactyl.mode = value ? modes.CARET : modes.NORMAL;
break;
}
- }
+ }
},
/**
@@ -601,29 +595,28 @@ const Options = Module("options", {
* @param {Object} extra An optional extra configuration hash (see
* {@link Map#extraInfo}).
* @optional
- * @returns {boolean} Whether the option was created.
*/
add: function (names, description, type, defaultValue, extraInfo) {
if (!extraInfo)
extraInfo = {};
- let option = Option(names, description, type, defaultValue, extraInfo);
-
- if (!option)
- return false;
-
- if (option.name in this._optionHash) {
- // never replace for now
- dactyl.log("Warning: " + names[0].quote() + " already exists, NOT replacing existing option.", 1);
- return false;
+ let name = names[0];
+ if (name in this._optionMap) {
+ dactyl.log("Warning: " + name.quote() + " already exists: replacing existing option.", 1);
+ this.remove(name);
}
- // quickly access options with options["wildmode"]:
- this.__defineGetter__(option.name, function () option.value);
- this.__defineSetter__(option.name, function (value) { option.value = value; });
+ let closure = function () options._optionMap[name];
+ memoize(this._options, this._options.length, closure);
+ memoize(this._optionMap, name, function () Option(names, description, type, defaultValue, extraInfo));
+ for (let alias in values(names.slice(1)))
+ memoize(this._optionMap, alias, closure);
+ if (extraInfo.setter)
+ memoize(this.needInit, this.needInit.length, closure);
- this._optionHash[option.name] = option;
- return true;
+ // quickly access options with options["wildmode"]:
+ this.__defineGetter__(name, function () this._optionMap[name].value);
+ this.__defineSetter__(name, function (value) { this._optionMap[name].value = value; });
},
/**
@@ -646,12 +639,8 @@ const Options = Module("options", {
if (!scope)
scope = Option.SCOPE_BOTH;
- if (name in this._optionHash)
- return (this._optionHash[name].scope & scope) && this._optionHash[name];
-
- for (let opt in values(this._optionHash))
- if (opt.hasName(name))
- return (opt.scope & scope) && opt;
+ if (name in this._optionMap && (this._optionMap[name].scope & scope))
+ return this._optionMap[name];
return null;
},
@@ -734,7 +723,7 @@ const Options = Module("options", {
};
commandline.commandOutput(
- template.options(config.hostApplication + " Options", prefs()));
+ template.options(config.host + " Options", prefs()));
},
/**
@@ -751,7 +740,7 @@ const Options = Module("options", {
let matches, prefix, postfix, valueGiven;
[matches, prefix, ret.name, postfix, valueGiven, ret.operator, ret.value] =
- args.match(/^\s*(no|inv)?([a-z_]*)([?&!])?\s*(([-+^]?)=(.*))?\s*$/) || [];
+ args.match(/^\s*(no|inv)?([a-z_-]*?)([?&!])?\s*(([-+^]?)=(.*))?\s*$/) || [];
ret.args = args;
ret.onlyNonDefault = false; // used for :set to print non-default options
@@ -760,8 +749,13 @@ const Options = Module("options", {
ret.onlyNonDefault = true;
}
- if (matches)
+ if (matches) {
ret.option = options.get(ret.name, ret.scope);
+ if (!ret.option && (ret.option = options.get(prefix + ret.name, ret.scope))) {
+ ret.name = prefix + ret.name;
+ prefix = "";
+ }
+ }
ret.prefix = prefix;
ret.postfix = postfix;
@@ -795,10 +789,10 @@ const Options = Module("options", {
* any of the options's names.
*/
remove: function (name) {
- for each (let option in this._optionHash) {
- if (option.hasName(name))
- delete this._optionHash[option.name];
- }
+ let opt = this.get(name);
+ for (let name in values(opt.names))
+ delete this._optionMap[name];
+ this._options = this._options.filter(function (o) o != opt);
},
/** @property {Object} The options store. */
@@ -1023,7 +1017,7 @@ const Options = Module("options", {
}
if (name == "all" && reset)
- commandline.input("Warning: Resetting all preferences may make " + config.hostApplication + " unusable. Continue (yes/[no]): ",
+ commandline.input("Warning: Resetting all preferences may make " + config.host + " unusable. Continue (yes/[no]): ",
function (resp) {
if (resp == "yes")
for (let pref in values(options.allPrefs()))
@@ -1037,20 +1031,14 @@ const Options = Module("options", {
else if (invertBoolean)
options.invertPref(name);
else if (valueGiven) {
- switch (value) {
- case undefined:
+ if (value == undefined)
value = "";
- break;
- case "true":
+ else if (value == "true")
value = true;
- break;
- case "false":
- value = false;
- break;
- default:
- if (/^\d+$/.test(value))
- value = parseInt(value, 10);
- }
+ else if (value == "false")
+ value = true;
+ else if (/^\d+$/.test(value))
+ value = parseInt(value, 10);
options.setPref(name, value);
}
else
@@ -1123,7 +1111,7 @@ const Options = Module("options", {
context.completions = [
[options._loadPreference(filter, null, false), "Current Value"],
[options._loadPreference(filter, null, true), "Default Value"]
- ].filter(function ([k]) k != null);
+ ].filter(function ([k]) k != null && k.length < 200);
return null;
}
@@ -1134,15 +1122,10 @@ const Options = Module("options", {
let prefix = opt.prefix;
if (context.filter.indexOf("=") == -1) {
- if (prefix)
- context.filters.push(function ({ item: opt }) opt.type == "boolean" || prefix == "inv" && opt.values instanceof Array);
- return completion.option(context, opt.scope);
+ if (false && prefix)
+ context.filters.push(function ({ item }) item.type == "boolean" || prefix == "inv" && isarray(item.values));
+ return completion.option(context, opt.scope, prefix);
}
- else if (prefix == "no")
- return null;
-
- if (prefix)
- context.advance(prefix.length);
let option = opt.option;
context.advance(context.filter.indexOf("=") + 1);
@@ -1155,17 +1138,33 @@ const Options = Module("options", {
if (opt.get || opt.reset || !option || prefix)
return null;
- if (!opt.value) {
+ if (!opt.value && !opt.operator && !opt.invert) {
context.fork("default", 0, this, function (context) {
context.title = ["Extra Completions"];
context.completions = [
[option.value, "Current value"],
[option.defaultValue, "Default value"]
- ].filter(function (f) f[0] != "");
+ ].filter(function (f) f[0] != "" && f[0].length < 200);
});
}
- return context.fork("values", 0, completion, "optionValue", opt.name, opt.operator);
+ let optcontext = context.fork("values");
+ completion.optionValue(optcontext, opt.name, opt.operator);
+
+ // Fill in the current values if we're removing
+ if (opt.operator == "-" && isarray(opt.values)) {
+ let have = set([i.text for (i in context.allItems)]);
+ context = context.fork("current-values", 0);
+ context.anchored = optcontext.anchored
+ context.maxItems = optcontext.maxItems
+
+ context.filters.push(function (i) !set.has(have, i.text));
+ completion.optionValue(context, opt.name, opt.operator, null,
+ function (context) {
+ context.generate = function () option.values.map(function (o) [o, ""])
+ });
+ context.title = ["Current values"];
+ }
}
commands.add(["let"],
@@ -1321,17 +1320,21 @@ const Options = Module("options", {
});
},
completion: function () {
- completion.option = function option(context, scope) {
+ completion.option = function option(context, scope, prefix) {
context.title = ["Option"];
context.keys = { text: "names", description: "description" };
context.completions = options;
+ if (prefix == "inv")
+ context.keys.text = function (opt)
+ opt.type == "boolean" || isarray(opt.values) ? opt.names.map(function (n) "inv" + n)
+ : opt.names;
if (scope)
- context.filters.push(function ({ item: opt }) opt.scope & scope);
+ context.filters.push(function ({ item }) item.scope & scope);
};
- completion.optionValue = function (context, name, op, curValue) {
+ completion.optionValue = function (context, name, op, curValue, completer) {
let opt = options.get(name);
- let completer = opt.completer;
+ completer = completer || opt.completer;
if (!completer)
return;
@@ -1372,31 +1375,24 @@ const Options = Module("options", {
context.advance(context.filter.length - len);
context.title = ["Option Value"];
- let completions = completer(context);
- if (!isarray(completions))
- completions = array(completions).__proto__;
- if (!completions)
- return;
-
// Not Vim compatible, but is a significant enough improvement
// that it's worth breaking compatibility.
if (isarray(newValues)) {
- completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1);
- switch (op) {
- case "+":
- completions = completions.filter(function (val) curValues.indexOf(val[0]) == -1);
- break;
- case "-":
- completions = completions.filter(function (val) curValues.indexOf(val[0]) > -1);
- break;
- }
+ context.filters.push(function (i) newValues.indexOf(i.text) == -1);
+ if (op == "+")
+ context.filters.push(function (i) curValues.indexOf(i.text) == -1);
+ if (op == "-")
+ context.filters.push(function (i) curValues.indexOf(i.text) > -1);
}
- context.completions = completions;
+
+ let res = completer.call(opt, context);
+ if (res)
+ context.completions = res;
};
completion.preference = function preference(context) {
context.anchored = false;
- context.title = [config.hostApplication + " Preference", "Value"];
+ context.title = [config.host + " Preference", "Value"];
context.keys = { text: function (item) item, description: function (item) options.getPref(item) };
context.completions = options.allPrefs();
};
@@ -1404,14 +1400,14 @@ const Options = Module("options", {
javascript: function () {
JavaScript.setCompleter(this.get, [function () ([o.name, o.description] for (o in options))]);
JavaScript.setCompleter([this.getPref, this.safeSetPref, this.setPref, this.resetPref, this.invertPref],
- [function () options.allPrefs().map(function (pref) [pref, ""])]);
+ [function (context) (context.anchored=false, options.allPrefs().map(function (pref) [pref, ""]))]);
},
sanitizer: function () {
sanitizer.addItem("options", {
description: "Options containing hostname data",
action: function (timespan, host) {
if (host)
- for (let opt in values(options._optionHash))
+ for (let opt in values(options._options))
if (timespan.contains(opt.lastSet * 1000) && opt.domains)
try {
opt.values = opt.filterDomain(host, opt.values);
@@ -1421,12 +1417,12 @@ const Options = Module("options", {
}
},
privateEnter: function () {
- for (let opt in values(options._optionHash))
+ for (let opt in values(options._options))
if (opt.privateData && (!callable(opt.privateData) || opt.privateData(opt.values)))
opt.oldValue = opt.value;
},
privateLeave: function () {
- for (let opt in values(options._optionHash))
+ for (let opt in values(options._options))
if (opt.oldValue != null) {
opt.value = opt.oldValue;
opt.oldValue = null;
diff --git a/common/content/quickmarks.js b/common/content/quickmarks.js
index 70dc1b92..d806e8ed 100644
--- a/common/content/quickmarks.js
+++ b/common/content/quickmarks.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -26,7 +26,7 @@ const QuickMarks = Module("quickmarks", {
*/
add: function add(qmark, location) {
this._qmarks.set(qmark, location);
- dactyl.echomsg("Added Quick Mark '" + qmark + "': " + location, 1);
+ dactyl.echomsg({ domains: [util.getHost(location)], message: "Added Quick Mark '" + qmark + "': " + location }, 1);
},
/**
diff --git a/common/content/statusline.js b/common/content/statusline.js
index f88aa79a..e7985887 100644
--- a/common/content/statusline.js
+++ b/common/content/statusline.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@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.
@@ -14,8 +14,9 @@ const StatusLine = Module("statusline", {
this._statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0
// our status bar fields
- this.widgets = dict(["status", "url", "inputbuffer", "progress", "tabcount", "bufferposition", "zoomlevel"].map(
- function (field) [field, document.getElementById("dactyl-statusline-field-" + field)]));
+ this.widgets = array(["status", "url", "inputbuffer", "progress", "tabcount", "bufferposition", "zoomlevel"]
+ .map(function (field) [field, document.getElementById("dactyl-statusline-field-" + field)]))
+ .toObject();
},
/**
@@ -36,7 +37,7 @@ const StatusLine = Module("statusline", {
insecure: "StatusLine"
};
- this._statusBar.setAttributeNS(NS.uri, "highlight", highlightGroup[type]);
+ highlight.highlightNode(this._statusBar, highlightGroup[type]);
},
// update all fields of the statusline
@@ -115,8 +116,8 @@ const StatusLine = Module("statusline", {
}
if (modules.bookmarks) {
if (bookmarks.isBookmarked(buffer.URL))
- modified += "\u2764"; // a heart symbol: ❤
- //modified += "\u2665"; // a heart symbol: ♥
+ modified += UTF8("❤");
+ //modified += UTF8("♥");
}
if (modified)
@@ -206,7 +207,9 @@ const StatusLine = Module("statusline", {
let win = document.commandDispatcher.focusedWindow;
if (!win)
return;
- percent = win.scrollMaxY == 0 ? -1 : win.scrollY / win.scrollMaxY;
+ win.scrollY;
+ percent = win.scrollY == 0 ? 0 : // This prevents a forced rendering
+ win.scrollMaxY == 0 ? -1 : win.scrollY / win.scrollMaxY;
}
let bufferPositionStr = "";
@@ -255,11 +258,11 @@ const StatusLine = Module("statusline", {
{
setter: function setter(value) {
if (value == 0)
- document.getElementById("status-bar").collapsed = true;
+ statusline._statusBar.collapsed = true;
else if (value == 1)
dactyl.echoerr("show status line only with > 1 window not implemented yet");
else
- document.getElementById("status-bar").collapsed = false;
+ statusline._statusBar.collapsed = false;
return value;
},
diff --git a/common/content/tabs.js b/common/content/tabs.js
index 5312054e..8949850c 100644
--- a/common/content/tabs.js
+++ b/common/content/tabs.js
@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -21,6 +21,13 @@ const Tabs = Module("tabs", {
this._lastBufferSwitchArgs = "";
this._lastBufferSwitchSpecial = true;
+ let fragment = dactyl.has("MacUnix") ? "tab-mac" : "tab";
+ this.tabBinding = styles.addSheet(true, "tab-binding", "chrome://browser/content/browser.xul",
+ ".tabbrowser-tab { -moz-binding: url(chrome://dactyl/content/bindings.xml#" + fragment + ") !important; }" +
+ // FIXME: better solution for themes?
+ ".tabbrowser-tab[busy] > .tab-icon > .tab-icon-image { list-style-image: url('chrome://global/skin/icons/loading_16.png') !important; }",
+ false, true);
+
// hide tabs initially to prevent flickering when 'stal' would hide them
// on startup
if (config.hasTabbrowser)
@@ -74,22 +81,6 @@ const Tabs = Module("tabs", {
return store.options;
},
- /**
- * @property {boolean} Whether the tab numbering XBL binding has been
- * applied.
- */
- get tabsBound() Boolean(styles.get(true, "tab-binding")),
- set tabsBound(val) {
- let fragment = dactyl.has("MacUnix") ? "tab-mac" : "tab";
- if (!val)
- styles.removeSheet(true, "tab-binding");
- else if (!this.tabsBound)
- styles.addSheet(true, "tab-binding", "chrome://browser/content/browser.xul",
- ".tabbrowser-tab { -moz-binding: url(chrome://dactyl/content/bindings.xml#" + fragment + ") !important; }" +
- // FIXME: better solution for themes?
- ".tabbrowser-tab[busy] > .tab-icon > .tab-icon-image { list-style-image: url('chrome://global/skin/icons/loading_16.png') !important; }");
- },
-
get visibleTabs() config.tabbrowser.visibleTabs || this.allTabs.filter(function (tab) !tab.hidden),
/**
@@ -721,7 +712,7 @@ const Tabs = Module("tabs", {
});
commands.add(["quita[ll]", "qa[ll]"],
- "Quit " + config.name,
+ "Quit " + config.appname,
function (args) { dactyl.quit(false, args.bang); }, {
argCount: "0",
bang: true
@@ -831,7 +822,7 @@ const Tabs = Module("tabs", {
argCount: "+",
completer: function (context, args) {
if (args.completeArg == 0) {
- context.filters.push(function ({ item: win }) win != window);
+ context.filters.push(function ({ item }) item != window);
completion.window(context);
}
}
diff --git a/common/content/x-click-but21.png b/common/content/x-click-but21.png
deleted file mode 100644
index 2c4632b0..00000000
--- a/common/content/x-click-but21.png
+++ /dev/null
Binary files differ