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

Merge branch 'master' into vimperator-2.1

Conflicts:
	common/content/io.js
	common/content/style.js
This commit is contained in:
Kris Maglione
2009-01-07 00:26:37 -05:00
54 changed files with 1801 additions and 1013 deletions

4
.gitignore vendored
View File

@@ -2,3 +2,7 @@
*/locale/*/*.html */locale/*/*.html
*/chrome */chrome
*~ *~
.*.swp
.*.swo
.swp
.DS_Store

148
HACKING Normal file
View File

@@ -0,0 +1,148 @@
= Hacking =
If you've taken to hacking Vimperator source code, we hope that you'll share
your changes. In case you do, please keep the following in mind, and we'll be
happy to accept your patches.
== Documentation ==
First of all, all new features and all user-visible changes to existing
features need to be documented. That means editing the appropriate help files
and adding a NEWS entry where appropriate. When editing the NEWS file, you
should add your change to the top of the list of changes. If your change
alters an interface (key binding, command) and is likely to cause trouble,
prefix it with 'IMPORTANT:', otherwise, place it below the other 'IMPORTANT'
entries. If you're not sure if your change merits a news entry, or if it's
important, please ask.
== Coding Style ==
In general: Just look at the existing source code!
We try to be quite consistent, but of course, that's not always possible.
=== The most important style issues are: ===
* Use 4 spaces to indent things, no tabs, not 2, nor 8 spaces. If you use Vim,
this should be taken care of automatically by the modeline (like the
one below).
* No trailing whitespace.
* Use " for enclosing strings instead of ', unless using ' avoids escaping of lots of "
Example: alert("foo") instead of alert('foo');
* Exactly one space after if/for/while/catch etc. and after a comma, but none
after a parenthesis or after a function call:
for (pre; condition; post)
but:
alert("foo");
* Opening curly brackets { must be on a new line, unless it is used in a closure:
function myFunction ()
{
if (foo)
{
baz = false;
return bar;
}
else
{
return baz;
}
}
but:
setTimeout(function () {
...
});
* No braces for one-line conditional statements:
Right:
if (foo)
frob();
else
unfrob();
* Prefer lambda-style functions where suitable:
Right: list.filter(function (elem) elem.good != elem.BAD);
Wrong: list.filter(function (elem) { return elem.good != elem.BAD });
* Anonymous function definitions should be formatted with a space after the
keyword "function". Example: function () {}, not function() {}.
* Prefer the use of let over var i.e. only use var when required.
For more details, see
https://developer.mozilla.org/en/New_in_JavaScript_1.7#Block_scope_with_let
* Reuse common local variable names E.g. "elem" is generally used for element,
"win" for windows etc.
* Prefer // over /* */ comments (exceptions for big comments are usually OK)
Right: if (HACK) // TODO: remove hack
Wrong: if (HACK) /* TODO: remove hack */
Documentation comment blocks use /** ... */
* Only wrap lines if it makes the code obviously clearer. Lines longer than 132
characters should probably be broken up rather than wrapped anyway.
* Use UNIX new lines (\n), not windows (\r\n) or old Mac ones (\r)
* Use Iterators, Array#forEach, or for (let i = 0; i < ary.length; i++)
to iterate over arrays. for (let i in ary) and for each (let i in ary)
include members in an Array.prototype, which some extensions alter.
Right:
for (let [,elem] in Iterator(ary))
for (let [k, v] in Iterator(obj))
ary.forEach(function (elem) { ...
Wrong:
for each (let elem in ary)
The exceptions to this rule are for objects with __iterator__ set,
and for XML objects (see README.E4X).
* Avoid using 'new' with constructors where possible, and use [] and
{} rather than new Array/new Object.
Right:
RegExp("^" + foo + "$")
Function(code)
new Date
Wrong:
new RegExp("^" + foo + "$")
new Function(code)
Date() // Right if you want a string-representation of the date
NOTE by mst: That one is debateable, actually I like the "new" as one
immediately sees that a new object of a class is created which is not
so obvious by var x = CompletionContext(); which could also mean that
CompletionContext() could return a cached object. What's thesnowdog's
opinion and why do you, Kris, think it's better/cleaner?
I don't think it's better/cleaner, it just seemed to be a consensus.
--Kris
I don't like unnecessary use of 'new', I don't like 'new'. --djk
== Testing/Optimization ==
TODO: Add some information here about testing/validation/etc.
Information about how/when to use :regressions might be nice.
Additionally, maybe there should be some benchmark information here --
something to let a developer know what's "too" slow...? Or general
guidelines about optimization?
== Source Code Management ==
TODO: Document the existence of remote branches and discuss when and how
to push to them. At least provide an index so that devs know where
to look if an old branch needs to be maintained or a feature needs
to be added to a new branch. Keep in mind that git is not the most
intuitive SCM.
I don't agree. git is about as intuitive as any other SCM, but,
regardless, it's by far one of the most popular. There are
countless git walkthroughs, FAQs, tips pages (not to mention 'git
help') that I don't see the need to duplicate them here. As for
branches, 'git branch' should be sufficient, and, if not, there's
a list on gitweb.
--Kris
# vim: set fdm=marker sw=4 ts=4 et ai:

View File

@@ -32,7 +32,7 @@ const Point = new Struct("x", "y");
/** /**
* A class to manage the primary web content buffer. The name comes * A class to manage the primary web content buffer. The name comes
* from vim's term, 'buffer', which signifies instances of open * from Vim's term, 'buffer', which signifies instances of open
* files. * files.
* @instance buffer * @instance buffer
*/ */
@@ -41,7 +41,8 @@ function Buffer() //{{{
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
/* FIXME: This doesn't belong here. */
// FIXME: This doesn't belong here.
let mainWindowID = config.mainWindowID || "main-window"; let mainWindowID = config.mainWindowID || "main-window";
let fontSize = util.computedStyle(document.getElementById(mainWindowID)).fontSize; let fontSize = util.computedStyle(document.getElementById(mainWindowID)).fontSize;
@@ -197,7 +198,7 @@ function Buffer() //{{{
{ {
if (mappings.repeat) if (mappings.repeat)
{ {
for (let i in util.interruptableRange(0, Math.max(count, 1), 100)) for (let i in util.interruptibleRange(0, Math.max(count, 1), 100))
mappings.repeat(); mappings.repeat();
} }
}, },
@@ -330,7 +331,7 @@ function Buffer() //{{{
"//xhtml:input[not(@type) or @type='text' or @type='password'] | //xhtml:textarea[not(@disabled) and not(@readonly)]" "//xhtml:input[not(@type) or @type='text' or @type='password'] | //xhtml:textarea[not(@disabled) and not(@readonly)]"
); );
for (match in matches) for (let match in matches)
{ {
let computedStyle = util.computedStyle(match); let computedStyle = util.computedStyle(match);
if (computedStyle.visibility != "hidden" && computedStyle.display != "none") if (computedStyle.visibility != "hidden" && computedStyle.display != "none")
@@ -339,11 +340,7 @@ function Buffer() //{{{
if (elements.length > 0) if (elements.length > 0)
{ {
if (count > elements.length) count = Math.min(Math.max(count, 1), elements.length);
count = elements.length;
else if (count < 1)
count = 1;
elements[count - 1].focus(); elements[count - 1].focus();
} }
else else
@@ -482,7 +479,7 @@ function Buffer() //{{{
if (arg && (liberator.has("Win32") || arg[0] != ">")) if (arg && (liberator.has("Win32") || arg[0] != ">"))
return liberator.echoerr("E488: Trailing characters"); return liberator.echoerr("E488: Trailing characters");
options.temporaryContext(function () { options.withContext(function () {
if (arg) if (arg)
{ {
options.setPref("print.print_to_file", "true"); options.setPref("print.print_to_file", "true");
@@ -570,12 +567,9 @@ function Buffer() //{{{
let file = io.getFile(filename); let file = io.getFile(filename);
if (file.exists() && !args.bang) if (file.exists() && !args.bang)
{ return void liberator.echoerr("E13: File exists (add ! to override)");
liberator.echoerr("E13: File exists (add ! to override)");
return;
}
chosenData = { file: file, uri: makeURI(doc.location.href, doc.characterSet) }; chosenData = { file: file, uri: window.makeURI(doc.location.href, doc.characterSet) };
} }
// if browser.download.useDownloadDir = false then the "Save As" // if browser.download.useDownloadDir = false then the "Save As"
@@ -682,7 +676,7 @@ function Buffer() //{{{
if (!isFeed) if (!isFeed)
{ {
let type = data.type && data.type.toLowerCase(); var type = data.type && data.type.toLowerCase();
type = type.replace(/^\s+|\s*(?:;.*)?$/g, ""); type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
isFeed = (type == "application/rss+xml" || type == "application/atom+xml"); isFeed = (type == "application/rss+xml" || type == "application/atom+xml");
@@ -817,8 +811,8 @@ function Buffer() //{{{
return { return {
/** /**
* The alternative stylesheets for the current buffer. Only * @property {Array} The alternative style sheets for the current
* returns stylesheets for the 'screen' media type. * buffer. Only returns style sheets for the 'screen' media type.
*/ */
get alternateStyleSheets() get alternateStyleSheets()
{ {
@@ -836,10 +830,11 @@ function Buffer() //{{{
get pageInfo() pageInfo, get pageInfo() pageInfo,
/** /**
* Returns whether the buffer is loaded. Values may be: * @property {number} A value indicating whether the buffer is loaded.
* 0 - Loading. * Values may be:
* 1 - Fully loaded. * 0 - Loading.
* 2 - Load failed. * 1 - Fully loaded.
* 2 - Load failed.
*/ */
get loaded() get loaded()
{ {
@@ -854,8 +849,8 @@ function Buffer() //{{{
}, },
/** /**
* The last focused input field in the buffer. Used by the * @property {Object} The last focused input field in the buffer. Used
* "gi" key binding. * by the "gi" key binding.
*/ */
get lastInputField() get lastInputField()
{ {
@@ -870,21 +865,24 @@ function Buffer() //{{{
}, },
/** /**
* The current top-level document's URL. * @property {string} The current top-level document's URL.
*/ */
get URL() get URL()
{ {
return window.content.document.location.href; return window.content.document.location.href;
}, },
/**
* @property {number} The buffer's height in pixels.
*/
get pageHeight() get pageHeight()
{ {
return window.content.innerHeight; return window.content.innerHeight;
}, },
/** /**
* The current browser's text zoom level, as a percentage with * @property {number} The current browser's text zoom level, as a
* 100 as 'normal'. Only affects text size. * percentage with 100 as 'normal'. Only affects text size.
*/ */
get textZoom() get textZoom()
{ {
@@ -896,9 +894,9 @@ function Buffer() //{{{
}, },
/** /**
* The current browser's text zoom level, as a percentage with * @property {number} The current browser's text zoom level, as a
* 100 as 'normal'. Affects text size, as well as image size * percentage with 100 as 'normal'. Affects text size, as well as
* and block size. * image size and block size.
*/ */
get fullZoom() get fullZoom()
{ {
@@ -910,7 +908,7 @@ function Buffer() //{{{
}, },
/** /**
* The current document's title. * @property {string} The current document's title.
*/ */
get title() get title()
{ {
@@ -918,6 +916,7 @@ function Buffer() //{{{
}, },
/** /**
* Adds a new section to the page information output.
* *
* @param {string} option The section's value in 'pageinfo'. * @param {string} option The section's value in 'pageinfo'.
* @param {string} title The heading for this section's * @param {string} title The heading for this section's
@@ -972,6 +971,8 @@ function Buffer() //{{{
* positioned in. * positioned in.
* *
* NOTE: might change the selection * NOTE: might change the selection
*
* @returns {string}
*/ */
// FIXME: getSelection() doesn't always preserve line endings, see: // FIXME: getSelection() doesn't always preserve line endings, see:
// https://www.mozdev.org/bugs/show_bug.cgi?id=19303 // https://www.mozdev.org/bugs/show_bug.cgi?id=19303
@@ -1026,9 +1027,8 @@ function Buffer() //{{{
}, },
/** /**
* Try to guess links the like of "next" and "prev". Though it * Tries to guess links the like of "next" and "prev". Though it has a
* has a singularly horrendous name, it turns out to be quite * singularly horrendous name, it turns out to be quite useful.
* useful.
* *
* @param {string} rel The relationship to look for. Looks for * @param {string} rel The relationship to look for. Looks for
* links with matching @rel or @rev attributes, and, * links with matching @rel or @rev attributes, and,
@@ -1083,12 +1083,12 @@ function Buffer() //{{{
return false; return false;
} }
let retVal = followFrame(window.content); let ret = followFrame(window.content);
if (!retVal) if (!ret)
// only loop through frames if the main content didnt match // only loop through frames if the main content didn't match
retVal = Array.some(window.content.frames, followFrame); ret = Array.some(window.content.frames, followFrame);
if (!retVal) if (!ret)
liberator.beep(); liberator.beep();
}, },
@@ -1125,7 +1125,7 @@ function Buffer() //{{{
case liberator.NEW_TAB: case liberator.NEW_TAB:
case liberator.NEW_BACKGROUND_TAB: case liberator.NEW_BACKGROUND_TAB:
ctrlKey = true; ctrlKey = true;
shiftKey = (where == liberator.NEW_BACKGROUND_TAB); shiftKey = (where != liberator.NEW_BACKGROUND_TAB);
break; break;
case liberator.NEW_WINDOW: case liberator.NEW_WINDOW:
shiftKey = true; shiftKey = true;
@@ -1147,13 +1147,19 @@ function Buffer() //{{{
}, },
/** /**
* The current document's selection controller. * @property {Object} The current document's selection controller.
*/ */
get selectionController() getBrowser().docShell get selectionController() getBrowser().docShell
.QueryInterface(Ci.nsIInterfaceRequestor) .QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay) .getInterface(Ci.nsISelectionDisplay)
.QueryInterface(Ci.nsISelectionController), .QueryInterface(Ci.nsISelectionController),
/**
* Saves a page link to disk.
*
* @param {Object} elem The page link to save.
* @param {boolean} skipPrompt Whether to open the "Save Link As..." dialog
*/
saveLink: function (elem, skipPrompt) saveLink: function (elem, skipPrompt)
{ {
let doc = elem.ownerDocument; let doc = elem.ownerDocument;
@@ -1229,7 +1235,13 @@ function Buffer() //{{{
win.scrollByPages(pages); win.scrollByPages(pages);
}, },
scrollByScrollSize: function (count, direction) /**
* Scrolls the buffer vertically <b>count</b> * 'scroll' rows.
*
* @param {number} count The multiple of 'scroll' lines to scroll.
* @param {number} direction The direction to scroll, down if 1 and up if -1.
*/
scrollByScrollSize: function (count, direction) // XXX: boolean
{ {
if (count > 0) if (count > 0)
options["scroll"] = count; options["scroll"] = count;
@@ -1244,7 +1256,9 @@ function Buffer() //{{{
}, },
/** /**
* Scrolls the current buffer vertically to <b>percentage</b> * Scrolls the current buffer vertically to <b>percentage</b>.
*
* @param {number} percentage The page percentile to scroll the buffer to.
*/ */
scrollToPercentile: function (percentage) scrollToPercentile: function (percentage)
{ {
@@ -1279,9 +1293,16 @@ function Buffer() //{{{
}, },
// TODO: allow callback for filtering out unwanted frames? User defined? // TODO: allow callback for filtering out unwanted frames? User defined?
/**
* Shifts the focus to another frame within the buffer. Each buffer
* contains at least one frame.
*
* @param {number} count The number of frames to skip through.
* @param {boolean} forward The direction of motion.
*/
shiftFrameFocus: function (count, forward) shiftFrameFocus: function (count, forward)
{ {
if (!window.content.document instanceof HTMLDocument) if (!(window.content.document instanceof HTMLDocument))
return; return;
count = Math.max(count, 1); count = Math.max(count, 1);
@@ -1357,11 +1378,23 @@ function Buffer() //{{{
// similar to pageInfo // similar to pageInfo
// TODO: print more useful information, just like the DOM inspector // TODO: print more useful information, just like the DOM inspector
/**
* Displays information about the specified element.
*
* @param {Object} elem
*/
showElementInfo: function (elem) showElementInfo: function (elem)
{ {
liberator.echo(<>Element:<br/>{util.objectToString(elem, true)}</>, commandline.FORCE_MULTILINE); liberator.echo(<>Element:<br/>{util.objectToString(elem, true)}</>, commandline.FORCE_MULTILINE);
}, },
/**
* Displays information about the current buffer.
*
* @param {boolean} verbose Display more verbose information.
* @param {string} sections A string limiting the displayed sections.
* @default The value of 'pageinfo'.
*/
showPageInfo: function (verbose, sections) showPageInfo: function (verbose, sections)
{ {
// Ctrl-g single line output // Ctrl-g single line output
@@ -1391,6 +1424,9 @@ function Buffer() //{{{
liberator.echo(list, commandline.FORCE_MULTILINE); liberator.echo(list, commandline.FORCE_MULTILINE);
}, },
/**
* Opens a viewer to inspect the source of the currently selected range.
*/
viewSelectionSource: function () viewSelectionSource: function ()
{ {
// copied (and tuned somebit) from browser.jar -> nsContextMenu.js // copied (and tuned somebit) from browser.jar -> nsContextMenu.js
@@ -1411,6 +1447,15 @@ function Buffer() //{{{
docUrl, docCharset, reference, "selection"); docUrl, docCharset, reference, "selection");
}, },
/**
* Opens a viewer to inspect the source of the current buffer or the
* specified <b>url</b>. Either the default viewer or the configured
* external editor is used.
*
* @param {string} url The URL of the source.
* @default The current buffer.
* @param {boolean} useExternalEditor View the source in the external editor.
*/
viewSource: function (url, useExternalEditor) viewSource: function (url, useExternalEditor)
{ {
url = url || buffer.URL; url = url || buffer.URL;
@@ -1421,11 +1466,23 @@ function Buffer() //{{{
liberator.open("view-source:" + url); liberator.open("view-source:" + url);
}, },
/**
* Increases the zoom level of the current buffer.
*
* @param {number} steps The number of zoom levels to jump.
* @param {boolean} fullZoom Whether to use full zoom or text zoom.
*/
zoomIn: function (steps, fullZoom) zoomIn: function (steps, fullZoom)
{ {
bumpZoomLevel(steps, fullZoom); bumpZoomLevel(steps, fullZoom);
}, },
/**
* Decreases the zoom level of the current buffer.
*
* @param {number} steps The number of zoom levels to jump.
* @param {boolean} fullZoom Whether to use full zoom or text zoom.
*/
zoomOut: function (steps, fullZoom) zoomOut: function (steps, fullZoom)
{ {
bumpZoomLevel(-steps, fullZoom); bumpZoomLevel(-steps, fullZoom);
@@ -1443,8 +1500,8 @@ function Marks() //{{{
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
var localMarks = storage.newMap('local-marks', true); var localMarks = storage.newMap("local-marks", true);
var urlMarks = storage.newMap('url-marks', true); var urlMarks = storage.newMap("url-marks", true);
var pendingJumps = []; var pendingJumps = [];
var appContent = document.getElementById("appcontent"); var appContent = document.getElementById("appcontent");
@@ -1471,7 +1528,7 @@ function Marks() //{{{
return name + ", " + mark.location + return name + ", " + mark.location +
", (" + Math.round(mark.position.x * 100) + ", (" + Math.round(mark.position.x * 100) +
"%, " + Math.round(mark.position.y * 100) + "%)" + "%, " + Math.round(mark.position.y * 100) + "%)" +
(('tab' in mark) ? ", tab: " + tabs.index(mark.tab) : ""); (("tab" in mark) ? ", tab: " + tabs.index(mark.tab) : "");
} }
function removeLocalMark(mark) function removeLocalMark(mark)

View File

@@ -28,14 +28,14 @@ the terms of any one of the MPL, the GPL or the LGPL.
/** @scope modules */ /** @scope modules */
// Do NOT create instances of this class yourself, use the helper method
// commands.add() instead
/** /**
* A class representing EX commands. Instances are created by * A class representing Ex commands. Instances are created by
* the {@link Commands} class. * the {@link Commands} class.
* *
* @private * @private
*/ */
// Do NOT create instances of this class yourself, use the helper method
// commands.add() instead
function Command(specs, description, action, extraInfo) //{{{ function Command(specs, description, action, extraInfo) //{{{
{ {
if (!specs || !action) if (!specs || !action)
@@ -86,7 +86,7 @@ function Command(specs, description, action, extraInfo) //{{{
/** @property {string[]} All of this command's long names, e.g., "command" */ /** @property {string[]} All of this command's long names, e.g., "command" */
this.longNames = expandedSpecs.longNames; this.longNames = expandedSpecs.longNames;
/** @property {string} The command's cannonical name. */ /** @property {string} The command's canonical name. */
this.name = this.longNames[0]; this.name = this.longNames[0];
/** @property {string[]} All of this command's long and short names. */ /** @property {string[]} All of this command's long and short names. */
this.names = expandedSpecs.names; // return all command name aliases this.names = expandedSpecs.names; // return all command name aliases
@@ -112,7 +112,7 @@ function Command(specs, description, action, extraInfo) //{{{
* arguments begin. For instance, with a value of 2, all arguments * arguments begin. For instance, with a value of 2, all arguments
* starting with the third are parsed as a single string, with all * starting with the third are parsed as a single string, with all
* quoting characters passed literally. This is especially useful for * quoting characters passed literally. This is especially useful for
* commands which take key mappings or ex command lines as * commands which take key mappings or Ex command lines as
* arguments. * arguments.
*/ */
this.literal = extraInfo.literal == null ? null : extraInfo.literal; this.literal = extraInfo.literal == null ? null : extraInfo.literal;
@@ -133,7 +133,7 @@ function Command(specs, description, action, extraInfo) //{{{
this.isUserCommand = extraInfo.isUserCommand || false; this.isUserCommand = extraInfo.isUserCommand || false;
/** /**
* @property {string} For commands defined via :command, contains * @property {string} For commands defined via :command, contains
* the EX command line to be executed upon invocation. * the Ex command line to be executed upon invocation.
*/ */
this.replacementText = extraInfo.replacementText || null; this.replacementText = extraInfo.replacementText || null;
}; };
@@ -148,7 +148,7 @@ Command.prototype = {
* @param {boolean} bang @deprecated Whether this command was * @param {boolean} bang @deprecated Whether this command was
* executed with a trailing !. * executed with a trailing !.
* @param {number} count @deprecated Whether this command was * @param {number} count @deprecated Whether this command was
* executed a leading count. * executed with a leading count.
* @param modifiers Any modifiers to be passed to * @param modifiers Any modifiers to be passed to
* {@link action} * {@link action}
*/ */
@@ -189,6 +189,7 @@ Command.prototype = {
* Returns whether this command may be invoked via <b>name</b>. * Returns whether this command may be invoked via <b>name</b>.
* *
* @param {string} name * @param {string} name
* @returns {boolean}
*/ */
hasName: function (name) hasName: function (name)
{ {
@@ -214,7 +215,7 @@ Command.prototype = {
* purposes. * purposes.
* @param {Object} extra Extra keys to be spliced into the * @param {Object} extra Extra keys to be spliced into the
* returned Args object. * returned Args object.
* @returns Args * @returns {Args}
* @see Commands#parseArgs * @see Commands#parseArgs
*/ */
parseArgs: function (args, complete, extra) commands.parseArgs(args, this.options, this.argCount, false, this.literal, complete, extra) parseArgs: function (args, complete, extra) commands.parseArgs(args, this.options, this.argCount, false, this.literal, complete, extra)
@@ -306,7 +307,7 @@ function Commands() //{{{
completion.setFunctionCompleter(commands.get, [function () ([c.name, c.description] for (c in commands))]); completion.setFunctionCompleter(commands.get, [function () ([c.name, c.description] for (c in commands))]);
}); });
var commandManager = { const self = {
// FIXME: remove later, when our option handler is better // FIXME: remove later, when our option handler is better
OPTION_ANY: 0, // can be given no argument or an argument of any type, OPTION_ANY: 0, // can be given no argument or an argument of any type,
@@ -717,27 +718,18 @@ function Commands() //{{{
return args; return args;
}, },
// return [null, null, null, null, heredoc_tag || false]; parseCommand: function (str)
// [count, cmd, special, args] = match;
parseCommand: function (str, tag)
{ {
// remove comments // remove comments
str.replace(/\s*".*$/, ""); str.replace(/\s*".*$/, "");
if (tag) // we already have a multiline heredoc construct // 0 - count, 1 - cmd, 2 - special, 3 - args
{
if (str == tag)
return [null, null, null, null, false];
else
return [null, null, null, str, tag];
}
// 0 - count, 1 - cmd, 2 - special, 3 - args, 4 - heredoc tag
let matches = str.match(/^:*(\d+|%)?([a-zA-Z]+|!)(!)?(?:\s*(.*?))?$/); let matches = str.match(/^:*(\d+|%)?([a-zA-Z]+|!)(!)?(?:\s*(.*?))?$/);
//var matches = str.match(/^:*(\d+|%)?([a-zA-Z]+|!)(!)?(?:\s*(.*?)\s*)?$/); //var matches = str.match(/^:*(\d+|%)?([a-zA-Z]+|!)(!)?(?:\s*(.*?)\s*)?$/);
if (!matches) if (!matches)
return [null, null, null, null, null]; return [null, null, null, null];
let [, count, cmd, special, args, heredoc] = matches;
let [, count, cmd, special, args] = matches;
// parse count // parse count
if (count) if (count)
@@ -745,14 +737,7 @@ function Commands() //{{{
else else
count = this.COUNT_NONE; count = this.COUNT_NONE;
if (args) return [count, cmd, !!special, args || ""];
{
tag = args.match(/<<\s*(\w+)\s*$/);
if (tag && tag[1])
heredoc = tag[1];
}
return [count, cmd, !!special, args || "", heredoc];
}, },
get complQuote() complQuote, get complQuote() complQuote,
@@ -769,7 +754,7 @@ function Commands() //{{{
{ {
return str.replace(/<((?:q-)?)([a-zA-Z]+)?>/g, function (match, quote, token) return str.replace(/<((?:q-)?)([a-zA-Z]+)?>/g, function (match, quote, token)
{ {
if (token == "lt") // Don't quote, as in vim (but, why so in vim? You'd think people wouldn't say <q-lt> if they didn't want it) if (token == "lt") // Don't quote, as in Vim (but, why so in Vim? You'd think people wouldn't say <q-lt> if they didn't want it)
return "<"; return "<";
let res = tokens[token]; let res = tokens[token];
if (res == undefined) // Ignore anything undefined if (res == undefined) // Ignore anything undefined
@@ -811,7 +796,7 @@ function Commands() //{{{
// TODO: Vim allows commands to be defined without {rep} if there are {attr}s // TODO: Vim allows commands to be defined without {rep} if there are {attr}s
// specified - useful? // specified - useful?
commandManager.add(["com[mand]"], self.add(["com[mand]"],
"List and define commands", "List and define commands",
function (args) function (args)
{ {
@@ -918,13 +903,13 @@ function Commands() //{{{
bang: true, bang: true,
completer: function (context) completion.userCommand(context), completer: function (context) completion.userCommand(context),
options: [ options: [
[["-nargs"], commandManager.OPTION_STRING, [["-nargs"], self.OPTION_STRING,
function (arg) /^[01*?+]$/.test(arg), ["0", "1", "*", "?", "+"]], function (arg) /^[01*?+]$/.test(arg), ["0", "1", "*", "?", "+"]],
[["-bang"], commandManager.OPTION_NOARG], [["-bang"], self.OPTION_NOARG],
[["-count"], commandManager.OPTION_NOARG], [["-count"], self.OPTION_NOARG],
[["-complete"], commandManager.OPTION_STRING, [["-complete"], self.OPTION_STRING,
function (arg) arg in completeOptionMap || /custom,\w+/.test(arg), function (arg) arg in completeOptionMap || /custom,\w+/.test(arg),
function (context) [[k, ''] for ([k, v] in Iterator(completeOptionMap))]] function (context) [[k, ""] for ([k, v] in Iterator(completeOptionMap))]]
], ],
literal: 1, literal: 1,
serial: function () [ serial: function () [
@@ -945,7 +930,7 @@ function Commands() //{{{
] ]
}); });
commandManager.add(["comc[lear]"], self.add(["comc[lear]"],
"Delete all user-defined commands", "Delete all user-defined commands",
function () function ()
{ {
@@ -953,7 +938,7 @@ function Commands() //{{{
}, },
{ argCount: "0" }); { argCount: "0" });
commandManager.add(["delc[ommand]"], self.add(["delc[ommand]"],
"Delete the specified user-defined command", "Delete the specified user-defined command",
function (args) function (args)
{ {
@@ -971,7 +956,7 @@ function Commands() //{{{
//}}} //}}}
return commandManager; return self;
}; //}}} }; //}}}

View File

@@ -66,7 +66,8 @@ function CompletionContext(editor, name, offset) //{{{
self.contexts[name] = this; self.contexts[name] = this;
/** /**
* @property {CompletionContext} This context's parent. {null} when this is a top-level context. * @property {CompletionContext} This context's parent. {null} when
* this is a top-level context.
*/ */
self.parent = parent; self.parent = parent;
@@ -82,7 +83,7 @@ function CompletionContext(editor, name, offset) //{{{
/** /**
* @property {boolean} Specifies that this context is not finished * @property {boolean} Specifies that this context is not finished
* generating results. * generating results.
* @default false * @default false
*/ */
self.incomplete = false; self.incomplete = false;
@@ -111,6 +112,12 @@ function CompletionContext(editor, name, offset) //{{{
this.editor = editor; this.editor = editor;
this.compare = function (a, b) String.localeCompare(a.text, b.text); 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
* is only needed for long, asynchronous completions
*/
this.cancel = null;
/** /**
* @property {function} The function used to filter the results. * @property {function} The function used to filter the results.
* @default Selects all results which match every predicate in the * @default Selects all results which match every predicate in the
@@ -141,16 +148,18 @@ function CompletionContext(editor, name, offset) //{{{
}]; }];
/** /**
* @property {boolean} Specifies whether this context results must * @property {boolean} Specifies whether this context results must
* match the filter at the begining of the string. * match the filter at the beginning of the string.
* @default true * @default true
*/ */
this.anchored = true; this.anchored = true;
/** /**
* @property {Object} A map of all contexts, keyed on their names. * @property {Object} A map of all contexts, keyed on their names.
* Names are assigned when a context is forked, with its specified * Names are assigned when a context is forked, with its specified
* name appended, after a '/', to its parent's name. * name appended, after a '/', to its parent's name. May
* contain inactive contexts. For active contexts, see
* {@link #contextList}.
*/ */
this.contexts = { name: this }; this.contexts = { "/": this };
/** /**
* @property {Object} A mapping of keys, for {@link #getKey}. Given * @property {Object} A mapping of keys, for {@link #getKey}. Given
* { key: value }, getKey(item, key) will return values as such: * { key: value }, getKey(item, key) will return values as such:
@@ -159,7 +168,7 @@ function CompletionContext(editor, name, offset) //{{{
*/ */
this.keys = { text: 0, description: 1, icon: "icon" }; this.keys = { text: 0, description: 1, icon: "icon" };
/** /**
* @property {number} This context's offset from the begining of * @property {number} This context's offset from the beginning of
* {@link #editor}'s value. * {@link #editor}'s value.
*/ */
this.offset = offset || 0; this.offset = offset || 0;
@@ -519,6 +528,15 @@ CompletionContext.prototype = {
this._filter = this._filter.substr(count); this._filter = this._filter.substr(count);
}, },
cancelAll: function ()
{
for (let [,context] in Iterator(this.contextList))
{
if (context.cancel)
context.cancel();
}
},
/** /**
* Gets a key from {@link #cache}, setting it to <b>defVal</b> if it * Gets a key from {@link #cache}, setting it to <b>defVal</b> if it
* doesn't already exists. * doesn't already exists.
@@ -622,6 +640,11 @@ CompletionContext.prototype = {
for (let type in this.selectionTypes) for (let type in this.selectionTypes)
this.highlight(0, 0, type); this.highlight(0, 0, type);
/**
* @property {[CompletionContext]} A list of active
* completion contexts, in the order in which they were
* instantiated.
*/
this.contextList = []; this.contextList = [];
this.offset = 0; this.offset = 0;
this.process = []; this.process = [];
@@ -631,6 +654,8 @@ CompletionContext.prototype = {
this.updateAsync = false; this.updateAsync = false;
this.waitingForTab = false; this.waitingForTab = false;
this.cancelAll();
if (this.editor) if (this.editor)
{ {
this.value = this.editor.selection.focusNode.textContent; this.value = this.editor.selection.focusNode.textContent;
@@ -653,7 +678,7 @@ CompletionContext.prototype = {
/** /**
* Wait for all subcontexts to complete. * Wait for all subcontexts to complete.
* *
* @param {boolean} interruptable When true, the call may be interrupted * @param {boolean} interruptible When true, the call may be interrupted
* via <C-c>. In this case, "Interrupted" may be thrown. * via <C-c>. In this case, "Interrupted" may be thrown.
* @param {number} timeout The maximum time, in milliseconds, to wait. * @param {number} timeout The maximum time, in milliseconds, to wait.
*/ */
@@ -682,10 +707,10 @@ function Completion() //{{{
const OFFSET = 0, CHAR = 1, STATEMENTS = 2, DOTS = 3, FULL_STATEMENTS = 4, COMMA = 5, FUNCTIONS = 6; const OFFSET = 0, CHAR = 1, STATEMENTS = 2, DOTS = 3, FULL_STATEMENTS = 4, COMMA = 5, FUNCTIONS = 6;
let stack = []; let stack = [];
let functions = []; let functions = [];
let top = []; /* The element on the top of the stack. */ let top = []; // The element on the top of the stack.
let last = ""; /* The last opening char pushed onto the stack. */ let last = ""; // The last opening char pushed onto the stack.
let lastNonwhite = ""; /* Last non-whitespace character we saw. */ let lastNonwhite = ""; // Last non-whitespace character we saw.
let lastChar = ""; /* Last character we saw, used for \ escaping quotes. */ let lastChar = ""; // Last character we saw, used for \ escaping quotes.
let compl = []; let compl = [];
let str = ""; let str = "";
@@ -732,11 +757,10 @@ function Completion() //{{{
return iterator; return iterator;
} }
/* Search the object for strings starting with @key. // Search the object for strings starting with @key.
* If @last is defined, key is a quoted string, it's // If @last is defined, key is a quoted string, it's
* wrapped in @last after @offset characters are sliced // wrapped in @last after @offset characters are sliced
* off of it and it's quoted. // off of it and it's quoted.
*/
this.objectKeys = function objectKeys(obj) this.objectKeys = function objectKeys(obj)
{ {
// Things we can dereference // Things we can dereference
@@ -808,11 +832,10 @@ function Completion() //{{{
} }
} }
/* Get an element from the stack. If @n is negative, // Get an element from the stack. If @n is negative,
* count from the top of the stack, otherwise, the bottom. // count from the top of the stack, otherwise, the bottom.
* If @m is provided, return the @mth value of element @o // If @m is provided, return the @mth value of element @o
* of the stack entey at @n. // of the stack entey at @n.
*/
let get = function get(n, m, o) let get = function get(n, m, o)
{ {
let a = stack[n >= 0 ? n : stack.length + n]; let a = stack[n >= 0 ? n : stack.length + n];
@@ -826,7 +849,7 @@ function Completion() //{{{
function buildStack(filter) function buildStack(filter)
{ {
let self = this; let self = this;
/* Push and pop the stack, maintaining references to 'top' and 'last'. */ // Push and pop the stack, maintaining references to 'top' and 'last'.
let push = function push(arg) let push = function push(arg)
{ {
top = [i, arg, [i], [], [], [], []]; top = [i, arg, [i], [], [], [], []];
@@ -854,7 +877,7 @@ function Completion() //{{{
return ret; return ret;
} }
let i = 0, c = ""; /* Current index and character, respectively. */ let i = 0, c = ""; // Current index and character, respectively.
// Reuse the old stack. // Reuse the old stack.
if (str && filter.substr(0, str.length) == str) if (str && filter.substr(0, str.length) == str)
@@ -870,11 +893,10 @@ function Completion() //{{{
push("#root"); push("#root");
} }
/* Build a parse stack, discarding entries as opening characters // Build a parse stack, discarding entries as opening characters
* match closing characters. The stack is walked from the top entry // match closing characters. The stack is walked from the top entry
* and down as many levels as it takes us to figure out what it is // and down as many levels as it takes us to figure out what it is
* that we're completing. // that we're completing.
*/
str = filter; str = filter;
let length = str.length; let length = str.length;
for (; i < length; lastChar = c, i++) for (; i < length; lastChar = c, i++)
@@ -906,7 +928,7 @@ function Completion() //{{{
switch (c) switch (c)
{ {
case "(": case "(":
/* Function call, or if/while/for/... */ // Function call, or if/while/for/...
if (/[\w$]/.test(lastNonwhite)) if (/[\w$]/.test(lastNonwhite))
{ {
functions.push(i); functions.push(i);
@@ -927,7 +949,7 @@ function Completion() //{{{
break; break;
case ")": pop("("); break; case ")": pop("("); break;
case "]": pop("["); break; case "]": pop("["); break;
case "}": pop("{"); /* Fallthrough */ case "}": pop("{"); // Fallthrough
case ";": case ";":
top[FULL_STATEMENTS].push(i); top[FULL_STATEMENTS].push(i);
break; break;
@@ -972,7 +994,7 @@ function Completion() //{{{
this.context.getCache("eval", Object); this.context.getCache("eval", 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. */ // Okay, have parse stack. Figure out what we're completing.
// Find any complete statements that we can eval before we eval our object. // Find any complete statements that we can eval before we eval our object.
// This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab> // This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab>
@@ -1039,7 +1061,7 @@ function Completion() //{{{
cacheKey = null; cacheKey = null;
let obj = [[cache.evalContext, "Local Variables"], [userContext, "Global Variables"], let obj = [[cache.evalContext, "Local Variables"], [userContext, "Global Variables"],
[modules, "modules"], [window, "window"]]; // Default objects; [modules, "modules"], [window, "window"]]; // Default objects;
/* Is this an object dereference? */ // Is this an object dereference?
if (dot < statement) // No. if (dot < statement) // No.
dot = statement - 1; dot = statement - 1;
else // Yes. Set the object to the string before the dot. else // Yes. Set the object to the string before the dot.
@@ -1073,7 +1095,7 @@ function Completion() //{{{
compl = function (context, obj) compl = function (context, obj)
{ {
context.process = [null, function highlight(item, v) template.highlight(v, true)]; context.process = [null, function highlight(item, v) template.highlight(v, true)];
// Sort in a logical fasion for object keys: // Sort in a logical fashion for object keys:
// Numbers are sorted as numbers, rather than strings, and appear first. // Numbers are sorted as numbers, rather than strings, and appear first.
// Constants are unsorted, and appear before other non-null strings. // Constants are unsorted, and appear before other non-null strings.
// Other strings are sorted in the default manner. // Other strings are sorted in the default manner.
@@ -1112,11 +1134,11 @@ function Completion() //{{{
// Otherwise, do nothing. // Otherwise, do nothing.
if (last == "'" || last == '"') if (last == "'" || last == '"')
{ {
/* //
* str = "foo[bar + 'baz" // str = "foo[bar + 'baz"
* obj = "foo" // obj = "foo"
* key = "bar + ''" // key = "bar + ''"
*/ //
// The top of the stack is the sting we're completing. // The top of the stack is the sting we're completing.
// Wrap it in its delimiters and eval it to process escape sequences. // Wrap it in its delimiters and eval it to process escape sequences.
@@ -1133,21 +1155,20 @@ function Completion() //{{{
return this.eval(key); return this.eval(key);
} }
/* Is this an object accessor? */ // Is this an object accessor?
if (get(-2)[CHAR] == "[") // Are we inside of []? if (get(-2)[CHAR] == "[") // Are we inside of []?
{ {
/* Stack: // Stack:
* [-1]: "... // [-1]: "...
* [-2]: [... // [-2]: [...
* [-3]: base statement // [-3]: base statement
*/
// Yes. If the [ starts at the begining of a logical // Yes. If the [ starts at the beginning of a logical
// statement, we're in an array literal, and we're done. // statement, we're in an array literal, and we're done.
if (get(-3, 0, STATEMENTS) == get(-2)[OFFSET]) if (get(-3, 0, STATEMENTS) == get(-2)[OFFSET])
return; return;
// Begining of the statement upto the opening [ // Beginning of the statement upto the opening [
let obj = getObj(-3, get(-2)[OFFSET]); let obj = getObj(-3, get(-2)[OFFSET]);
return complete.call(this, obj, getKey(), null, string, last); return complete.call(this, obj, getKey(), null, string, last);
@@ -1156,11 +1177,10 @@ function Completion() //{{{
// Is this a function call? // Is this a function call?
if (get(-2)[CHAR] == "(") if (get(-2)[CHAR] == "(")
{ {
/* Stack: // Stack:
* [-1]: "... // [-1]: "...
* [-2]: (... // [-2]: (...
* [-3]: base statement // [-3]: base statement
*/
// Does the opening "(" mark a function call? // Does the opening "(" mark a function call?
if (get(-3, 0, FUNCTIONS) != get(-2)[OFFSET]) if (get(-3, 0, FUNCTIONS) != get(-2)[OFFSET])
@@ -1209,15 +1229,15 @@ function Completion() //{{{
return; return;
} }
/* //
* str = "foo.bar.baz" // str = "foo.bar.baz"
* obj = "foo.bar" // obj = "foo.bar"
* key = "baz" // key = "baz"
* //
* str = "foo" // str = "foo"
* obj = [modules, window] // obj = [modules, window]
* key = "foo" // key = "foo"
*/ //
let [offset, obj, key] = getObjKey(-1); let [offset, obj, key] = getObjKey(-1);
@@ -1230,7 +1250,7 @@ function Completion() //{{{
} }
if (!/^(?:[a-zA-Z_$][\w$]*)?$/.test(key)) if (!/^(?:[a-zA-Z_$][\w$]*)?$/.test(key))
return; /* Not a word. Forget it. Can this even happen? */ return; // Not a word. Forget it. Can this even happen?
try try
{ // FIXME { // FIXME
@@ -1250,7 +1270,7 @@ function Completion() //{{{
////////////////////// PUBLIC SECTION ////////////////////////////////////////// ////////////////////// PUBLIC SECTION //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
let self = { const self = {
setFunctionCompleter: function setFunctionCompleter(funcs, completers) setFunctionCompleter: function setFunctionCompleter(funcs, completers)
{ {
@@ -1338,6 +1358,7 @@ function Completion() //{{{
context.completions = config.autocommands; context.completions = config.autocommands;
}, },
// TODO: shouldn't these app-specific completers be moved to config.js? --djk
bookmark: function bookmark(context, tags, extra) bookmark: function bookmark(context, tags, extra)
{ {
context.title = ["Bookmark", "Title"]; context.title = ["Bookmark", "Title"];
@@ -1552,13 +1573,15 @@ function Completion() //{{{
location: function location(context) location: function location(context)
{ {
if (!services.get("autoCompleteSearch")) if (!services.get("autoCompleteSearch"))
return return;
context.anchored = false; context.anchored = false;
context.title = ["Smart Completions"]; context.title = ["Smart Completions"];
context.keys.icon = 2; context.keys.icon = 2;
context.incomplete = true; context.incomplete = true;
context.hasItems = context.completions.length > 0; // XXX context.hasItems = context.completions.length > 0; // XXX
context.filterFunc = null; context.filterFunc = null;
context.cancel = function () services.get("autoCompleteSearch").stopSearch();
context.compare = null; context.compare = null;
let timer = new Timer(50, 100, function (result) { let timer = new Timer(50, 100, function (result) {
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING; context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
@@ -1627,9 +1650,8 @@ function Completion() //{{{
let completions = completer(context); let completions = completer(context);
if (!completions) if (!completions)
return; return;
/* Not vim compatible, but is a significant enough improvement // Not Vim compatible, but is a significant enough improvement
* that it's worth breaking compatibility. // that it's worth breaking compatibility.
*/
if (newValues instanceof Array) if (newValues instanceof Array)
{ {
completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1); completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1);

View File

@@ -217,7 +217,7 @@ function Editor() //{{{
var myModes = [modes.INSERT, modes.COMMAND_LINE]; var myModes = [modes.INSERT, modes.COMMAND_LINE];
/* KEYS COUNT CARET TEXTAREA VISUAL_TEXTAREA */ // KEYS COUNT CARET TEXTAREA VISUAL_TEXTAREA
addMovementMap(["k", "<Up>"], true, "lineMove", false, "cmd_linePrevious", selectPreviousLine); addMovementMap(["k", "<Up>"], true, "lineMove", false, "cmd_linePrevious", selectPreviousLine);
addMovementMap(["j", "<Down>", "<Return>"], true, "lineMove", true, "cmd_lineNext", selectNextLine); addMovementMap(["j", "<Down>", "<Return>"], true, "lineMove", true, "cmd_lineNext", selectNextLine);
addMovementMap(["h", "<Left>", "<BS>"], true, "characterMove", false, "cmd_charPrevious", "cmd_selectCharPrevious"); addMovementMap(["h", "<Left>", "<BS>"], true, "characterMove", false, "cmd_charPrevious", "cmd_selectCharPrevious");
@@ -371,10 +371,14 @@ function Editor() //{{{
{ flags: Mappings.flags.COUNT }); { flags: Mappings.flags.COUNT });
// visual mode // visual mode
mappings.add([modes.CARET, modes.TEXTAREA, modes.VISUAL], mappings.add([modes.CARET, modes.TEXTAREA],
["v"], "Start visual mode", ["v"], "Start visual mode",
function (count) { modes.set(modes.VISUAL, liberator.mode); }); function (count) { modes.set(modes.VISUAL, liberator.mode); });
mappings.add([modes.VISUAL],
["v"], "End visual mode",
function (count) { events.onEscape() });
mappings.add([modes.TEXTAREA], mappings.add([modes.TEXTAREA],
["V"], "Start visual line mode", ["V"], "Start visual line mode",
function (count) function (count)
@@ -557,9 +561,9 @@ function Editor() //{{{
unselectText: function () unselectText: function ()
{ {
let elt = window.document.commandDispatcher.focusedElement; let elem = window.document.commandDispatcher.focusedElement;
if (elt && elt.selectionEnd) if (elem && elem.selectionEnd)
elt.selectionEnd = elt.selectionStart; elem.selectionEnd = elem.selectionStart;
}, },
selectedText: function () selectedText: function ()
@@ -570,20 +574,20 @@ function Editor() //{{{
pasteClipboard: function () pasteClipboard: function ()
{ {
let elt = window.document.commandDispatcher.focusedElement; let elem = window.document.commandDispatcher.focusedElement;
if (elt.setSelectionRange && util.readFromClipboard()) if (elem.setSelectionRange && util.readFromClipboard())
// readFromClipboard would return 'undefined' if not checked // readFromClipboard would return 'undefined' if not checked
// dunno about .setSelectionRange // dunno about .setSelectionRange
{ {
let rangeStart = elt.selectionStart; // caret position let rangeStart = elem.selectionStart; // caret position
let rangeEnd = elt.selectionEnd; let rangeEnd = elem.selectionEnd;
let tempStr1 = elt.value.substring(0, rangeStart); let tempStr1 = elem.value.substring(0, rangeStart);
let tempStr2 = util.readFromClipboard(); let tempStr2 = util.readFromClipboard();
let tempStr3 = elt.value.substring(rangeEnd); let tempStr3 = elem.value.substring(rangeEnd);
elt.value = tempStr1 + tempStr2 + tempStr3; elem.value = tempStr1 + tempStr2 + tempStr3;
elt.selectionStart = rangeStart + tempStr2.length; elem.selectionStart = rangeStart + tempStr2.length;
elt.selectionEnd = elt.selectionStart; elem.selectionEnd = elem.selectionStart;
} }
}, },
@@ -709,7 +713,7 @@ function Editor() //{{{
// This function will move/select up to given "pos" // This function will move/select up to given "pos"
// Simple setSelectionRange() would be better, but we want to maintain the correct // Simple setSelectionRange() would be better, but we want to maintain the correct
// order of selectionStart/End (a firefox bug always makes selectionStart <= selectionEnd) // order of selectionStart/End (a Firefox bug always makes selectionStart <= selectionEnd)
// Use only for small movements! // Use only for small movements!
moveToPosition: function (pos, forward, select) moveToPosition: function (pos, forward, select)
{ {
@@ -809,7 +813,7 @@ function Editor() //{{{
} }
args.push(path); args.push(path);
liberator.callFunctionInThread(null, io.run, args.shift(), args, true); liberator.callFunctionInThread(null, io.run, io.expandPath(args.shift()), args, true);
}, },
// TODO: clean up with 2 functions for textboxes and currentEditor? // TODO: clean up with 2 functions for textboxes and currentEditor?
@@ -900,7 +904,7 @@ function Editor() //{{{
// //
// if filter == ! remove all and add it as only END // if filter == ! remove all and add it as only END
// //
// variant 1: rhs matches anywere in loop // variant 1: rhs matches anywhere in loop
// //
// 1 mod matches anywhere in loop // 1 mod matches anywhere in loop
// a) simple replace and // a) simple replace and
@@ -913,7 +917,7 @@ function Editor() //{{{
// (b) a ! is there. do nothing END) // (b) a ! is there. do nothing END)
// //
// variant 2: rhs matches *no*were in loop and filter is c or i // variant 2: rhs matches *no*were in loop and filter is c or i
// everykind of current combo is possible to 1 {c,i,!} or two {c and i} // every kind of current combo is possible to 1 {c,i,!} or two {c and i}
// //
// 1 mod is ! split into two i + c END // 1 mod is ! split into two i + c END
// 1 not !: opposite mode (first), add/change 'second' and END // 1 not !: opposite mode (first), add/change 'second' and END

View File

@@ -4,7 +4,7 @@ catch (e)
{ {
__liberator_eval_error = e; __liberator_eval_error = e;
} }
// Important: The eval statement *must* remain on the first line // IMPORTANT: The eval statement *must* remain on the first line
// in order for line numbering in any errors to remain correct. // in order for line numbering in any errors to remain correct.
// //
// vim: set fdm=marker sw=4 ts=4 et: // vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -37,13 +37,12 @@ function AutoCommands() //{{{
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
const AutoCommand = new Struct("event", "pattern", "command");
var store = []; var store = [];
var lastFocus = null;
function matchAutoCmd(autoCmd, event, regex) function matchAutoCmd(autoCmd, event, regex)
{ {
return (!event || autoCmd.event == event) && return (!event || autoCmd.event == event) && (!regex || autoCmd.pattern.source == regex);
(!regex || autoCmd.pattern.source == regex);
} }
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
@@ -72,6 +71,7 @@ function AutoCommands() //{{{
{ {
let [event, regex, cmd] = args; let [event, regex, cmd] = args;
let events = null; let events = null;
if (event) if (event)
{ {
// NOTE: event can only be a comma separated list for |:au {event} {pat} {cmd}| // NOTE: event can only be a comma separated list for |:au {event} {pat} {cmd}|
@@ -96,6 +96,7 @@ function AutoCommands() //{{{
{ {
if (event == "*") if (event == "*")
event = null; event = null;
if (args.bang) if (args.bang)
{ {
// TODO: "*" only appears to work in Vim when there is a {group} specified // TODO: "*" only appears to work in Vim when there is a {group} specified
@@ -181,6 +182,16 @@ function AutoCommands() //{{{
__iterator__: function () util.Array.iterator(store), __iterator__: function () util.Array.iterator(store),
/**
* Adds a new autocommand. <b>cmd</b> will be executed when one of the
* specified <b>events</b> occurs and the URL of the applicable buffer
* matches <b>regex</b>.
*
* @param {Array} events The array of event names for which this
* autocommand should be executed.
* @param {string} regex The URL pattern to match against the buffer URL
* @param {string} cmd The Ex command to run
*/
add: function (events, regex, cmd) add: function (events, regex, cmd)
{ {
if (typeof events == "string") if (typeof events == "string")
@@ -188,20 +199,43 @@ function AutoCommands() //{{{
events = events.split(","); events = events.split(",");
liberator.log("DEPRECATED: the events list arg to autocommands.add() should be an array of event names"); liberator.log("DEPRECATED: the events list arg to autocommands.add() should be an array of event names");
} }
events.forEach(function (event) events.forEach(function (event) {
store.push({ event: event, pattern: RegExp(regex), command: cmd })); store.push(new AutoCommand(event, RegExp(regex), cmd));
});
}, },
/**
* Returns all autocommands with a matching <b>event</b> and
* <b>regex</b>.
*
* @param {string} event The event name filter.
* @param {string} regex The URL pattern filter.
* @returns {AutoCommand[]}
*/
get: function (event, regex) get: function (event, regex)
{ {
return store.filter(function (autoCmd) matchAutoCmd(autoCmd, event, regex)); return store.filter(function (autoCmd) matchAutoCmd(autoCmd, event, regex));
}, },
/**
* Deletes all autocommands with a matching <b>event</b> and
* <b>regex</b>.
*
* @param {string} event The event name filter.
* @param {string} regex The URL pattern filter.
*/
remove: function (event, regex) remove: function (event, regex)
{ {
store = store.filter(function (autoCmd) !matchAutoCmd(autoCmd, event, regex)); store = store.filter(function (autoCmd) !matchAutoCmd(autoCmd, event, regex));
}, },
/**
* Lists all autocommands with a matching <b>event</b> and
* <b>regex</b>.
*
* @param {string} event The event name filter.
* @param {string} regex The URL pattern filter.
*/
list: function (event, regex) list: function (event, regex)
{ {
let cmds = {}; let cmds = {};
@@ -237,6 +271,14 @@ function AutoCommands() //{{{
commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE); commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
}, },
/**
* Triggers the execution of all autocommands registered for
* <b>event</b>. A map of <b>args</b> is passed to each autocommand
* when it is being executed.
*
* @param {string} event The event to fire.
* @param {Object} args The args to pass to each autocommand.
*/
trigger: function (event, args) trigger: function (event, args)
{ {
if (options.get("eventignore").has("all", event)) if (options.get("eventignore").has("all", event))
@@ -273,7 +315,7 @@ function AutoCommands() //{{{
} }
else else
{ {
liberator.execute(commands.replaceTokens(autoCmd.command, args)); liberator.execute(commands.replaceTokens(autoCmd.command, args), null, true);
} }
} }
} }
@@ -295,10 +337,12 @@ function Events() //{{{
var fullscreen = window.fullScreen; var fullscreen = window.fullScreen;
var lastFocus = null;
var inputBufferLength = 0; // count the number of keys in v.input.buffer (can be different from v.input.buffer.length) var inputBufferLength = 0; // count the number of keys in v.input.buffer (can be different from v.input.buffer.length)
var skipMap = false; // while feeding the keys (stored in v.input.buffer | no map found) - ignore mappings var skipMap = false; // while feeding the keys (stored in v.input.buffer | no map found) - ignore mappings
var macros = storage.newMap('macros', true); var macros = storage.newMap("macros", true);
var currentMacro = ""; var currentMacro = "";
var lastMacro = ""; var lastMacro = "";
@@ -457,14 +501,14 @@ function Events() //{{{
function isFormElemFocused() function isFormElemFocused()
{ {
let elt = window.document.commandDispatcher.focusedElement; let elem = window.document.commandDispatcher.focusedElement;
if (elt == null) if (elem == null)
return false; return false;
try try
{ // sometimes the elt doesn't have .localName { // sometimes the elem doesn't have .localName
let tagname = elt.localName.toLowerCase(); let tagname = elem.localName.toLowerCase();
let type = elt.type.toLowerCase(); let type = elem.type.toLowerCase();
if ((tagname == "input" && (type != "image")) || if ((tagname == "input" && (type != "image")) ||
tagname == "textarea" || tagname == "textarea" ||
@@ -524,7 +568,7 @@ function Events() //{{{
{ {
// hacky way to get rid of "Transfering data from ..." on sites with frames // hacky way to get rid of "Transfering data from ..." on sites with frames
// when you click on a link inside a frameset, because asyncUpdateUI // when you click on a link inside a frameset, because asyncUpdateUI
// is not triggered there (firefox bug?) // is not triggered there (Firefox bug?)
setTimeout(statusline.updateUrl, 10); setTimeout(statusline.updateUrl, 10);
return; return;
} }
@@ -568,7 +612,7 @@ function Events() //{{{
{ {
try try
{ {
eventManager[method](event); self[method](event);
} }
catch (e) catch (e)
{ {
@@ -587,7 +631,6 @@ function Events() //{{{
// load all macros inside ~/.vimperator/macros/ // load all macros inside ~/.vimperator/macros/
// setTimeout needed since io. is loaded after events. // setTimeout needed since io. is loaded after events.
setTimeout (function () { setTimeout (function () {
// FIXME: largely duplicated for loading plugins
try try
{ {
let dirs = io.getRuntimeDirectories("macros"); let dirs = io.getRuntimeDirectories("macros");
@@ -715,7 +758,7 @@ function Events() //{{{
////////////////////// PUBLIC SECTION ////////////////////////////////////////// ////////////////////// PUBLIC SECTION //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
var eventManager = { const self = {
feedingKeys: false, feedingKeys: false,
@@ -805,7 +848,7 @@ function Events() //{{{
{ {
if (lastMacro.length == 1) if (lastMacro.length == 1)
// TODO: ignore this like Vim? // TODO: ignore this like Vim?
liberator.echoerr("Exxx: Register " + lastMacro + " not set"); liberator.echoerr("Exxx: Register '" + lastMacro + "' not set");
else else
liberator.echoerr("Exxx: Named macro '" + lastMacro + "' not set"); liberator.echoerr("Exxx: Named macro '" + lastMacro + "' not set");
} }
@@ -832,12 +875,18 @@ function Events() //{{{
} }
}, },
// This method pushes keys into the event queue from liberator /**
// it is similar to vim's feedkeys() method, but cannot cope with * Pushes keys into the event queue from liberator it is similar to
// 2 partially-fed strings, you have to feed one parsable string * Vim's feedkeys() method, but cannot cope with 2 partially-fed
// * strings, you have to feed one parsable string.
// @param keys: a string like "2<C-f>" to pass *
// if you want < to be taken literally, prepend it with a \\ * @param {string} keys A string like "2<C-f>" to pass if you want "<"
* to be taken literally, prepend it with a "\\".
* @param {boolean} noremap Allow recursive mappings.
* @param {boolean} silent Whether the command should be echoed to the
* command-line.
* @returns {boolean}
*/
feedkeys: function (keys, noremap, silent) feedkeys: function (keys, noremap, silent)
{ {
let doc = window.document; let doc = window.document;
@@ -965,7 +1014,7 @@ function Events() //{{{
if (event.metaKey) if (event.metaKey)
modifier += "M-"; modifier += "M-";
if (event.type == "keypress") if (/^key/.test(event.type))
{ {
if (event.charCode == 0) if (event.charCode == 0)
{ {
@@ -1043,8 +1092,9 @@ function Events() //{{{
if (buffer.loaded == 1) if (buffer.loaded == 1)
return true; return true;
const maxWaitTime = 25;
let start = Date.now(); let start = Date.now();
let end = start + 25000; // maximum time to wait - TODO: add option let end = start + (maxWaitTime * 1000); // maximum time to wait - TODO: add option
let now; let now;
while (now = Date.now(), now < end) while (now = Date.now(), now < end)
{ {
@@ -1061,14 +1111,14 @@ function Events() //{{{
break; break;
} }
else else
liberator.echomsg("Waiting for page to load..."); liberator.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
} }
modes.show(); modes.show();
// TODO: allow macros to be continued when page does not fully load with an option // TODO: allow macros to be continued when page does not fully load with an option
let ret = (buffer.loaded == 1); let ret = (buffer.loaded == 1);
if (!ret) if (!ret)
liberator.echoerr("Page did not load completely in " + ms + " milliseconds. Macro stopped."); liberator.echoerr("Page did not load completely in " + maxWaitTime + " seconds. Macro stopped.");
liberator.dump("done waiting: " + ret); liberator.dump("done waiting: " + ret);
// sometimes the input widget had focus when replaying a macro // sometimes the input widget had focus when replaying a macro
@@ -1078,10 +1128,10 @@ function Events() //{{{
return ret; return ret;
}, },
// argument "event" is delibarately not used, as i don't seem to have // argument "event" is deliberately not used, as i don't seem to have
// access to the real focus target // access to the real focus target
// //
// the ugly wantsModeReset is needed, because firefox generates a massive // the ugly wantsModeReset is needed, because Firefox generates a massive
// amount of focus changes for things like <C-v><C-k> (focusing the search field) // amount of focus changes for things like <C-v><C-k> (focusing the search field)
onFocusChange: function (event) onFocusChange: function (event)
{ {
@@ -1128,7 +1178,7 @@ function Events() //{{{
if (config.name == "Muttator") if (config.name == "Muttator")
{ {
// we switch to -- MESSAGE -- mode for muttator, when the main HTML widget gets focus // we switch to -- MESSAGE -- mode for Muttator, when the main HTML widget gets focus
if (hasHTMLDocument(win) || elem instanceof HTMLAnchorElement) if (hasHTMLDocument(win) || elem instanceof HTMLAnchorElement)
{ {
if (config.isComposeWindow) if (config.isComposeWindow)
@@ -1334,7 +1384,7 @@ function Events() //{{{
return false; return false;
} }
// XXX: ugly hack for now pass certain keys to firefox as they are without beeping // XXX: ugly hack for now pass certain keys to Firefox as they are without beeping
// also fixes key navigation in combo boxes, submitting forms, etc. // also fixes key navigation in combo boxes, submitting forms, etc.
// FIXME: breaks iabbr for now --mst // FIXME: breaks iabbr for now --mst
if ((config.name == "Vimperator" && liberator.mode == modes.NORMAL) if ((config.name == "Vimperator" && liberator.mode == modes.NORMAL)
@@ -1373,7 +1423,7 @@ function Events() //{{{
return false; return false;
} }
// others are left to generate the 'input' event or handled by firefox // others are left to generate the 'input' event or handled by Firefox
return; return;
} }
} }
@@ -1503,7 +1553,7 @@ function Events() //{{{
if (key != "<Esc>" && key != "<C-[>") if (key != "<Esc>" && key != "<C-[>")
{ {
// allow key to be passed to firefox if we can't handle it // allow key to be passed to Firefox if we can't handle it
stop = false; stop = false;
if (liberator.mode == modes.COMMAND_LINE) if (liberator.mode == modes.COMMAND_LINE)
@@ -1673,7 +1723,7 @@ function Events() //{{{
} }
}; //}}} }; //}}}
window.XULBrowserWindow = eventManager.progressListener; window.XULBrowserWindow = self.progressListener;
window.QueryInterface(Ci.nsIInterfaceRequestor) window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation) .getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem).treeOwner .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
@@ -1682,21 +1732,21 @@ function Events() //{{{
.XULBrowserWindow = window.XULBrowserWindow; .XULBrowserWindow = window.XULBrowserWindow;
try try
{ {
getBrowser().addProgressListener(eventManager.progressListener, Ci.nsIWebProgress.NOTIFY_ALL); getBrowser().addProgressListener(self.progressListener, Ci.nsIWebProgress.NOTIFY_ALL);
} }
catch (e) {} catch (e) {}
eventManager.prefObserver.register(); self.prefObserver.register();
liberator.registerObserver("shutdown", function () { liberator.registerObserver("shutdown", function () {
eventManager.destroy(); self.destroy();
eventManager.prefObserver.unregister(); self.prefObserver.unregister();
}); });
window.addEventListener("keypress", wrapListener("onKeyPress"), true); window.addEventListener("keypress", wrapListener("onKeyPress"), true);
window.addEventListener("keydown", wrapListener("onKeyUpOrDown"), true); window.addEventListener("keydown", wrapListener("onKeyUpOrDown"), true);
window.addEventListener("keyup", wrapListener("onKeyUpOrDown"), true); window.addEventListener("keyup", wrapListener("onKeyUpOrDown"), true);
return eventManager; return self;
}; //}}} }; //}}}

View File

@@ -108,7 +108,7 @@ function Search() //{{{
// strip case-sensitive modifiers // strip case-sensitive modifiers
pattern = pattern.replace(/(\\)?\\[cC]/g, function ($0, $1) { return $1 ? $0 : ""; }); pattern = pattern.replace(/(\\)?\\[cC]/g, function ($0, $1) { return $1 ? $0 : ""; });
// remove any modifer escape \ // remove any modifier escape \
pattern = pattern.replace(/\\(\\[cClL])/g, "$1"); pattern = pattern.replace(/\\(\\[cClL])/g, "$1");
searchString = pattern; searchString = pattern;
@@ -440,7 +440,7 @@ function Search() //{{{
// TODO: code to reposition the document to the place before search started // TODO: code to reposition the document to the place before search started
}, },
// FIXME: thunderbird incompatible // FIXME: Thunderbird incompatible
// this is not dependent on the value of 'hlsearch' // this is not dependent on the value of 'hlsearch'
highlight: function (text) highlight: function (text)
{ {
@@ -469,7 +469,6 @@ function Search() //{{{
// highlighted // highlighted
getBrowser().fastFind.collapseSelection(); getBrowser().fastFind.collapseSelection();
} }
}; };
//}}} //}}}
}; //}}} }; //}}}

View File

@@ -9,3 +9,4 @@ let url = page ? "chrome://liberator/locale/" + page : content.history.previous;
win.getBrowser().loadURIWithFlags(url, Components.interfaces.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY, null, null, null); win.getBrowser().loadURIWithFlags(url, Components.interfaces.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY, null, null, null);
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -47,7 +47,7 @@ function Hints() //{{{
var hintNumber = 0; // only the numerical part of the hint var hintNumber = 0; // only the numerical part of the hint
var usedTabKey = false; // when we used <Tab> to select an element var usedTabKey = false; // when we used <Tab> to select an element
var prevInput = ""; // record previous user input type, "text" || "number" var prevInput = ""; // record previous user input type, "text" || "number"
var extendedhintCount; // for the count arugument of Mode#action (extended hint only) var extendedhintCount; // for the count argument of Mode#action (extended hint only)
// hints[] = [elem, text, span, imgspan, elem.style.backgroundColor, elem.style.color] // hints[] = [elem, text, span, imgspan, elem.style.backgroundColor, elem.style.color]
var pageHints = []; var pageHints = [];
@@ -64,25 +64,43 @@ function Hints() //{{{
Mode.defaultValue("tags", function () function () options.hinttags); Mode.defaultValue("tags", function () function () options.hinttags);
function extended() options.extendedhinttags; function extended() options.extendedhinttags;
const hintModes = { const hintModes = {
";": Mode("Focus hint", function (elem) buffer.focusElement(elem), extended), ";": Mode("Focus hint", function (elem) buffer.focusElement(elem), extended),
a: Mode("Save hint with prompt", function (elem) buffer.saveLink(elem, false)), "?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended),
f: Mode("Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () "//body | //xhtml:body"), s: Mode("Save hint", function (elem) buffer.saveLink(elem, true)),
s: Mode("Save hint", function (elem) buffer.saveLink(elem, true)), a: Mode("Save hint with prompt", function (elem) buffer.saveLink(elem, false)),
o: Mode("Follow hint", function (elem) buffer.followLink(elem, liberator.CURRENT_TAB)), f: Mode("Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () "//body | //xhtml:body"),
t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, liberator.NEW_TAB)), o: Mode("Follow hint", function (elem) buffer.followLink(elem, liberator.CURRENT_TAB)),
b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB)), t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, liberator.NEW_TAB)),
v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended), b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB)),
V: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, true), extended), w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, liberator.NEW_WINDOW), extended),
w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, liberator.NEW_WINDOW), extended), F: Mode("Follow hint sequence in tabs", hintSequenceElement),
O: Mode("Preselect hint in an :open query", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)),
"?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended), T: Mode("Preselect hint in a :tabopen query", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)),
O: Mode("Open location based on hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)), W: Mode("Preselect hint in a :winopen query", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)),
T: Mode("Open new tab based on hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)), v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended),
W: Mode("Open new window based on hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)), V: Mode("View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true), extended),
y: Mode("Yank hint location", function (elem, loc) util.copyToClipboard(loc, true)), y: Mode("Yank hint location", function (elem, loc) util.copyToClipboard(loc, true)),
Y: Mode("Yank hint description", function (elem) util.copyToClipboard(elem.textContent || "", true), extended) Y: Mode("Yank hint description", function (elem) util.copyToClipboard(elem.textContent || "", true), extended)
}; };
// Used to open multiple hints
function hintSequenceElement(elem)
{
// Want to always open sequence hints in background
// (remember: NEW_BACKGROUND_TAB and NEW_TAB semantics assume
// that loadInBackground=true)
if (options.getPref("browser.tabs.loadInBackground"))
buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB);
else
buffer.followLink(elem, liberator.NEW_TAB);
// Move to next element in sequence
// TODO: Maybe we find a *simple* way to keep the hints displayed rather than
// showing them again, or is this short flash actually needed as a "usability
// feature"? --mst
hints.show("F");
}
// reset all important variables // reset all important variables
function reset() function reset()
{ {
@@ -209,7 +227,7 @@ function Hints() //{{{
let scrollY = doc.defaultView.scrollY; let scrollY = doc.defaultView.scrollY;
inner: inner:
for (let i in (util.interruptableRange(start, end + 1, 500))) for (let i in (util.interruptibleRange(start, end + 1, 500)))
{ {
let hint = pageHints[i]; let hint = pageHints[i];
[elem, text, span, imgspan] = hint; [elem, text, span, imgspan] = hint;
@@ -340,7 +358,7 @@ function Hints() //{{{
removeHints(timeout); removeHints(timeout);
if (timeout == 0) if (timeout == 0)
// force a possible mode change, based on wheter an input field has focus // force a possible mode change, based on whether an input field has focus
events.onFocusChange(); events.onFocusChange();
setTimeout(function () { setTimeout(function () {
if (modes.extended & modes.HINTS) if (modes.extended & modes.HINTS)

View File

@@ -66,7 +66,7 @@ function IO() //{{{
const WINDOWS = liberator.has("Win32"); const WINDOWS = liberator.has("Win32");
const EXTENSION_NAME = config.name.toLowerCase(); // "vimperator" or "muttator" const EXTENSION_NAME = config.name.toLowerCase(); // "vimperator" or "muttator"
const downloadManager = Cc["@mozilla.org/download-manager;1"].createInstance(Ci.nsIDownloadManager); const downloadManager = Cc["@mozilla.org/download-manager;1"].createInstance(Ci.nsIDownloadManager);
var processDir = services.get("directory").get("CurWorkD", Ci.nsIFile); var processDir = services.get("directory").get("CurWorkD", Ci.nsIFile);
var cwd = processDir; var cwd = processDir;
@@ -108,10 +108,10 @@ function IO() //{{{
function joinPaths(head, tail) function joinPaths(head, tail)
{ {
let path = ioManager.getFile(head); let path = self.getFile(head);
try try
{ {
path.appendRelativePath(ioManager.expandPath(tail, true)); // FIXME: should only expand env vars and normalise path separators path.appendRelativePath(self.expandPath(tail, true)); // FIXME: should only expand env vars and normalise path separators
if (path.exists() && path.normalize) if (path.exists() && path.normalize)
path.normalize(); path.normalize();
} }
@@ -379,14 +379,14 @@ function IO() //{{{
liberator.registerObserver("load_completion", function () liberator.registerObserver("load_completion", function ()
{ {
completion.setFunctionCompleter([ioManager.getFile, ioManager.expandPath], completion.setFunctionCompleter([self.getFile, self.expandPath],
[function (context, obj, args) { [function (context, obj, args) {
context.quote[2] = ""; context.quote[2] = "";
completion.file(context, true); completion.file(context, true);
}]); }]);
}); });
var ioManager = { const self = {
MODE_RDONLY: 0x01, MODE_RDONLY: 0x01,
MODE_WRONLY: 0x02, MODE_WRONLY: 0x02,
@@ -405,7 +405,7 @@ function IO() //{{{
// Firefox's CWD - see // https://bugzilla.mozilla.org/show_bug.cgi?id=280953 // Firefox's CWD - see // https://bugzilla.mozilla.org/show_bug.cgi?id=280953
getCurrentDirectory: function () getCurrentDirectory: function ()
{ {
let dir = ioManager.getFile(cwd.path); let dir = self.getFile(cwd.path);
// NOTE: the directory could have been deleted underneath us so // NOTE: the directory could have been deleted underneath us so
// fallback to Firefox's CWD // fallback to Firefox's CWD
@@ -425,7 +425,7 @@ function IO() //{{{
} }
else else
{ {
let dir = ioManager.getFile(newdir); let dir = self.getFile(newdir);
if (!dir.exists() || !dir.isDirectory()) if (!dir.exists() || !dir.isDirectory())
{ {
@@ -436,7 +436,7 @@ function IO() //{{{
[cwd, oldcwd] = [dir, this.getCurrentDirectory()]; [cwd, oldcwd] = [dir, this.getCurrentDirectory()];
} }
return ioManager.getCurrentDirectory(); return self.getCurrentDirectory();
}, },
getRuntimeDirectories: function (specialDirectory) getRuntimeDirectories: function (specialDirectory)
@@ -482,10 +482,10 @@ function IO() //{{{
} }
else else
{ {
let expandedPath = ioManager.expandPath(path); let expandedPath = self.expandPath(path);
if (!isAbsolutePath(expandedPath) && !noCheckPWD) if (!isAbsolutePath(expandedPath) && !noCheckPWD)
file = joinPaths(ioManager.getCurrentDirectory().path, expandedPath); file = joinPaths(self.getCurrentDirectory().path, expandedPath);
else else
file.initWithPath(expandedPath); file.initWithPath(expandedPath);
} }
@@ -502,7 +502,7 @@ function IO() //{{{
switch (EXTENSION_NAME) switch (EXTENSION_NAME)
{ {
case "muttator": case "muttator":
tmpName = "mutt-ator-mail"; // to allow vim to :set ft=mail automatically tmpName = "mutt-ator-mail"; // to allow Vim to :set ft=mail automatically
break; break;
case "vimperator": case "vimperator":
try try
@@ -529,7 +529,7 @@ function IO() //{{{
readDirectory: function (file, sort) readDirectory: function (file, sort)
{ {
if (typeof file == "string") if (typeof file == "string")
file = ioManager.getFile(file); file = self.getFile(file);
else if (!(file instanceof Ci.nsILocalFile)) else if (!(file instanceof Ci.nsILocalFile))
throw Cr.NS_ERROR_INVALID_ARG; // FIXME: does not work as expected, just shows undefined: undefined throw Cr.NS_ERROR_INVALID_ARG; // FIXME: does not work as expected, just shows undefined: undefined
@@ -543,11 +543,12 @@ function IO() //{{{
array.push(entry.QueryInterface(Ci.nsIFile)); array.push(entry.QueryInterface(Ci.nsIFile));
} }
if (sort) if (sort)
return array.sort(function (a, b) b.isDirectory() - a.isDirectory() || String.localeCompare(a.path, b.path)); array.sort(function (a, b) b.isDirectory() - a.isDirectory() || String.localeCompare(a.path, b.path));
return array; return array;
} }
else else
return []; // XXX: or should it throw an error, probably yes? return []; // XXX: or should it throw an error, probably yes?
// Yes --djk
}, },
// file is either a full pathname or an instance of file instanceof nsILocalFile // file is either a full pathname or an instance of file instanceof nsILocalFile
@@ -559,7 +560,7 @@ function IO() //{{{
let toCharset = "UTF-8"; let toCharset = "UTF-8";
if (typeof file == "string") if (typeof file == "string")
file = ioManager.getFile(file); file = self.getFile(file);
else if (!(file instanceof Ci.nsILocalFile)) else if (!(file instanceof Ci.nsILocalFile))
throw Cr.NS_ERROR_INVALID_ARG; // FIXME: does not work as expected, just shows undefined: undefined throw Cr.NS_ERROR_INVALID_ARG; // FIXME: does not work as expected, just shows undefined: undefined
@@ -587,14 +588,14 @@ function IO() //{{{
let charset = "UTF-8"; // Can be any character encoding name that Mozilla supports let charset = "UTF-8"; // Can be any character encoding name that Mozilla supports
if (typeof file == "string") if (typeof file == "string")
file = ioManager.getFile(file); file = self.getFile(file);
else if (!(file instanceof Ci.nsILocalFile)) else if (!(file instanceof Ci.nsILocalFile))
throw Cr.NS_ERROR_INVALID_ARG; // FIXME: does not work as expected, just shows undefined: undefined throw Cr.NS_ERROR_INVALID_ARG; // FIXME: does not work as expected, just shows undefined: undefined
if (mode == ">>") if (mode == ">>")
mode = ioManager.MODE_WRONLY | ioManager.MODE_CREATE | ioManager.MODE_APPEND; mode = self.MODE_WRONLY | self.MODE_CREATE | self.MODE_APPEND;
else if (!mode || mode == ">") else if (!mode || mode == ">")
mode = ioManager.MODE_WRONLY | ioManager.MODE_CREATE | ioManager.MODE_TRUNCATE; mode = self.MODE_WRONLY | self.MODE_CREATE | self.MODE_TRUNCATE;
if (!perms) if (!perms)
perms = 0644; perms = 0644;
@@ -616,12 +617,12 @@ function IO() //{{{
if (isAbsolutePath(program)) if (isAbsolutePath(program))
{ {
file = ioManager.getFile(program, true); file = self.getFile(program, true);
} }
else else
{ {
let dirs = services.get("environment").get("PATH").split(WINDOWS ? ";" : ":"); let dirs = services.get("environment").get("PATH").split(WINDOWS ? ";" : ":");
// Windows tries the cwd first TODO: desirable? // Windows tries the CWD first TODO: desirable?
if (WINDOWS) if (WINDOWS)
dirs = [io.getCurrentDirectory().path].concat(dirs); dirs = [io.getCurrentDirectory().path].concat(dirs);
@@ -693,9 +694,9 @@ lookup:
} }
if (res > 0) // FIXME: Is this really right? Shouldn't we always show both? if (res > 0) // FIXME: Is this really right? Shouldn't we always show both?
var output = ioManager.readFile(stderr) + "\nshell returned " + res; var output = self.readFile(stderr) + "\nshell returned " + res;
else else
output = ioManager.readFile(stdout); output = self.readFile(stdout);
// if there is only one \n at the end, chop it off // if there is only one \n at the end, chop it off
if (output && output.indexOf("\n") == output.length - 1) if (output && output.indexOf("\n") == output.length - 1)
@@ -740,15 +741,15 @@ lookup:
return found; return found;
}, },
// files which end in .js are sourced as pure javascript files, // files which end in .js are sourced as pure JavaScript files,
// no need (actually forbidden) to add: js <<EOF ... EOF around those files // no need (actually forbidden) to add: js <<EOF ... EOF around those files
source: function (filename, silent) source: function (filename, silent)
{ {
let wasSourcing = ioManager.sourcing; let wasSourcing = self.sourcing;
try try
{ {
var file = ioManager.getFile(filename); var file = self.getFile(filename);
ioManager.sourcing = { self.sourcing = {
file: file.path, file: file.path,
line: 0 line: 0
}; };
@@ -770,10 +771,10 @@ lookup:
liberator.echomsg("sourcing " + filename.quote(), 2); liberator.echomsg("sourcing " + filename.quote(), 2);
let str = ioManager.readFile(file); let str = self.readFile(file);
let uri = ioService.newFileURI(file); let uri = ioService.newFileURI(file);
// handle pure javascript files specially // handle pure JavaScript files specially
if (/\.js$/.test(filename)) if (/\.js$/.test(filename))
{ {
try try
@@ -797,7 +798,7 @@ lookup:
{ {
let heredoc = ""; let heredoc = "";
let heredocEnd = null; // the string which ends the heredoc let heredocEnd = null; // the string which ends the heredoc
let lines = str.split("\n"); let lines = str.split(/\r\n|[\r\n]/);
for (let [i, line] in Iterator(lines)) for (let [i, line] in Iterator(lines))
{ {
@@ -816,7 +817,7 @@ lookup:
} }
else else
{ {
ioManager.sourcing.line = i + 1; self.sourcing.line = i + 1;
// skip line comments and blank lines // skip line comments and blank lines
line = line.replace(/\r$/, ""); line = line.replace(/\r$/, "");
@@ -891,7 +892,7 @@ lookup:
} }
finally finally
{ {
ioManager.sourcing = wasSourcing; self.sourcing = wasSourcing;
} }
}, },
@@ -911,7 +912,7 @@ lookup:
} }
}; //}}} }; //}}}
return ioManager; return self;
}; //}}} }; //}}}
@@ -921,8 +922,16 @@ IO.PATH_SEP = (function () {
return file.path[0]; return file.path[0];
})(); })();
IO.__defineGetter__("runtimePath", function () services.get("environment").get(config.name.toUpperCase() + "_RUNTIME") || IO.__defineGetter__("runtimePath", function () {
"~/" + (liberator.has("Win32") ? "" : ".") + config.name.toLowerCase()); const rtpvar = config.name.toUpperCase() + "_RUNTIME";
let rtp = services.get("environment").get(rtpvar);
if (!rtp)
{
rtp = "~/" + (liberator.has("Win32") ? "" : ".") + config.name.toLowerCase();
services.get("environment").set(rtpvar, rtp);
}
return rtp;
});
IO.expandPath = function (path, relative) IO.expandPath = function (path, relative)
{ {
@@ -947,7 +956,7 @@ IO.expandPath = function (path, relative)
// Try $HOME first, on all systems // Try $HOME first, on all systems
let home = services.get("environment").get("HOME"); let home = services.get("environment").get("HOME");
// Windows has its own ideosyncratic $HOME variables. // Windows has its own idiosyncratic $HOME variables.
if (!home && WINDOWS) if (!home && WINDOWS)
home = services.get("environment").get("USERPROFILE") || home = services.get("environment").get("USERPROFILE") ||
services.get("environment").get("HOMEDRIVE") + services.get("environment").get("HOMEPATH"); services.get("environment").get("HOMEDRIVE") + services.get("environment").get("HOMEPATH");

View File

@@ -57,11 +57,14 @@ const liberator = (function () //{{{
run: function () { this.func.apply(this.self, this.args); } run: function () { this.func.apply(this.self, this.args); }
}; };
var callbacks = []; const callbacks = {};
var observers = []; const observers = {};
function registerObserver(type, callback) function registerObserver(type, callback)
{ {
observers.push([type, callback]); if (!(type in observers))
observers[type] = [];
observers[type].push(callback);
} }
let nError = 0; let nError = 0;
@@ -83,7 +86,7 @@ const liberator = (function () //{{{
} }
} }
// Only general options are added here, which are valid for all vimperator like extensions // Only general options are added here, which are valid for all Vimperator like extensions
registerObserver("load_options", function () registerObserver("load_options", function ()
{ {
options.add(["errorbells", "eb"], options.add(["errorbells", "eb"],
@@ -364,7 +367,7 @@ const liberator = (function () //{{{
"Run a JavaScript command through eval()", "Run a JavaScript command through eval()",
function (args) function (args)
{ {
if (args.bang) // open javascript console if (args.bang) // open JavaScript console
{ {
liberator.open("chrome://global/content/console.xul", liberator.open("chrome://global/content/console.xul",
(options["newtab"] && options.get("newtab").has("all", "javascript")) (options["newtab"] && options.get("newtab").has("all", "javascript"))
@@ -449,7 +452,7 @@ const liberator = (function () //{{{
let each, eachUnits, totalUnits; let each, eachUnits, totalUnits;
let total = 0; let total = 0;
for (let i in util.interruptableRange(0, count, 500)) for (let i in util.interruptibleRange(0, count, 500))
{ {
let now = Date.now(); let now = Date.now();
method(); method();
@@ -605,6 +608,11 @@ const liberator = (function () //{{{
// ###VERSION### and ###DATE### are replaced by the Makefile // ###VERSION### and ###DATE### are replaced by the Makefile
version: "###VERSION### (created: ###DATE###)", version: "###VERSION### (created: ###DATE###)",
// NOTE: services.get("profile").selectedProfile.name is not rightness.
// If default profile Firefox runs without arguments,
// then selectedProfile returns last selected profile! (not current one!)
profileName: services.get("directory").get("ProfD", Ci.nsIFile).leafName.replace(/^.+?\./, ""),
// TODO: move to events.js? // TODO: move to events.js?
input: { input: {
buffer: "", // partial command storage buffer: "", // partial command storage
@@ -622,19 +630,15 @@ const liberator = (function () //{{{
// TODO: move to ui.js? // TODO: move to ui.js?
registerCallback: function (type, mode, func) registerCallback: function (type, mode, func)
{ {
// TODO: check if callback is already registered if (!(type in callbacks))
callbacks.push([type, mode, func]); callbacks[type] = {};
callbacks[type][mode] = func;
}, },
triggerCallback: function (type, mode, data) triggerCallback: function (type, mode, data)
{ {
// liberator.dump("type: " + type + " mode: " + mode + "data: " + data + "\n"); if (callbacks[type] && callbacks[type][mode])
for (let i = 0; i < callbacks.length; i++) return callbacks[type][mode].call(this, data);
{
let [thistype, thismode, thisfunc] = callbacks[i];
if (mode == thismode && type == thistype)
return thisfunc.call(this, data);
}
return false; return false;
}, },
@@ -642,16 +646,14 @@ const liberator = (function () //{{{
unregisterObserver: function (type, callback) unregisterObserver: function (type, callback)
{ {
observers = observers.filter(function ([t, c]) t != type || c != callback); if (type in observers)
observers[type] = observers[type].filter(function (c) c != callback);
}, },
triggerObserver: function (type) triggerObserver: function (type)
{ {
for (let [,[thistype, callback]] in Iterator(observers)) for (let [,fn] in Iterator(observers[type] || []))
{ fn.apply(null, Array.slice(arguments, 1));
if (thistype == type)
callback.apply(null, Array.slice(arguments, 1));
}
}, },
beep: function () beep: function ()
@@ -988,49 +990,53 @@ const liberator = (function () //{{{
loadPlugins: function () loadPlugins: function ()
{ {
// FIXME: largely duplicated for loading macros function sourceDirectory(dir)
try
{ {
let dirs = io.getRuntimeDirectories("plugin"); if (!dir.isReadable())
if (dirs.length == 0)
{ {
liberator.log("No user plugin directory found", 3); liberator.echoerr("E484: Can't open file " + dir.path);
return; return;
} }
for (let [,dir] in Iterator(dirs))
{
// TODO: search plugins/**/* for plugins
liberator.echomsg('Searching for "plugin/*.{js,vimp}" in ' + dir.path.quote(), 2);
liberator.log("Sourcing plugin directory: " + dir.path + "...", 3); liberator.log("Sourcing plugin directory: " + dir.path + "...", 3);
io.readDirectory(dir.path, true).forEach(function (file) {
let files = io.readDirectory(dir.path, true); if (file.isFile() && /\.(js|vimp)$/i.test(file.path) && !(file.path in liberator.pluginFiles))
{
files.forEach(function (file) { try
if (!file.isDirectory() && /\.(js|vimp)$/i.test(file.path) && !(file.path in liberator.pluginFiles))
{ {
try io.source(file.path, false);
{ liberator.pluginFiles[file.path] = true;
io.source(file.path, false);
liberator.pluginFiles[file.path] = true;
}
catch (e)
{
liberator.reportError(e);
}
} }
}); catch (e)
} {
liberator.reportError(e);
}
}
else if (file.isDirectory())
{
sourceDirectory(file);
}
});
} }
catch (e)
let dirs = io.getRuntimeDirectories("plugin");
if (dirs.length == 0)
{ {
// thrown if directory does not exist liberator.log("No user plugin directory found", 3);
liberator.log("Error sourcing plugin directory: " + e, 9); return;
} }
liberator.echomsg('Searching for "plugin/**/*.{js,vimp}" in '
+ [dir.path.replace(/.plugin$/, "") for each (dir in dirs)].join(",").quote(), 2);
dirs.forEach(function (dir) {
liberator.echomsg("Searching for " + (dir.path + "/**/*.{js,vimp}").quote(), 3);
sourceDirectory(dir);
});
}, },
// logs a message to the javascript error console // logs a message to the JavaScript error console
// if msg is an object, it is beautified // if msg is an object, it is beautified
// TODO: add proper level constants // TODO: add proper level constants
log: function (msg, level) log: function (msg, level)
@@ -1049,20 +1055,24 @@ const liberator = (function () //{{{
if (typeof msg == "object") if (typeof msg == "object")
msg = util.objectToString(msg, false); msg = util.objectToString(msg, false);
const consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService); services.get("console").logStringMessage(config.name.toLowerCase() + ": " + msg);
consoleService.logStringMessage(config.name.toLowerCase() + ": " + msg);
}, },
// open one or more URLs /**
// * Opens one or more URLs. Returns true when load was initiated, or
// @param urls: either a string or an array of urls * false on error.
// The array can look like this: *
// ["url1", "url2", "url3", ...] or: * @param {FIXME} urls Either a URL string or an array of URLs.
// [["url1", postdata1], ["url2", postdata2], ...] * The array can look like this:
// @param where: if ommited, CURRENT_TAB is assumed * ["url1", "url2", "url3", ...]
// but NEW_TAB is set when liberator.forceNewTab is true. * or:
// @param force: Don't prompt whether to open more than 20 tabs. * [["url1", postdata1], ["url2", postdata2], ...]
// @returns true when load was initiated, or false on error * @param {number} where If ommited, CURRENT_TAB is assumed but NEW_TAB
* is set when liberator.forceNewTab is true.
* @param {boolean} force Don't prompt whether to open more than 20
* tabs.
* @returns {boolean}
*/
open: function (urls, where, force) open: function (urls, where, force)
{ {
// convert the string to an array of converted URLs // convert the string to an array of converted URLs
@@ -1083,6 +1093,8 @@ const liberator = (function () //{{{
if (urls.length == 0) if (urls.length == 0)
return false; return false;
let browser = window.getBrowser();
function open(urls, where) function open(urls, where)
{ {
let url = Array.concat(urls)[0]; let url = Array.concat(urls)[0];
@@ -1092,7 +1104,7 @@ const liberator = (function () //{{{
switch (where) switch (where)
{ {
case liberator.CURRENT_TAB: case liberator.CURRENT_TAB:
getBrowser().loadURIWithFlags(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, postdata); browser.loadURIWithFlags(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, postdata);
break; break;
case liberator.NEW_BACKGROUND_TAB: case liberator.NEW_BACKGROUND_TAB:
@@ -1100,21 +1112,21 @@ const liberator = (function () //{{{
if (!liberator.has("tabs")) if (!liberator.has("tabs"))
return open(urls, liberator.NEW_WINDOW); return open(urls, liberator.NEW_WINDOW);
let tab = getBrowser().addTab(url, null, null, postdata); options.withContext(function () {
options.setPref("browser.tabs.loadInBackground", true);
if (where == liberator.NEW_TAB) browser.loadOneTab(url, null, null, postdata, where == liberator.NEW_BACKGROUND_TAB);
getBrowser().selectedTab = tab; });
break; break;
case liberator.NEW_WINDOW: case liberator.NEW_WINDOW:
window.open(); window.open();
services.get("windowMediator").getMostRecentWindow("navigator:browser") let win = services.get("windowMediator").getMostRecentWindow("navigator:browser");
.loadURI(url, null, postdata); win.loadURI(url, null, postdata);
browser = win.getBrowser();
break; break;
default: default:
liberator.echoerr("Exxx: Invalid 'where' directive in liberator.open(...)"); throw Error("Invalid 'where' directive in liberator.open(...)");
return false;
} }
} }
@@ -1123,7 +1135,7 @@ const liberator = (function () //{{{
else if (!where) else if (!where)
where = liberator.CURRENT_TAB; where = liberator.CURRENT_TAB;
for (let [i, url] in Iterator(urls)) for (let [,url] in Iterator(urls))
{ {
open(url, where); open(url, where);
where = liberator.NEW_BACKGROUND_TAB; where = liberator.NEW_BACKGROUND_TAB;
@@ -1227,7 +1239,7 @@ const liberator = (function () //{{{
let infoPath = services.create("file"); let infoPath = services.create("file");
infoPath.initWithPath(IO.expandPath(IO.runtimePath.replace(/,.*/, ""))); infoPath.initWithPath(IO.expandPath(IO.runtimePath.replace(/,.*/, "")));
infoPath.append("info"); infoPath.append("info");
infoPath.append(services.get("profile").selectedProfile.name); infoPath.append(liberator.profileName);
storage.infoPath = infoPath; storage.infoPath = infoPath;
} }
catch (e) catch (e)
@@ -1235,8 +1247,6 @@ const liberator = (function () //{{{
liberator.reportError(e); liberator.reportError(e);
} }
liberator.triggerObserver("load");
// commands must always be the first module to be initialized // commands must always be the first module to be initialized
loadModule("commands", Commands); loadModule("commands", Commands);
loadModule("options", Options); loadModule("options", Options);
@@ -1254,6 +1264,8 @@ const liberator = (function () //{{{
if (config.init) if (config.init)
config.init(); config.init();
liberator.triggerObserver("load");
liberator.log("All modules loaded", 3); liberator.log("All modules loaded", 3);
// first time intro message // first time intro message
@@ -1404,6 +1416,21 @@ const liberator = (function () //{{{
window.liberator = liberator; window.liberator = liberator;
// FIXME: Ugly, etc.
window.addEventListener("liberatorHelpLink", function (event) {
let elem = event.target;
liberator.dump(String(elem));
if (/^(option|mapping|command)$/.test(elem.className))
var tag = elem.textContent.replace(/\s.*/, "");
if (elem.className == "command")
tag = tag.replace(/\[.*?\]/g, "");
if (tag)
var page = liberator.findHelp(tag);
if (page)
elem.href = "chrome://liberator/locale/" + page;
},
true, true);
// called when the chrome is fully loaded and before the main window is shown // called when the chrome is fully loaded and before the main window is shown
window.addEventListener("load", liberator.startup, false); window.addEventListener("load", liberator.startup, false);
window.addEventListener("unload", liberator.shutdown, false); window.addEventListener("unload", liberator.shutdown, false);

View File

@@ -85,6 +85,7 @@ the terms of any one of the MPL, the GPL or the LGPL.
<label class="plain" id="liberator-commandline-prompt" flex="0" crop="end" value="" collapsed="true"/> <label class="plain" id="liberator-commandline-prompt" flex="0" crop="end" value="" collapsed="true"/>
<textbox class="plain" id="liberator-commandline-command" flex="1" type="timed" timeout="100" <textbox class="plain" id="liberator-commandline-command" flex="1" type="timed" timeout="100"
oninput="liberator.modules.commandline.onEvent(event);" oninput="liberator.modules.commandline.onEvent(event);"
onkeyup="liberator.modules.commandline.onEvent(event);"
onfocus="liberator.modules.commandline.onEvent(event);" onfocus="liberator.modules.commandline.onEvent(event);"
onblur="liberator.modules.commandline.onEvent(event);"/> onblur="liberator.modules.commandline.onEvent(event);"/>
</hbox> </hbox>

View File

@@ -283,7 +283,7 @@ function Mappings() //{{{
// FIXME: // FIXME:
Mappings.flags = { Mappings.flags = {
ALLOW_EVENT_ROUTING: 1 << 0, // if set, return true inside the map command to pass the event further to firefox ALLOW_EVENT_ROUTING: 1 << 0, // if set, return true inside the map command to pass the event further to Firefox
MOTION: 1 << 1, MOTION: 1 << 1,
COUNT: 1 << 2, COUNT: 1 << 2,
ARGUMENT: 1 << 3 ARGUMENT: 1 << 3

View File

@@ -126,7 +126,8 @@ const modes = (function () //{{{
////////////////////// PUBLIC SECTION ////////////////////////////////////////// ////////////////////// PUBLIC SECTION //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
var self = { const self = {
NONE: 0, NONE: 0,
__iterator__: function () util.Array.iterator(this.all), __iterator__: function () util.Array.iterator(this.all),

View File

@@ -125,7 +125,7 @@ Option.prototype = {
aValue = this.globalvalue; aValue = this.globalvalue;
if (this.getter) if (this.getter)
this.getter.call(this, aValue); return this.getter.call(this, aValue);
return aValue; return aValue;
}, },
@@ -393,11 +393,196 @@ function Options() //{{{
} }
} }
function setAction(args, modifiers)
{
let bang = args.bang;
if (!args.length)
args[0] = "";
for (let [,arg] in args)
{
if (bang)
{
let onlyNonDefault = false;
let reset = false;
let invertBoolean = false;
if (args[0] == "")
{
var name = "all";
onlyNonDefault = true;
}
else
{
var [matches, name, postfix, valueGiven, operator, value] =
arg.match(/^\s*?([a-zA-Z0-9\.\-_{}]+)([?&!])?\s*(([-+^]?)=(.*))?\s*$/);
reset = (postfix == "&");
invertBoolean = (postfix == "!");
}
if (name == "all" && reset)
liberator.echoerr("You can't reset all options, it could make " + config.hostApplication + " unusable.");
else if (name == "all")
options.listPrefs(onlyNonDefault, "");
else if (reset)
options.resetPref(name);
else if (invertBoolean)
options.invertPref(name);
else if (valueGiven)
{
switch (value)
{
case undefined:
value = "";
break;
case "true":
value = true;
break;
case "false":
value = false;
break;
default:
if (/^\d+$/.test(value))
value = parseInt(value, 10);
}
options.setPref(name, value);
}
else
{
options.listPrefs(onlyNonDefault, name);
}
return;
}
let opt = options.parseOpt(arg, modifiers);
if (!opt)
{
liberator.echoerr("Error parsing :set command: " + arg);
return;
}
let option = opt.option;
if (option == null && !opt.all)
{
liberator.echoerr("No such option: " + opt.name);
return;
}
// reset a variable to its default value
if (opt.reset)
{
if (opt.all)
{
for (let option in options)
option.reset();
}
else
{
option.reset();
}
}
// read access
else if (opt.get)
{
if (opt.all)
{
options.list(opt.onlyNonDefault, opt.scope);
}
else
{
if (option.type == "boolean")
liberator.echo((opt.optionValue ? " " : "no") + option.name);
else
liberator.echo(" " + option.name + "=" + opt.optionValue);
}
}
// write access
// NOTE: the behavior is generally Vim compatible but could be
// improved. i.e. Vim's behavior is pretty sloppy to no real benefit
else
{
if (opt.option.type == "boolean")
{
if (opt.valueGiven)
{
liberator.echoerr("E474: Invalid argument: " + arg);
return;
}
opt.values = !opt.unsetBoolean;
}
let res = opt.option.op(opt.operator || "=", opt.values, opt.scope, opt.invert);
if (res)
liberator.echoerr(res);
}
}
}
function setCompleter(context, args, modifiers)
{
let filter = context.filter;
if (args.bang) // list completions for about:config entries
{
if (filter[filter.length - 1] == "=")
{
context.advance(filter.length);
filter = filter.substr(0, filter.length - 1);
context.completions = [
[loadPreference(filter, null, false), "Current Value"],
[loadPreference(filter, null, true), "Default Value"]
].filter(function ([k]) k != null);
return;
}
return completion.preference(context);
}
let opt = options.parseOpt(filter, modifiers);
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);
}
else if (prefix == "no")
return;
if (prefix)
context.advance(prefix.length);
let option = opt.option;
context.advance(context.filter.indexOf("=") + 1);
if (!option)
{
context.message = "No such option: " + opt.name;
context.highlight(0, name.length, "SPELLCHECK");
}
if (opt.get || opt.reset || !option || prefix)
return;
if (!opt.value)
{
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] != "");
});
}
completion.optionValue(context, opt.name, opt.operator);
}
// //
// firefox preferences which need to be changed to work well with vimperator // Firefox preferences which need to be changed to work well with Vimperator
// //
// work around firefox popup blocker // work around Firefox popup blocker
// TODO: Make this work like safeSetPref // TODO: Make this work like safeSetPref
var popupAllowedEvents = loadPreference("dom.popup_allowed_events", "change click dblclick mouseup reset submit"); var popupAllowedEvents = loadPreference("dom.popup_allowed_events", "change click dblclick mouseup reset submit");
if (!/keypress/.test(popupAllowedEvents)) if (!/keypress/.test(popupAllowedEvents))
@@ -417,7 +602,7 @@ function Options() //{{{
// TODO: move to buffer.js // TODO: move to buffer.js
// we have our own typeahead find implementation // we have our own typeahead find implementation
options.safeSetPref("accessibility.typeaheadfind.autostart", false); options.safeSetPref("accessibility.typeaheadfind.autostart", false);
options.safeSetPref("accessibility.typeaheadfind", false); // actually the above setting should do it, but has no effect in firefox options.safeSetPref("accessibility.typeaheadfind", false); // actually the above setting should do it, but has no effect in Firefox
}); });
// start with saved session // start with saved session
@@ -521,14 +706,14 @@ function Options() //{{{
"Set local option", "Set local option",
function (args) function (args)
{ {
commands.get("set").execute(args.string, args.bang, args.count, { scope: options.OPTION_SCOPE_LOCAL }); return setAction(args, { scope: options.OPTION_SCOPE_LOCAL });
}, },
{ {
bang: true, bang: true,
count: true, count: true,
completer: function (context, args) completer: function (context, args)
{ {
return commands.get("set").completer(context.filter, args.bang, args.count, { scope: options.OPTION_SCOPE_LOCAL }); return setCompleter(context, args, { scope: options.OPTION_SCOPE_LOCAL });
}, },
literal: 0 literal: 0
} }
@@ -538,14 +723,14 @@ function Options() //{{{
"Set global option", "Set global option",
function (args) function (args)
{ {
commands.get("set").execute(args.string, args.bang, args.count, { scope: options.OPTION_SCOPE_GLOBAL }); return setAction(args, { scope: options.OPTION_SCOPE_GLOBAL });
}, },
{ {
bang: true, bang: true,
count: true, count: true,
completer: function (context, args) completer: function (context, args)
{ {
return commands.get("set").completer(context.filter, args.bang, args.count, { scope: options.OPTION_SCOPE_GLOBAL }); return setCompleter(context, args, { scope: options.OPTION_SCOPE_GLOBAL });
}, },
literal: 0 literal: 0
} }
@@ -553,190 +738,15 @@ function Options() //{{{
commands.add(["se[t]"], commands.add(["se[t]"],
"Set an option", "Set an option",
function (args, modifiers) function (args)
{ {
let bang = args.bang; return setAction(args);
if (!args.length)
args[0] = "";
for (let [,arg] in args)
{
if (bang)
{
let onlyNonDefault = false;
let reset = false;
let invertBoolean = false;
if (args[0] == "")
{
var name = "all";
onlyNonDefault = true;
}
else
{
var [matches, name, postfix, valueGiven, operator, value] =
arg.match(/^\s*?([a-zA-Z0-9\.\-_{}]+)([?&!])?\s*(([-+^]?)=(.*))?\s*$/);
reset = (postfix == "&");
invertBoolean = (postfix == "!");
}
if (name == "all" && reset)
liberator.echoerr("You can't reset all options, it could make " + config.hostApplication + " unusable.");
else if (name == "all")
options.listPrefs(onlyNonDefault, "");
else if (reset)
options.resetPref(name);
else if (invertBoolean)
options.invertPref(name);
else if (valueGiven)
{
switch (value)
{
case undefined:
value = "";
break;
case "true":
value = true;
break;
case "false":
value = false;
break;
default:
if (/^\d+$/.test(value))
value = parseInt(value, 10);
}
options.setPref(name, value);
}
else
{
options.listPrefs(onlyNonDefault, name);
}
return;
}
let opt = options.parseOpt(arg, modifiers);
if (!opt)
{
liberator.echoerr("Error parsing :set command: " + arg);
return;
}
let option = opt.option;
if (option == null && !opt.all)
{
liberator.echoerr("No such option: " + opt.name);
return;
}
// reset a variable to its default value
if (opt.reset)
{
if (opt.all)
{
for (let option in options)
option.reset();
}
else
{
option.reset();
}
}
// read access
else if (opt.get)
{
if (opt.all)
{
options.list(opt.onlyNonDefault, opt.scope);
}
else
{
if (option.type == "boolean")
liberator.echo((opt.optionValue ? " " : "no") + option.name);
else
liberator.echo(" " + option.name + "=" + opt.optionValue);
}
}
// write access
// NOTE: the behavior is generally Vim compatible but could be
// improved. i.e. Vim's behavior is pretty sloppy to no real benefit
else
{
if (opt.option.type == "boolean")
{
if (opt.valueGiven)
{
liberator.echoerr("E474: Invalid argument: " + arg);
return;
}
opt.values = !opt.unsetBoolean;
}
let res = opt.option.op(opt.operator || "=", opt.values, opt.scope, opt.invert);
if (res)
liberator.echoerr(res);
}
}
}, },
{ {
bang: true, bang: true,
completer: function (context, args, modifiers) completer: function (context, args)
{ {
let filter = context.filter; return setCompleter(context, args);
if (args.bang) // list completions for about:config entries
{
if (filter[filter.length - 1] == "=")
{
context.advance(filter.length);
filter = filter.substr(0, filter.length - 1);
context.completions = [
[loadPreference(filter, null, false), "Current Value"],
[loadPreference(filter, null, true), "Default Value"]
].filter(function ([k]) k != null);
return;
}
return completion.preference(context);
}
let opt = options.parseOpt(filter, modifiers);
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);
}
else if (prefix == "no")
return;
if (prefix)
context.advance(prefix.length);
let option = opt.option;
context.advance(context.filter.indexOf("=") + 1);
if (!option)
{
context.message = "No such option: " + opt.name;
context.highlight(0, name.length, "SPELLCHECK");
}
if (opt.get || opt.reset || !option || prefix)
return;
if (!opt.value)
{
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] != "");
});
}
completion.optionValue(context, opt.name, opt.operator);
}, },
serial: function () [ serial: function () [
{ {
@@ -760,7 +770,6 @@ function Options() //{{{
//for (let i = 0, name = names[i]; i < length; name = names[++i]) //for (let i = 0, name = names[i]; i < length; name = names[++i])
for (let [,name] in args) for (let [,name] in args)
{ {
let name = args[i];
let reference = liberator.variableReference(name); let reference = liberator.variableReference(name);
if (!reference[0]) if (!reference[0])
{ {
@@ -857,7 +866,7 @@ function Options() //{{{
isDefault: opt.value == opt.defaultValue, isDefault: opt.value == opt.defaultValue,
name: opt.name, name: opt.name,
default: opt.defaultValue, default: opt.defaultValue,
pre: "\u00a0\u00a0", /* Unicode nonbreaking space. */ pre: "\u00a0\u00a0", // Unicode nonbreaking space.
value: <></> value: <></>
}; };
@@ -905,7 +914,7 @@ function Options() //{{{
default: loadPreference(pref, null, true), default: loadPreference(pref, null, true),
value: <>={template.highlight(value, true, 100)}</>, value: <>={template.highlight(value, true, 100)}</>,
name: pref, name: pref,
pre: "\u00a0\u00a0" /* Unicode nonbreaking space. */ pre: "\u00a0\u00a0" // Unicode nonbreaking space.
}; };
yield option; yield option;
@@ -982,14 +991,14 @@ function Options() //{{{
setPref: function (name, value) setPref: function (name, value)
{ {
return storePreference(name, value); storePreference(name, value);
}, },
resetPref: function (name) resetPref: function (name)
{ {
try try
{ {
return services.get("pref").clearUserPref(name); services.get("pref").clearUserPref(name);
} }
catch (e) catch (e)
{ {
@@ -1017,7 +1026,7 @@ function Options() //{{{
storePreference(k, v); storePreference(k, v);
}, },
temporaryContext: function (fn, self) withContext: function (fn, self)
{ {
try try
{ {

View File

@@ -15,7 +15,7 @@ const Cu = Components.utils;
/** /**
* Cached XPCOM services and instances. * Cached XPCOM services and instances.
* *
* @constructor * @constructor
*/ */
function Services() function Services()
@@ -45,6 +45,7 @@ function Services()
get: function (name) services[name], get: function (name) services[name],
create: function (name) classes[name]() create: function (name) classes[name]()
}; };
self.add("appStartup", "@mozilla.org/toolkit/app-startup;1", Ci.nsIAppStartup); self.add("appStartup", "@mozilla.org/toolkit/app-startup;1", Ci.nsIAppStartup);
self.add("autoCompleteSearch", "@mozilla.org/browser/global-history;2", Ci.nsIAutoCompleteSearch); self.add("autoCompleteSearch", "@mozilla.org/browser/global-history;2", Ci.nsIAutoCompleteSearch);
self.add("browserSearch", "@mozilla.org/browser/search-service;1", Ci.nsIBrowserSearchService); self.add("browserSearch", "@mozilla.org/browser/search-service;1", Ci.nsIBrowserSearchService);
@@ -55,7 +56,8 @@ function Services()
self.add("extensionManager", "@mozilla.org/extensions/manager;1", Ci.nsIExtensionManager); self.add("extensionManager", "@mozilla.org/extensions/manager;1", Ci.nsIExtensionManager);
self.add("json", "@mozilla.org/dom/json;1", Ci.nsIJSON, "createInstance"); self.add("json", "@mozilla.org/dom/json;1", Ci.nsIJSON, "createInstance");
self.add("observer", "@mozilla.org/observer-service;1", Ci.nsIObserverService); self.add("observer", "@mozilla.org/observer-service;1", Ci.nsIObserverService);
self.add("pref", "@mozilla.org/preferences-service;1", [Ci.nsIPrefService, Ci.nsIPrefBranch, Ci.nsIPrefBranch2]); self.add("io", "@mozilla.org/network/io-service;1", Ci.nsIIOService);
self.add("pref", "@mozilla.org/preferences-service;1", [Ci.nsIPrefService, Ci.nsIPrefBranch, Ci.nsIPrefBranch2]);
self.add("profile", "@mozilla.org/toolkit/profile-service;1", Ci.nsIToolkitProfileService); self.add("profile", "@mozilla.org/toolkit/profile-service;1", Ci.nsIToolkitProfileService);
self.add("sessionStore", "@mozilla.org/browser/sessionstore;1", Ci.nsISessionStore); self.add("sessionStore", "@mozilla.org/browser/sessionstore;1", Ci.nsISessionStore);
self.add("subscriptLoader", "@mozilla.org/moz/jssubscript-loader;1", Ci.mozIJSSubScriptLoader); self.add("subscriptLoader", "@mozilla.org/moz/jssubscript-loader;1", Ci.mozIJSSubScriptLoader);
@@ -63,11 +65,13 @@ function Services()
self.add("windowMediator", "@mozilla.org/appshell/window-mediator;1", Ci.nsIWindowMediator); self.add("windowMediator", "@mozilla.org/appshell/window-mediator;1", Ci.nsIWindowMediator);
self.add("windowWatcher", "@mozilla.org/embedcomp/window-watcher;1", Ci.nsIWindowWatcher); self.add("windowWatcher", "@mozilla.org/embedcomp/window-watcher;1", Ci.nsIWindowWatcher);
self.addClass("file", "@mozilla.org/file/local;1", Ci.nsILocalFile); self.addClass("file", "@mozilla.org/file/local;1", Ci.nsILocalFile);
self.addClass("find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind); self.addClass("find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind);
self.addClass("process", "@mozilla.org/process/util;1", Ci.nsIProcess); self.addClass("process", "@mozilla.org/process/util;1", Ci.nsIProcess);
return self; return self;
}; };
var services = Services(); var services = Services();
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -72,8 +72,8 @@ Highlights.prototype.CSS = <![CDATA[
Question color: green; background: white; font-weight: bold; Question color: green; background: white; font-weight: bold;
StatusLine color: white; background: black; StatusLine color: white; background: black;
StatusLineBroken color: black; background: #FF6060; /* light-red */ StatusLineBroken color: black; background: #FF6060 /* light-red */
StatusLineSecure color: black; background: #B0FF00; /* light-green */ StatusLineSecure color: black; background: #B0FF00 /* light-green */
TabClose TabClose
TabIcon TabIcon
@@ -129,7 +129,7 @@ Highlights.prototype.CSS = <![CDATA[
/** /**
* A class to manage highlighting rules. The parameters are the * A class to manage highlighting rules. The parameters are the
* standard paramaters for any {@link Storage} object. * standard parameters for any {@link Storage} object.
* *
* @author Kris Maglione <maglione.k@gmail.com> * @author Kris Maglione <maglione.k@gmail.com>
*/ */
@@ -178,17 +178,22 @@ function Highlights(name, store, serial)
let css = newStyle.replace(/(?:!\s*important\s*)?(?:;?\s*$|;)/g, "!important;") let css = newStyle.replace(/(?:!\s*important\s*)?(?:;?\s*$|;)/g, "!important;")
.replace(";!important;", ";", "g"); // Seeming Spidermonkey bug .replace(";!important;", ";", "g"); // Seeming Spidermonkey bug
css = style.selector + " { " + css + " }"; if (!/^\s*(?:!\s*important\s*)?;*\s*$/.test(css))
{
css = style.selector + " { " + css + " }";
let error = styles.addSheet(true, style.selector, style.filter, css); let error = styles.addSheet(true, style.selector, style.filter, css);
if (error) if (error)
return error; return error;
}
style.value = newStyle; style.value = newStyle;
highlight[style.class] = style; highlight[style.class] = style;
}; };
/** /**
* Gets a CSS selector given a highlight group. * Gets a CSS selector given a highlight group.
*
* @param {string} class
*/ */
this.selector = function (class) this.selector = function (class)
{ {
@@ -233,30 +238,28 @@ function Highlights(name, store, serial)
} }
/** /**
* Manages named and unnamed user stylesheets, which apply to both * Manages named and unnamed user style sheets, which apply to both
* chrome and content pages. The parameters are the standard * chrome and content pages. The parameters are the standard
* paramaters for any {@link Storage} object. * parameters for any {@link Storage} object.
* *
* @author Kris Maglione <maglione.k@gmail.com> * @author Kris Maglione <maglione.k@gmail.com>
*/ */
function Styles(name, store, serial) function Styles(name, store, serial)
{ {
/* Can't reference liberator or Components inside Styles -- // Can't reference liberator or Components inside Styles --
* they're members of the window object, which disappear // they're members of the window object, which disappear
* with this window. // with this window.
*/
const util = modules.util; const util = modules.util;
const sleep = liberator.sleep; const sleep = liberator.sleep;
const storage = modules.storage; const storage = modules.storage;
const consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService); const ios = services.get("io");
const ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
const namespace = '@namespace html "' + XHTML + '";\n' + const namespace = '@namespace html "' + XHTML + '";\n' +
'@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";\n' + '@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";\n' +
'@namespace liberator "' + NS.uri + '";\n'; '@namespace liberator "' + NS.uri + '";\n';
const Sheet = new Struct("name", "sites", "css", "ref"); const Sheet = new Struct("name", "sites", "css", "ref");
let cssUri = function (css) "chrome-data:text/css," + encodeURI(css); let cssUri = function (css) "chrome-data:text/css," + window.encodeURI(css);
let userSheets = []; let userSheets = [];
let systemSheets = []; let systemSheets = [];
@@ -270,13 +273,12 @@ function Styles(name, store, serial)
this.__defineGetter__("userNames", function () Iterator(userNames)); this.__defineGetter__("userNames", function () Iterator(userNames));
/** /**
* Add a new stylesheet. * Add a new style sheet.
* *
* @param {boolean} system Declares whether this is a system or * @param {boolean} system Declares whether this is a system or
* user sheet. System sheets are used internally by * user sheet. System sheets are used internally by
* @liberator. * @liberator.
>>>>>>> master:common/content/style.js * @param {string} name The name given to the style sheet by
* @param {string} name The name given to the stylesheet by
* which it may be later referenced. * which it may be later referenced.
* @param {string} filter The sites to which this sheet will * @param {string} filter The sites to which this sheet will
* apply. Can be a domain name or a URL. Any URL ending in * apply. Can be a domain name or a URL. Any URL ending in
@@ -335,6 +337,12 @@ function Styles(name, store, serial)
/** /**
* Find sheets matching the parameters. See {@link #addSheet} * Find sheets matching the parameters. See {@link #addSheet}
* for parameters. * for parameters.
*
* @param {boolean} system
* @param {string} name
* @param {string} filter
* @param {string} css
* @param {number} index
*/ */
this.findSheets = function (system, name, filter, css, index) this.findSheets = function (system, name, filter, css, index)
{ {
@@ -355,10 +363,16 @@ function Styles(name, store, serial)
}; };
/** /**
* Remove a stylesheet. See {@link #addSheet} for parameters. * Remove a style sheet. See {@link #addSheet} for parameters.
* In cases where <b>filter</b> is supplied, the given filters * In cases where <b>filter</b> is supplied, the given filters
* are removed from matching sheets. If any remain, the sheet is * are removed from matching sheets. If any remain, the sheet is
* left in place. * left in place.
*
* @param {boolean} system
* @param {string} name
* @param {string} filter
* @param {string} css
* @param {number} index
*/ */
this.removeSheet = function (system, name, filter, css, index) this.removeSheet = function (system, name, filter, css, index)
{ {
@@ -403,9 +417,9 @@ function Styles(name, store, serial)
}; };
/** /**
* Register a user stylesheet at the given URI. * Register a user style sheet at the given URI.
* *
* @param {string} uri The UrI of the sheet to register. * @param {string} uri The URI of the sheet to register.
* @param {boolean} reload Whether to reload any sheets that are * @param {boolean} reload Whether to reload any sheets that are
* already registered. * already registered.
*/ */
@@ -420,6 +434,8 @@ function Styles(name, store, serial)
/** /**
* Unregister a sheet at the given URI. * Unregister a sheet at the given URI.
*
* @param {string} uri The URI of the sheet to unregister.
*/ */
this.unregisterSheet = function (uri) this.unregisterSheet = function (uri)
{ {
@@ -430,7 +446,9 @@ function Styles(name, store, serial)
// FIXME // FIXME
/** /**
* Register an agent stylesheet. * Register an agent style sheet.
*
* @param {string} uri The URI of the sheet to register.
* @deprecated * @deprecated
*/ */
this.registerAgentSheet = function (uri) this.registerAgentSheet = function (uri)
@@ -441,7 +459,9 @@ function Styles(name, store, serial)
}; };
/** /**
* Unregister an agent stylesheet. * Unregister an agent style sheet.
*
* @param {string} uri The URI of the sheet to unregister.
* @deprecated * @deprecated
*/ */
this.unregisterAgentSheet = function (uri) this.unregisterAgentSheet = function (uri)
@@ -514,7 +534,6 @@ liberator.registerObserver("load_completion", function ()
liberator.registerObserver("load_commands", function () liberator.registerObserver("load_commands", function ()
{ {
// TODO: :colo default needs :hi clear
commands.add(["colo[rscheme]"], commands.add(["colo[rscheme]"],
"Load a color scheme", "Load a color scheme",
function (args) function (args)
@@ -598,7 +617,7 @@ liberator.registerObserver("load_commands", function ()
}); });
commands.add(["dels[tyle]"], commands.add(["dels[tyle]"],
"Remove a user stylesheet", "Remove a user style sheet",
function (args) function (args)
{ {
styles.removeSheet(false, args["-name"], args[0], args.literalArg, args["-index"]); styles.removeSheet(false, args["-name"], args[0], args.literalArg, args["-index"]);

View File

@@ -44,12 +44,12 @@ function Tabs() //{{{
{ {
if (!tabmail) if (!tabmail)
{ {
tabmail = document.getElementById('tabmail'); tabmail = document.getElementById("tabmail");
tabmail.__defineGetter__('mTabContainer', function () this.tabContainer); tabmail.__defineGetter__("mTabContainer", function () this.tabContainer);
tabmail.__defineGetter__('mTabs', function () this.tabContainer.childNodes); tabmail.__defineGetter__("mTabs", function () this.tabContainer.childNodes);
tabmail.__defineGetter__('mCurrentTab', function () this.tabContainer.selectedItem); tabmail.__defineGetter__("mCurrentTab", function () this.tabContainer.selectedItem);
tabmail.__defineGetter__('mStrip', function () this.tabStrip); tabmail.__defineGetter__("mStrip", function () this.tabStrip);
tabmail.__defineGetter__('browsers', function () [browser for (browser in Iterator(this.mTabs))] ); tabmail.__defineGetter__("browsers", function () [browser for (browser in Iterator(this.mTabs))] );
} }
return tabmail; return tabmail;
}; };
@@ -123,7 +123,7 @@ function Tabs() //{{{
let tabStrip = tabs.tabStrip; let tabStrip = tabs.tabStrip;
if (!tabStrip) if (!tabStrip)
return options['showtabline']; // XXX return options["showtabline"]; // XXX
if (value == 0) if (value == 0)
{ {
@@ -677,9 +677,9 @@ function Tabs() //{{{
return store.options; return store.options;
}, },
getLocalStore: function (tab) getLocalStore: function (tabIndex)
{ {
let tab = this.getTab(tab); let tab = this.getTab(tabIndex);
if (!tab.liberatorStore) if (!tab.liberatorStore)
tab.liberatorStore = {}; tab.liberatorStore = {};
return tab.liberatorStore; return tab.liberatorStore;
@@ -737,8 +737,8 @@ function Tabs() //{{{
{ {
if (index != undefined) if (index != undefined)
return getBrowser().mTabs[index]; return getBrowser().mTabs[index];
else
return getBrowser().mCurrentTab; return getBrowser().mCurrentTab;
}, },
get closedTabs() get closedTabs()

View File

@@ -7,7 +7,7 @@ const template = {
map: function map(iter, fn, sep, interruptable) map: function map(iter, fn, sep, interruptable)
{ {
if (iter.length) /* Kludge? */ if (iter.length) // FIXME: Kludge?
iter = util.Array.iterator(iter); iter = util.Array.iterator(iter);
let ret = <></>; let ret = <></>;
let n = 0; let n = 0;
@@ -287,7 +287,7 @@ const template = {
tabular: function tabular(headings, style, iter) tabular: function tabular(headings, style, iter)
{ {
/* This might be mind-bogglingly slow. We'll see. */ // TODO: This might be mind-bogglingly slow. We'll see.
// <e4x> // <e4x>
return this.commandOutput( return this.commandOutput(
<table> <table>

View File

@@ -28,7 +28,7 @@ the terms of any one of the MPL, the GPL or the LGPL.
/** @scope modules */ /** @scope modules */
/* /**
* This class is used for prompting of user input and echoing of messages * This class is used for prompting of user input and echoing of messages
* *
* it consists of a prompt and command field * it consists of a prompt and command field
@@ -75,6 +75,12 @@ function CommandLine() //{{{
var keepCommand = false; var keepCommand = false;
var lastEcho = null; var lastEcho = null;
/**
* A class for managing the history of an inputField
*
* @param {Object} inputField
* @param {string} mode
*/
function History(inputField, mode) function History(inputField, mode)
{ {
if (!(this instanceof arguments.callee)) if (!(this instanceof arguments.callee))
@@ -85,27 +91,42 @@ function CommandLine() //{{{
this.reset(); this.reset();
} }
History.prototype = { History.prototype = {
/**
* Empties the history.
*/
reset: function () reset: function ()
{ {
this.index = null; this.index = null;
}, },
/**
* Permanently save the history
*/
save: function () save: function ()
{ {
let str = this.input.value; let str = this.input.value;
if (/^\s*$/.test(str)) if (/^\s*$/.test(str))
return; return;
this.store.mutate('filter', function (line) line != str); this.store.mutate("filter", function (line) line != str);
this.store.push(str); this.store.push(str);
this.store.truncate(options["history"], true); this.store.truncate(options["history"], true);
}, },
/**
* Set the current match to val
*
* @param {string} val
*/
replace: function (val) replace: function (val)
{ {
this.input.value = val; this.input.value = val;
liberator.triggerCallback("change", currentExtendedMode, val); liberator.triggerCallback("change", currentExtendedMode, val);
}, },
/**
* move up or (if backward) down in the history
*
* @param {boolean} backward
* @param {boolean} matchCurrent XXX: what?
*/
select: function (backward, matchCurrent) select: function (backward, matchCurrent)
{ {
// always reset the tab completion if we use up/down keys // always reset the tab completion if we use up/down keys
@@ -154,6 +175,11 @@ function CommandLine() //{{{
} }
}; };
/**
* A class for tab completions on an input field
*
* @param {Object} input
*/
function Completions(input) function Completions(input)
{ {
if (!(this instanceof arguments.callee)) if (!(this instanceof arguments.callee))
@@ -326,7 +352,7 @@ function CommandLine() //{{{
{ {
case this.UP: case this.UP:
if (this.selected == null) if (this.selected == null)
idx = this.items.length - 1; idx = -2
else else
idx = this.selected - 1; idx = this.selected - 1;
break; break;
@@ -343,8 +369,8 @@ function CommandLine() //{{{
idx = Math.max(0, Math.min(this.items.length - 1, idx)); idx = Math.max(0, Math.min(this.items.length - 1, idx));
break; break;
} }
this.itemList.selectItem(idx);
if (idx < 0 || idx >= this.items.length || idx == null) if (idx == -1 || this.items.length && idx >= this.items.length || idx == null)
{ {
// Wrapped. Start again. // Wrapped. Start again.
this.selected = null; this.selected = null;
@@ -352,28 +378,41 @@ function CommandLine() //{{{
} }
else else
{ {
// Wait for contexts to complete if necessary.
// FIXME: Need to make idx relative to individual contexts.
let list = this.context.contextList.reverse();
if (idx == -2)
list = list.slice().reverse();
let n = 0;
for (let [,context] in Iterator(list))
{
function done() !(idx >= n + context.items.length || idx == -2 && !context.items.length);
while (context.incomplete && !done())
liberator.threadYield(true, true);
if (done())
break;
n += context.items.length;
}
// See previous FIXME. This will break if new items in
// a previous context come in.
if (idx < 0)
idx = this.items.length - 1;
this.selected = idx; this.selected = idx;
this.completion = this.items[idx].text; this.completion = this.items[idx].text;
} }
this.itemList.selectItem(idx);
}, },
tab: function tab(reverse) tab: function tab(reverse)
{ {
autocompleteTimer.flush();
// Check if we need to run the completer. // Check if we need to run the completer.
if (this.context.waitingForTab || this.wildIndex == -1) if (this.context.waitingForTab || this.wildIndex == -1)
this.complete(true, true); this.complete(true, true);
if (this.items.length == 0)
{
// No items. Wait for any unfinished completers.
let end = Date.now() + 5000;
while (this.context.incomplete && this.items.length == 0 && Date.now() < end)
liberator.threadYield();
if (this.items.length == 0)
return liberator.beep();
}
switch (this.wildtype.replace(/.*:/, "")) switch (this.wildtype.replace(/.*:/, ""))
{ {
case "": case "":
@@ -392,6 +431,9 @@ function CommandLine() //{{{
break; break;
} }
if (this.items.length == 0)
return void liberator.beep();
if (this.type.list) if (this.type.list)
completionList.show(); completionList.show();
@@ -511,16 +553,28 @@ function CommandLine() //{{{
var multilineRegexp = null; var multilineRegexp = null;
var multilineCallback = null; var multilineCallback = null;
/**
* @private - highlight the messageBox according to group
*/
function setHighlightGroup(group) function setHighlightGroup(group)
{ {
messageBox.setAttributeNS(NS.uri, "highlight", group); messageBox.setAttributeNS(NS.uri, "highlight", group);
} }
// Whether the command line must be open. /**
* @private - Determines whether the command line should be visible.
*
* @return {boolean}
*/
function commandShown() modes.main == modes.COMMAND_LINE && function commandShown() modes.main == modes.COMMAND_LINE &&
!(modes.extended & (modes.INPUT_MULTILINE | modes.OUTPUT_MULTILINE)); !(modes.extended & (modes.INPUT_MULTILINE | modes.OUTPUT_MULTILINE));
// sets the prompt - for example, : or / /**
* @private - set the prompt to val styled with highlightGroup
*
* @param {string} val
* @param {string} highlightGroup
*/
function setPrompt(val, highlightGroup) function setPrompt(val, highlightGroup)
{ {
promptWidget.value = val; promptWidget.value = val;
@@ -529,7 +583,11 @@ function CommandLine() //{{{
promptWidget.setAttributeNS(NS.uri, "highlight", highlightGroup || commandline.HL_NORMAL); promptWidget.setAttributeNS(NS.uri, "highlight", highlightGroup || commandline.HL_NORMAL);
} }
// sets the command - e.g. 'tabopen', 'open http://example.com/' /**
* @private - set the command to cmd and move the user's cursor to the end.
*
* @param {string} cmd
*/
function setCommand(cmd) function setCommand(cmd)
{ {
commandWidget.value = cmd; commandWidget.value = cmd;
@@ -537,6 +595,14 @@ function CommandLine() //{{{
commandWidget.selectionEnd = cmd.length; commandWidget.selectionEnd = cmd.length;
} }
/**
* @private - display a message styled with highlightGroup
* and, if forceSingle is true, ensure it takes only one line.
*
* @param {string} str
* @param {string} highlightGroup
* @param {boolean} forceSingle
*/
function echoLine(str, highlightGroup, forceSingle) function echoLine(str, highlightGroup, forceSingle)
{ {
setHighlightGroup(highlightGroup); setHighlightGroup(highlightGroup);
@@ -552,7 +618,14 @@ function CommandLine() //{{{
echoMultiline(<span highlight="Message">{str}</span>, highlightGroup); echoMultiline(<span highlight="Message">{str}</span>, highlightGroup);
} }
// TODO: resize upon a window resize /**
* Display a multiline message, possible through a "more" like interface
*
* TODO: resize upon a window resize
*
* @param {string} str
* @param {string} highlightGroup
*/
function echoMultiline(str, highlightGroup) function echoMultiline(str, highlightGroup)
{ {
let doc = multilineOutputWidget.contentDocument; let doc = multilineOutputWidget.contentDocument;
@@ -560,11 +633,10 @@ function CommandLine() //{{{
liberator.triggerObserver("echoMultiline", str, highlightGroup); liberator.triggerObserver("echoMultiline", str, highlightGroup);
/* If it's already XML, assume it knows what it's doing. // If it's already XML, assume it knows what it's doing.
* Otherwise, white space is significant. // Otherwise, white space is significant.
* The problem elsewhere is that E4X tends to insert new lines // The problem elsewhere is that E4X tends to insert new lines
* after interpolated data. // after interpolated data.
*/
XML.ignoreWhitespace = typeof str != "xml"; XML.ignoreWhitespace = typeof str != "xml";
lastMowOutput = <div class="ex-command-output" style="white-space: nowrap" highlight={highlightGroup}>{template.maybeXML(str)}</div>; lastMowOutput = <div class="ex-command-output" style="white-space: nowrap" highlight={highlightGroup}>{template.maybeXML(str)}</div>;
let output = util.xmlToDom(lastMowOutput, doc); let output = util.xmlToDom(lastMowOutput, doc);
@@ -598,6 +670,10 @@ function CommandLine() //{{{
commandline.updateMorePrompt(); commandline.updateMorePrompt();
} }
/**
* @private - ensure that the Multiline input widget is the
* correct size.
*/
function autosizeMultilineInputWidget() function autosizeMultilineInputWidget()
{ {
let lines = multilineInputWidget.value.split("\n").length - 1; let lines = multilineInputWidget.value.split("\n").length - 1;
@@ -605,7 +681,16 @@ function CommandLine() //{{{
multilineInputWidget.setAttribute("rows", Math.max(lines, 1)); multilineInputWidget.setAttribute("rows", Math.max(lines, 1));
} }
// used for the :echo[err] commands /**
* @private - eval()s a javascript expression
* and returns a string suitable to be echo'd.
*
* If useColor is true, util.objectToString will
* colorize object output.
*
* @param {string} arg
* @param {boolean} useColor
*/
function echoArgumentToString(arg, useColor) function echoArgumentToString(arg, useColor)
{ {
if (!arg) if (!arg)
@@ -885,6 +970,9 @@ function CommandLine() //{{{
storage.styles.removeSheet(true, "silent-mode"); storage.styles.removeSheet(true, "silent-mode");
}, },
/**
* XXX: This function is not used!
*/
runSilently: function (fn, self) runSilently: function (fn, self)
{ {
let wasSilent = this.silent; let wasSilent = this.silent;
@@ -912,6 +1000,16 @@ function CommandLine() //{{{
get message() messageBox.value, get message() messageBox.value,
/**
* Changes the command line to display the following prompt (usually ":")
* followed by the command, in the given mode. Valid modes are
* attributes of the "modes" variable, and modes.EX is probably
* a good choice.
*
* @param {string} prompt
* @param {string} cmd
* @param {number} mode
*/
open: function open(prompt, cmd, extendedMode) open: function open(prompt, cmd, extendedMode)
{ {
// save the current prompts, we need it later if the command widget // save the current prompts, we need it later if the command widget
@@ -936,7 +1034,11 @@ function CommandLine() //{{{
liberator.triggerCallback("change", currentExtendedMode, cmd); liberator.triggerCallback("change", currentExtendedMode, cmd);
}, },
// normally used when pressing esc, does not execute a command /**
* Removes any input from the command line, without executing its
* contents. Removes any "More" windows or other such output.
* Pressing <ESC> in EX mode normally has this effect.
*/
close: function close() close: function close()
{ {
let mode = currentExtendedMode; let mode = currentExtendedMode;
@@ -946,6 +1048,7 @@ function CommandLine() //{{{
if (history) if (history)
history.save(); history.save();
this.resetCompletions(); // cancels any asynchronous completion still going on, must be before completions = null
completions = null; completions = null;
history = null; history = null;
@@ -969,14 +1072,33 @@ function CommandLine() //{{{
keepCommand = false; keepCommand = false;
}, },
/**
* Hide any auto-completion/More-ing that is happening.
*/
hide: function hide() hide: function hide()
{ {
commandlineWidget.collapsed = true; commandlineWidget.collapsed = true;
}, },
// liberator.echo uses different order of flags as it omits the hightlight group, change v.commandline.echo argument order? --mst /**
* Output the given string onto the command line coloured
* using the rules according to highlightGroup. If not
* given higlightGroup defaults to commandline.HL_NORMAL
* and other possibe values are at commandline.HL_[A-Z]*.
*
* Flags can be any of:
* commandline.APPEND_TO_MESSAGES (causes message to be added to the messagesHistory)
* commandline.FORCE_SINGLELINE | commandline.DISALLOW_MULTILINE
* commandline.FORCE_MULTILINE
*
* @param {string} str
* @param {string} highlightGroup
* @param {number} flags
*/
echo: function echo(str, highlightGroup, flags) echo: function echo(str, highlightGroup, flags)
{ {
// liberator.echo uses different order of flags as it omits the highlight group, change v.commandline.echo argument order? --mst
if (silent) if (silent)
return false; return false;
@@ -1021,8 +1143,23 @@ function CommandLine() //{{{
return true; return true;
}, },
// this will prompt the user for a string /**
// commandline.input("(s)ave or (o)pen the file?") * Prompt the user for a string and execute the given
* callback with that as the only argument on <CR>
* extra can have any of the following attributes:
*
* onChange: A function to be called with the current input every time it changes
* completer: A function called with a ?context? when the user tries to tabcomplete
* promptHighlight: The HighlightGroup to use (default commandline.HL_QUESTION, others
* can be found at commandline.HL_[A-Z]*)
*
* This function sets the mode to modes.COMMAND_LINE, and thus popping the mode will
* stop further input from being waited for (useful for stopping onChange)
*
* @param {string} prompt
* @param {function(string)} callback
* @param {Object} extra
*/
input: function input(prompt, callback, extra) input: function input(prompt, callback, extra)
{ {
extra = extra || {}; extra = extra || {};
@@ -1042,8 +1179,14 @@ function CommandLine() //{{{
completions = Completions(commandWidget.inputField); completions = Completions(commandWidget.inputField);
}, },
// reads a multi line input and returns the string once the last line matches /**
// @param untilRegexp * Get a multiline input from a user, up to but not including
* the line which matches the given regular expression. Then
* execute the callback with that string as a parameter.
*
* @param {RegExp} untilRegexp
* @param {function(string)} callbackFunc
*/
inputMultiline: function inputMultiline(untilRegexp, callbackFunc) inputMultiline: function inputMultiline(untilRegexp, callbackFunc)
{ {
// Kludge. // Kludge.
@@ -1063,6 +1206,13 @@ function CommandLine() //{{{
setTimeout(function () { multilineInputWidget.focus(); }, 10); setTimeout(function () { multilineInputWidget.focus(); }, 10);
}, },
/**
* Handle events, the come from liberator when liberator.mode = modes.COMMAND_LINE
* but also takes blur/focus/input events raw from #liberator-commandline-command
* in the XUL
*
* @param {Event} event
*/
onEvent: function onEvent(event) onEvent: function onEvent(event)
{ {
let command = this.command; let command = this.command;
@@ -1085,7 +1235,7 @@ function CommandLine() //{{{
} }
else if (event.type == "input") else if (event.type == "input")
{ {
this.resetCompletions(); //this.resetCompletions(); -> already handled by "keypress" below (hopefully), so don't do it twice
liberator.triggerCallback("change", currentExtendedMode, command); liberator.triggerCallback("change", currentExtendedMode, command);
} }
else if (event.type == "keypress") else if (event.type == "keypress")
@@ -1150,11 +1300,18 @@ function CommandLine() //{{{
} }
else if (event.type == "keyup") else if (event.type == "keyup")
{ {
let key = events.toString(event);
if (key == "<Tab>" || key == "<S-Tab>") if (key == "<Tab>" || key == "<S-Tab>")
tabTimer.flush(); tabTimer.flush();
} }
}, },
/**
* Multiline input events, they will come straight from
* #liberator-multiline-input in the XUL.
*
* @param {Event} event
*/
onMultilineInputEvent: function onMultilineInputEvent(event) onMultilineInputEvent: function onMultilineInputEvent(event)
{ {
if (event.type == "keypress") if (event.type == "keypress")
@@ -1189,8 +1346,16 @@ function CommandLine() //{{{
return true; return true;
}, },
// FIXME: if 'more' is set and the MOW is not scrollable we should still /**
// allow a down motion after an up rather than closing * Handle events when we are in multiline output mode,
* these come from liberator when modes.extended & modes.MULTILINE_OUTPUT
* and also from #liberator-multiline-output in the XUL
*
* FIXME: if 'more' is set and the MOW is not scrollable we should still
* allow a down motion after an up rather than closing
*
* @param {Event} event
*/
onMultilineOutputEvent: function onMultilineOutputEvent(event) onMultilineOutputEvent: function onMultilineOutputEvent(event)
{ {
let win = multilineOutputWidget.contentWindow; let win = multilineOutputWidget.contentWindow;
@@ -1298,7 +1463,7 @@ function CommandLine() //{{{
} }
break; break;
// let firefox handle those to select table cells or show a context menu // let Firefox handle those to select table cells or show a context menu
case "<C-LeftMouse>": case "<C-LeftMouse>":
case "<RightMouse>": case "<RightMouse>":
case "<C-S-LeftMouse>": case "<C-S-LeftMouse>":
@@ -1400,6 +1565,15 @@ function CommandLine() //{{{
} }
}, },
/**
* Refresh or remove the prompt that displays when in multiline mode.
* showHelp will cause the possible key-options to be displayed,
* force will cause a display of the default message even if it
* could be at the end of the output.
*
* @param {boolean} force
* @param {boolean} showHelp
*/
updateMorePrompt: function updateMorePrompt(force, showHelp) updateMorePrompt: function updateMorePrompt(force, showHelp)
{ {
if (outputContainer.collapsed) if (outputContainer.collapsed)
@@ -1417,6 +1591,14 @@ function CommandLine() //{{{
echoLine("Press ENTER or type command to continue", this.HL_QUESTION, true); echoLine("Press ENTER or type command to continue", this.HL_QUESTION, true);
}, },
/**
* Changes the height of the multilineOutputWidget to fit
* its contents, if <b>open</b> is true, it will cause the
* widget to uncollapse, if not it will leave the widget
* closed.
*
* @param {boolean} open
*/
updateOutputHeight: function updateOutputHeight(open) updateOutputHeight: function updateOutputHeight(open)
{ {
if (!open && outputContainer.collapsed) if (!open && outputContainer.collapsed)
@@ -1439,11 +1621,18 @@ function CommandLine() //{{{
outputContainer.collapsed = false; outputContainer.collapsed = false;
}, },
/**
* Disable any active completion functions by calling their cancelFunc's
* Will also remove the completions preview window.
*/
resetCompletions: function resetCompletions() resetCompletions: function resetCompletions()
{ {
autocompleteTimer.reset(); autocompleteTimer.reset();
// liberator.dump("Resetting completions...");
if (completions) if (completions)
{ {
completions.context.cancelAll();
completions.wildIndex = -1; completions.wildIndex = -1;
completions.previewClear(); completions.previewClear();
} }
@@ -1457,9 +1646,9 @@ function CommandLine() //{{{
/** /**
* The list which is used for the completion box (and QuickFix window in future) * The list which is used for the completion box (and QuickFix window in future)
* *
* @param id: the id of the the XUL <iframe> which we want to fill * @param {string} id The id of the XUL <iframe> which we want to fill it
* it MUST be inside a <vbox> (or any other html element, * MUST be inside a <vbox> (or any other html element, because otherwise
* because otherwise setting the height does not work properly * setting the height does not work properly
*/ */
function ItemList(id) //{{{ function ItemList(id) //{{{
{ {
@@ -1505,7 +1694,7 @@ function ItemList(id) //{{{
minHeight = Math.max(minHeight, divNodes.completions.getBoundingClientRect().bottom); minHeight = Math.max(minHeight, divNodes.completions.getBoundingClientRect().bottom);
container.height = minHeight; container.height = minHeight;
if (container.collapsed) if (container.collapsed)
div.style.minWidth = undefined; div.style.minWidth = "";
// FIXME: Belongs elsewhere. // FIXME: Belongs elsewhere.
commandline.updateOutputHeight(false); commandline.updateOutputHeight(false);
} }
@@ -1550,10 +1739,10 @@ function ItemList(id) //{{{
} }
/** /**
* uses the entries in "items" to fill the listbox * Uses the entries in "items" to fill the listbox and
* does incremental filling to speed up things * does incremental filling to speed up things.
* *
* @param offset: start at this index and show maxItems * @param {number} offset Start at this index and show maxItems
*/ */
function fill(offset) function fill(offset)
{ {
@@ -1671,7 +1860,7 @@ function ItemList(id) //{{{
// select index, refill list if necessary // select index, refill list if necessary
selectItem: function selectItem(index) selectItem: function selectItem(index)
{ {
//if (container.collapsed) // fixme //if (container.collapsed) // FIXME
// return; // return;
//let now = Date.now(); //let now = Date.now();
@@ -1773,6 +1962,14 @@ function StatusLine() //{{{
return { return {
/**
* Update the status bar to indicate how secure the website is
* secure => https:// with valid certificate
* broken => https:// with invalid certificate
* insecure => http://
*
* @param {'secure'|'broken'|'insecure'} type
*/
setClass: function setClass(type) setClass: function setClass(type)
{ {
const highlightGroup = { const highlightGroup = {
@@ -1794,7 +1991,14 @@ function StatusLine() //{{{
this.updateBufferPosition(); this.updateBufferPosition();
}, },
// if "url" is ommited, build a usable string for the URL /**
* Update which URL is displayed on the status line,
* if url is omitted then buffer.URL is used instead and
* status icons [+-❤] are updated to match whether one can
* go back/forwards in history/have bookmarked the page.
*
* @param {string} url
*/
updateUrl: function updateUrl(url) updateUrl: function updateUrl(url)
{ {
if (typeof url == "string") if (typeof url == "string")
@@ -1805,7 +2009,7 @@ function StatusLine() //{{{
url = buffer.URL; url = buffer.URL;
// make it even more vim-like // make it even more Vim-like
if (url == "about:blank") if (url == "about:blank")
{ {
if (!buffer.title) if (!buffer.title)
@@ -1837,6 +2041,13 @@ function StatusLine() //{{{
urlWidget.value = url; urlWidget.value = url;
}, },
/**
* Set the contents of the status line's input buffer
* to the given string.
*
* Used for displaying partial key combinations in
* normal mode.
*/
updateInputBuffer: function updateInputBuffer(buffer) updateInputBuffer: function updateInputBuffer(buffer)
{ {
if (!buffer || typeof buffer != "string") if (!buffer || typeof buffer != "string")
@@ -1845,6 +2056,17 @@ function StatusLine() //{{{
inputBufferWidget.value = buffer; inputBufferWidget.value = buffer;
}, },
/**
* Update the display of the progress bar.
* If the parameter is a string, it will be
* displayed literally. Otherwise it must be a number
* less than one.
* Negative numbers cause a "Loading..." status,
* Positive (< 1) numbers cause an arrow ==> of length
* proportional to the arrow.
*
* @param {string|number} progress
*/
updateProgress: function updateProgress(progress) updateProgress: function updateProgress(progress)
{ {
if (!progress) if (!progress)
@@ -1872,7 +2094,13 @@ function StatusLine() //{{{
} }
}, },
// you can omit either of the 2 arguments /**
* Display the correct tabcount (e.g. [1/5]) on the status bar.
* If either parameter is omitted, they will be calculated.
*
* @param {number} currentIndex
* @param {number} totalTabs
*/
updateTabCount: function updateTabCount(currentIndex, totalTabs) updateTabCount: function updateTabCount(currentIndex, totalTabs)
{ {
if (!liberator.has("tabs")) if (!liberator.has("tabs"))
@@ -1897,7 +2125,16 @@ function StatusLine() //{{{
tabCountWidget.value = "[" + currentIndex + "/" + totalTabs + "]"; tabCountWidget.value = "[" + currentIndex + "/" + totalTabs + "]";
}, },
// percent is given between 0 and 1 /**
* Display the correct position on the status bar, if the
* percent parameter is omitted it will be calculated.
*
* Negative numbers are set to "All", Zero implies "Top"
* One or above is "Bot", and anything else is multiplied by
* a hundred and displayed as a percentage.
*
* @param {number} percent
*/
updateBufferPosition: function updateBufferPosition(percent) updateBufferPosition: function updateBufferPosition(percent)
{ {
if (!percent || typeof percent != "number") if (!percent || typeof percent != "number")

View File

@@ -57,15 +57,19 @@ const util = { //{{{
}, },
/** /**
* Flatten an array, such that all elements of the array are * Flattens an array, such that all elements of the array are
* joined into a single array: * joined into a single array:
* [["foo", ["bar"]], ["baz"], "quux"] -> ["foo", ["bar"], "baz", "quux"] * [["foo", ["bar"]], ["baz"], "quux"] -> ["foo", ["bar"], "baz", "quux"]
*
* @param {Array} ary
* @returns {Array}
*/ */
flatten: function flatten(ary) Array.concat.apply([], ary), flatten: function flatten(ary) Array.concat.apply([], ary),
/** /**
* Returns an Iterator for an array's values. * Returns an Iterator for an array's values.
* *
* @param {Array} ary
* @returns {Iterator(Object)} * @returns {Iterator(Object)}
*/ */
iterator: function iterator(ary) iterator: function iterator(ary)
@@ -76,8 +80,9 @@ const util = { //{{{
}, },
/** /**
* Returns an Iterator for the arrays indices and values. * Returns an Iterator for an array's indices and values.
* *
* @param {Array} ary
* @returns {Iterator([{number}, {Object}])} * @returns {Iterator([{number}, {Object}])}
*/ */
iterator2: function (ary) iterator2: function (ary)
@@ -94,6 +99,7 @@ const util = { //{{{
* *
* @param {Array} ary * @param {Array} ary
* @param {boolean} unsorted * @param {boolean} unsorted
* @returns {Array}
*/ */
uniq: function uniq(ary, unsorted) uniq: function uniq(ary, unsorted)
{ {
@@ -135,10 +141,10 @@ const util = { //{{{
/** /**
* Clips a string to a given length. If the input string is longer * Clips a string to a given length. If the input string is longer
* than <b>length</b>, an elipsis is appended. * than <b>length</b>, an ellipsis is appended.
* *
* @param {string} str * @param {string} str The string to truncate.
* @param {number} length * @param {number} length The length of the returned string.
* @returns {string} * @returns {string}
*/ */
clip: function clip(str, length) clip: function clip(str, length)
@@ -169,6 +175,13 @@ const util = { //{{{
return node.ownerDocument.defaultView.getComputedStyle(node, null); return node.ownerDocument.defaultView.getComputedStyle(node, null);
}, },
/**
* Copies a string to the system clipboard. If <b>verbose</b> is specified
* the copied string is also echoed to the command-line.
*
* @param {string} str
* @param {boolean} verbose
*/
copyToClipboard: function copyToClipboard(str, verbose) copyToClipboard: function copyToClipboard(str, verbose)
{ {
const clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); const clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
@@ -178,12 +191,26 @@ const util = { //{{{
liberator.echo("Yanked " + str, commandline.FORCE_SINGLELINE); liberator.echo("Yanked " + str, commandline.FORCE_SINGLELINE);
}, },
/**
* Converts any arbitrary string into an URI object.
*
* @param {string} str
* @returns {Object}
*/
// FIXME: newURI needed too?
createURI: function createURI(str) createURI: function createURI(str)
{ {
const fixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup); const fixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
return fixup.createFixupURI(str, fixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP); return fixup.createFixupURI(str, fixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP);
}, },
/**
* Converts HTML special characters in <b>str</b> to the equivalent HTML
* entities.
*
* @param {string} str
* @returns {string}
*/
escapeHTML: function escapeHTML(str) escapeHTML: function escapeHTML(str)
{ {
// XXX: the following code is _much_ slower than a simple .replace() // XXX: the following code is _much_ slower than a simple .replace()
@@ -195,11 +222,26 @@ const util = { //{{{
return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}, },
/**
* Escapes Regular Expression special characters in <b>str</b>.
*
* @param {string} str
* @returns {string}
*/
escapeRegex: function escapeRegex(str) escapeRegex: function escapeRegex(str)
{ {
return str.replace(/([\\{}()[\].?*+])/g, "\\$1"); return str.replace(/([\\{}()[\].?*+])/g, "\\$1");
}, },
/**
* Escapes quotes, newline and tab characters in <b>str</b>. The returned
* string is delimited by <b>delimiter</b> or " if <b>delimiter</b> is not
* specified.
*
* @param {string} str
* @param {string} delimiter
* @returns {string}
*/
escapeString: function escapeString(str, delimiter) escapeString: function escapeString(str, delimiter)
{ {
if (delimiter == undefined) if (delimiter == undefined)
@@ -207,11 +249,20 @@ const util = { //{{{
return delimiter + str.replace(/([\\'"])/g, "\\$1").replace("\n", "\\n", "g").replace("\t", "\\t", "g") + delimiter; return delimiter + str.replace(/([\\'"])/g, "\\$1").replace("\n", "\\n", "g").replace("\t", "\\t", "g") + delimiter;
}, },
formatBytes: function formatBytes(num, decimalPlaces, humanReadable) /**
* Converts <b>bytes</b> to a pretty printed data size string.
*
* @param {number} bytes The number of bytes.
* @param {string} decimalPlaces The number of decimal places to use if
* <b>humanReadable</b> is true.
* @param {boolean} humanReadable Use byte multiples.
* @returns {string}
*/
formatBytes: function formatBytes(bytes, decimalPlaces, humanReadable)
{ {
const unitVal = ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; const unitVal = ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
let unitIndex = 0; let unitIndex = 0;
let tmpNum = parseInt(num, 10) || 0; let tmpNum = parseInt(bytes, 10) || 0;
let strNum = [tmpNum + ""]; let strNum = [tmpNum + ""];
if (humanReadable) if (humanReadable)
@@ -242,33 +293,40 @@ const util = { //{{{
return strNum[0] + " " + unitVal[unitIndex]; return strNum[0] + " " + unitVal[unitIndex];
}, },
// generates an Asciidoc help entry, "command" can also be a mapping /**
generateHelp: function generateHelp(command, extraHelp) * Generates an Asciidoc help entry.
*
* @param {Object} obj A liberator <b>Command</b>, <b>Mapping</b> or
* <b>Option</b> object
* @param {string} extraHelp Extra help text beyond the description.
* @returns {string}
*/
generateHelp: function generateHelp(obj, extraHelp)
{ {
let start = "", end = ""; let start = "", end = "";
if (command instanceof liberator.Command) if (obj instanceof Command)
start = ":"; start = ":";
else if (command instanceof liberator.Option) else if (obj instanceof Option)
start = end = "'"; start = end = "'";
let ret = ""; let ret = "";
let longHelp = false; let longHelp = false;
if ((command.help && command.description) && (command.help.length + command.description.length) > 50) if ((obj.help && obj.description) && (obj.help.length + obj.description.length) > 50)
longHelp = true; longHelp = true;
// the tags which are printed on the top right // the tags which are printed on the top right
for (let j = command.names.length - 1; j >= 0; j--) for (let j = obj.names.length - 1; j >= 0; j--)
ret += "|" + start + command.names[j] + end + "| "; ret += "|" + start + obj.names[j] + end + "| ";
if (longHelp) if (longHelp)
ret += "+"; ret += "+";
ret += "\n"; ret += "\n";
// the usage information for the command // the usage information
let usage = command.names[0]; let usage = obj.names[0];
if (command.specs) // for :commands if (obj.specs) // for :commands
usage = command.specs[0]; usage = obj.specs[0];
usage = usage.replace(/{/, "\\\\{").replace(/}/, "\\\\}"); usage = usage.replace(/{/, "\\\\{").replace(/}/, "\\\\}");
usage = usage.replace(/'/, "\\'").replace(/`/, "\\`"); usage = usage.replace(/'/, "\\'").replace(/`/, "\\`");
@@ -279,9 +337,9 @@ const util = { //{{{
ret += "\n________________________________________________________________________________\n"; ret += "\n________________________________________________________________________________\n";
// the actual help text // the actual help text
if (command.description) if (obj.description)
{ {
ret += command.description + "."; // the help description ret += obj.description + "."; // the help description
if (extraHelp) if (extraHelp)
ret += " +\n" + extraHelp; ret += " +\n" + extraHelp;
} }
@@ -294,6 +352,16 @@ const util = { //{{{
return ret; return ret;
}, },
/**
* Sends a synchronous HTTP request to <b>url</b> and returns the
* XMLHttpRequest object. If <b>callback</b> is specified the request is
* asynchronous and the <b>callback</b> is invoked with the object as its
* argument.
*
* @param {string} url
* @param {function} callback
* @returns {Object}
*/
httpGet: function httpGet(url, callback) httpGet: function httpGet(url, callback)
{ {
try try
@@ -317,8 +385,21 @@ const util = { //{{{
} }
}, },
/**
* The identity function.
*
* @param {Object} k
* @returns {Object}
*/
identity: function identity(k) k, identity: function identity(k) k,
/**
* Returns the intersection of two rectangles.
*
* @param {Object} r1
* @param {Object} r2
* @returns {Object}
*/
intersection: function (r1, r2) ({ intersection: function (r1, r2) ({
get width() this.right - this.left, get width() this.right - this.left,
get height() this.bottom - this.top, get height() this.bottom - this.top,
@@ -328,6 +409,14 @@ const util = { //{{{
bottom: Math.min(r1.bottom, r2.bottom) bottom: Math.min(r1.bottom, r2.bottom)
}), }),
/**
* Returns the array that results from applying <b>fn</b> to each property
* of <b>obj</b>.
*
* @param {Object} obj
* @param {function} fn
* @returns {Array}
*/
map: function map(obj, fn) map: function map(obj, fn)
{ {
let ary = []; let ary = [];
@@ -336,20 +425,32 @@ const util = { //{{{
return ary; return ary;
}, },
newURI: function (url) /**
* Converts a URI string into an URI object.
*
* @param {string} uri
* @returns {Object}
*/
// FIXME: createURI needed too?
newURI: function (uri)
{ {
const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); return services.get("io").newURI(uri, null, null);
return ioService.newURI(url, null, null);
}, },
// if color = true it uses HTML markup to color certain items /**
* Pretty print a JavaScript object. Use HTML markup to color certain items
* if <b>color</b> is true.
*
* @param {Object} object The object to pretty print.
* @param {boolean} color Whether the output should be colored.
* @returns {string}
*/
objectToString: function objectToString(object, color) objectToString: function objectToString(object, color)
{ {
/* Use E4X literals so html is automatically quoted // Use E4X literals so html is automatically quoted
* only when it's asked for. Noone wants to see &lt; // only when it's asked for. Noone wants to see &lt;
* on their console or :map :foo in their buffer // on their console or :map :foo in their buffer
* when they expect :map <C-f> :foo. // when they expect :map <C-f> :foo.
*/
XML.prettyPrinting = false; XML.prettyPrinting = false;
XML.ignoreWhitespace = false; XML.ignoreWhitespace = false;
@@ -417,6 +518,15 @@ const util = { //{{{
return color ? string : [s for each (s in string)].join(""); return color ? string : [s for each (s in string)].join("");
}, },
/**
* A generator that returns the values between <b>start</b> and <b>end</b>.
* If <b>reverse</b> is true then the values are returned in reverse order.
*
* @param {number} start The interval's start value.
* @param {number} end The interval's end value.
* @param {boolean} reverse Reverse the order in which the values are produced.
* @returns {Iterator(Object)}
*/
range: function range(start, end, reverse) range: function range(start, end, reverse)
{ {
if (!reverse) if (!reverse)
@@ -431,7 +541,16 @@ const util = { //{{{
} }
}, },
interruptableRange: function interruptableRange(start, end, time) /**
* An interruptible generator that returns all values between <b>start</b>
* and <b>end</b>. The thread yields every <b>time</b> milliseconds.
*
* @param {number} start The interval's start value.
* @param {number} end The interval's end value.
* @param {number} time The time in milliseconds between thread yields.
* @returns {Iterator(Object)}
*/
interruptibleRange: function interruptibleRange(start, end, time)
{ {
let endTime = Date.now() + time; let endTime = Date.now() + time;
while (start < end) while (start < end)
@@ -445,15 +564,22 @@ const util = { //{{{
} }
}, },
// same as Firefox's readFromClipboard function, but needed for apps like Thunderbird /**
* Reads a string from the system clipboard.
*
* This is same as Firefox's readFromClipboard function, but is needed for
* apps like Thunderbird which do not provide it.
*
* @returns {string}
*/
readFromClipboard: function readFromClipboard() readFromClipboard: function readFromClipboard()
{ {
let url; let url;
try try
{ {
const clipboard = Cc['@mozilla.org/widget/clipboard;1'].getService(Ci.nsIClipboard); const clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
const transferable = Cc['@mozilla.org/widget/transferable;1'].createInstance(Ci.nsITransferable); const transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
transferable.addDataFlavor("text/unicode"); transferable.addDataFlavor("text/unicode");
@@ -478,11 +604,18 @@ const util = { //{{{
return url; return url;
}, },
// takes a string like 'google bla, www.osnews.com' /**
// and returns an array ['www.google.com/search?q=bla', 'www.osnews.com'] * Returns an array of URLs parsed from <b>str</b>.
*
* Given a string like 'google bla, www.osnews.com' return an array
* ['www.google.com/search?q=bla', 'www.osnews.com']
*
* @param {string} str
* @returns {Array}
*/
stringToURLArray: function stringToURLArray(str) stringToURLArray: function stringToURLArray(str)
{ {
let urls = str.split(RegExp("\s*" + options["urlseparator"] + "\s*")); let urls = str.split(RegExp("\\s*" + options["urlseparator"] + "\\s*"));
return urls.map(function (url) { return urls.map(function (url) {
try try
@@ -525,6 +658,14 @@ const util = { //{{{
}); });
}, },
/**
* Converts an E4X XML literal to a DOM node.
*
* @param {Node} node
* @param {Document} doc
* @param {Object} nodes
* @returns {Node}
*/
xmlToDom: function xmlToDom(node, doc, nodes) xmlToDom: function xmlToDom(node, doc, nodes)
{ {
XML.prettyPrinting = false; XML.prettyPrinting = false;

View File

@@ -34,6 +34,7 @@ const Ci = Components.interfaces;
const Cr = Components.results; const Cr = Components.results;
const Cu = Components.utils; const Cu = Components.utils;
// XXX: does not belong here
function Timer(minInterval, maxInterval, callback) function Timer(minInterval, maxInterval, callback)
{ {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
@@ -57,7 +58,7 @@ function Timer(minInterval, maxInterval, callback)
}; };
this.tell = function (arg) this.tell = function (arg)
{ {
if (arg !== undefined) if (arguments.length > 0)
this.arg = arg; this.arg = arg;
let now = Date.now(); let now = Date.now();

View File

@@ -31,7 +31,7 @@ const config = { //{{{
name: "Muttator", name: "Muttator",
hostApplication: "Thunderbird", // TODO: can this be found out otherwise? gBrandBundle.getString("brandShortName"); hostApplication: "Thunderbird", // TODO: can this be found out otherwise? gBrandBundle.getString("brandShortName");
/*** optional options, there are checked for existance and a fallback provided ***/ /*** optional options, there are checked for existence and a fallback provided ***/
features: ["hints", "mail", "marks", "addressbook", "tabs"], features: ["hints", "mail", "marks", "addressbook", "tabs"],
defaults: { guioptions: "frb" }, defaults: { guioptions: "frb" },

View File

@@ -588,14 +588,14 @@ function Mail() //{{{
if (mail.currentFolder.isServer) if (mail.currentFolder.isServer)
return liberator.beep(); return liberator.beep();
mail.currentFolder.markAllMessagesRead(); mail.currentFolder.markAllMessagesRead(msgWindow);
}); });
mappings.add(myModes, ["<C-t>"], mappings.add(myModes, ["<C-t>"],
"Mark all messages as read", "Mark all messages as read",
function () function ()
{ {
mail.getFolders("", false).forEach(function (folder) { folder.markAllMessagesRead(); }); mail.getFolders("", false).forEach(function (folder) { folder.markAllMessagesRead(msgWindow); });
}); });
// DISPLAY OPTIONS // DISPLAY OPTIONS
@@ -890,12 +890,13 @@ function Mail() //{{{
return false; return false;
}, },
/* /**
* general-purpose method to find messages * General-purpose method to find messages
* @param validatorFunc(msg): return true/false whether msg should be selected or not *
* @param canWrap: when true, wraps around folders * @param {function} validatorFunc(msg): return true/false whether msg should be selected or not
* @param openThreads: should we open closed threads? * @param {boolean} canWrap: when true, wraps around folders
* @param reverse: change direction of searching * @param {boolean} openThreads: should we open closed threads?
* @param {boolean} reverse: change direction of searching
*/ */
selectMessage: function (validatorFunc, canWrap, openThreads, reverse, count) selectMessage: function (validatorFunc, canWrap, openThreads, reverse, count)
{ {

View File

@@ -1,3 +1,7 @@
2009:
* Jonathan Austin
* Steven Romanow
2008: 2008:
* John Baber * John Baber
* Mark Orr * Mark Orr

View File

@@ -7,8 +7,7 @@
* IMPORTANT: Due to much improved autocompletion, changed default 'complete' option * IMPORTANT: Due to much improved autocompletion, changed default 'complete' option
value to 'sfl', listing intelligent Firefox location bar results. Removed possibility value to 'sfl', listing intelligent Firefox location bar results. Removed possibility
to use 'h' in 'complete'. to use 'h' in 'complete'.
* IMPORTANT: AlwaysHint modes were removed as they didn't make too * IMPORTANT: AlwaysHint mode with ;F mode changed the semantics slightly
much sense with the new hint system
* IMPORTANT: command actions now take an args object, returned from * IMPORTANT: command actions now take an args object, returned from
commands.parseArgs, as their first argument. This will break any commands commands.parseArgs, as their first argument. This will break any commands
not using the args parser explicitly. The old string value is now not using the args parser explicitly. The old string value is now

View File

@@ -3,7 +3,6 @@ Priority list:
BUGS: BUGS:
- add window resize support to hints - add window resize support to hints
- can't reverse tab through the vimperator toolbar
- searching backwards incrementally does not work i.e. with 'incsearch' set - searching backwards incrementally does not work i.e. with 'incsearch' set
- http://msdn2.microsoft.com/en-us/library/ms535258.aspx does not scroll with j/k/etc. - http://msdn2.microsoft.com/en-us/library/ms535258.aspx does not scroll with j/k/etc.
same for http://forum.mootools.net/topic.php?id=3458 and same for http://forum.mootools.net/topic.php?id=3458 and
@@ -22,7 +21,19 @@ BUGS:
(recent CVS regressions): (recent CVS regressions):
- visual caret mode is broken - visual caret mode is broken
- BookmarkAdd is fired once for each bookmark periodically i.e. not in response to adding a bookmark - the message system is a bit of a debacle at the moment but I'm not sure how
it's supposed to work. MST, can you spec it when you have some time?
E.g. :ls | :echomsg "Foobar" doesn't add "Foobar" to the already open MOW.
Obviously I think it should but I'm not sure if it's a bug or not in your
view, thanks. --djk
The spec is easy: echomsg() is used for informational purposes, and should therefore
never need user interaction. Therefore: If the MOW is open, print the message there,
but never open the MOW for an echomsg(). --mst
- While the old :open foo<tab> was broken/annoying, so is the one after 02-01-2008, as
I am often waiting ~20sec or more after doing :open not-cached-things<tab>.
We should probably just abort searching after 5 secs if we already have found some entries.
- :set noflashblock seems broken (= :set fb? afterwards says "fb"), let's see if that's a
plugin or a vimp issue.
FEATURES: FEATURES:
9 finish :help TODOs 9 finish :help TODOs
@@ -30,6 +41,15 @@ FEATURES:
9 adaptive timeout for auto-completions, :set completions can be updated more often than 9 adaptive timeout for auto-completions, :set completions can be updated more often than
:open foo :open foo
9 use the storage module for autocommands 9 use the storage module for autocommands
8 support 'activate' in buffer.followLink?
Leave this to the bookmarks.tabs.loadInBackground. Hint activation
should be nearly equivalent to the corresponding mouse motion, and that
mouse movement would be governed by the FF pref. However, :tabopen is
something Vimp specific, and so it needs a specific setting (i.e.,
activate). OTOH, I think it would be better if ";t" *always* opens a
new foreground tab and ";b" *always* opensa new background tab. So "F"
should be the only hint mode that changes based on loadInBackground.
--Ted
8 add support for filename special characters such as % 8 add support for filename special characters such as %
8 :redir and 'verbosefile' 8 :redir and 'verbosefile'
8 middleclick in content == p, and if command line is open, paste there the clipboard buffer 8 middleclick in content == p, and if command line is open, paste there the clipboard buffer
@@ -37,8 +57,10 @@ FEATURES:
8 :addsearch wikpedia http://en.wikipedia.org/wiki/Special:Search?search=%s to allow saving of 8 :addsearch wikpedia http://en.wikipedia.org/wiki/Special:Search?search=%s to allow saving of
quick searches in the RC file. quick searches in the RC file.
Why not just add a bookmark? --Kris Why not just add a bookmark? --Kris
7 adaptive learning for tab-completions This would require performance tests, how fast it is to add 20 keywords that way, as we need
(https://bugzilla.mozilla.org/show_bug.cgi?id=395739 could help) to search all existing bookmarks to see if the keyword is already defined, and then just update
that bookmark. --mst
8 allow for multiple ex commands separated with |
7 use ctrl-n/p in insert mode for word completion 7 use ctrl-n/p in insert mode for word completion
7 implement QuickFix window based on ItemList 7 implement QuickFix window based on ItemList
7 [ctrl-o/i] to Go back to a Previous Position (done partly, however currently does not use a per tab jumplist) 7 [ctrl-o/i] to Go back to a Previous Position (done partly, however currently does not use a per tab jumplist)
@@ -53,9 +75,10 @@ FEATURES:
6 support private mode (and :set [no]private): http://ehsanakhgari.org/blog/2008-11-08/prepare-your-add-private-browsing 6 support private mode (and :set [no]private): http://ehsanakhgari.org/blog/2008-11-08/prepare-your-add-private-browsing
6 add [count] support to :b* and :tab* commands where missing 6 add [count] support to :b* and :tab* commands where missing
6 registers 6 registers
6 allow for multiple ex commands separated with | Here, unlike Vim, y and "*y would be equivalent. That is, the pasteboard would
always be the default register. --Ted
6 check/correct spellings in insert mode with some mappings 6 check/correct spellings in insert mode with some mappings
6 add more autocommands (TabClose, TabOpen, TabChanged, DownloadPre/Post any more?) 6 add more autocommands (TabClose, TabOpen, TabChanged any more?)
6 jump to the next heading with ]h, next image ]i, previous textbox [t and so on 6 jump to the next heading with ]h, next image ]i, previous textbox [t and so on
6 :grep support (needs location list) 6 :grep support (needs location list)
6 use '' to jump between marks like vim 6 use '' to jump between marks like vim
@@ -68,12 +91,13 @@ FEATURES:
5 make a command to search within google search results 5 make a command to search within google search results
(http://gadelkareem.com/2007/01/28/using-google-ajax-api-as-an-array/) (http://gadelkareem.com/2007/01/28/using-google-ajax-api-as-an-array/)
maybe impossible, needs a per-site key from google maybe impossible, needs a per-site key from google
4 y and Y could maybe changed to, but probably not: Y, yy and yl=yank location, ys=yank selection,
yd=yank domain name, yt=yank title, yw=yank current word, yf=yank filename, (other things to yank?)
4 } { should jump to the next paragraph of the page (maybe impossible) 4 } { should jump to the next paragraph of the page (maybe impossible)
3 A format for 'guitablabel' and 'statusline' 3 A format for 'guitablabel' and 'statusline'
3 add a command-line window (:help cmdline-window in Vim). 3 add a command-line window (:help cmdline-window in Vim).
3 Splitting Windows with [:sp :vsp ctrl-w,s ctrl-w,v] and closing with [ctrl-w,q], moving with [ctrl-w,w or tab] 3 Splitting Windows with [:sp :vsp ctrl-w,s ctrl-w,v] and closing with [ctrl-w,q], moving with [ctrl-w,w or tab]
have a look into the split browser extension have a look into the split browser extension
1 Add information to liberator/HACKING file about testing and optimization
1 Document remote branches in liberator/HACKING
1 Reformat liberator/HACKING so that git diff can find sections and report changes @ somewhere
- many other ideas are listed in the wiki - many other ideas are listed in the wiki

View File

@@ -29,7 +29,7 @@ the terms of any one of the MPL, the GPL or the LGPL.
const DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png"; const DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png";
// Try to import older command line history, quick marks, etc. // Try to import older command line history, quick marks, etc.
liberator.registerObserver("load_options", function () { liberator.registerObserver("load", function () {
if (!options.getPref("extensions.vimperator.commandline_cmd_history")) if (!options.getPref("extensions.vimperator.commandline_cmd_history"))
return; return;
@@ -61,12 +61,20 @@ function Bookmarks() //{{{
const taggingService = PlacesUtils.tagging; const taggingService = PlacesUtils.tagging;
const faviconService = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService); const faviconService = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService);
// XXX for strange Firefox bug :(
// Error: [Exception... "Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIObserverService.addObserver]"
// nsresult: "0x8000ffff (NS_ERROR_UNEXPECTED)"
// location: "JS frame :: file://~firefox/components/nsTaggingService.js :: anonymous :: line 89"
// data: no]
// Source file: file://~firefox/components/nsTaggingService.js
taggingService.getTagsForURI(window.makeURI("http://mysterious.bug"), {});
const Bookmark = new Struct("url", "title", "icon", "keyword", "tags", "id"); const Bookmark = new Struct("url", "title", "icon", "keyword", "tags", "id");
const Keyword = new Struct("keyword", "title", "icon", "url"); const Keyword = new Struct("keyword", "title", "icon", "url");
Bookmark.defaultValue("icon", function () getFavicon(this.url)); Bookmark.defaultValue("icon", function () getFavicon(this.url));
Bookmark.prototype.__defineGetter__("extra", function () [ Bookmark.prototype.__defineGetter__("extra", function () [
['keyword', this.keyword, "Keyword"], ["keyword", this.keyword, "Keyword"],
['tags', this.tags.join(', '), "Tag"] ["tags", this.tags.join(", "), "Tag"]
].filter(function (item) item[1])); ].filter(function (item) item[1]));
const storage = modules.storage; const storage = modules.storage;
@@ -411,7 +419,7 @@ function Bookmarks() //{{{
get format() ({ get format() ({
anchored: false, anchored: false,
title: ["URL", "Info"], title: ["URL", "Info"],
keys: { text: "url", description: "title", icon: "icon", extra: "extra" }, keys: { text: "url", description: "title", icon: "icon", extra: "extra", tags: "tags" },
process: [template.icon, template.bookmarkDescription] process: [template.icon, template.bookmarkDescription]
}), }),
@@ -692,7 +700,7 @@ function History() //{{{
"Go back in the browser history", "Go back in the browser history",
function (args) function (args)
{ {
args = args.string; let url = args.literalArg;
if (args.bang) if (args.bang)
{ {
@@ -700,12 +708,12 @@ function History() //{{{
} }
else else
{ {
if (args) if (url)
{ {
let sh = window.getWebNavigation().sessionHistory; let sh = window.getWebNavigation().sessionHistory;
for (let i = sh.index - 1; i >= 0; i--) for (let i in util.range(sh.index, 0, true))
{ {
if (sh.getEntryAtIndex(i, false).URI.spec == args) if (sh.getEntryAtIndex(i, false).URI.spec == url)
{ {
window.getWebNavigation().gotoIndex(i); window.getWebNavigation().gotoIndex(i);
return; return;
@@ -715,7 +723,7 @@ function History() //{{{
} }
else else
{ {
history.stepTo(args.count > 0 ? -1 * args.count : -1); history.stepTo(-Math.max(args.count, 1));
} }
} }
}, },
@@ -738,7 +746,7 @@ function History() //{{{
"Go forward in the browser history", "Go forward in the browser history",
function (args) function (args)
{ {
args = args.string; let url = args.literalArg;
if (args.bang) if (args.bang)
{ {
@@ -746,12 +754,12 @@ function History() //{{{
} }
else else
{ {
if (args) if (url)
{ {
let sh = window.getWebNavigation().sessionHistory; let sh = window.getWebNavigation().sessionHistory;
for (let i in util.range(sh.index + 1, sh.count)) for (let i in util.range(sh.index + 1, sh.count))
{ {
if (sh.getEntryAtIndex(i, false).URI.spec == args) if (sh.getEntryAtIndex(i, false).URI.spec == url)
{ {
window.getWebNavigation().gotoIndex(i); window.getWebNavigation().gotoIndex(i);
return; return;
@@ -761,7 +769,7 @@ function History() //{{{
} }
else else
{ {
history.stepTo(args.count > 0 ? args.count : 1); history.stepTo(Math.max(args.count, 1));
} }
} }
}, },
@@ -837,31 +845,30 @@ function History() //{{{
if (index >= 0 && index < window.getWebNavigation().sessionHistory.count) if (index >= 0 && index < window.getWebNavigation().sessionHistory.count)
window.getWebNavigation().gotoIndex(index); window.getWebNavigation().gotoIndex(index);
else else
liberator.beep(); liberator.beep(); // XXX: really wanted?
}, },
goToStart: function goToStart() goToStart: function goToStart()
{ {
let index = window.getWebNavigation().sessionHistory.index; let index = window.getWebNavigation().sessionHistory.index;
if (index == 0)
{
liberator.beep(); // XXX: really wanted?
return;
}
window.getWebNavigation().gotoIndex(0); if (index > 0)
window.getWebNavigation().gotoIndex(0);
else
liberator.beep(); // XXX: really wanted?
}, },
goToEnd: function goToEnd() goToEnd: function goToEnd()
{ {
let index = window.getWebNavigation().sessionHistory.index; let sh = window.getWebNavigation().sessionHistory;
if (index == window.getWebNavigation().sessionHistory.count - 1) let max = sh.count - 1;
{
liberator.beep(); if (sh.index < max)
return; window.getWebNavigation().gotoIndex(max);
} else
liberator.beep(); // XXX: really wanted?
window.getWebNavigation().gotoIndex(max);
}, },
// if openItems is true, open the matching history items in tabs rather than display // if openItems is true, open the matching history items in tabs rather than display

View File

@@ -31,7 +31,7 @@ const config = { //{{{
name: "Vimperator", name: "Vimperator",
hostApplication: "Firefox", hostApplication: "Firefox",
/*** optional options, there are checked for existance and a fallback provided ***/ /*** optional options, there are checked for existence and a fallback provided ***/
features: ["bookmarks", "hints", "history", "marks", "quickmarks", "session", "tabs", "windows"], features: ["bookmarks", "hints", "history", "marks", "quickmarks", "session", "tabs", "windows"],
defaults: { guioptions: "rb" }, defaults: { guioptions: "rb" },
@@ -430,16 +430,12 @@ const config = { //{{{
{ {
setter: function (value) setter: function (value)
{ {
const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService2); const ioService = services.get("io");
ioService.offline = !value; ioService.offline = !value;
gPrefService.setBoolPref("browser.offline", ioService.offline); gPrefService.setBoolPref("browser.offline", ioService.offline);
return value; return value;
}, },
getter: function () getter: function () !services.get("io").offline
{
const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService2);
return ioService.offline;
}
}); });
options.add(["titlestring"], options.add(["titlestring"],

File diff suppressed because one or more lines are too long

View File

@@ -57,18 +57,18 @@ ________________________________________________________________________________
|:doautoa| |:doautoall| |:doautoa| |:doautoall|
||:doautoa[ll] {event} [url]|| + ||:doautoa[ll] {event} [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Apply the autocommands matching the specified URL to all buffers. If no [url] Apply the autocommands matching the specified URL to all buffers. If no
is specified use the current URL. [a][url][a] is specified use the current URL.
________________________________________________________________________________ ________________________________________________________________________________
|:do| |:doautocmd| |:do| |:doautocmd|
||:do[autocmd] {event} [url]|| + ||:do[autocmd] {event} [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Apply the autocommands matching the specified URL to the current buffer. If no Apply the autocommands matching the specified URL to the current buffer. If no
[url] is specified use the current URL. [a][url][a] is specified use the current URL.
________________________________________________________________________________ ________________________________________________________________________________
section:Examples[autocmd-examples] section:Examples[autocmd-examples]

View File

@@ -30,29 +30,31 @@ ________________________________________________________________________________
section:Opening{nbsp}web{nbsp}pages[opening] section:Opening{nbsp}web{nbsp}pages[opening]
|o| |:o| |:open| |o| |:o| |:open|
||:o[pen][!] [arg1], [arg2], ...|| + ||:o[pen][!] [a][arg1][a], [a][arg2][a], ...|| +
||o|| ||o||
________________________________________________________________________________ ________________________________________________________________________________
Open one or more URLs in the current tab. Open one or more URLs in the current tab.
Multiple URLs can be separated with 'urlseparator' (default: ", " Note that the Multiple URLs can be separated with 'urlseparator' (default: ", " Note that the
space after the comma is required.") space after the comma is required.")
The first URL is opened in the current tab, and all other URLs are
opened in new tabs.
Each token is analyzed and in this order: Each token is analyzed and in this order:
1. Opened as a local file if it is an existing relative or absolute filename. . Opened as a local file if it is an existing relative or absolute filename.
- [c]:open /etc/fstab[c] shows the file system table. * [c]:open /etc/fstab[c] shows the file system table.
- [c]:open ../other/foo.html[c] in your home directory opens * [c]:open ../other/foo.html[c] in your home directory opens
[a]/home/other/foo.html[a] [a]/home/other/foo.html[a]
2. Opened with the specified search engine if the token looks like a search . Opened with the specified search engine if the token looks like a search
string and the first word is the name of a search engine ([c]:open wikipedia string and the first word is the name of a search engine ([c]:open wikipedia
linus torvalds[c] opens the Wikipedia entry for linus torvalds). The short linus torvalds[c] opens the Wikipedia entry for linus torvalds). The short
name of a search engine is automatically guessed from its name. If you want name of a search engine is automatically guessed from its name. If you want
to set a custom name, you can change it with [c]:dialog searchengines[c]. to set a custom name, you can change it with [c]:dialog searchengines[c].
3. Opened with the default search engine or keyword (specified with the . Opened with the default search engine or keyword (specified with the
'defsearch' option) if the first word is no search engine ([c]:open linus 'defsearch' option) if the first word is no search engine ([c]:open linus
torvalds[c] opens a Google search for linux torvalds). torvalds[c] opens a Google search for linux torvalds).
4. Passed directly to Firefox in all other cases ([c]:open www.osnews.com, . Passed directly to Firefox in all other cases ([c]:open www.osnews.com,
www.slashdot.org[c] opens OSNews in the current, and Slashdot in a new www.slashdot.org[c] opens OSNews in the current, and Slashdot in a new
background tab). background tab).
You can use [c]:open -tags linux torvalds<Tab>[c] to complete bookmarks with You can use [c]:open -tags linux torvalds<Tab>[c] to complete bookmarks with
tag "linux" and which contain "torvalds". Note that -tags support is only tag "linux" and which contain "torvalds". Note that -tags support is only
@@ -65,19 +67,18 @@ ________________________________________________________________________________
|t| |:t| |:tabopen| |:tabnew| |:tabe| |:tabedit| |t| |:t| |:tabopen| |:tabnew| |:tabe| |:tabedit|
||:tabopen[!] [arg1], [arg2], ...|| + ||:tabopen[!] [a][arg1][a], [a][arg2][a], ...|| +
||t|| ||t||
________________________________________________________________________________ ________________________________________________________________________________
Just like [c]:open[c], but opens the resulting web page(s) Just like [c]:open[c], but also uses a new tab for the first URL. When
in a new tab. When used with [!], the 'tabopen' value of the 'activate' option used with [!], the 'tabopen' value of the 'activate' option is negated.
is negated.
________________________________________________________________________________ ________________________________________________________________________________
|T| + |T| +
||T|| ||T||
________________________________________________________________________________ ________________________________________________________________________________
Open one or more URLs in a new tab, based on current location. Works like Open one or more URLs in a new tab based on current location. Works like
[m]t[m], but preselects current URL in the [c]:tabopen[c] query. [m]t[m], but preselects current URL in the [c]:tabopen[c] query.
________________________________________________________________________________ ________________________________________________________________________________
@@ -94,16 +95,15 @@ ________________________________________________________________________________
|O| + |O| +
||O|| ||O||
________________________________________________________________________________ ________________________________________________________________________________
Open one or more URLs in the current tab, based on current location. Works Open one or more URLs in the current tab based on current location. Works
like [m]o[m], but preselects current URL in the [c]:open[c] query. like [m]o[m], but preselects current URL in the [c]:open[c] query.
________________________________________________________________________________ ________________________________________________________________________________
|:winopen| |:wopen| |:winedit| |:winopen| |:wopen| |:winedit|
||:wino[pen][!] [arg1], [arg2], ...|| + ||:wino[pen][!] [a][arg1][a], [a][arg2][a], ...|| +
________________________________________________________________________________ ________________________________________________________________________________
Just like help::open[browsing.html#opening], but opens the resulting web page(s) Just like [c]:tabopen[c], but opens the resulting web page(s) in a new window.
in a new window.
________________________________________________________________________________ ________________________________________________________________________________
@@ -274,11 +274,10 @@ ________________________________________________________________________________
section:Writing[writing,save-file] section:Writing[writing,save-file]
|:w| |:write| |:sav| |:saveas| + |:w| |:write| |:sav| |:saveas| +
||:sav[eas][!] [file]|| ||:sav[eas][!] [a][file][a]||
________________________________________________________________________________ ________________________________________________________________________________
Save current web page to disk. If [file] is omitted, save to the page's Save current web page to disk. If [a][file][a] is omitted, save to the page's
default filename. Existing documents will only be overwritten if [!] is default filename. Existing documents will only be overwritten if [!] is given.
given.
________________________________________________________________________________ ________________________________________________________________________________
section:Quitting[quitting,save-session] section:Quitting[quitting,save-session]

View File

@@ -10,7 +10,7 @@ section:Buffer{nbsp}information[buffer-information]
|<C-g>| + |<C-g>| +
||<C-g>|| ||<C-g>||
________________________________________________________________________________ ________________________________________________________________________________
Print the current file name. Also shows some additional file information like Print the current file name. Also shows some additional file information like
file size or the last modified date. file size or the last modified date.
________________________________________________________________________________ ________________________________________________________________________________
@@ -47,10 +47,10 @@ ________________________________________________________________________________
|:vie| |:viewsource| |:vie| |:viewsource|
||:vie[wsource][!] [url]|| + ||:vie[wsource][!] [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
View source code of current document. If [url] is specified then view the View source code of current document. If [a][url][a] is specified then view the
source of that document. When [!] is given, it is opened with the external source of that document. When [!] is given, it is opened with the external
editor. editor.
________________________________________________________________________________ ________________________________________________________________________________
@@ -97,24 +97,29 @@ ________________________________________________________________________________
|<Left>| |h| + |<Left>| |h| +
||[count]h|| ||[count]h||
________________________________________________________________________________ ________________________________________________________________________________
Scroll document to the left. Count is supported: [m]10h[m] will move 10 times as much to the left. + Scroll document to the left. If [count] is specified then move [count] times as
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is set). much to the left. +
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is
set).
________________________________________________________________________________ ________________________________________________________________________________
|<C-e>| |<Down>| |j| + |<C-e>| |<Down>| |j| +
||[count]j|| ||[count]j||
________________________________________________________________________________ ________________________________________________________________________________
Scroll document down. Count is supported: [m]10j[m] will move 10 times as much down. + Scroll document down. If [count] is specified then move [count] times as much
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is set). down. +
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is
set).
________________________________________________________________________________ ________________________________________________________________________________
|<C-y>| |<Up>| |k| + |<C-y>| |<Up>| |k| +
||[count]k|| ||[count]k||
________________________________________________________________________________ ________________________________________________________________________________
Scroll document up. Count is supported: [m]10k[m] will move 10 times as much up. + Scroll document up. If [count] is specified then move [count] times as much up. +
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is set). If the document cannot scroll more, a beep is emitted (unless 'visualbell' is
set).
________________________________________________________________________________ ________________________________________________________________________________
@@ -139,8 +144,10 @@ ________________________________________________________________________________
|<Right>| |l| + |<Right>| |l| +
||[count]l|| ||[count]l||
________________________________________________________________________________ ________________________________________________________________________________
Scroll document to the right. Count is supported: [m]10l[m] will move 10 times as much to the right. + Scroll document to the right. If [count] is specified then move [count] times
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is set). as much to the right. +
If the document cannot scroll more, a beep is emitted (unless 'visualbell' is
set).
________________________________________________________________________________ ________________________________________________________________________________
@@ -217,11 +224,11 @@ ________________________________________________________________________________
section:Zooming[zooming,zoom] section:Zooming[zooming,zoom]
The zooming commands are dependent on two properties - a zoom range and a The zooming commands are dependent on two properties -- a zoom range and a
series of levels within that range. series of levels within that range.
The absolute value of the page zoom is limited to a value within the configured The absolute value of the page zoom is limited to a value within the configured
zoom range (default: 30% - 300%). The zoom levels are used by zoom range (default: 30%--300%). The zoom levels are used by
[m]zi[m]/[m]zo[m], and similar commands, to change the zoom value in steps. The [m]zi[m]/[m]zo[m], and similar commands, to change the zoom value in steps. The
default zoom levels are 30%, 50%, 67%, 80%, 90%, 100%, 110%, 120%, 133%, 150%, default zoom levels are 30%, 50%, 67%, 80%, 90%, 100%, 110%, 120%, 133%, 150%,
170%, 200%, 240%, 300%. 170%, 200%, 240%, 300%.
@@ -306,12 +313,12 @@ ________________________________________________________________________________
|:zo| |:zoom| |:zo| |:zoom|
||:zo[om][!] [value]|| + ||:zo[om][!] [a][value][a]|| +
||:zo[om][!] +{value} | -{value}|| + ||:zo[om][!] +{value} | -{value}|| +
________________________________________________________________________________ ________________________________________________________________________________
Set zoom value of current web page. [value] can be an absolute value between 30 Set zoom value of current web page. [a][value][a] can be an absolute value
and 300% or a relative value if prefixed with "-" or "+". If [value] is between 30 and 300% or a relative value if prefixed with "-" or "+". If
omitted, zoom is reset to 100%. [a][value][a] is omitted, zoom is reset to 100%.
Normally this command operates on the text zoom, if used with [!] it operates Normally this command operates on the text zoom, if used with [!] it operates
on full zoom. on full zoom.
@@ -339,14 +346,14 @@ ________________________________________________________________________________
section:Alternate{nbsp}style{nbsp}sheets[alternate-stylesheet] section:Alternate{nbsp}style{nbsp}sheets[alternate-stylesheet]
Page authors may specify alternate style sheets for an HTML document. Users Page authors may specify alternate style sheets for an HTML document. Users can
can then switch between these various style sheets, selecting their favorite. then switch between these various style sheets, selecting their favorite.
|:pagest| |:pagestyle| |:pagest| |:pagestyle|
||:pagest[yle] [stylesheet]|| + ||:pagest[yle] [a][stylesheet][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Select the author style sheet to apply. If [stylesheet] is not specified the Select the author style sheet to apply. If [a][stylesheet][a] is not specified
page's default style sheet is used. the page's default style sheet is used.
All author styling can be removed by setting the 'usermode' option. All author styling can be removed by setting the 'usermode' option.
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -66,7 +66,7 @@ section:Command-line{nbsp}completion[cmdline-completion]
||<Tab>|| ||<Tab>||
________________________________________________________________________________ ________________________________________________________________________________
Complete the word in front of the cursor according to the behavior specified in Complete the word in front of the cursor according to the behavior specified in
'wildmode'. If 'wildmode' contains "list" and there are multiple matches then 'wildmode'. If 'wildmode' contains "list" and there are multiple matches then
the completion menu window is opened. the completion menu window is opened.
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -8,7 +8,7 @@ http://www.methods.co.nz/asciidoc/index.html[asciidoc] version 8.x or
newer. The are placed in the _src/locale/en-US/_ directory and compiled with newer. The are placed in the _src/locale/en-US/_ directory and compiled with
_make doc_. Please refer to the _make doc_. Please refer to the
http://www.methods.co.nz/asciidoc/userguide.html[asciidoc documentation] above http://www.methods.co.nz/asciidoc/userguide.html[asciidoc documentation] above
for details. Usually you can just write text as is, and mostly it will be for details. Usually you can just write text as is, and mostly it will be
interpreted correctly. The only difficult part is to write special sections interpreted correctly. The only difficult part is to write special sections
like for help::help[various.html#online-help]. like for help::help[various.html#online-help].
@@ -53,10 +53,11 @@ Some notes about the code above:
- The actual help code for this command is embedded in at least 4 underscores - The actual help code for this command is embedded in at least 4 underscores
(_). This generates a quoteblock and indents the text so it is more clear (_). This generates a quoteblock and indents the text so it is more clear
that it belongs to the command. that it belongs to the command.
- Wrap things in *$$[c]$$* and they are drawn like a :command. Also *$$[o]$$* - Wrap things in *$$[c]$$* and they are drawn like a :command. Also *$$[o]$$*,
and *$$[m]$$* are available to show options and mappings. *$$[m]$$* and *$$[a]$$* are available to markup options, mappings, and
- Any string within \{...\} and $$[arg]$$, $$[url]$$, $$[count]$$ and $$[!]$$ are arguments.
automatically drawn in a blue color. - As a convenience, any string within \{...\} and $$[count]$$ and $$[!]$$ are
automatically marked up as an argument.
There are also some additional asciidoc commands specifically for writing There are also some additional asciidoc commands specifically for writing
Vimperator documentation: Vimperator documentation:

View File

@@ -8,10 +8,9 @@ INTRO TO BE WRITTEN...
||:ec[ho] {expr}|| ||:ec[ho] {expr}||
________________________________________________________________________________ ________________________________________________________________________________
Echo the expression. Useful for showing informational messages. Multiple lines Echo the expression. Useful for showing informational messages. Multiple lines
can be separated by \n. {expr} can either be a quoted string, or any can be separated by \n. {expr} can either be a quoted string, or any expression
expression which can be fed to eval() like 4+5. You can also view the source which can be fed to eval() like 4+5. You can also view the source code of
code of objects and functions if the return value of {expr} is an object or objects and functions if the return value of {expr} is an object or function.
function.
________________________________________________________________________________ ________________________________________________________________________________
@@ -43,8 +42,8 @@ ________________________________________________________________________________
|:js| |:javas| |:javascript| |:js| |:javas| |:javascript|
||:javas[cript] \\{cmd\\}|| + ||:javas[cript] {cmd}|| +
||:javascript <<\\{endpattern\\}\n\\{script\\}\n\\{endpattern\\}|| + ||:javascript <<{endpattern}\n{empty}{script}\n{empty}{endpattern} || +
||:javascript[!]|| ||:javascript[!]||
________________________________________________________________________________ ________________________________________________________________________________
Run any JavaScript command through eval(). Acts as a JavaScript interpreter by Run any JavaScript command through eval(). Acts as a JavaScript interpreter by

View File

@@ -16,12 +16,9 @@ window.addEventListener("message", function (event) {
}, true); }, true);
document.addEventListener("click", function (event) { document.addEventListener("click", function (event) {
let elem = event.target; let evt = document.createEvent("UIEvents");
if (/^(option|mapping|command)$/.test(elem.className)) evt.initEvent("liberatorHelpLink", true, true);
var tag = elem.textContent.replace(/\s.*/, ""); event.target.dispatchEvent(evt);
if (elem.className == "command")
tag = tag.replace(/\[.*?\]/g, "");
if (tag)
elem.href = "chrome://liberator/content/help.xul?" + encodeURIComponent(tag);
}, true); }, true);
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -5,7 +5,7 @@ HEADER
INTRO TO BE WRITTEN... INTRO TO BE WRITTEN...
|f| + |f| +
||f\\{hint\\}|| ||#f#{hint}||
________________________________________________________________________________ ________________________________________________________________________________
Start QuickHint mode. In QuickHint mode, every hintable item (according to the Start QuickHint mode. In QuickHint mode, every hintable item (according to the
'hinttags' XPath query) is assigned a unique number. You can now either type 'hinttags' XPath query) is assigned a unique number. You can now either type
@@ -20,7 +20,7 @@ ________________________________________________________________________________
|F| + |F| +
||F\\{hint\\}|| ||#F#{hint}||
________________________________________________________________________________ ________________________________________________________________________________
Start QuickHint mode, but open link in a new tab. Like normal QuickHint mode Start QuickHint mode, but open link in a new tab. Like normal QuickHint mode
(activated with [m]f[m]) but opens the link in a new tab. (activated with [m]f[m]) but opens the link in a new tab.
@@ -30,33 +30,38 @@ ________________________________________________________________________________
|extended-hints| + |extended-hints| +
|;| + |;| +
||;\\{mode\\}\\{hint\\}|| ||#;#{mode}{empty}{hint}||
________________________________________________________________________________ ________________________________________________________________________________
Start an extended hint mode. ExtendedHint mode is useful, since in this mode Start an extended hint mode. ExtendedHint mode is useful, since in this mode
you can yank link locations, open them in a new window or save images. If you can yank link locations, open them in a new window or save images. If
you want to yank the location of hint [a]24[a], press [m];y[m] to start you want to yank the location of hint [a]24[a], press [m];y[m] to start
this hint mode. Then press [a]24[a] to copy the hint location. this hint mode. Then press [a]24[a] to copy the hint location.
{mode} can be either one of: + {mode} can be one of: +
* [m];[m] to focus a link and hover it with the mouse * |;;| [m];[m] to focus a link and hover it with the mouse
* [m]?[m] to show information about the element (incomplete) * |;?| [m]?[m] to show information about the element (incomplete)
* [m]a[m] to save its destination (prompting for save location) * |;s| [m]s[m] to save its destination
* [m]f[m] to focus a frame * |;a| [m]a[m] to save its destination (prompting for save location)
* [m]s[m] to save its destination * |;f| [m]f[m] to focus a frame
* [m]o[m] to open its location in the current tab * |;o| [m]o[m] to open its location in the current tab
* [m]t[m] to open its location in a new tab * |;t| [m]t[m] to open its location in a new tab
* [m]b[m] like [m]t[m] but inverts the option whether the tab is activated * |;b| [m]b[m] to open its location in a new background tab
* [m]O[m] to open its location in an [c]:open[c] query * |;w| [m]w[m] to open its destination in a new window
* [m]T[m] to open its location in a [c]:tabopen[c] query * |;F| [m]F[m] to follow a sequence of [m]<CR>[m]-delimited hints in background tabs
* [m]v[m] to view its destination source * |;O| [m]O[m] to preselect its location in an [c]:open[c] query
* [m]w[m] to open its destination in a new window * |;T| [m]T[m] to preselect its location in a [c]:tabopen[c] query
* [m]W[m] to open its location in a [c]:winopen[c] query * |;W| [m]W[m] to preselect its location in a [c]:winopen[c] query
* [m]y[m] to yank its destination location * |;v| [m]v[m] to view its destination source
* [m]Y[m] to yank its text description * |;V| [m]V[m] to view its destination source in the external editor
* |;y| [m]y[m] to yank its destination location
* |;Y| [m]Y[m] to yank its text description
Hintable elements for all extended hint modes can be set in the Hintable elements for all extended hint modes can be set in the
'extendedhinttags' XPath string. 'extendedhinttags' XPath string.
Note: The behavior of [m];t[m] and [m];b[m] is inverted if the
\'browser.tabs.loadInBackground' Firefox preference is set to false.
________________________________________________________________________________ ________________________________________________________________________________
// vim: set syntax=asciidoc: // vim: set syntax=asciidoc:

View File

@@ -259,7 +259,7 @@ section:Options[option-index]
||'cdpath'|| List of directories searched when executing :cd + ||'cdpath'|| List of directories searched when executing :cd +
||'complete'|| Items which are completed at the :[tab]open prompt + ||'complete'|| Items which are completed at the :[tab]open prompt +
||'defsearch'|| Set the default search engine + ||'defsearch'|| Set the default search engine +
||'disabledcssheets'|| Set disabled CSS stylesheets + ||'disabledcssheets'|| Set disabled CSS style sheets +
||'editor'|| Set the external text editor + ||'editor'|| Set the external text editor +
||'errorbells'|| Ring the bell when an error message is displayed + ||'errorbells'|| Ring the bell when an error message is displayed +
||'eventignore'|| List of autocommand event names which should be ignored + ||'eventignore'|| List of autocommand event names which should be ignored +

View File

@@ -38,7 +38,7 @@ more, you can either send me greetings, patches or make a donation:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Of course as a believer in free open source software, only make a donation Of course as a believer in free open source software, only make a donation
if you really like Vimperator and the money doesn't hurt - otherwise just use if you really like Vimperator and the money doesn't hurt -- otherwise just use
it, recommend it and like it :) it, recommend it and like it :)
section:Help{nbsp}topics[overview] section:Help{nbsp}topics[overview]

View File

@@ -5,8 +5,8 @@ Key mappings, abbreviations, and user-defined commands.
section:Key{nbsp}mapping[key-mapping,mapping,macro] section:Key{nbsp}mapping[key-mapping,mapping,macro]
The key mapping commands can be used to either redefine the standard key The key mapping commands can be used to either redefine the standard key
bindings or define new ones. A mapping consists of a key, or sequence of keys, bindings or define new ones. A mapping consists of a key, or sequence of keys,
which are translated to a string of characters. Example: which are translated to a string of characters. Example:
:map <F2> :echo new Date().toDateString()<CR> :map <F2> :echo new Date().toDateString()<CR>
@@ -20,7 +20,7 @@ Command-line modes.
|<Nop>| + |<Nop>| +
||<Nop>|| ||<Nop>||
________________________________________________________________________________ ________________________________________________________________________________
Do nothing. This command is useful for disabling a specific mapping. [c]:map Do nothing. This command is useful for disabling a specific mapping. [c]:map
<C-n> <Nop>[c] will prevent [m]<C-n>[m] from doing anything. <C-n> <Nop>[c] will prevent [m]<C-n>[m] from doing anything.
________________________________________________________________________________ ________________________________________________________________________________
@@ -28,9 +28,9 @@ ________________________________________________________________________________
|<CR>| |map_return| + |<CR>| |map_return| +
||<CR>|| ||<CR>||
________________________________________________________________________________ ________________________________________________________________________________
Expand to a line terminator in a key mapping. An Ex command in the {rhs} of a Expand to a line terminator in a key mapping. An Ex command in the {rhs} of a
mapping requires a a line terminator after it so that it is executed when the mapping requires a a line terminator after it so that it is executed when the
mapping is expanded. [m]<CR>[m] should be used for this purpose. mapping is expanded. [m]<CR>[m] should be used for this purpose.
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -15,7 +15,7 @@ Vimperator supports a number of different marks:
section:Bookmarks[bookmarks] section:Bookmarks[bookmarks]
|a| |:bma| |:bmark| |a| |:bma| |:bmark|
||:bma[rk][!] [-title=title] [-keyword=kw] [-tags=tag1,tag2] [url]|| + ||:bma[rk][!] [a][-title=title][a] [a][-keyword=kw][a] [a][-tags=tag1,tag2][a] [a][url][a]|| +
||a|| ||a||
____________________________________________________________________________ ____________________________________________________________________________
Add a bookmark. + Add a bookmark. +
@@ -27,12 +27,12 @@ The following options are interpreted:
- -keyword=keyword (short option: -k) - -keyword=keyword (short option: -k)
If [!] is present, a new bookmark is always added. Otherwise, the first If [!] is present, a new bookmark is always added. Otherwise, the first
bookmark matching [url] is updated. bookmark matching [a][url][a] is updated.
When creating a new bookmark, if [a][-title][a] isn't given, either the web When creating a new bookmark, if [a][-title][a] isn't given, either the web
page's title or URL is used. You can omit the optional [url] argument, so just page's title or URL is used. You can omit the optional [a][url][a] argument, so
do [c]:bmark[c] to bookmark the currently loaded web page with a default title just do [c]:bmark[c] to bookmark the currently loaded web page with a default
and without any tags. title and without any tags.
____________________________________________________________________________ ____________________________________________________________________________
@@ -47,10 +47,11 @@ ________________________________________________________________________________
|:bmarks| |:bmarks|
||:bmarks[!] [filter]|| + ||:bmarks[!] [a][filter][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
List or open multiple bookmarks. Open the message window at the bottom of the List or open multiple bookmarks. Open the message window at the bottom of the
screen with all bookmarks which match [filter] either in the title or URL. screen with all bookmarks which match [a][filter][a] either in the title or
URL.
The special version [c]:bmarks![c] works the same as [c]:bmarks[c] except it The special version [c]:bmarks![c] works the same as [c]:bmarks[c] except it
opens all the found bookmarks in new tabs. opens all the found bookmarks in new tabs.
@@ -62,10 +63,10 @@ ________________________________________________________________________________
|:delbm| |:delbmarks| |:delbm| |:delbmarks|
||:delbm[arks] [url]|| + ||:delbm[arks] [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Delete a bookmark. Deletes *all* bookmarks which match the [url]. Delete a bookmark. Deletes *all* bookmarks which match the [a][url][a]. If
If omitted, [url] defaults to the URL of the current buffer. Use [m]<Tab>[m] omitted, [a][url][a] defaults to the URL of the current buffer. Use [m]<Tab>[m]
key on a string to complete the URL which you want to delete. key on a string to complete the URL which you want to delete.
The following options WILL be interpreted in the future: The following options WILL be interpreted in the future:
@@ -94,40 +95,40 @@ ________________________________________________________________________________
|<M-Left>| |<A-Left>| |H| + |<M-Left>| |<A-Left>| |H| +
||[count]H|| ||[count]H||
________________________________________________________________________________ ________________________________________________________________________________
Go back in the browser history. Count is supported: [m]3H[m] goes back 3 steps. Go back in the browser history. If [count] is specified go back [count] pages.
________________________________________________________________________________ ________________________________________________________________________________
|<M-Right>| |<A-Right>| |L| + |<M-Right>| |<A-Right>| |L| +
||[count]L|| ||[count]L||
________________________________________________________________________________ ________________________________________________________________________________
Go forward in the browser history. Count is supported: [m]3L[m] goes forward 3 steps. Go forward in the browser history. If [count] is specified go forward [count]
pages.
________________________________________________________________________________ ________________________________________________________________________________
|:ba| |:back| |:ba| |:back|
||:[count]ba[ck][!] [url]|| + ||:[count]ba[ck][!] [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Go back in the browser history. Count is supported, [c]:3back[c] goes back 3 Go back in the browser history. If [count] is specified go back [count] pages. +
pages in the browser history. +
The special version [c]:back![c] goes to the beginning of the browser history. The special version [c]:back![c] goes to the beginning of the browser history.
________________________________________________________________________________ ________________________________________________________________________________
|:fw| |:fo| |:forward| |:fw| |:fo| |:forward|
||:[count]fo[rward][!] [url]|| + ||:[count]fo[rward][!] [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Go forward in the browser history. Count is supported, [c]:3forward[c] goes Go forward in the browser history. If [count] is specified go forward [count]
forward 3 pages in the browser history. The special version [c]:forward![c] pages. +
goes to the end of the browser history. The special version [c]:forward![c] goes to the end of the browser history.
________________________________________________________________________________ ________________________________________________________________________________
|:hs| |:hist| |:history| |:hs| |:hist| |:history|
||:hist[ory][!] [filter]|| + ||:hist[ory][!] [a][filter][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Show recently visited URLs. Open the message window at the bottom of the Show recently visited URLs. Open the message window at the bottom of the screen
screen with all history items which match [filter] either in the title or URL. with all history items which match [a][filter][a] either in the title or URL.
The special version [c]:history![c] works the same as [c]:history[c] except The special version [c]:history![c] works the same as [c]:history[c] except
it opens all the found items in new tabs. it opens all the found items in new tabs.
@@ -183,7 +184,7 @@ ________________________________________________________________________________
|:qma| |:qmark| |:qma| |:qmark|
||:qma[rk] {a-zA-Z0-9} [url]|| + ||:qma[rk] {a-zA-Z0-9} [a][url][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Mark a URL with a letter for quick access. You can also mark whole groups like this: + Mark a URL with a letter for quick access. You can also mark whole groups like this: +
[c]:qmark f \http://forum1.com, \http://forum2.com, imdb some artist[c] [c]:qmark f \http://forum1.com, \http://forum2.com, imdb some artist[c]
@@ -191,9 +192,10 @@ ________________________________________________________________________________
|:qmarks| |:qmarks|
||:qmarks [arg]|| ||:qmarks [a][arg][a]||
________________________________________________________________________________ ________________________________________________________________________________
Show all QuickMarks. If [arg] is specified then limit the list to those QuickMarks mentioned. Show all QuickMarks. If [a][arg][a] is specified then limit the list to those
QuickMarks mentioned.
________________________________________________________________________________ ________________________________________________________________________________
section:Local{nbsp}marks[localmarks] section:Local{nbsp}marks[localmarks]
@@ -237,9 +239,10 @@ ________________________________________________________________________________
|:marks| + |:marks| +
||:marks [arg]|| ||:marks [a][arg][a]||
________________________________________________________________________________ ________________________________________________________________________________
Show all location marks of current web page. If [arg] is specified then limit the list to those marks mentioned. Show all location marks of current web page. If [a][arg][a] is specified then
limit the list to those marks mentioned.
________________________________________________________________________________ ________________________________________________________________________________
// vim: set syntax=asciidoc: // vim: set syntax=asciidoc:

View File

@@ -26,7 +26,7 @@ Show all options. Show all options.
____ ____
|E518| |E519| |E518| |E519|
||:se[t] {option}*|| ||:se[t] {option}?||
____ ____
Show value of {option}. Show value of {option}.
____ ____
@@ -185,7 +185,7 @@ preferences.
________________________________________________________________________________ ________________________________________________________________________________
|:set-!| |:set!| |:set-!|
||:se[t]! {preference}={value}|| + ||:se[t]! {preference}={value}|| +
________________________________________________________________________________ ________________________________________________________________________________
Change any Firefox {preference} (those in the about:config window). You can also Change any Firefox {preference} (those in the about:config window). You can also
@@ -209,8 +209,9 @@ Define when tabs are automatically activated. Available items:
____ ____
|$CDPATH|
|\'cd'| |\'cdpath'| |\'cd'| |\'cdpath'|
||'cdpath' 'cd'|| string (default: black) ||'cdpath' 'cd'|| string (default: equivalent to _$CDPATH_ or ",,")
____ ____
List of directories searched when executing the :cd command. This is only used List of directories searched when executing the :cd command. This is only used
for relative paths, if an absolute path is specified then the option is for relative paths, if an absolute path is specified then the option is
@@ -239,9 +240,9 @@ ____
|\'ds'| |\'defsearch'| |\'ds'| |\'defsearch'|
||'defsearch' 'ds'|| string (default: "google") ||'defsearch' 'ds'|| string (default: "google")
____ ____
Sets the default search engine. Sets the default search engine. The default search engine name is used in the
The default search engine name is used in the [c]:[tab]open [arg][c] command if [c]:[tab]open [arg][c] command if [a][arg][a] neither looks like a URL or like
[[arg]] neither looks like a URL or like a specified search engine/keyword. a specified search engine/keyword.
This means, it you set 'defsearch' to "youtube", then [c]:open arnold This means, it you set 'defsearch' to "youtube", then [c]:open arnold
schwarzenegger[c] will be exactly the same as [c]:open youtube arnold schwarzenegger[c] will be exactly the same as [c]:open youtube arnold
@@ -249,11 +250,11 @@ schwarzenegger[c]. Therefore, you need to add a keyword or search engine
"youtube" first. "youtube" first.
If 'defsearch' is empty, then Firefox will always attempt to open the If 'defsearch' is empty, then Firefox will always attempt to open the
raw [[arg]]. raw [a][arg][a].
____ ____
|\'editor'| |i_<Ctrl-i>| |\'editor'| |i_<C-i>|
||'editor'|| string (default: "gvim -f") ||'editor'|| string (default: "gvim -f")
____ ____
Set the external text editor. Set the external text editor.
@@ -469,7 +470,10 @@ ____
|\'nolpl'| |\'lpl'| |\'noloadplugins'| |\'loadplugins'| |\'nolpl'| |\'lpl'| |\'noloadplugins'| |\'loadplugins'|
||'loadplugins' 'lpl'|| boolean (default on) ||'loadplugins' 'lpl'|| boolean (default on)
____ ____
Load plugin scripts when starting up. Load plugin scripts when starting up. When on, yet unloaded plugins are
automatically loaded after the vimperatorrc file has been sourced. To
load plugins earlier, use the [c]:loadplugins[c] command within the
vimperatorrc.
____ ____
@@ -528,7 +532,7 @@ ____
||'pageinfo' 'pa'|| ||'pageinfo' 'pa'||
charlist (default: gfm) charlist (default: gfm)
____ ____
Desired info on [c]:pa[geinfo][c]. Available items: Desired info on [c]:pa[geinfo][c]. Available items:
.--------`---------------- .--------`----------------
*g* General info *g* General info
@@ -594,7 +598,7 @@ ____
|\'rtp'| |\'runtimepath'| |\'rtp'| |\'runtimepath'|
||'runtimepath' 'rtp'|| stringlist ||'runtimepath' 'rtp'|| stringlist
____ ____
(default: \'$VIMPERATOR_RUNTIME' or Unix, Mac: "\~/.vimperator", Windows: "\~/vimperator") (default: _$VIMPERATOR_RUNTIME_ or Unix, Mac: "\~/.vimperator", Windows: "\~/vimperator")
List of directories searched for runtime files: + List of directories searched for runtime files: +
macros/ + macros/ +
@@ -603,6 +607,9 @@ plugin/ +
Example: [c]:set runtimepath=\~/myvimperator,\~/.vimperator[c] + Example: [c]:set runtimepath=\~/myvimperator,\~/.vimperator[c] +
This will search for plugins in both "\~/myvimperator/plugin" and This will search for plugins in both "\~/myvimperator/plugin" and
"\~/.vimperator/plugin" "\~/.vimperator/plugin"
On startup, if the environment variable _$VIMPERATOR_RUNTIME_ does not
exist, Vimperator will set it to match this value.
____ ____
@@ -618,18 +625,18 @@ ____
|\'shell'| |\'sh'| |\'shell'| |\'sh'|
||'shell' 'sh'|| string (default: "-c", Win32: "/c") ||'shell' 'sh'|| string (default: _$SHELL_ or "sh", Win32: "cmd.exe")
____ ____
Shell to use for executing :! and :run commands. Shell to use for executing :! and :run commands.
____ ____
|\'shellcmdflag'| |\'shcf'| |\'shellcmdflag'| |\'shcf'|
||'shellcmdflag' 'shcf'|| string (default: $SHELL or "sh", Win32: "cmd.exe") ||'shellcmdflag' 'shcf'|| string (default: "-c", Win32: "/c")
____ ____
Flag passed to shell when executing :! and :run commands. Flag passed to shell when executing :! and :run commands.
E.g. bash -c gvim E.g. "bash -c gvim"
____ ____

View File

@@ -3,9 +3,9 @@ HEADER
|text-search-commands| + |text-search-commands| +
Vimperator provides a Vim-like interface to Firefox's standard text search Vimperator provides a Vim-like interface to Firefox's standard text search
functionality. There is no support for using regular expressions in search functionality. There is no support for using regular expressions in search
commands as Firefox does not provide native regexp support. It is unlikely commands as Firefox does not provide native regexp support. It is unlikely that
that this will ever be available. this will ever be available.
|/| + |/| +
||/\\{pattern\\}[/]<CR>|| + ||/\\{pattern\\}[/]<CR>|| +
@@ -13,7 +13,7 @@ ________________________________________________________________________________
Search forward for the first occurrence of {pattern}. Search forward for the first occurrence of {pattern}.
If "\c" appears anywhere in the pattern the whole pattern is handled as though If "\c" appears anywhere in the pattern the whole pattern is handled as though
'ignorecase' is on. "\C" forces case-sensitive matching for the whole pattern. + 'ignorecase' is on. "\C" forces case-sensitive matching for the whole pattern. +
If "\l" appears in the pattern only the text of links is searched for a If "\l" appears in the pattern only the text of links is searched for a
match as though 'linksearch' is on. "\L" forces the entire page to be searched match as though 'linksearch' is on. "\L" forces the entire page to be searched
for a match. for a match.

View File

@@ -6,7 +6,7 @@ HEADER
||:ha[rdcopy][!]|| ||:ha[rdcopy][!]||
________________________________________________________________________________ ________________________________________________________________________________
Print current document. Open a GUI dialog where you can select the printer, Print current document. Open a GUI dialog where you can select the printer,
number of copies, orientation, etc. When used with [!], the dialog is skipped number of copies, orientation, etc. When used with [!], the dialog is skipped
and the default printer used. and the default printer used.
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -16,10 +16,10 @@ ____________________________________________________________________________
|:macros| |:macros|
||:mac[ros] [args]|| + ||:mac[ros] [a][pat][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
List recorded macros matching the optional regular expression [args]. If no List recorded macros matching the optional regular expression [a][pat][a]. If
regexp is given, list all macros. no regexp is given, list all macros.
________________________________________________________________________________ ________________________________________________________________________________
@@ -95,9 +95,11 @@ ________________________________________________________________________________
|:lpl| |:loadplugins| |:lpl| |:loadplugins|
||:loadplugins|| + ||:loadplugins|| +
________________________________________________________________________________ ________________________________________________________________________________
Load all unloaded plugins immediately. This is useful both for sourcing new Load all unloaded plugins immediately. Because plugins are automatically
plugins without restarting vimperator, and making sure that a plugin is loaded loaded after vimperatorrc is sourced, this command must be placed early
so that you can use its commands from your vimperatorrc. in the vimperatorrc file if vimperatorrc also includes commands that are
implemented by plugins. Additionally, this command allows for sourcing
new plugins without restarting vimperator.
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -5,40 +5,46 @@ be documented here.
section:Initialization[initialization,startup] section:Initialization[initialization,startup]
At startup Vimperator can perform user initialization commands. When one of At startup, Vimperator completes the following tasks in order.
the following is successfully located, it is executed, and no further
locations are tried.
|$VIMPERATOR_INIT| . Vimperator can perform user initialization commands. When
1. _$VIMPERATOR_INIT_ - May contain a single ex command, usually one of the following is successfully located, it is executed, and no
[c]:source {file}[c]. further locations are tried.
2. [a]\~/_vimperatorrc[a] - Windows only. If this file exists, its contents
are executed.
3. [a]\~/.vimperatorrc[a] - If this file exists, its contents are executed.
If 'exrc' is set then any RC file in the current directory is also sourced. .. |$VIMPERATOR_INIT| _$VIMPERATOR_INIT_ -- May contain a single ex
command (e.g.,
"[c]:source {file}[c]").
.. [a]\~/_vimperatorrc[a] -- Windows only. If this file exists, its
contents are executed.
.. [a]\~/.vimperatorrc[a] -- If this file exists, its contents are
executed.
The plugin directory can be in any of the directories in 'runtimepath'. . If 'exrc' is set, then any RC file in the current directory is also sourced.
All directories in 'runtimepath' are searched for plugins and they are are all . All directories in 'runtimepath' are searched for a "plugin"
loaded. subdirectory and all yet unloaded plugins are loaded. For each
plugin directory, all *.\{js,vimp} files (including those in further
subdirectories) are sourced alphabetically. No plugins will be sourced
if 'noloadplugins' is set. Any particular plugin will not be loaded
if it has already been loaded (e.g., by an earlier [c]:loadplugins[c]
command).
Plugins will not be sourced if 'noloadplugins' is set. The user's ~ (i.e., "home") directory is determined as follows:
The user's \'$HOME'(~) directory is determined as follows: * On Unix and Mac, the environment variable _$HOME_ is used.
* On Windows, Vimperator checks for the existence of _%HOME%_, then
* Unix and Mac - _$HOME_ is used. _%USERPROFILE%_, and then _%HOMEDRIVE%%HOMEPATH%_. It uses the first one
* Windows - if _%HOME%_ is set then this is used, otherwise _%USERPROFILE%_ or finally it finds.
_%HOMEDRIVE%%HOMEPATH%_.
section:Saving{nbsp}settings[save-settings] section:Saving{nbsp}settings[save-settings]
|:mkv| |:mkvimperatorrc| |:mkv| |:mkvimperatorrc|
||:mkv[imperatorrc][!] [file]|| + ||:mkv[imperatorrc][!] [a][file][a]|| +
________________________________________________________________________________ ________________________________________________________________________________
Write current key mappings and changed options to [file]. If no [file] is Write current key mappings and changed options to [a][file][a]. If no
specified then _~/.vimperatorrc_ is written unless this file already exists. The [a][file][a] is specified then _~/.vimperatorrc_ is written unless this file
special version [c]:mkvimperatorrc![c] will overwrite [file] if it exists. already exists. The special version [c]:mkvimperatorrc![c] will overwrite
[a][file][a] if it exists.
Warning: this differs from Vim's behavior which defaults to writing the file Warning: this differs from Vim's behavior which defaults to writing the file
in the current directory. in the current directory.

View File

@@ -92,14 +92,14 @@ ________________________________________________________________________________
|:sty| |:style| + |:sty| |:style| +
||:sty[le][!] [-name={name}] [-append] {filter} [{css}]|| + ||:sty[le][!] [-name={name}] [-append] {filter} [{css}]|| +
________________________________________________________________________________ ________________________________________________________________________________
Add CSS styles to the browser or to web pages. {filter} is a Add CSS styles to the browser or to web pages. {filter} is a comma
comma separated list of URLs to match. URLs ending with [c]*[c] separated list of URLs to match. URLs ending with [c]*[c] are matched as
are matched as prefixes, URLs not containing any [c]:[c] or prefixes, URLs not containing any [c]:[c] or [c]/[c] characters are
[c]/[c] characters are matched as domains. If {name} (short matched as domains. If {name} (short option: [c]-n[c]) is provided, any
option: [c]-n[c]) is provided, any existing style with the same existing style with the same name is overridden, and the style may later
name is overridden, and the style may later be deleted using be deleted using {name}. If -append (short option: [c]-a[c]) is provided
{name}. If -append (short option: -a) is provided along with -name, along with [c]-name[c], {css} and {filter} are appended to its current
{css} and {filter} are appended to its current value. value.
If {css} isn't provided, matching styles are listed. If {css} isn't provided, matching styles are listed.
________________________________________________________________________________ ________________________________________________________________________________
@@ -112,8 +112,10 @@ the filter are disabled. For instance, a filter [c]mozilla.org[c], given a
style for [c]www.google.com,mozilla.org[c], will result in a style for style for [c]www.google.com,mozilla.org[c], will result in a style for
[c]www.google.com[c]. The available options are: [c]www.google.com[c]. The available options are:
- -name: The name provided to [c]:style[c] (short option: -n) * [c]-name[c]: The name provided to [c]:style[c] (short option:
- -index: For unnamed styles, the index listed by [c]:style[c] (short option: -i) [c]-n[c])
* [c]-index[c]: For unnamed styles, the index listed by [c]:style[c]
(short option: [c]-i[c])
________________________________________________________________________________ ________________________________________________________________________________
// vim: set syntax=asciidoc: // vim: set syntax=asciidoc:

View File

@@ -3,17 +3,17 @@ HEADER
|tabs| + |tabs| +
Tabs are used to be able to view many web pages at the same time. Each tab Tabs are used to be able to view many web pages at the same time. Each tab
contains exactly one buffer - multiple buffers per tab are not supported. As a contains exactly one buffer -- multiple buffers per tab are not supported. As a
result many buffer and tab commands are interchangeable. result many buffer and tab commands are interchangeable.
section:Listing{nbsp}tabs[listing-tabs] section:Listing{nbsp}tabs[listing-tabs]
|B| |:tabs| |:ls| |:files| |:buffers| |B| |:tabs| |:ls| |:files| |:buffers|
||:buffers [filter]|| + ||:buffers [a][filter][a]|| +
||B|| ||B||
________________________________________________________________________________ ________________________________________________________________________________
Show a list of buffers (=tabs) matching [filter]. Without [filter] list all Show a list of buffers (=tabs) matching [a][filter][a]. Without [a][filter][a]
tabs. list all tabs.
________________________________________________________________________________ ________________________________________________________________________________
section:Opening{nbsp}tabs[opening-tabs] section:Opening{nbsp}tabs[opening-tabs]
@@ -63,7 +63,7 @@ ________________________________________________________________________________
||[count]gt|| ||[count]gt||
________________________________________________________________________________ ________________________________________________________________________________
Go to the next tab. Cycles to the first tab, when the last is selected. + Go to the next tab. Cycles to the first tab, when the last is selected. +
Count is supported: [m]3gt[m] goes to the third tab. If [count] is specified go to the [count]th tab.
________________________________________________________________________________ ________________________________________________________________________________
@@ -71,7 +71,7 @@ ________________________________________________________________________________
||[count]gT|| ||[count]gT||
________________________________________________________________________________ ________________________________________________________________________________
Go {count} pages back. Wraps around from the first tab to the last tab. + Go {count} pages back. Wraps around from the first tab to the last tab. +
Count is supported: [m]3gT[m] goes three tabs back. If [count] is specified go back [count] tabs.
________________________________________________________________________________ ________________________________________________________________________________
@@ -174,16 +174,15 @@ ________________________________________________________________________________
section:Closing{nbsp}tabs[closing-tabs] section:Closing{nbsp}tabs[closing-tabs]
|d| |:tabc| |:tabclose| |:bun| |:bunload| |:bw| |:bwipeout| |:bd| |:bdelete| |d| |:tabc| |:tabclose| |:bun| |:bunload| |:bw| |:bwipeout| |:bd| |:bdelete|
||:[count]bd[elete][!] [arg]|| + ||:[count]bd[elete][!] [a][arg][a]|| +
||[count]d|| ||[count]d||
________________________________________________________________________________ ________________________________________________________________________________
Delete current buffer (=tab). Count is supported, [c]:2bd[c] removes two tabs Delete current buffer (=tab). If [count] is specified then [count] tabs are
and the one to the right is selected. Afterwards, the tab to the right of the removed. Afterwards, the tab to the right of the deleted tab(s) is selected.
deleted one is selected.
When used with [arg], remove all tabs which contain [arg] in the hostname. When used with [a][arg][a], remove all tabs which contain [a][arg][a] in the
[!] forces this command to also search for [arg] in the full URL and also hostname. [!] forces this command to also search for [a][arg][a] in the full
the title of the tab. Use with care. URL and also the title of the tab. Use with care.
________________________________________________________________________________ ________________________________________________________________________________
@@ -195,11 +194,11 @@ ________________________________________________________________________________
|u| |:u| |:undo| |u| |:u| |:undo|
||:[count]u[ndo] [url]|| + ||:[count]u[ndo] [a][url][a]|| +
||[count]u|| ||[count]u||
________________________________________________________________________________ ________________________________________________________________________________
Undo closing of a tab. If a count is given, don't close the last but the Undo closing of a tab. If a count is given, don't close the last but the
[count]th last tab. With [url] restores the tab matching the URL. [count]th last tab. With [a][url][a] restores the tab matching the URL.
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -11,14 +11,14 @@ section:Quick-start{nbsp}tutorial[tutorial]
If you've started using Vimperator from scratch (i.e., without any If you've started using Vimperator from scratch (i.e., without any
customization), you should be looking at this help page in a relatively customization), you should be looking at this help page in a relatively
bare-looking window. The menubar, navigation bar, and bookmark bars are bare-looking window. The menubar, navigation bar, and bookmark bars are hidden.
hidden. In case you missed the notice in the help:Introduction[intro.html], In case you missed the notice in the help:Introduction[intro.html], you can
you can regain these by issuing the command regain these by issuing the command
:set go+=mTb<CR> :set go+=mTb<CR>
where [m]<CR>[m] represents pressing the <Enter> or <Return> key. where [m]<CR>[m] represents pressing the <Enter> or <Return> key.
If you're a veteran Vim user, this may look familiar. It should. If you're a veteran Vim user, this may look familiar. It should.
However, in this author's opinion, the best way to get familiar with However, in this author's opinion, the best way to get familiar with
Vimperator is to leave these disabled for now. (The above action can be Vimperator is to leave these disabled for now. (The above action can be
@@ -27,29 +27,29 @@ reversed with [c]:set go=<CR>[c]) You can look at the entry for
section:Vimperator's{nbsp}modal{nbsp}interface[modal] section:Vimperator's{nbsp}modal{nbsp}interface[modal]
Vimperator's power, like Vim's, comes from it's modal interface. Keys have Vimperator's power, like Vim's, comes from it's modal interface. Keys have
different meanings depending on which mode the browser is in. Vimperator has different meanings depending on which mode the browser is in. Vimperator has
several modes, but the 2 most important are ``normal'' mode and several modes, but the 2 most important are ``normal'' mode and
``command-line'' mode. ``command-line'' mode.
When Vimperator starts, it is in normal mode by default. This is probably When Vimperator starts, it is in normal mode by default. This is probably where
where you will spend the majority of your time. you will spend the majority of your time.
The other core mode of Vimperator, command-line mode, can be entered from The other core mode of Vimperator, command-line mode, can be entered from
normal mode by typing a \':' (colon). You will frequently see Vimperator normal mode by typing a \':' (colon). You will frequently see Vimperator
commands start with a \':', indicating that what follows is a command. commands start with a \':', indicating that what follows is a command.
To return to normal mode command-line mode, type [m]<Esc>[m]. Pressing To return to normal mode command-line mode, type [m]<Esc>[m]. Pressing
[m]<Esc>[m] will also return you to normal mode from most other modes in [m]<Esc>[m] will also return you to normal mode from most other modes in
Vimperator. Vimperator.
section:Getting{nbsp}help[getting-help] section:Getting{nbsp}help[getting-help]
Vim is a great editor but it's not much of a web browser. So even seasoned Vim is a great editor but it's not much of a web browser. So even seasoned Vim
Vim users will probably have to look at Vimperator documentation sooner or users will probably have to look at Vimperator documentation sooner or later.
later. Most of the documentation for Vimperator's features are easily found Most of the documentation for Vimperator's features are easily found using the
using the [c]:help[c] command. For example, you can find help on the [c]:help[c] command. For example, you can find help on the [c]:help[c] command
[c]:help[c] command by typing by typing
:help :help<CR> :help :help<CR>
@@ -71,7 +71,7 @@ section:Mouseless[living-mouseless]
The efficiency of Vimperator, as with the legendary editor it was inspired by, The efficiency of Vimperator, as with the legendary editor it was inspired by,
relies on the user being able to keep his fingers on the keyboard where they relies on the user being able to keep his fingers on the keyboard where they
can do the most good. While there are some areas where the mouse is clearly can do the most good. While there are some areas where the mouse is clearly
superior at, such as GUI design or some games, Vimperator acts on the superior at, such as GUI design or some games, Vimperator acts on the
assumption that the web browser doesn't have to be one of those. assumption that the web browser doesn't have to be one of those.
@@ -114,10 +114,10 @@ Vimmers.
* [m]d[m] -- * [m]d[m] --
close the active tab (delete the buffer) close the active tab (delete the buffer)
To open a web page in a new tab, use the [c]:tabopen {url}[c]. To open a URL To open a web page in a new tab, use the [c]:tabopen {url}[c]. To open a URL in
in the current tab, use [c]:open[c]. The normal mode the current tab, use [c]:open[c]. The normal mode mappings [m]t[m] and [m]o[m],
mappings [m]t[m] and [m]o[m], respectively, map to these commands, so the respectively, map to these commands, so the following pairs sequences are
following pairs sequences are equivalent: equivalent:
:open my.webmail.com<CR> :open my.webmail.com<CR>
omy.webmail.com<CR> omy.webmail.com<CR>
@@ -127,39 +127,39 @@ following pairs sequences are equivalent:
section:Some{nbsp}hints{nbsp}about{nbsp}surfing...[hints-tutorial] section:Some{nbsp}hints{nbsp}about{nbsp}surfing...[hints-tutorial]
So now you can navigate around in Vimperator. But wait... how do you *open* a So now you can navigate around in Vimperator. But wait... how do you *open* a
page or tab linked in a web page? How do you ``click'' on all those links page or tab linked in a web page? How do you ``click'' on all those links
without your tailed friend? without your tailed friend?
The answer is ``hints''. Activating hints displays a number next to every The answer is ``hints''. Activating hints displays a number next to every link
link Vimperator can find. To follow the link, simply type the number Vimperator can find. To follow the link, simply type the number corresponding
corresponding to the hint, a white number inside a red square by default. to the hint, a white number inside a red square by default.
For text links, there's an additional shortcut; you can type some text For text links, there's an additional shortcut; you can type some text
contained in the link and Vimperator will search all the links it can find and contained in the link and Vimperator will search all the links it can find and
only hint the matching links, further narrowing down the list. If the text only hint the matching links, further narrowing down the list. If the text you
you type uniquely identifies any given link, Vimperator will follow that link type uniquely identifies any given link, Vimperator will follow that link
immediately without any further user input. immediately without any further user input.
Whichever way you choose to indicate your target link, once Vimperator has Whichever way you choose to indicate your target link, once Vimperator has
highlighted the link you want, simply hit [m]<Enter>[m] to open it. highlighted the link you want, simply hit [m]<Enter>[m] to open it.
The most common hint mode is called help:QuickHint{nbsp}mode[various.html,f]. The most common hint mode is called help:QuickHint{nbsp}mode[various.html,f].
To activate QuickHint mode, press either [m]f[m] or [m]F[m]. The lower-case To activate QuickHint mode, press either [m]f[m] or [m]F[m]. The lower-case
[m]f[m] will open the resulting link in the current tab, while the upper-case [m]f[m] will open the resulting link in the current tab, while the upper-case
[m]F[m] will open it in a new tab. [m]F[m] will open it in a new tab.
To test it, try this link: http://vimperator.org/[Vimperator Homepage]. To test it, try this link: http://vimperator.org/[Vimperator Homepage].
Activate QuickHint mode with [m]f[m] or [m]F[m] to highlight all currently Activate QuickHint mode with [m]f[m] or [m]F[m] to highlight all currently
visible links. Then start typing the text of the link. The link should be visible links. Then start typing the text of the link. The link should be
uniquely identified soon, and Vimperator will open it. Once you're done, uniquely identified soon, and Vimperator will open it. Once you're done,
remember to use [m]<C-o>[m] (``History Back'') or [m]d[m] (``Delete Buffer'') remember to use [m]<C-o>[m] (``History Back'') or [m]d[m] (``Delete Buffer'')
to return here, depending on which key you used to activate QuickHint mode. to return here, depending on which key you used to activate QuickHint mode.
section:Common{nbsp}issues[common-issues] section:Common{nbsp}issues[common-issues]
Say you get half-way done typing in a new URL, only to remember that you've Say you get half-way done typing in a new URL, only to remember that you've
already got that page open in the previous tab. Your command-line might look already got that page open in the previous tab. Your command-line might look
something like this: something like this:
:open my.partial.url/fooba :open my.partial.url/fooba
@@ -171,15 +171,14 @@ following:
section:Saving{nbsp}for{nbsp}posterity{nbsp}-{nbsp}vimperatorrc[vimperatorrc] section:Saving{nbsp}for{nbsp}posterity{nbsp}-{nbsp}vimperatorrc[vimperatorrc]
Once you get Vimperator set up with your desired options, maps, and Once you get Vimperator set up with your desired options, maps, and commands,
commands, you'll probably want them to be available the next time you you'll probably want them to be available the next time you open Vimperator.
open Vimperator. Continuing the Vim theme, this is done with a Continuing the Vim theme, this is done with a vimperatorrc file.
vimperatorrc file.
To save your current settings and allow them to be loaded automatically To save your current settings and allow them to be loaded automatically
next time you start Vimperator, issue the [c]:mkv[c] command. next time you start Vimperator, issue the [c]:mkv[c] command.
This will create the file *$HOME/.vimperatorrc* containing your settings. This will create the file *_$HOME_/.vimperatorrc* containing your settings.
It is a simple text file, just like a vimrc file and can be easily It is a simple text file, just like a vimrc file and can be easily
edited to suit your preferences. edited to suit your preferences.
@@ -195,27 +194,27 @@ Vimperator supports all of Vim's classic methods of exiting.
section:Where{nbsp}did{nbsp}Firefox{nbsp}go?[whither-firefox] section:Where{nbsp}did{nbsp}Firefox{nbsp}go?[whither-firefox]
You might feel pretty disoriented now. Don't worry. This is still Firefox You might feel pretty disoriented now. Don't worry. This is still Firefox
underneath. Here are some ways Vimperator allows Firefox to shine through. underneath. Here are some ways Vimperator allows Firefox to shine through. See
See the [c]:help[c] for these commands and mappings for more information on the [c]:help[c] for these commands and mappings for more information on how to
how to make the best use of them. make the best use of them.
* [c]:dialog[c] -- * [c]:dialog[c] --
To access some of Firefox's many dialog windows, you can use the To access some of Firefox's many dialog windows, you can use the
[c]:dialog[c] command. See [c]:help :dialog[c]. [c]:dialog[c] command. See [c]:help :dialog[c].
* [c]:bmarks[c] -- * [c]:bmarks[c] --
Vimperator provides a new interface to bookmarks, but they're still your Vimperator provides a new interface to bookmarks, but they're still your
standard Firefox bookmarks under the hood. [c]:bmark[c] will add a new standard Firefox bookmarks under the hood. [c]:bmark[c] will add a new
bookmark, while [c]:bmarks[c] will list the bookmarks currently defined. bookmark, while [c]:bmarks[c] will list the bookmarks currently defined.
* [c]:history[c] -- * [c]:history[c] --
It's exactly what it sounds like. This command will display a colorized, It's exactly what it sounds like. This command will display a colorized,
scrollable and clickable list of the locations in Vimperator's history. scrollable and clickable list of the locations in Vimperator's history.
* [c]:emenu[c] -- * [c]:emenu[c] --
Access the Firefox menus through the Vimperator command-line. Access the Firefox menus through the Vimperator command-line.
Feel free to explore at this point. If you use the [c]:tabopen[c] command, Feel free to explore at this point. If you use the [c]:tabopen[c] command,
remember to use the [m]gt[m]/[m]gT[m] mappings to get back to this page. If remember to use the [m]gt[m]/[m]gT[m] mappings to get back to this page. If
using the [c]:open[c] command, use the history keys (e.g., [m]H[m]) to return. using the [c]:open[c] command, use the history keys (e.g., [m]H[m]) to return.
If you get hopelessly lost, just type [c]:help<CR>[c] and click the If you get hopelessly lost, just type [c]:help<CR>[c] and click the
``Tutorial'' link to return. ``Tutorial'' link to return.
@@ -228,7 +227,7 @@ section:Get{nbsp}me{nbsp}out{nbsp}of{nbsp}here![removal]
If you've given it a fair shot and determined ... TODO If you've given it a fair shot and determined ... TODO
The Vimperator way to do this is with the command [c]:addons[c]. Issuing this The Vimperator way to do this is with the command [c]:addons[c]. Issuing this
command brings up the Firefox Add-ons dialog window; you can then remove it as command brings up the Firefox Add-ons dialog window; you can then remove it as
normal, selecting Vimperator from the list and clicking (yes, clicking) normal, selecting Vimperator from the list and clicking (yes, clicking)
*Uninstall*. *Uninstall*.
@@ -239,16 +238,16 @@ as above, with [c]:set go+=m[c], and select *Add-ons* from the *Tools* menu.
section:I'm{nbsp}interested...but{nbsp}lost![support] section:I'm{nbsp}interested...but{nbsp}lost![support]
Vimperator has an energetic and growing user base. If you've run into a Vimperator has an energetic and growing user base. If you've run into a problem
problem that you can't seem to solve with Vimperator, or if you think you might that you can't seem to solve with Vimperator, or if you think you might have
have found a bug, please let us know! There is support available on the found a bug, please let us know! There is support available on the
http://vimperator.cutup.org/index.php?title=Main_Page[wiki], or in the http://vimperator.cutup.org/index.php?title=Main_Page[wiki], or in the
#vimperator IRC channel on http://freenode.net/[freenode]. #vimperator IRC channel on http://freenode.net/[freenode].
If you have any feature requests or (even better) offers to help, we'd love to If you have any feature requests or (even better) offers to help, we'd love to
hear from you as well. Developers work on Vimperator whenever possible, but hear from you as well. Developers work on Vimperator whenever possible, but we
we are neither infinite nor omnipotent; please bear with us. If you can't are neither infinite nor omnipotent; please bear with us. If you can't wait for
wait for us to get around to it, rest assured patches are welcome! See us to get around to it, rest assured patches are welcome! See the
the help:Developer[developer.html] page for more information. help:Developer[developer.html] page for more information.
// vim: set syntax=asciidoc: // vim: set syntax=asciidoc:

View File

@@ -18,6 +18,7 @@ var skipTests = [":bmarks", "gg"];
// Put definitions here which might change due to internal liberator refactoring // Put definitions here which might change due to internal liberator refactoring
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
var doc; // document where we output status messages
var multilineOutput = document.getElementById("liberator-multiline-output") var multilineOutput = document.getElementById("liberator-multiline-output")
var singlelineOutput = document.getElementById("liberator-commandline-command") var singlelineOutput = document.getElementById("liberator-commandline-command")
@@ -28,10 +29,10 @@ var singlelineOutput = document.getElementById("liberator-commandline-command")
// previous command // previous command
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// A series of ex commands or mappings, each with a // A series of Ex commands or mappings, each with a
// function checking whether the command succeeded // function checking whether the command succeeded
// If the string starts with a ":" it is executed as an ex command, otherwise as a mapping // If the string starts with a ":" it is executed as an Ex command, otherwise as a mapping
// You can also mix commands mappings // You can also mix commands and mappings
let tests = [ let tests = [
{ cmds: [":!dir"], { cmds: [":!dir"],
verify: function () getMultilineOutput().length > 10 }, verify: function () getMultilineOutput().length > 10 },
@@ -45,6 +46,8 @@ let tests = [
verify: function () getSinglelineOutput() == "test" }, verify: function () getSinglelineOutput() == "test" },
{ cmds: [":qmark V http://test.vimperator.org", ":qmarks"], { cmds: [":qmark V http://test.vimperator.org", ":qmarks"],
verify: function () getMultilineOutput().indexOf("test.vimperator.org") >= 0 }, verify: function () getMultilineOutput().indexOf("test.vimperator.org") >= 0 },
{ cmds: [":javascript liberator.echo('test', commandline.FORCE_MULTILINE)"],
verify: function () getMultilineOutput() == "test" },
// { cmds: [":echomsg \"testmsg\""], // { cmds: [":echomsg \"testmsg\""],
// verify: function () getOutput() == "testmsg" }, // verify: function () getOutput() == "testmsg" },
// { cmds: [":echoerr \"testerr\""], // { cmds: [":echoerr \"testerr\""],
@@ -56,7 +59,7 @@ let tests = [
// testing tab behavior // testing tab behavior
]; ];
// these functions highly depend on the liberator API, so use ex command tests whenever possible // these functions highly depend on the liberator API, so use Ex command tests whenever possible
let functions = [ let functions = [
function () { return bookmarks.get("").length > 0 }, // will fail for people without bookmarks :( Might want to add one before function () { return bookmarks.get("").length > 0 }, // will fail for people without bookmarks :( Might want to add one before
function () { return history.get("").length > 0 } function () { return history.get("").length > 0 }
@@ -64,7 +67,7 @@ let functions = [
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// functions below should be as generic as possible, and not require being rewritten // functions below should be as generic as possible, and not require being rewritten
// even after doing major vimperator refactoring // even after doing major Vimperator refactoring
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
function resetEnvironment() function resetEnvironment()
@@ -89,15 +92,14 @@ function getBufferPosition()
y: win.scrollMaxY ? win.pageYOffset / win.scrollMaxY : 0 } y: win.scrollMaxY ? win.pageYOffset / win.scrollMaxY : 0 }
}; };
// TODO: need to find a way to wait for page load
function getLocation() window.content.document.location.href; function getLocation() window.content.document.location.href;
var doc;
function echoLine(str, group) function echoLine(str, group)
{ {
if (!doc) if (!doc)
return; return;
doc.body.appendChild(util.xmlToDom( doc.body.appendChild(util.xmlToDom(
<div highlight={group} style="border: 1px solid gray; white-space: pre; height: 1.5em; line-height: 1.5em;">{str}</div>, <div highlight={group} style="border: 1px solid gray; white-space: pre; height: 1.5em; line-height: 1.5em;">{str}</div>,
doc)); doc));
@@ -106,6 +108,7 @@ function echoMulti(str, group)
{ {
if (!doc) if (!doc)
return; return;
doc.body.appendChild(util.xmlToDom(<div class="ex-command-output" doc.body.appendChild(util.xmlToDom(<div class="ex-command-output"
style="white-space: nowrap; border: 1px solid black; min-height: 1.5em;" style="white-space: nowrap; border: 1px solid black; min-height: 1.5em;"
highlight={group}>{template.maybeXML(str)}</div>, highlight={group}>{template.maybeXML(str)}</div>,
@@ -120,13 +123,13 @@ commands.addUserCommand(["regr[essions]"],
// TODO: count (better even range) support to just run test 34 of 102 // TODO: count (better even range) support to just run test 34 of 102
// TODO: bang support to either: a) run commands like deleting bookmarks which // TODO: bang support to either: a) run commands like deleting bookmarks which
// should only be done in a clean profile or b) run functions and not // should only be done in a clean profile or b) run functions and not
// just ex command tests; Yet to be decided // just Ex command tests; Yet to be decided
let updateOutputHeight = null; let updateOutputHeight = null;
function init() function init()
{ {
liberator.registerObserver("echoLine", echoLine); liberator.registerObserver("echoLine", echoLine);
liberator.registerObserver("echoMulti", echoMulti); liberator.registerObserver("echoMultiline", echoMulti);
liberator.open("chrome://liberator/content/buffer.xhtml", liberator.NEW_TAB); liberator.open("chrome://liberator/content/buffer.xhtml", liberator.NEW_TAB);
events.waitForPageLoad(); events.waitForPageLoad();
doc = content.document; doc = content.document;
@@ -144,7 +147,7 @@ commands.addUserCommand(["regr[essions]"],
function cleanup() function cleanup()
{ {
liberator.unregisterObserver("echoLine", echoLine); liberator.unregisterObserver("echoLine", echoLine);
liberator.unregisterObserver("echoMulti", echoMulti); liberator.unregisterObserver("echoMultiline", echoMulti);
commandline.updateOutputHeight = updateOutputHeight; commandline.updateOutputHeight = updateOutputHeight;
} }
@@ -178,7 +181,7 @@ commands.addUserCommand(["regr[essions]"],
} }
}; };
liberator.echomsg("Running test " + currentTest + " of " + totalTests + ": " + testDescription, 0); commandline.echo("Running test " + currentTest + " of " + totalTests + ": " + testDescription, "Filter", commandline.APPEND_TO_MESSAGES);
resetEnvironment(); resetEnvironment();
if ("init" in test) if ("init" in test)
test.init(); test.init();
@@ -187,7 +190,7 @@ commands.addUserCommand(["regr[essions]"],
if (cmd[0] == ":") if (cmd[0] == ":")
liberator.execute(cmd); liberator.execute(cmd);
else else
events.feedkeys(cmd); events.feedkeys(cmd);
}); });
if (!test.verify()) if (!test.verify())
@@ -203,7 +206,7 @@ commands.addUserCommand(["regr[essions]"],
if (args.count >= 1 && currentTest != args.count) if (args.count >= 1 && currentTest != args.count)
continue; continue;
liberator.echomsg("Running test " + currentTest + " of " + totalTests + ": " + util.clip(func.toString().replace(/[\s\n]+/gm, " "), 80)); commandline.echo("Running test " + currentTest + " of " + totalTests + ": " + util.clip(func.toString().replace(/[\s\n]+/gm, " "), 80), "Filter", commandline.APPEND_TO_MESSAGES);
resetEnvironment(); resetEnvironment();
if (!func()) if (!func())

View File

@@ -1,7 +1,7 @@
" Vim syntax file " Vim syntax file
" Language: VIMperator configuration file " Language: VIMperator configuration file
" Maintainer: Doug Kearns <dougkearns@gmail.com> " Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2008 Dec 07 " Last Change: 2008 Dec 31
if exists("b:current_syntax") if exists("b:current_syntax")
finish finish
@@ -23,13 +23,13 @@ syn keyword vimperatorCommand ab[breviate] ab[clear] addo[ns] b[uffer] ba[ck] bd
\ cm[ap] cmapc[lear] cno[remap] comc[lear] com[mand] cu[nmap] do[autocmd] doautoa[ll] delbm[arks] delc[ommand] delmac[ros] \ cm[ap] cmapc[lear] cno[remap] comc[lear] com[mand] cu[nmap] do[autocmd] doautoa[ll] delbm[arks] delc[ommand] delmac[ros]
\ delm[arks] delqm[arks] dels[tyle] dia[log] dl downl[oads] e[dit] ec[ho] echoe[rr] echom[sg] em[enu] exe[cute] exu[sage] \ delm[arks] delqm[arks] dels[tyle] dia[log] dl downl[oads] e[dit] ec[ho] echoe[rr] echom[sg] em[enu] exe[cute] exu[sage]
\ fini[sh] files fo[rward] fw h[elp] ha[rdcopy] hi[ghlight] hist[ory] hs ia[bbrev] iabc[lear] im[ap] imapc[lear] ino[remap] \ fini[sh] files fo[rward] fw h[elp] ha[rdcopy] hi[ghlight] hist[ory] hs ia[bbrev] iabc[lear] im[ap] imapc[lear] ino[remap]
\ iuna[bbrev] iu[nmap] javas[cript] ju[mps] js let ls macros ma[rk] map mapc[lear] marks mes[sages] mkv[imperatorrc] no[remap] \ iuna[bbrev] iu[nmap] javas[cript] ju[mps] js let loadplugins lpl ls macros ma[rk] map mapc[lear] marks mes[sages]
\ noh[lsearch] norm[al] o[pen] optionu[sage] pa[geinfo] pagest[yle] pc[lose] pl[ay] pref[erences] prefs pw[d] q[uit] qa[ll] \ mkv[imperatorrc] no[remap] noh[lsearch] norm[al] o[pen] optionu[sage] pa[geinfo] pagest[yle] pc[lose] pl[ay] pref[erences]
\ qma[rk] qmarks quita[ll] re[draw] re[load] reloada[ll] res[tart] run runt[ime] sty[le] sav[eas] sb[ar] sb[open] sbcl[ose] \ prefs pw[d] q[uit] qa[ll] qma[rk] qmarks quita[ll] re[draw] re[load] reloada[ll] res[tart] run runt[ime] sty[le] sav[eas]
\ scrip[tnames] se[t] setg[lobal] setl[ocal] sideb[ar] so[urce] st[op] tN[ext] t[open] tab tabde[tach] tabd[uplicate] \ sb[ar] sb[open] sbcl[ose] scrip[tnames] se[t] setg[lobal] setl[ocal] sideb[ar] so[urce] st[op] tN[ext] t[open] tab
\ tabN[ext] tabc[lose] tabe[dit] tabfir[st] tabl[ast] tabm[ove] tabn[ext] tabnew tabo[nly] tabopen tabp[revious] tabr[ewind] \ tabde[tach] tabd[uplicate] tabN[ext] tabc[lose] tabe[dit] tabfir[st] tabl[ast] tabm[ove] tabn[ext] tabnew tabo[nly] tabopen
\ tabs time tn[ext] tp[revious] u[ndo] una[bbreviate] undoa[ll] unl[et] unm[ap] ve[rsion] vie[wsource] viu[sage] w[rite] \ tabp[revious] tabr[ewind] tabs time tn[ext] tp[revious] u[ndo] una[bbreviate] undoa[ll] unl[et] unm[ap] ve[rsion]
\ wc[lose] win[open] winc[lose] wine[dit] wo[pen] wqa[ll] wq xa[ll] zo[om] \ vie[wsource] viu[sage] w[rite] wc[lose] win[open] winc[lose] wine[dit] wo[pen] wqa[ll] wq xa[ll] zo[om]
\ contained \ contained
syn match vimperatorCommand "!" contained syn match vimperatorCommand "!" contained
@@ -43,7 +43,7 @@ syn keyword vimperatorAutoEvent BookmarkAdd DOMLoad LocationChange PageLoadPre P
syn match vimperatorAutoEventList "\(\a\+,\)*\a\+" contained contains=vimperatorAutoEvent syn match vimperatorAutoEventList "\(\a\+,\)*\a\+" contained contains=vimperatorAutoEvent
syn region vimperatorSet matchgroup=vimperatorCommand start="\%(^\s*:\=\)\@<=\<\%(setl\%[ocal]\|setg\%[lobal]\|set\=\)\=\>" syn region vimperatorSet matchgroup=vimperatorCommand start="\%(^\s*:\=\)\@<=\<\%(setl\%[ocal]\|setg\%[lobal]\|set\=\)\=\>"
\ end="$" keepend oneline contains=vimperatorOption,vimperatorComment,vimperatorString \ end="$" keepend oneline contains=vimperatorOption,vimperatorString
syn keyword vimperatorOption activate act alfc albc cdpath cd complete cpt defsearch ds editor extendedhinttags eht eventignore ei syn keyword vimperatorOption activate act alfc albc cdpath cd complete cpt defsearch ds editor extendedhinttags eht eventignore ei
\ followhints fh guioptions go helpfile hf hintmatching hm hs hinttags ht hinttimeout hto history hi laststatus ls lbc lfc \ followhints fh guioptions go helpfile hf hintmatching hm hs hinttags ht hinttimeout hto history hi laststatus ls lbc lfc