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

Merge branch 'master' into vimperator-2.1

Conflicts:
	common/content/io.js
	vimperator/locale/en-US/starting.txt
This commit is contained in:
Kris Maglione
2009-01-15 03:14:08 -05:00
58 changed files with 1395 additions and 1006 deletions

29
.gitignore vendored
View File

@@ -1,8 +1,31 @@
## To see if new rules exclude any existing files, run
##
## git ls-files -i --exclude-standard
##
## after modifying this file.
## Generated by the build process
*.xpi *.xpi
*/locale/*/*.html */locale/*/*.html
*/chrome */chrome
## Editor backup and swap files
*~ *~
.*.swp .\#*
.*.swo \#**\#
.swp .*.sw[op]
.sw[op]
## Generated by Mac filesystem
.DS_Store .DS_Store
## For rejects
*.orig
*.rej
*.ancestor
*.current
*.patched
## Generated by StGit
patches-*
.stgit-edit.txt

56
HACKING
View File

@@ -79,7 +79,9 @@ We try to be quite consistent, but of course, that's not always possible.
* Prefer // over /* */ comments (exceptions for big comments are usually OK) * Prefer // over /* */ comments (exceptions for big comments are usually OK)
Right: if (HACK) // TODO: remove hack Right: if (HACK) // TODO: remove hack
Wrong: if (HACK) /* TODO: remove hack */ Wrong: if (HACK) /* TODO: remove hack */
Documentation comment blocks use /** ... */
* Documentation comment blocks use /** ... */ Wrap these lines at 80
characters.
* Only wrap lines if it makes the code obviously clearer. Lines longer than 132 * Only wrap lines if it makes the code obviously clearer. Lines longer than 132
characters should probably be broken up rather than wrapped anyway. characters should probably be broken up rather than wrapped anyway.
@@ -121,6 +123,43 @@ We try to be quite consistent, but of course, that's not always possible.
I don't like unnecessary use of 'new', I don't like 'new'. --djk I don't like unnecessary use of 'new', I don't like 'new'. --djk
There is semantic value to using "new." It's good CBSE. --Ted
There's no semantic value. It's reasonable to infer that any function
named in CamelCase is a constructor. That's the case with all such
internal functions. As far as I'm concerned, 'new' is a hack. Actually,
most of JS is a hack...
--Kris
What he said. Although, I would have said "a pretty nifty language
with some regrettable design decisions" now that I'm in therapy.
--djk
There is semantic value: With new you know for SURE it's calling the
constructor of a class, with CamelCase only you just ASSUME you do.
I am all about making code clearer also to new developers. And this
includes getting rid of as many assumptions as possible, by making
things explicit, when they don't hurt readability (and new doesn't
for me). It's not so important, that i'll change all instances to
new immediately, but will probably do so over time, when I see it.
--mst
JavaScript doesn't have classes... What about all the other
'constructor' functions such as Commands? And I think it does hurt
readability because it's pointless.
Anyway, if it's important enough to change it should all be
changed at once. I've removed most of these sorts of
inconsistencies and I wouldn't like to see them reintroduced.
--djk
Actually, you're not sure of anything. You can call new (function (a)
a.substr(2)), and you don't get a new object. The only difference is
that it's called with 'this' set. Given that it's uncouth to name a
non-constructor function in CamelCase, and that most internal
constructors don't require new (and some, like String, break when
you use it), it just seems superfluous and distracting.
--Kris
== Testing/Optimization == == Testing/Optimization ==
TODO: Add some information here about testing/validation/etc. TODO: Add some information here about testing/validation/etc.
@@ -142,7 +181,16 @@ TODO: Document the existence of remote branches and discuss when and how
countless git walkthroughs, FAQs, tips pages (not to mention 'git countless git walkthroughs, FAQs, tips pages (not to mention 'git
help') that I don't see the need to duplicate them here. As for 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 branches, 'git branch' should be sufficient, and, if not, there's
a list on gitweb. a list on gitweb. --Kris
--Kris
# vim: set fdm=marker sw=4 ts=4 et ai: I wasn't trying to say that git was a problem (though other DVCS
have more accessible help systems; except for very complex
projects, I think Mercurial is a much more comfortable DVCS to
learn, use, and navigate). I was saying that it might be nice if
the remote branches (and related polices) were documented. Yes,
anyone can do a "git branch -r", but seeing that a branch exists
is not the same as understanding why it's there. --Ted
Sure, I agree. --djk
// vim: set ft=asciidoc fdm=marker sw=4 ts=4 et ai:

View File

@@ -10,7 +10,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -8,4 +8,3 @@ $(TARGETS:%=\%.%):
$(MAKE) -C $* $(@:$*.%=%) $(MAKE) -C $* $(@:$*.%=%)
$(TARGETS): %: $(DIRS:%=%.%) $(TARGETS): %: $(DIRS:%=%.%)

View File

@@ -5,8 +5,8 @@ OS = $(shell uname -s)
BUILD_DATE = $(shell date "+%Y/%m/%d %H:%M:%S") BUILD_DATE = $(shell date "+%Y/%m/%d %H:%M:%S")
BASE = $(TOP)/../common BASE = $(TOP)/../common
DOC_SRC_FILES = $(wildcard locale/*/*.txt) DOC_SRC_FILES = $(wildcard locale/*/*.txt) $(wildcard locale/*/*.t2t)
DOC_FILES = ${DOC_SRC_FILES:%.txt=%.html} LOCALES = $(wildcard locale/*)
MAKE_JAR = VERSION="$(VERSION)" DATE="$(BUILD_DATE)" sh $(BASE)/make_jar.sh MAKE_JAR = VERSION="$(VERSION)" DATE="$(BUILD_DATE)" sh $(BASE)/make_jar.sh
@@ -63,8 +63,6 @@ info:
@echo -e "jar files $(shell echo ${JAR_FILES} | sed 's/ /\\n /g' )" @echo -e "jar files $(shell echo ${JAR_FILES} | sed 's/ /\\n /g' )"
@echo "xpi files ${XPI_FILES}" @echo "xpi files ${XPI_FILES}"
.PHONY: check-asciidoc
doc: check-asciidoc ${DOC_FILES}
xpi: ${XPI} xpi: ${XPI}
jar: ${JAR} jar: ${JAR}
@@ -80,11 +78,10 @@ ${RDF}: ${RDF_IN} Makefile
clean: clean:
@echo "Cleanup..." @echo "Cleanup..."
rm -f ${JAR} ${XPI} rm -f ${JAR} ${XPI}
find . -name '*~' -exec rm -f {} \;
distclean: clean distclean: clean
@echo "More cleanup..." @echo "More cleanup..."
rm -f ${DOC_FILES} @set -e; for locale in $(LOCALES); do $(MAKE) -C clean; doc; done
rm -rf ${BUILD_DIR} rm -rf ${BUILD_DIR}
#### xpi #### xpi
@@ -103,21 +100,7 @@ $(JAR): doc
$(MAKE_JAR) "$(JAR)" "$(JAR_BASES)" "$(JAR_DIRS)" "$(JAR_TEXTS)" "$(JAR_BINS)" "$(JAR_FILES)" $(MAKE_JAR) "$(JAR)" "$(JAR_BASES)" "$(JAR_DIRS)" "$(JAR_TEXTS)" "$(JAR_BINS)" "$(JAR_FILES)"
@echo "SUCCESS: $@" @echo "SUCCESS: $@"
#### doc #### doc (see Makefile.doc)
check-asciidoc:
@asciidoc --version | awk '{ exit $$2 !~ /^8\.2\./ }' || \
echo >&2 "Warning: asciidoc versions other than 8.2.x are unsupported"
${DOC_FILES}: %.html: %.txt $(BASE)/Makefile.common locale/en-US/asciidoc.conf
@echo "DOC $@"
${ASCIIDOC} --unsafe -a linkcss -a quirks! -a doctitle="$(shell basename $@)" -o $@ $<
T2T = $(wildcard locale/*/*.t2t)
t2t: $(T2T:%.t2t=%.xhtml)
$(T2T:%.t2t=%.xhtml): locale/en-US/config.t2t
%.xhtml: %.t2t
@echo "T2T $@"
txt2tags --quiet $<
doc:
@set -e; for locale in $(LOCALES); do $(MAKE) -C $$locale doc; done

75
common/Makefile.doc Normal file
View File

@@ -0,0 +1,75 @@
# Symlink me to locale/*/Makefile
#### configuration
BASE = ../../../common
THIS_LOCALE = $(notdir $(shell pwd))
ADC_SRC_FILES = $(wildcard *.txt)
ADC_FILES = $(ADC_SRC_FILES:%.txt=%.html)
ADC_DEPS = $(wildcard asciidoc.conf)
T2T_SRC_FILES = $(wildcard *.t2t)
T2T_FILES = $(T2T_SRC_FILES:%.t2t=%.xhtml)
T2T_DEPS = $(wildcard config.t2t)
DOC_FILES = $(ADC_FILES) $(T2T_FILES)
ASCIIDOC = asciidoc
TXT2TAGS = txt2tags
AWK = awk
.SILENT:
#### rules
.PHONY: all help doc asciidoc check-asciidoc clean distclean
all: doc
doc: asciidoc t2t
help:
@echo "${NAME} ${VERSION} build"
@echo
@echo " make help - display this help"
@echo " make doc - build doc files"
@echo " make asciidoc - build asciidoc'd files only"
@echo " make t2t - build txt2tags'd files only"
@echo " make clean - clean up"
@echo " make distclean - clean up more"
clean:
@echo "Cleanup..."
distclean: clean
@echo "More cleanup..."
rm -f $(DOC_FILES)
#### Makes single-file makes easier to type
%: %.html %.t2t %.xhtml %.t2t ;
%: %.html %.txt ;
%: %.xhtml %.t2t ;
#### asciidoc
asciidoc: check-asciidoc $(ADC_FILES)
check-asciidoc:
@$(ASCIIDOC) --version | $(AWK) '{ exit $$2 !~ /^8\.2\./ }' || \
echo >&2 "Warning: asciidoc versions other than 8.2.x are unsupported"
$(ADC_FILES): %.html: %.txt $(BASE)/Makefile.doc $(ADC_DEPS)
@echo "DOC locale/$(THIS_LOCALE)/$@"
$(ASCIIDOC) --unsafe -a linkcss -a quirks! -a doctitle="$(shell basename $@)" -o $@ $<
#### txt2tags
t2t: $(T2T_FILES)
$(T2T_FILES): %.xhtml: %.t2t $(BASE)/Makefile.doc $(T2T_DEPS)
@echo "T2T locale/$(THIS_LOCALE)/$@"
txt2tags --quiet $<

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -157,7 +157,7 @@ function Buffer() //{{{
options.add(["pageinfo", "pa"], "Desired info on :pa[geinfo]", "charlist", "gfm", options.add(["pageinfo", "pa"], "Desired info on :pa[geinfo]", "charlist", "gfm",
{ {
completer: function (filter) [[k, v[1]] for ([k, v] in Iterator(pageInfo))], completer: function (context) [[k, v[1]] for ([k, v] in Iterator(pageInfo))],
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -170,7 +170,7 @@ function Buffer() //{{{
"Show the destination of the link under the cursor in the status bar", "Show the destination of the link under the cursor in the status bar",
"number", 1, "number", 1,
{ {
completer: function (filter) [ completer: function (context) [
["0", "Don't show link destination"], ["0", "Don't show link destination"],
["1", "Show the link in the status line"], ["1", "Show the link in the status line"],
["2", "Show the link in the command line"] ["2", "Show the link in the command line"]
@@ -356,8 +356,7 @@ function Buffer() //{{{
function () function ()
{ {
liberator.open(util.readFromClipboard(), liberator.open(util.readFromClipboard(),
/\bpaste\b/.test(options["activate"]) ? liberator[options.get("activate").has("paste") ? "NEW_BACKGROUND_TAB" : "NEW_TAB"]);
liberator.NEW_BACKGROUND_TAB : liberator.NEW_TAB);
}); });
mappings.add(myModes, ["p", "<MiddleMouse>"], mappings.add(myModes, ["p", "<MiddleMouse>"],
@@ -849,7 +848,7 @@ function Buffer() //{{{
}, },
/** /**
* @property {Object} The last focused input field in the buffer. Used * @property {Node} The last focused input field in the buffer. Used
* by the "gi" key binding. * by the "gi" key binding.
*/ */
get lastInputField() get lastInputField()
@@ -987,6 +986,7 @@ function Buffer() //{{{
selController.wordMove(false, false); selController.wordMove(false, false);
selController.wordMove(true, true); selController.wordMove(true, true);
selController.setCaretEnabled(caretmode); selController.setCaretEnabled(caretmode);
return String.match(selection, /\w*/)[0];
} }
let range = selection.getRangeAt(0); let range = selection.getRangeAt(0);
if (util.computedStyle(range.startContainer).whiteSpace == "pre" if (util.computedStyle(range.startContainer).whiteSpace == "pre"
@@ -1139,15 +1139,18 @@ function Buffer() //{{{
elem.focus(); elem.focus();
let evt = doc.createEvent("MouseEvents"); let evt = doc.createEvent("MouseEvents");
options.withContext(function () {
options.setPref("browser.tabs.loadInBackground", true);
["mousedown", "mouseup", "click"].forEach(function (event) { ["mousedown", "mouseup", "click"].forEach(function (event) {
evt.initMouseEvent(event, true, true, view, 1, offsetX, offsetY, 0, 0, evt.initMouseEvent(event, true, true, view, 1, offsetX, offsetY, 0, 0,
ctrlKey, /*altKey*/0, shiftKey, /*metaKey*/ ctrlKey, 0, null); ctrlKey, /*altKey*/0, shiftKey, /*metaKey*/ ctrlKey, 0, null);
elem.dispatchEvent(evt); elem.dispatchEvent(evt);
}); });
});
}, },
/** /**
* @property {Object} The current document's selection controller. * @property {nsISelectionController} The current document's selection controller.
*/ */
get selectionController() getBrowser().docShell get selectionController() getBrowser().docShell
.QueryInterface(Ci.nsIInterfaceRequestor) .QueryInterface(Ci.nsIInterfaceRequestor)
@@ -1157,8 +1160,8 @@ function Buffer() //{{{
/** /**
* Saves a page link to disk. * Saves a page link to disk.
* *
* @param {Object} elem The page link to save. * @param {HTMLAnchorElement} elem The page link to save.
* @param {boolean} skipPrompt Whether to open the "Save Link As..." dialog * @param {boolean} skipPrompt Whether to open the "Save Link As..." dialog.
*/ */
saveLink: function (elem, skipPrompt) saveLink: function (elem, skipPrompt)
{ {
@@ -1381,7 +1384,7 @@ function Buffer() //{{{
/** /**
* Displays information about the specified element. * Displays information about the specified element.
* *
* @param {Object} elem * @param {Node} elem
*/ */
showElementInfo: function (elem) showElementInfo: function (elem)
{ {
@@ -1662,7 +1665,10 @@ function Marks() //{{{
marks.remove(args, special); marks.remove(args, special);
}, },
{ bang: true }); {
bang: true,
completer: function (context) completion.mark(context)
});
commands.add(["ma[rk]"], commands.add(["ma[rk]"],
"Mark current location within the web page", "Mark current location within the web page",
@@ -1707,6 +1713,8 @@ function Marks() //{{{
return { return {
get all() getSortedMarks(),
/** /**
* Add a named mark for the current buffer, at its current position. * Add a named mark for the current buffer, at its current position.
* If mark matches [A-Z], it's considered a URL mark, and will jump to * If mark matches [A-Z], it's considered a URL mark, and will jump to

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -150,7 +150,7 @@ Command.prototype = {
* @param {number} count @deprecated Whether this command was * @param {number} count @deprecated Whether this command was
* executed with 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}.
*/ */
execute: function (args, bang, count, modifiers) execute: function (args, bang, count, modifiers)
{ {
@@ -233,15 +233,6 @@ function Commands() //{{{
var exCommands = []; var exCommands = [];
function parseBool(arg)
{
if (arg == "true" || arg == "1" || arg == "on")
return true;
if (arg == "false" || arg == "0" || arg == "off")
return false;
return NaN;
}
const QUOTE_STYLE = "vimperator"; const QUOTE_STYLE = "vimperator";
const quoteMap = { const quoteMap = {
@@ -264,16 +255,24 @@ function Commands() //{{{
"": quote("", "\\\\ ") "": quote("", "\\\\ ")
}; };
function parseBool(arg)
{
if (/^(true|1|on)$/i.test(arg))
return true;
if (/^(false|0|off)$/i.test(arg))
return false;
return NaN;
}
const ArgType = new Struct("description", "parse"); const ArgType = new Struct("description", "parse");
const argTypes = [ const argTypes = [
null, null,
["no arg", function (arg) !arg], ArgType("no arg", function (arg) !arg || null),
["boolean", parseBool], ArgType("boolean", parseBool),
["string", function (val) val], ArgType("string", function (val) val),
["int", parseInt], ArgType("int", parseInt),
["float", parseFloat], ArgType("float", parseFloat),
["list", function (arg) arg && arg.split(/\s*,\s*/)] ArgType("list", function (arg) arg && arg.split(/\s*,\s*/))
].map(function (x) x && ArgType.apply(null, x)); ];
function addCommand(command, isUserCommand, replace) function addCommand(command, isUserCommand, replace)
{ {
@@ -358,7 +357,7 @@ function Commands() //{{{
let str = args.literalArg; let str = args.literalArg;
if (str) if (str)
res.push(/\n/.test(str) ? "<<EOF\n" + str + "EOF" : str); res.push(/\n/.test(str) ? "<<EOF\n" + str.replace(/\n$/, "") + "\nEOF" : str);
return res.join(" "); return res.join(" ");
}, },
@@ -843,7 +842,7 @@ function Commands() //{{{
} }
else else
{ {
completeFunc = function () completion[completeOptionMap[completeOpt]].apply(this, Array.slice(arguments)); completeFunc = completion[completeOptionMap[completeOpt]];
} }
} }
@@ -854,11 +853,7 @@ function Commands() //{{{
argCount: nargsOpt, argCount: nargsOpt,
bang: bangOpt, bang: bangOpt,
count: countOpt, count: countOpt,
completer: function (context, args) completer: completeFunc,
{
if (completeFunc)
return completeFunc(context, args)
},
replacementText: args.literalArg replacementText: args.literalArg
}, args.bang); }, args.bang);
@@ -870,8 +865,7 @@ function Commands() //{{{
function completerToString(completer) function completerToString(completer)
{ {
if (completer) if (completer)
return [k for ([k, v] in Iterator(completeOptionMap)) return [k for ([k, v] in Iterator(completeOptionMap)) if (completer == completion[v])][0] || "custom";
if (v == completer.name)][0] || "custom";
else else
return ""; return "";
} }
@@ -907,6 +901,7 @@ function Commands() //{{{
function (arg) /^[01*?+]$/.test(arg), ["0", "1", "*", "?", "+"]], function (arg) /^[01*?+]$/.test(arg), ["0", "1", "*", "?", "+"]],
[["-bang"], self.OPTION_NOARG], [["-bang"], self.OPTION_NOARG],
[["-count"], self.OPTION_NOARG], [["-count"], self.OPTION_NOARG],
// TODO: "E180: invalid complete value: " + arg
[["-complete"], self.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))]]

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -159,7 +159,7 @@ function CompletionContext(editor, name, offset) //{{{
* contain inactive contexts. For active contexts, see * contain inactive contexts. For active contexts, see
* {@link #contextList}. * {@link #contextList}.
*/ */
this.contexts = { "/": 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:
@@ -285,7 +285,7 @@ CompletionContext.prototype = {
set completions(items) set completions(items)
{ {
// Accept a generator // Accept a generator
if (!(items instanceof Array)) if (!("length" in items))
items = [x for (x in Iterator(items))]; items = [x for (x in Iterator(items))];
delete this.cache.filtered; delete this.cache.filtered;
delete this.cache.filter; delete this.cache.filter;
@@ -1388,7 +1388,6 @@ function Completion() //{{{
{ process.call(this, item, text) } { process.call(this, item, text) }
</>]; </>];
context.completions = util.map(tabs.browsers, function ([i, browser]) { context.completions = util.map(tabs.browsers, function ([i, browser]) {
let indicator = " "; let indicator = " ";
if (i == tabs.index()) if (i == tabs.index())
@@ -1608,7 +1607,23 @@ function Completion() //{{{
context.completions = [item for (item in events.getMacros())]; context.completions = [item for (item in events.getMacros())];
}, },
menuItem: function menuItem(filter) commands.get("emenu").completer(filter), // XXX mark: function mark(context)
{
function percent(i) Math.round(i * 100);
// FIXME: Line/Column doesn't make sense with %
context.title = ["Mark", "Line Column File"];
context.keys.description = function ([,m]) percent(m.position.y) + "% " + percent(m.position.x) + "% " + m.location;
context.completions = marks.all;
},
menuItem: function menuItem(context)
{
context.title = ["Menu Path", "Label"];
context.anchored = false;
context.keys = { text: "fullMenuPath", description: "label" };
context.completions = liberator.menuItems;
},
option: function option(context, scope) option: function option(context, scope)
{ {

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -189,8 +189,8 @@ function AutoCommands() //{{{
* *
* @param {Array} events The array of event names for which this * @param {Array} events The array of event names for which this
* autocommand should be executed. * autocommand should be executed.
* @param {string} regex The URL pattern to match against the buffer URL * @param {string} regex The URL pattern to match against the buffer URL.
* @param {string} cmd The Ex command to run * @param {string} cmd The Ex command to run.
*/ */
add: function (events, regex, cmd) add: function (events, regex, cmd)
{ {
@@ -630,7 +630,7 @@ 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 () {
try try
{ {
let dirs = io.getRuntimeDirectories("macros"); let dirs = io.getRuntimeDirectories("macros");
@@ -769,8 +769,11 @@ function Events() //{{{
// removeEventListeners() to avoid mem leaks // removeEventListeners() to avoid mem leaks
liberator.dump("TODO: remove all eventlisteners"); liberator.dump("TODO: remove all eventlisteners");
if (typeof getBrowser != "undefined") try
{
getBrowser().removeProgressListener(this.progressListener); getBrowser().removeProgressListener(this.progressListener);
}
catch (e) {}
window.removeEventListener("popupshown", enterPopupMode, true); window.removeEventListener("popupshown", enterPopupMode, true);
window.removeEventListener("popuphidden", exitPopupMode, true); window.removeEventListener("popuphidden", exitPopupMode, true);
@@ -915,7 +918,7 @@ function Events() //{{{
//if (keys[i] == "\\") // FIXME: support the escape key //if (keys[i] == "\\") // FIXME: support the escape key
if (keys[i] == "<" && !escapeKey) // start a complex key if (keys[i] == "<" && !escapeKey) // start a complex key
{ {
let [match, modifier, keyname] = keys.substr(i).match(/<([CSMA]-)*(.+?)>/i) || []; let [match, modifier, keyname] = keys.substr(i).match(/<((?:[CSMA]-)*)(.+?)>/i) || [];
if (keyname) if (keyname)
{ {
if (modifier) // check for modifiers if (modifier) // check for modifiers

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -123,8 +123,8 @@ function Search() //{{{
* *
* The Initial Developer of the Original Code is * The Initial Developer of the Original Code is
* Netscape Communications Corporation. * Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003 * Portions created by the Initial Developer are Copyright (c) 2003
* the Initial Developer. All Rights Reserved. * by the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Blake Ross <blake@cs.stanford.edu> (Original Author) * Blake Ross <blake@cs.stanford.edu> (Original Author)
@@ -436,7 +436,6 @@ function Search() //{{{
// escape while typing a search // escape while typing a search
searchCanceled: function () searchCanceled: function ()
{ {
this.clear();
// TODO: code to reposition the document to the place before search started // TODO: code to reposition the document to the place before search started
}, },

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -73,10 +73,10 @@ function Hints() //{{{
t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, liberator.NEW_TAB)), t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, liberator.NEW_TAB)),
b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB)), b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB)),
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), F: Mode("Open multiple hints in tabs", hintAction_F),
O: Mode("Preselect hint in an :open query", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)), O: Mode(":open URL based on hint location", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)),
T: Mode("Preselect hint in a :tabopen query", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)), T: Mode(":tabopen URL based on hint location", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)),
W: Mode("Preselect hint in a :winopen query", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)), W: Mode(":winopen URL based on hint location", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)),
v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended), v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended),
V: Mode("View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true), extended), V: Mode("View hint source 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)),
@@ -84,17 +84,10 @@ function Hints() //{{{
}; };
// Used to open multiple hints // Used to open multiple hints
function hintSequenceElement(elem) function hintAction_F(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); 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 // 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 // showing them again, or is this short flash actually needed as a "usability
// feature"? --mst // feature"? --mst
@@ -580,10 +573,12 @@ function Hints() //{{{
"How links are matched", "How links are matched",
"string", "contains", "string", "contains",
{ {
completer: function (filter) completer: function (context) [
{ ["contains", "The typed characters are split on whitespace. The resulting groups must all appear in the hint."],
return [[m, ""] for each (m in ["contains", "wordstartswith", "firstletters", "custom"])]; ["wordstartswith", "The typed characters are split on whitespace. The resulting groups must all match the beginings of words, in order."],
}, ["firstletters", "Behaves like wordstartswith, but all groups much match a sequence of words."],
["custom", "Delegate to a custom function: liberator.plugins.customHintMatcher(hintString)"],
],
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -599,9 +594,19 @@ function Hints() //{{{
"Start QuickHint mode", "Start QuickHint mode",
function () { hints.show("o"); }); function () { hints.show("o"); });
// At the moment, "F" calls
// buffer.followLink(clicked_element, DO_WHAT_FIREFOX_DOES_WITH_CNTRL_CLICK)
// It is not clear that it shouldn't be:
// buffer.followLink(clicked_element, !DO_WHAT_FIREFOX_DOES_WITH_CNTRL_CLICK)
// In fact, it might be nice if there was a "dual" to F (like H and
// gH, except that gF is already taken). --tpp
//
// Likewise, it might be nice to have a liberator.NEW_FOREGROUND_TAB
// and then make liberator.NEW_TAB always do what a Cntrl+Click
// does. --tpp
mappings.add(myModes, ["F"], mappings.add(myModes, ["F"],
"Start QuickHint mode, but open link in a new tab", "Start QuickHint mode, but open link in a new tab",
function () { hints.show("t"); }); function () { hints.show(options.getPref("browser.tabs.loadInBackground") ? "b" : "t"); });
mappings.add(myModes, [";"], mappings.add(myModes, [";"],
"Start an extended hint mode", "Start an extended hint mode",

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Code based on venkman Code based on venkman
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
@@ -40,7 +40,7 @@ function Script(file)
return self; return self;
} }
plugins.contexts[file.path] = this; plugins.contexts[file.path] = this;
this.NAME = file.leafName.replace(/\..*/, "").replace(/-([a-z])/, function (_0, _1) _1.toUpperCase()); this.NAME = file.leafName.replace(/\..*/, "").replace(/-([a-z])/g, function (m, n1) n1.toUpperCase());
this.PATH = file.path; this.PATH = file.path;
this.__context__ = this; this.__context__ = this;
@@ -48,13 +48,14 @@ function Script(file)
for (let [,dir] in Iterator(io.getRuntimeDirectories("plugin"))) for (let [,dir] in Iterator(io.getRuntimeDirectories("plugin")))
{ {
if (dir.contains(file, false)) if (dir.contains(file, false))
plugins[name] = this.NAME; plugins[this.NAME] = this;
} }
} }
Script.prototype = plugins; Script.prototype = plugins;
// TODO: why are we passing around strings rather than file objects? // TODO: why are we passing around strings rather than file objects?
/** /**
* Provides a basic interface to common system I/O operations.
* @instance io * @instance io
*/ */
function IO() //{{{ function IO() //{{{
@@ -388,21 +389,94 @@ function IO() //{{{
const self = { const self = {
/**
* @property {number} Open for reading only.
* @final
*/
MODE_RDONLY: 0x01, MODE_RDONLY: 0x01,
/**
* @property {number} Open for writing only.
* @final
*/
MODE_WRONLY: 0x02, MODE_WRONLY: 0x02,
/**
* @property {number} Open for reading and writing.
* @final
*/
MODE_RDWR: 0x04, MODE_RDWR: 0x04,
/**
* @property {number} If the file does not exist, the file is created.
* If the file exists, this flag has no effect.
* @final
*/
MODE_CREATE: 0x08, MODE_CREATE: 0x08,
/**
* @property {number} The file pointer is set to the end of the file
* prior to each write.
* @final
*/
MODE_APPEND: 0x10, MODE_APPEND: 0x10,
/**
* @property {number} If the file exists, its length is truncated to 0.
* @final
*/
MODE_TRUNCATE: 0x20, MODE_TRUNCATE: 0x20,
/**
* @property {number} If set, each write will wait for both the file
* data and file status to be physically updated.
* @final
*/
MODE_SYNC: 0x40, MODE_SYNC: 0x40,
/**
* @property {number} With MODE_CREATE, if the file does not exist, the
* file is created. If the file already exists, no action and NULL
* is returned.
* @final
*/
MODE_EXCL: 0x80, MODE_EXCL: 0x80,
/**
* @property {Object} The current file sourcing context. As a file is
* being sourced the 'file' and 'line' properties of this context
* object are updated appropriately.
*/
sourcing: null, sourcing: null,
/**
* Expands "~" and environment variables in <b>path</b>.
*
* "~" is expanded to to the value of $HOME. On Windows if this is not
* set then the following are tried in order:
* $USERPROFILE
* ${HOMDRIVE}$HOMEPATH
*
* The variable notation is $VAR (terminated by a non-word character)
* or ${VAR}. %VAR% is also supported on Windows.
*
* @param {string} path The unexpanded path string.
* @param {boolean} relative Whether the path is relative or absolute.
* @returns {string}
*/
expandPath: IO.expandPath, expandPath: IO.expandPath,
// TODO: there seems to be no way, short of a new component, to change // TODO: there seems to be no way, short of a new component, to change
// 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
/**
* Returns the current working directory.
*
* It's not possible to change the real CWD of Firefox so this state is
* maintained internally. External commands run via {@link #system} are
* executed in this directory.
*
* @returns {nsIFile}
*/
getCurrentDirectory: function () getCurrentDirectory: function ()
{ {
let dir = self.getFile(cwd.path); let dir = self.getFile(cwd.path);
@@ -415,17 +489,23 @@ function IO() //{{{
return processDir; return processDir;
}, },
setCurrentDirectory: function (newdir) /**
* Sets the current working directory.
*
* @param {string} newDir The new CWD. This may be a relative or
* absolute path and is expanded by {@link #expandPath}.
*/
setCurrentDirectory: function (newDir)
{ {
newdir = newdir || "~"; newDir = newDir || "~";
if (newdir == "-") if (newDir == "-")
{ {
[cwd, oldcwd] = [oldcwd, this.getCurrentDirectory()]; [cwd, oldcwd] = [oldcwd, this.getCurrentDirectory()];
} }
else else
{ {
let dir = self.getFile(newdir); let dir = self.getFile(newDir);
if (!dir.exists() || !dir.isDirectory()) if (!dir.exists() || !dir.isDirectory())
{ {
@@ -439,16 +519,30 @@ function IO() //{{{
return self.getCurrentDirectory(); return self.getCurrentDirectory();
}, },
getRuntimeDirectories: function (specialDirectory) /**
* Returns all directories named <b>name<b/> in 'runtimepath'.
*
* @param {string} name
* @returns {nsIFile[])
*/
getRuntimeDirectories: function (name)
{ {
let dirs = getPathsFromPathList(options["runtimepath"]); let dirs = getPathsFromPathList(options["runtimepath"]);
dirs = dirs.map(function (dir) joinPaths(dir, specialDirectory)) dirs = dirs.map(function (dir) joinPaths(dir, name))
.filter(function (dir) dir.exists() && dir.isDirectory() && dir.isReadable()); .filter(function (dir) dir.exists() && dir.isDirectory() && dir.isReadable());
return dirs; return dirs;
}, },
/**
* Returns the first user RC file found in <b>dir</b>.
*
* @param {string} dir The directory to search.
* @param {boolean} always When true, return a path whether
* the file exists or not.
* @default $HOME.
*/
getRCFile: function (dir, always) getRCFile: function (dir, always)
{ {
dir = dir || "~"; dir = dir || "~";
@@ -471,6 +565,14 @@ function IO() //{{{
// return a nsILocalFile for path where you can call isDirectory(), etc. on // return a nsILocalFile for path where you can call isDirectory(), etc. on
// caller must check with .exists() if the returned file really exists // caller must check with .exists() if the returned file really exists
// also expands relative paths // also expands relative paths
/**
* Returns an nsIFile object for <b>path</b>, which is expanded
* according to {@link #expandPath}.
*
* @param {string} path The path used to create the file object.
* @param {boolean} noCheckPWD Whether to allow a relative path.
* @returns {nsIFile}
*/
getFile: function (path, noCheckPWD) getFile: function (path, noCheckPWD)
{ {
let file = services.create("file"); let file = services.create("file");
@@ -494,7 +596,11 @@ function IO() //{{{
}, },
// TODO: make secure // TODO: make secure
// returns a nsILocalFile or null if it could not be created /**
* Creates a temporary file.
*
* @returns {nsIFile}
*/
createTempFile: function () createTempFile: function ()
{ {
let tmpName = EXTENSION_NAME + ".tmp"; let tmpName = EXTENSION_NAME + ".tmp";
@@ -525,17 +631,25 @@ function IO() //{{{
}, },
// file is either a full pathname or an instance of file instanceof nsILocalFile /**
readDirectory: function (file, sort) * Returns the list of files in <b>dir</b>.
*
* @param {nsIFile|string} dir The directory to read, either a full
* pathname or an instance of nsIFile.
* @param {boolean} sort Whether to sort the returned directory
* entries.
* @returns {nsIFile[]}
*/
readDirectory: function (dir, sort)
{ {
if (typeof file == "string") if (typeof dir == "string")
file = self.getFile(file); dir = self.getFile(dir);
else if (!(file instanceof Ci.nsILocalFile)) else if (!(dir 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 (file.isDirectory()) if (dir.isDirectory())
{ {
let entries = file.directoryEntries; let entries = dir.directoryEntries;
let array = []; let array = [];
while (entries.hasMoreElements()) while (entries.hasMoreElements())
{ {
@@ -551,8 +665,13 @@ function IO() //{{{
// Yes --djk // Yes --djk
}, },
// file is either a full pathname or an instance of file instanceof nsILocalFile /**
// reads a file in "text" mode and returns the string * Reads a file in "text" mode and returns the content as a string.
*
* @param {nsIFile|string} file The file to read, either a full
* pathname or an instance of nsIFile.
* @returns {string}
*/
readFile: function (file) readFile: function (file)
{ {
let ifstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); let ifstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
@@ -578,9 +697,30 @@ function IO() //{{{
return buffer; return buffer;
}, },
// file is either a full pathname or an instance of file instanceof nsILocalFile /**
// default permission = 0644, only used when creating a new file, does not change permissions if the file exists * Writes the string <b>buf</b> to a file.
// mode can be ">" or ">>" in addition to the normal MODE_* flags *
* @param {nsIFile|string} file The file to write, either a full
* pathname or an instance of nsIFile.
* @param {string} buf The file content.
* @param {string|number} mode The file access mode, a bitwise OR of
* the following flags:
* {@link #MODE_RDONLY}: 0x01
* {@link #MODE_WRONLY}: 0x02
* {@link #MODE_RDWR}: 0x04
* {@link #MODE_CREATE}: 0x08
* {@link #MODE_APPEND}: 0x10
* {@link #MODE_TRUNCATE}: 0x20
* {@link #MODE_SYNC}: 0x40
* Alternatively, the following abbreviations may be used:
* ">" is equivalent to {@link #MODE_WRONLY} | {@link #MODE_CREATE} | {@link #MODE_TRUNCATE}
* ">>" is equivalent to {@link #MODE_WRONLY} | {@link #MODE_CREATE} | {@link #MODE_APPEND}
* @default ">"
* @param {number} perms The file mode bits of the created file. This
* is only used when creating a new file and does not change
* permissions if the file exists.
* @default 0644
*/
writeFile: function (file, buf, mode, perms) writeFile: function (file, buf, mode, perms)
{ {
let ofstream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); let ofstream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
@@ -608,6 +748,13 @@ function IO() //{{{
ofstream.close(); ofstream.close();
}, },
/**
* Runs an external program.
*
* @param {string} program The program to run.
* @param {string[]} args An array of arguments to pass to <b>program</b>.
* @param {boolean} blocking Whether to wait until the process terminates.
*/
run: function (program, args, blocking) run: function (program, args, blocking)
{ {
args = args || []; args = args || [];
@@ -666,47 +813,17 @@ lookup:
return process.exitValue; return process.exitValue;
}, },
// when https://bugzilla.mozilla.org/show_bug.cgi?id=68702 is fixed
// is fixed, should use that instead of a tmpfile
system: function (command, input)
{
liberator.echomsg("Calling shell to execute: " + command, 4);
function escape(str) '"' + str.replace(/[\\"$]/g, "\\$&") + '"';
return this.withTempFiles(function (stdin, stdout, stderr, cmd) {
if (input)
this.writeFile(stdin, input);
if (WINDOWS)
{
command = "cd /D " + cwd.path + " && " + command + " > " + stdout.path + " 2> " + stderr.path + " < " + stdin.path;
var res = this.run(options["shell"], options["shellcmdflag"].split(/\s+/).concat(command), true);
}
else
{
this.writeFile(cmd, "cd " + escape(cwd.path) + "\n" +
["exec", ">" + escape(stdout.path), "2>" + escape(stderr.path), "<" + escape(stdin.path),
escape(options["shell"]), options["shellcmdflag"], escape(command)].join(" "));
res = this.run("/bin/sh", ["-e", cmd.path], true);
}
if (res > 0) // FIXME: Is this really right? Shouldn't we always show both?
var output = self.readFile(stderr) + "\nshell returned " + res;
else
output = self.readFile(stdout);
// if there is only one \n at the end, chop it off
if (output && output.indexOf("\n") == output.length - 1)
output = output.substr(0, output.length - 1);
return output;
}) || "";
},
// FIXME: multiple paths? // FIXME: multiple paths?
/**
* Sources files found in 'runtimepath'. For each relative path in
* <b>paths</b> each directory in 'runtimepath' is searched and if a
* matching file is found it is sourced. Only the first file found (per
* specified path) is sourced unless <b>all</b> is specified, then
* all found files are sourced.
*
* @param {string[]} paths An array of relative paths to source.
* @param {boolean} all Whether all found files should be sourced.
*/
sourceFromRuntimePath: function (paths, all) sourceFromRuntimePath: function (paths, all)
{ {
let dirs = getPathsFromPathList(options["runtimepath"]); let dirs = getPathsFromPathList(options["runtimepath"]);
@@ -741,8 +858,12 @@ lookup:
return found; return found;
}, },
// files which end in .js are sourced as pure JavaScript files, /**
// no need (actually forbidden) to add: js <<EOF ... EOF around those files * Reads Ex commands, JavaScript or CSS from <b>filename</b>.
*
* @param {string} filename The name of the file to source.
* @param {boolean} silent Whether errors should be reported.
*/
source: function (filename, silent) source: function (filename, silent)
{ {
let wasSourcing = self.sourcing; let wasSourcing = self.sourcing;
@@ -772,7 +893,7 @@ lookup:
liberator.echomsg("sourcing " + filename.quote(), 2); liberator.echomsg("sourcing " + filename.quote(), 2);
let str = self.readFile(file); let str = self.readFile(file);
let uri = ioService.newFileURI(file); let uri = services.get("io").newFileURI(file);
// handle pure JavaScript files specially // handle pure JavaScript files specially
if (/\.js$/.test(filename)) if (/\.js$/.test(filename))
@@ -896,11 +1017,68 @@ lookup:
} }
}, },
// TODO: when https://bugzilla.mozilla.org/show_bug.cgi?id=68702 is
// fixed is fixed, should use that instead of a tmpfile
/**
* Runs <b>command</b> in a subshell and returns the output in a
* string. The shell used is that specified by the 'shell' option.
*
* @param {string} command The command to run.
* @param {string} input Any input to be provided to the command on stdin.
* @returns {string}
*/
system: function (command, input)
{
liberator.echomsg("Calling shell to execute: " + command, 4);
function escape(str) '"' + str.replace(/[\\"$]/g, "\\$&") + '"';
return this.withTempFiles(function (stdin, stdout, cmd) {
if (input)
this.writeFile(stdin, input);
// TODO: implement 'shellredir'
if (WINDOWS)
{
command = "cd /D " + cwd.path + " && " + command + " > " + stdout.path + " 2>&1" + " < " + stdin.path;
var res = this.run(options["shell"], options["shellcmdflag"].split(/\s+/).concat(command), true);
}
else
{
this.writeFile(cmd, "cd " + escape(cwd.path) + "\n" +
["exec", ">" + escape(stdout.path), "2>&1", "<" + escape(stdin.path),
escape(options["shell"]), options["shellcmdflag"], escape(command)].join(" "));
res = this.run("/bin/sh", ["-e", cmd.path], true);
}
let output = self.readFile(stdout);
if (res > 0)
output += "\nshell returned " + res;
// if there is only one \n at the end, chop it off
else if (output && output.indexOf("\n") == output.length - 1)
output = output.substr(0, output.length - 1);
return output;
}) || "";
},
/**
* Creates a temporary file context for executing external commands.
* <b>fn</b> is called with a temp file, created with
* {@link #createTempFile}, for each explicit argument. Ensures that
* all files are removed when <b>fn</b> returns.
*
* @param {function} fn The function to execute.
* @param {Object} self The 'this' object used when executing fn.
* @return {boolean} false if temp files couldn't be created,
* otherwise, the return value of <b>fn</b>.
*/
withTempFiles: function (fn, self) withTempFiles: function (fn, self)
{ {
let args = util.map(util.range(0, fn.length), this.createTempFile); let args = util.map(util.range(0, fn.length), this.createTempFile);
if (!args.every(util.identity)) if (!args.every(util.identity))
return false; return false;
try try
{ {
return fn.apply(self || this, args); return fn.apply(self || this, args);
@@ -922,6 +1100,10 @@ IO.PATH_SEP = (function () {
return file.path[0]; return file.path[0];
})(); })();
/**
* @property {string} The value of the $VIMPERATOR_RUNTIME environment
* variable.
*/
IO.__defineGetter__("runtimePath", function () { IO.__defineGetter__("runtimePath", function () {
const rtpvar = config.name.toUpperCase() + "_RUNTIME"; const rtpvar = config.name.toUpperCase() + "_RUNTIME";
let rtp = services.get("environment").get(rtpvar); let rtp = services.get("environment").get(rtpvar);

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -28,7 +28,7 @@ the terms of any one of the MPL, the GPL or the LGPL.
/** @scope modules */ /** @scope modules */
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm", modules);
const plugins = {}; const plugins = {};
plugins.__proto__ = modules; plugins.__proto__ = modules;
@@ -153,7 +153,7 @@ const liberator = (function () //{{{
group.setter(value); group.setter(value);
return value; return value;
}, },
completer: function (filter) completer: function (context)
{ {
let opts = [v.opts for ([k, v] in Iterator(groups))]; let opts = [v.opts for ([k, v] in Iterator(groups))];
opts = opts.map(function (opt) [[k, v[0]] for ([k, v] in Iterator(opt))]); opts = opts.map(function (opt) [[k, v[0]] for ([k, v] in Iterator(opt))]);
@@ -206,6 +206,34 @@ const liberator = (function () //{{{
function () { liberator.quit(true); }); function () { liberator.quit(true); });
}); });
// TODO: move this
function getMenuItems()
{
function addChildren(node, parent)
{
for (let [,item] in Iterator(node.childNodes))
{
if (item.childNodes.length == 0 && item.localName == "menuitem"
&& !/rdf:http:/.test(item.label)) // FIXME
{
item.fullMenuPath = parent + item.label;
items.push(item);
}
else
{
let path = parent;
if (item.localName == "menu")
path += item.label + ".";
addChildren(item, path);
}
}
}
let items = [];
addChildren(document.getElementById(config.guioptions["m"][1]), "");
return items;
}
registerObserver("load_commands", function () registerObserver("load_commands", function ()
{ {
commands.add(["addo[ns]"], commands.add(["addo[ns]"],
@@ -256,34 +284,6 @@ const liberator = (function () //{{{
completer: function (context, args) completion.dialog(context) completer: function (context, args) completion.dialog(context)
}); });
// TODO: move this
function getMenuItems()
{
function addChildren(node, parent)
{
for (let [,item] in Iterator(node.childNodes))
{
if (item.childNodes.length == 0 && item.localName == "menuitem"
&& !/rdf:http:/.test(item.label)) // FIXME
{
item.fullMenuPath = parent + item.label;
items.push(item);
}
else
{
let path = parent;
if (item.localName == "menu")
path += item.label + ".";
addChildren(item, path);
}
}
}
let items = [];
addChildren(document.getElementById(config.guioptions["m"][1]), "");
return items;
}
commands.add(["em[enu]"], commands.add(["em[enu]"],
"Execute the specified menu item from the command line", "Execute the specified menu item from the command line",
function (args) function (args)
@@ -305,13 +305,7 @@ const liberator = (function () //{{{
}, },
{ {
argCount: "1", argCount: "1",
// TODO: add this as a standard menu completion function completer: function (context) completion.menuItem(context),
completer: function (context)
{
context.title = ["Menu Path", "Label"];
context.keys = { text: "fullMenuPath", description: "label" };
context.completions = getMenuItems();
},
literal: 0 literal: 0
}); });
@@ -597,6 +591,8 @@ const liberator = (function () //{{{
get mode() modes.main, get mode() modes.main,
set mode(value) modes.main = value, set mode(value) modes.main = value,
get menuItems() getMenuItems(),
// Global constants // Global constants
CURRENT_TAB: 1, CURRENT_TAB: 1,
NEW_TAB: 2, NEW_TAB: 2,
@@ -652,8 +648,9 @@ const liberator = (function () //{{{
triggerObserver: function (type) triggerObserver: function (type)
{ {
let args = Array.slice(arguments, 1);
for (let [,fn] in Iterator(observers[type] || [])) for (let [,fn] in Iterator(observers[type] || []))
fn.apply(null, Array.slice(arguments, 1)); fn.apply(null, args);
}, },
beep: function () beep: function ()

View File

@@ -13,7 +13,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -113,8 +113,7 @@ const modes = (function () //{{{
if (newMode == modes.NORMAL) if (newMode == modes.NORMAL)
{ {
// disable caret mode when we want to switch to normal mode // disable caret mode when we want to switch to normal mode
let value = options.getPref("accessibility.browsewithcaret", false); if (options.getPref("accessibility.browsewithcaret"))
if (value)
options.setPref("accessibility.browsewithcaret", false); options.setPref("accessibility.browsewithcaret", false);
statusline.updateUrl(); statusline.updateUrl();
@@ -171,7 +170,7 @@ const modes = (function () //{{{
// helper function to set both modes in one go // helper function to set both modes in one go
// if silent == true, you also need to take care of the mode handling changes yourself // if silent == true, you also need to take care of the mode handling changes yourself
set: function (mainMode, extendedMode, silent) set: function (mainMode, extendedMode, silent, stack)
{ {
silent = (silent || main == mainMode && extended == extendedMode); silent = (silent || main == mainMode && extended == extendedMode);
// if a main mode is set, the extended is always cleared // if a main mode is set, the extended is always cleared
@@ -187,6 +186,7 @@ const modes = (function () //{{{
if (main != oldMain) if (main != oldMain)
handleModeChange(oldMain, mainMode, oldExtended); handleModeChange(oldMain, mainMode, oldExtended);
} }
liberator.triggerObserver("modeChange", [oldMain, oldExtended], [main, extended], stack);
if (!silent) if (!silent)
this.show(); this.show();
@@ -195,18 +195,19 @@ const modes = (function () //{{{
push: function (mainMode, extendedMode, silent) push: function (mainMode, extendedMode, silent)
{ {
modeStack.push([main, extended]); modeStack.push([main, extended]);
this.set(mainMode, extendedMode, silent); this.set(mainMode, extendedMode, silent, { push: modeStack[modeStack.length - 1] });
}, },
pop: function (silent) pop: function (silent)
{ {
let a = modeStack.pop(); let a = modeStack.pop();
if (a) if (a)
this.set(a[0], a[1], silent); this.set(a[0], a[1], silent, { pop: a });
else else
this.reset(silent); this.reset(silent);
}, },
// TODO: Deprecate this in favor of addMode? --Kris
setCustomMode: function (modestr, oneventfunc, stopfunc) setCustomMode: function (modestr, oneventfunc, stopfunc)
{ {
// TODO this.plugin[id]... ('id' maybe submode or what..) // TODO this.plugin[id]... ('id' maybe submode or what..)
@@ -247,18 +248,10 @@ const modes = (function () //{{{
set isReplaying(value) { isReplaying = value; this.show(); }, set isReplaying(value) { isReplaying = value; this.show(); },
get main() main, get main() main,
set main(value) { set main(value) { this.set(value); },
if (value != main)
handleModeChange(main, value);
main = value;
// setting the main mode always resets any extended mode
extended = modes.NONE;
this.show();
},
get extended() extended, get extended() extended,
set extended(value) { extended = value; this.show(); } set extended(value) { this.set(null, value) }
}; };
@@ -285,7 +278,6 @@ const modes = (function () //{{{
self.addMode("SEARCH_BACKWARD", true); self.addMode("SEARCH_BACKWARD", true);
self.addMode("MENU", true); // a popupmenu is active self.addMode("MENU", true); // a popupmenu is active
self.addMode("LINE", true); // linewise visual mode self.addMode("LINE", true); // linewise visual mode
self.addMode("RECORDING", true);
self.addMode("PROMPT", true); self.addMode("PROMPT", true);
return self; return self;

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -1015,17 +1015,38 @@ function Options() //{{{
liberator.echoerr("E488: Trailing characters: " + name + "!"); liberator.echoerr("E488: Trailing characters: " + name + "!");
}, },
/**
* Pushes a new preference context onto the context stack.
*
* @see #withContext
*/
pushContext: function () pushContext: function ()
{ {
prefContexts.push({}); prefContexts.push({});
}, },
/**
* Pops the top preference context from the stack.
*
* @see #withContext
*/
popContext: function () popContext: function ()
{ {
for (let [k, v] in Iterator(prefContexts.pop())) for (let [k, v] in Iterator(prefContexts.pop()))
storePreference(k, v); storePreference(k, v);
}, },
/**
* Executes <b>fn</b> with a new preference context. When <b>fn</b>
* returns, the context is popped and any preferences set via
* {@link #setPref} or {@link #invertPref} are restored to their
* previous values.
*
* @param {function} fn The function to call.
* @param {object} fn The 'this' object with which to call <b>fn</b>
* @see #pushContext
* @see #popContext
*/
withContext: function (fn, self) withContext: function (fn, self)
{ {
try try

View File

@@ -1,5 +1,5 @@
/***** BEGIN LICENSE BLOCK ***** {{{ /***** BEGIN LICENSE BLOCK ***** {{{
©2008 Kris Maglione <maglione.k at Gmail> Copyright © 2008-2009 by Kris Maglione <maglione.k at Gmail>
Distributable under the terms of the MIT license, which allows Distributable under the terms of the MIT license, which allows
for sublicensing under any compatible license, including the MPL, for sublicensing under any compatible license, including the MPL,
GPL, and MPL. Anyone who changes this file is welcome to relicense GPL, and MPL. Anyone who changes this file is welcome to relicense

View File

@@ -1,5 +1,5 @@
/***** BEGIN LICENSE BLOCK ***** {{{ /***** BEGIN LICENSE BLOCK ***** {{{
©2008 Kris Maglione <maglione.k at Gmail> Copyright © 2008-2009 by Kris Maglione <maglione.k at Gmail>
Distributable under the terms of the MIT license, which allows Distributable under the terms of the MIT license, which allows
for sublicensing under any compatible license, including the MPL, for sublicensing under any compatible license, including the MPL,
GPL, and MPL. Anyone who changes this file is welcome to relicense GPL, and MPL. Anyone who changes this file is welcome to relicense

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -140,14 +140,11 @@ function Tabs() //{{{
return value; return value;
}, },
completer: function (filter) completer: function (context) [
{
return [
["0", "Never show tab bar"], ["0", "Never show tab bar"],
["1", "Show tab bar only if more than one tab is open"], ["1", "Show tab bar only if more than one tab is open"],
["2", "Always show tab bar"] ["2", "Always show tab bar"]
]; ],
},
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -157,15 +154,12 @@ function Tabs() //{{{
"Define when tabs are automatically activated", "Define when tabs are automatically activated",
"stringlist", "homepage,quickmark,tabopen,paste", "stringlist", "homepage,quickmark,tabopen,paste",
{ {
completer: function (filter) completer: function (context) [
{
return [
["homepage", "gH mapping"], ["homepage", "gH mapping"],
["quickmark", "go and gn mappings"], ["quickmark", "go and gn mappings"],
["tabopen", ":tabopen[!] command"], ["tabopen", ":tabopen[!] command"],
["paste", "P and gP mappings"] ["paste", "P and gP mappings"]
]; ],
},
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -173,17 +167,14 @@ function Tabs() //{{{
"Define which commands should output in a new tab by default", "Define which commands should output in a new tab by default",
"stringlist", "", "stringlist", "",
{ {
completer: function (filter) completer: function (context) [
{
return [
["all", "All commands"], ["all", "All commands"],
["addons", ":addo[ns] command"], ["addons", ":addo[ns] command"],
["downloads", ":downl[oads] command"], ["downloads", ":downl[oads] command"],
["help", ":h[elp] command"], ["help", ":h[elp] command"],
["javascript", ":javascript! or :js! command"], ["javascript", ":javascript! or :js! command"],
["prefs", ":pref[erences]! or :prefs! command"] ["prefs", ":pref[erences]! or :prefs! command"]
]; ],
},
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -204,16 +195,13 @@ function Tabs() //{{{
return value; return value;
}, },
completer: function (filter) completer: function (context) [
{
return [
["0", "Force to open in the current tab"], ["0", "Force to open in the current tab"],
["1", "Always open in a new tab"], ["1", "Always open in a new tab"],
["2", "Open in a new window if it has a specific requested size (default in Firefox)"], ["2", "Open in a new window if it has a specific requested size (default in Firefox)"],
["3", "Always open in a new window"], ["3", "Always open in a new window"],
["4", "Open in the same tab unless it has a specific requested size"] ["4", "Open in the same tab unless it has a specific requested size"]
]; ],
},
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
let fragment = liberator.has("MacUnix") ? "tab-mac" : "tab"; let fragment = liberator.has("MacUnix") ? "tab-mac" : "tab";
@@ -629,6 +617,7 @@ function Tabs() //{{{
argCount: "?", argCount: "?",
completer: function (context) completer: function (context)
{ {
context.anchored = false;
context.keys = { text: function (item) item.state.entries[0].url, description: "title" }; context.keys = { text: function (item) item.state.entries[0].url, description: "title" };
context.completions = tabs.closedTabs; context.completions = tabs.closedTabs;
}, },

View File

@@ -1,3 +1,30 @@
/***** BEGIN LICENSE BLOCK ***** {{{
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/
/** @scope modules */ /** @scope modules */

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -29,10 +29,10 @@ 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 be sure to only create objects of
* be sure to only create objects of this class when the chrome is ready * this class when the chrome is ready.
*/ */
function CommandLine() //{{{ function CommandLine() //{{{
{ {
@@ -43,7 +43,7 @@ function CommandLine() //{{{
storage.newArray("history-search", true); storage.newArray("history-search", true);
storage.newArray("history-command", true); storage.newArray("history-command", true);
var messageHistory = { var messageHistory = { // {{{
_messages: [], _messages: [],
get messages() get messages()
{ {
@@ -68,7 +68,7 @@ function CommandLine() //{{{
this._messages.push(message); this._messages.push(message);
} }
}; }; // }}}
var lastMowOutput = null; var lastMowOutput = null;
var silent = false; var silent = false;
@@ -76,12 +76,12 @@ function CommandLine() //{{{
var lastEcho = null; var lastEcho = null;
/** /**
* A class for managing the history of an inputField * A class for managing the history of an inputField.
* *
* @param {Object} inputField * @param {HTMLInputElement} inputField
* @param {string} mode * @param {string} mode The mode for which we need history.
*/ */
function History(inputField, mode) function History(inputField, mode) // {{{
{ {
if (!(this instanceof arguments.callee)) if (!(this instanceof arguments.callee))
return new arguments.callee(inputField, mode); return new arguments.callee(inputField, mode);
@@ -92,14 +92,15 @@ function CommandLine() //{{{
} }
History.prototype = { History.prototype = {
/** /**
* Empties the history. * Reset the history index to the first entry.
*/ */
reset: function () reset: function ()
{ {
this.index = null; this.index = null;
}, },
/** /**
* Permanently save the history * Save the last entry to the permanent store. All duplicate entries
* are removed and the list is truncated, if necessary.
*/ */
save: function () save: function ()
{ {
@@ -111,9 +112,9 @@ function CommandLine() //{{{
this.store.truncate(options["history"], true); this.store.truncate(options["history"], true);
}, },
/** /**
* Set the current match to val * Replace the current input field value.
* *
* @param {string} val * @param {string} val The new value.
*/ */
replace: function (val) replace: function (val)
{ {
@@ -122,10 +123,11 @@ function CommandLine() //{{{
}, },
/** /**
* move up or (if backward) down in the history * Move forward or backward in history.
* *
* @param {boolean} backward * @param {boolean} backward Direction to move.
* @param {boolean} matchCurrent XXX: what? * @param {boolean} matchCurrent Search for matches starting
* with the current input value.
*/ */
select: function (backward, matchCurrent) select: function (backward, matchCurrent)
{ {
@@ -173,14 +175,14 @@ function CommandLine() //{{{
} }
} }
} }
}; }; // }}}
/** /**
* A class for tab completions on an input field * A class for tab completions on an input field.
* *
* @param {Object} input * @param {Object} input
*/ */
function Completions(input) function Completions(input) // {{{
{ {
if (!(this instanceof arguments.callee)) if (!(this instanceof arguments.callee))
return new arguments.callee(input); return new arguments.callee(input);
@@ -380,24 +382,53 @@ function CommandLine() //{{{
{ {
// Wait for contexts to complete if necessary. // Wait for contexts to complete if necessary.
// FIXME: Need to make idx relative to individual contexts. // FIXME: Need to make idx relative to individual contexts.
let list = this.context.contextList.reverse(); let list = this.context.contextList;
if (idx == -2) if (idx == -2)
list = list.slice().reverse(); list = list.slice().reverse();
let n = 0; let n = 0;
try
{
this.waiting = true;
for (let [,context] in Iterator(list)) for (let [,context] in Iterator(list))
{ {
function done() !(idx >= n + context.items.length || idx == -2 && !context.items.length); function done() !(idx >= n + context.items.length || idx == -2 && !context.items.length);
while (context.incomplete && !done()) while (context.incomplete && !done())
liberator.threadYield(true, true); // threadYield(true, true) would be better, but it does not return on my
// machine until all awesomebar completions were reported, making
// :open foo<tab> nearly unusable, if the first 2 foo-completions would
// be there fast, but it takes up to 20 sec to find more foo-completions
//
// The strange thing is, I tested the 2009-01-07 nightly at work in Windows
// and it seemed to work perfectly there. Will have to see if it's a
// hardware (dual core there, vs. P4 at home) issue or an OS issue.
//
// While I *really* prefer this solution over my hack
// when it works, we can't have a nearly-defect :open
// prompt when releasing vimp 2.0, even not just on certain
// computers, as :open is probably the most often used ex-command
// in vimperator
//
// liberator.threadYield(false, true); is just a temporary measure as
// it has other problems (hitting tab often in a row), until we find the
// source of the problem (which we hopefully do, as I really don't want to
// have to revert to my hack when better solutions exist)
liberator.threadYield(false, true);
if (done()) if (done())
break; break;
n += context.items.length; n += context.items.length;
} }
}
finally
{
this.waiting = false;
}
// See previous FIXME. This will break if new items in // See previous FIXME. This will break if new items in
// a previous context come in. // a previous context come in.
if (idx < 0) if (idx < 0)
idx = this.items.length - 1; idx = this.items.length - 1;
if (this.items.length == 0)
return;
this.selected = idx; this.selected = idx;
this.completion = this.items[idx].text; this.completion = this.items[idx].text;
@@ -406,6 +437,8 @@ function CommandLine() //{{{
this.itemList.selectItem(idx); this.itemList.selectItem(idx);
}, },
tabs: [],
tab: function tab(reverse) tab: function tab(reverse)
{ {
autocompleteTimer.flush(); autocompleteTimer.flush();
@@ -413,6 +446,13 @@ function CommandLine() //{{{
if (this.context.waitingForTab || this.wildIndex == -1) if (this.context.waitingForTab || this.wildIndex == -1)
this.complete(true, true); this.complete(true, true);
this.tabs.push(reverse);
if (this.waiting)
return;
while (this.tabs.length)
{
reverse = this.tabs.shift();
switch (this.wildtype.replace(/.*:/, "")) switch (this.wildtype.replace(/.*:/, ""))
{ {
case "": case "":
@@ -431,9 +471,6 @@ 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();
@@ -442,7 +479,11 @@ function CommandLine() //{{{
statusTimer.tell(); statusTimer.tell();
} }
if (this.items.length == 0)
liberator.beep();
} }
}; // }}}
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
////////////////////// TIMERS ////////////////////////////////////////////////// ////////////////////// TIMERS //////////////////////////////////////////////////
@@ -455,13 +496,18 @@ function CommandLine() //{{{
statusline.updateProgress("match " + (completions.selected + 1) + " of " + completions.items.length); statusline.updateProgress("match " + (completions.selected + 1) + " of " + completions.items.length);
}); });
var autocompleteTimer = new Timer(201, 500, function autocompleteTell(tabPressed) { var autocompleteTimer = new Timer(200, 500, function autocompleteTell(tabPressed) {
if (events.feedingKeys || !completions) if (!events.feedingKeys && completions && options.get("wildoptions").has("auto"))
return; {
completions.complete(true, false); completions.complete(true, false);
completions.itemList.show(); completions.itemList.show();
}
}); });
// This timer just prevents <Tab>s from queueing up when the
// system is under load (and, thus, giving us several minutes of
// the completion list scrolling). Multiple <Tab> presses are
// still processed normally, as the time is flushed on "keyup".
var tabTimer = new Timer(0, 0, function tabTell(event) { var tabTimer = new Timer(0, 0, function tabTell(event) {
if (completions) if (completions)
completions.tab(event.shiftKey); completions.tab(event.shiftKey);
@@ -471,10 +517,7 @@ function CommandLine() //{{{
////////////////////// CALLBACKS /////////////////////////////////////////////// ////////////////////// CALLBACKS ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
// callback for prompt mode var input = {};
var promptSubmitCallback = null;
var promptChangeCallback = null;
var promptCompleter = null;
liberator.registerCallback("submit", modes.EX, function (command) { liberator.registerCallback("submit", modes.EX, function (command) {
liberator.execute(command); liberator.execute(command);
@@ -483,28 +526,28 @@ function CommandLine() //{{{
context.fork("ex", 0, completion, "ex"); context.fork("ex", 0, completion, "ex");
}); });
liberator.registerCallback("change", modes.EX, function (command) { liberator.registerCallback("change", modes.EX, function (command) {
if (options.get("wildoptions").has("auto"))
autocompleteTimer.tell(false); autocompleteTimer.tell(false);
}); });
liberator.registerCallback("cancel", modes.PROMPT, closePrompt); liberator.registerCallback("cancel", modes.PROMPT, closePrompt);
liberator.registerCallback("submit", modes.PROMPT, closePrompt); liberator.registerCallback("submit", modes.PROMPT, closePrompt);
liberator.registerCallback("change", modes.PROMPT, function (str) { liberator.registerCallback("change", modes.PROMPT, function (str) {
liberator.triggerCallback("change", modes.EX, str); if (input.complete)
if (promptChangeCallback) autocompleteTimer.tell(false);
return promptChangeCallback.call(commandline, str); if (input.change)
return input.change.call(commandline, str);
}); });
liberator.registerCallback("complete", modes.PROMPT, function (context) { liberator.registerCallback("complete", modes.PROMPT, function (context) {
if (promptCompleter) if (input.complete)
context.fork("input", 0, commandline, promptCompleter); context.fork("input", 0, commandline, input.complete);
}); });
function closePrompt(value) function closePrompt(value)
{ {
let callback = promptSubmitCallback; let callback = input.submit;
promptSubmitCallback = null; input = {};
if (callback) if (callback)
callback.call(commandline, value == null ? commandline.command : value); callback.call(commandline, value != null ? value : commandline.command);
} }
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
@@ -554,7 +597,7 @@ function CommandLine() //{{{
var multilineCallback = null; var multilineCallback = null;
/** /**
* @private - highlight the messageBox according to group * Highlight the messageBox according to <b>group</b>.
*/ */
function setHighlightGroup(group) function setHighlightGroup(group)
{ {
@@ -562,7 +605,7 @@ function CommandLine() //{{{
} }
/** /**
* @private - Determines whether the command line should be visible. * Determines whether the command-line should be visible.
* *
* @return {boolean} * @return {boolean}
*/ */
@@ -570,7 +613,7 @@ function CommandLine() //{{{
!(modes.extended & (modes.INPUT_MULTILINE | modes.OUTPUT_MULTILINE)); !(modes.extended & (modes.INPUT_MULTILINE | modes.OUTPUT_MULTILINE));
/** /**
* @private - set the prompt to val styled with highlightGroup * Set the command-line prompt.
* *
* @param {string} val * @param {string} val
* @param {string} highlightGroup * @param {string} highlightGroup
@@ -584,7 +627,8 @@ function CommandLine() //{{{
} }
/** /**
* @private - set the command to cmd and move the user's cursor to the end. * Set the command-line input value. The caret is reset to the
* end of the line.
* *
* @param {string} cmd * @param {string} cmd
*/ */
@@ -596,12 +640,12 @@ function CommandLine() //{{{
} }
/** /**
* @private - display a message styled with highlightGroup * Display a message in the command-line area.
* and, if forceSingle is true, ensure it takes only one line.
* *
* @param {string} str * @param {string} str
* @param {string} highlightGroup * @param {string} highlightGroup
* @param {boolean} forceSingle * @param {boolean} forceSingle If provided, don't let over-long
* messages move to the MOW.
*/ */
function echoLine(str, highlightGroup, forceSingle) function echoLine(str, highlightGroup, forceSingle)
{ {
@@ -619,13 +663,12 @@ function CommandLine() //{{{
} }
/** /**
* Display a multiline message, possible through a "more" like interface * Display a multiline message.
*
* TODO: resize upon a window resize
* *
* @param {string} str * @param {string} str
* @param {string} highlightGroup * @param {string} highlightGroup
*/ */
// TODO: resize upon a window resize
function echoMultiline(str, highlightGroup) function echoMultiline(str, highlightGroup)
{ {
let doc = multilineOutputWidget.contentDocument; let doc = multilineOutputWidget.contentDocument;
@@ -642,7 +685,6 @@ function CommandLine() //{{{
let output = util.xmlToDom(lastMowOutput, doc); let output = util.xmlToDom(lastMowOutput, doc);
XML.ignoreWhitespace = true; XML.ignoreWhitespace = true;
// FIXME: need to make sure an open MOW is closed when commands // FIXME: need to make sure an open MOW is closed when commands
// that don't generate output are executed // that don't generate output are executed
if (outputContainer.collapsed) if (outputContainer.collapsed)
@@ -671,8 +713,7 @@ function CommandLine() //{{{
} }
/** /**
* @private - ensure that the Multiline input widget is the * Ensure that the multiline input widget is the correct size.
* correct size.
*/ */
function autosizeMultilineInputWidget() function autosizeMultilineInputWidget()
{ {
@@ -682,14 +723,12 @@ function CommandLine() //{{{
} }
/** /**
* @private - eval()s a javascript expression * eval() a JavaScript expression and return a string suitable
* and returns a string suitable to be echo'd. * to be echoed.
*
* If useColor is true, util.objectToString will
* colorize object output.
* *
* @param {string} arg * @param {string} arg
* @param {boolean} useColor * @param {boolean} useColor When true, the result is a
* highlighted XML object.
*/ */
function echoArgumentToString(arg, useColor) function echoArgumentToString(arg, useColor)
{ {
@@ -757,7 +796,7 @@ function CommandLine() //{{{
"Items which are completed at the :[tab]open prompt", "Items which are completed at the :[tab]open prompt",
"charlist", "sfl", "charlist", "sfl",
{ {
completer: function completer(filter) [k for each (k in completion.urlCompleters)], completer: function (context) [k for each (k in completion.urlCompleters)],
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -796,9 +835,7 @@ function CommandLine() //{{{
"Define how command line completion works", "Define how command line completion works",
"stringlist", "list:full", "stringlist", "list:full",
{ {
completer: function completer(filter) completer: function (context) [
{
return [
// Why do we need ""? // Why do we need ""?
["", "Complete only the first match"], ["", "Complete only the first match"],
["full", "Complete the next full match"], ["full", "Complete the next full match"],
@@ -806,8 +843,7 @@ function CommandLine() //{{{
["list", "If more than one match, list all matches"], ["list", "If more than one match, list all matches"],
["list:full", "List all and complete first match"], ["list:full", "List all and complete first match"],
["list:longest", "List all and complete common string"] ["list:longest", "List all and complete common string"]
]; ],
},
validator: Option.validateCompleter, validator: Option.validateCompleter,
checkHas: function (value, val) checkHas: function (value, val)
{ {
@@ -837,7 +873,7 @@ function CommandLine() //{{{
var myModes = [modes.COMMAND_LINE]; var myModes = [modes.COMMAND_LINE];
// TODO: move "<Esc>", "<C-[" here from mappings // TODO: move "<Esc>", "<C-[>" here from mappings
mappings.add(myModes, mappings.add(myModes,
["<C-c>"], "Focus content", ["<C-c>"], "Focus content",
function () { events.onEscape(); }); function () { events.onEscape(); });
@@ -941,14 +977,14 @@ function CommandLine() //{{{
return { return {
HL_NORMAL : "Normal", HL_NORMAL: "Normal",
HL_ERRORMSG : "ErrorMsg", HL_ERRORMSG: "ErrorMsg",
HL_MODEMSG : "ModeMsg", HL_MODEMSG: "ModeMsg",
HL_MOREMSG : "MoreMsg", HL_MOREMSG: "MoreMsg",
HL_QUESTION : "Question", HL_QUESTION: "Question",
HL_INFOMSG : "InfoMsg", HL_INFOMSG: "InfoMsg",
HL_WARNINGMSG : "WarningMsg", HL_WARNINGMSG: "WarningMsg",
HL_LINENR : "LineNr", HL_LINENR: "LineNr",
FORCE_MULTILINE : 1 << 0, FORCE_MULTILINE : 1 << 0,
FORCE_SINGLELINE : 1 << 1, FORCE_SINGLELINE : 1 << 1,
@@ -962,7 +998,8 @@ function CommandLine() //{{{
get mode() (modes.extended == modes.EX) ? "cmd" : "search", get mode() (modes.extended == modes.EX) ? "cmd" : "search",
get silent() silent, get silent() silent,
set silent(val) { set silent(val)
{
silent = val; silent = val;
if (silent) if (silent)
storage.styles.addSheet(true, "silent-mode", "chrome://*", "#liberator-commandline > * { opacity: 0 }"); storage.styles.addSheet(true, "silent-mode", "chrome://*", "#liberator-commandline > * { opacity: 0 }");
@@ -970,9 +1007,6 @@ 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;
@@ -991,6 +1025,8 @@ function CommandLine() //{{{
{ {
try try
{ {
// The long path is because of complications with the
// completion preview.
return commandWidget.inputField.editor.rootElement.firstChild.textContent; return commandWidget.inputField.editor.rootElement.firstChild.textContent;
} }
catch (e) {} catch (e) {}
@@ -1001,14 +1037,14 @@ function CommandLine() //{{{
get message() messageBox.value, get message() messageBox.value,
/** /**
* Changes the command line to display the following prompt (usually ":") * Open the command-line. The main mode is set to
* followed by the command, in the given mode. Valid modes are * COMMAND_LINE, the extended mode to <b>extendedMode</b>.
* attributes of the "modes" variable, and modes.EX is probably * Further, callbacks defined for <b>extendedMode</b> are
* a good choice. * triggered as appropriate (see {@link Liberator#registerCallback}).
* *
* @param {string} prompt * @param {string} prompt
* @param {string} cmd * @param {string} cmd
* @param {number} mode * @param {number} extendedMode
*/ */
open: function open(prompt, cmd, extendedMode) open: function open(prompt, cmd, extendedMode)
{ {
@@ -1031,13 +1067,14 @@ function CommandLine() //{{{
completions = Completions(commandWidget.inputField); completions = Completions(commandWidget.inputField);
// open the completion list automatically if wanted // open the completion list automatically if wanted
if (cmd.length)
liberator.triggerCallback("change", currentExtendedMode, cmd); liberator.triggerCallback("change", currentExtendedMode, cmd);
}, },
/** /**
* Removes any input from the command line, without executing its * Closes the command-line. This is ordinarily triggered automatically
* contents. Removes any "More" windows or other such output. * by a mode change. Will not hide the command-line immediately if
* Pressing <ESC> in EX mode normally has this effect. * called directly after a successful command, otherwise it will.
*/ */
close: function close() close: function close()
{ {
@@ -1048,7 +1085,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 this.resetCompletions(); // cancels any asynchronous completion still going on, must be before we set completions = null
completions = null; completions = null;
history = null; history = null;
@@ -1072,9 +1109,9 @@ function CommandLine() //{{{
keepCommand = false; keepCommand = false;
}, },
/** /**
* Hide any auto-completion/More-ing that is happening. * Hides the command-line, and shows any status messages that
* are under it.
*/ */
hide: function hide() hide: function hide()
{ {
@@ -1082,23 +1119,28 @@ function CommandLine() //{{{
}, },
/** /**
* Output the given string onto the command line coloured * Output the given string onto the command-line. With no flags, the
* using the rules according to highlightGroup. If not * message will be shown in the status line if it's short enough to
* given higlightGroup defaults to commandline.HL_NORMAL * fit, and contains no new lines, and isn't XML. Otherwise, it will be
* and other possibe values are at commandline.HL_[A-Z]*. * shown in the MOW.
*
* 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} str
* @param {string} highlightGroup * @param {string} highlightGroup The Highlight group for the
* @param {number} flags * message. @default "Normal"
* @param {number} flags Changes the behavior as follows:
* commandline.APPEND_TO_MESSAGES - Causes message to be added to the
* messages history, and shown by :messages.
* commandline.FORCE_SINGLELINE - Forbids the command from being
* pushed to the MOW if it's too long or of there are already
* status messages being shown.
* commandline.DISALLOW_MULTILINE - Cancels the operation if the MOW
* is already visible.
* commandline.FORCE_MULTILINE - Forces the message to appear in
* the MOW.
*/ */
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 // liberator.echo uses different order of flags as it omits the highlight group, change commandline.echo argument order? --mst
if (silent) if (silent)
return false; return false;
@@ -1144,29 +1186,28 @@ function CommandLine() //{{{
}, },
/** /**
* Prompt the user for a string and execute the given * Prompt the user. Sets modes.main to COMMAND_LINE, which the user may
* callback with that as the only argument on <CR> * pop at any time to close the prompt.
* extra can have any of the following attributes:
* *
* onChange: A function to be called with the current input every time it changes * @param {string} prompt The input prompt to use.
* 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 {function(string)} callback
* @param {Object} extra * @param {object} extra
* @... {function} onChange - A function to be called with the current
* input every time it changes.
* @... {function(CompletionContext)} completer - A completion function
* for the user's input.
* @... {string} promptHighlight - The HighlightGroup used for the
* prompt. @default "Question"
*/ */
input: function input(prompt, callback, extra) input: function _input(prompt, callback, extra)
{ {
extra = extra || {}; extra = extra || {};
promptSubmitCallback = callback; input = {
promptChangeCallback = extra.onChange; submit: callback,
promptCompleter = extra.completer; change: extra.onChange,
complete: extra.completer,
};
modes.push(modes.COMMAND_LINE, modes.PROMPT); modes.push(modes.COMMAND_LINE, modes.PROMPT);
currentExtendedMode = modes.PROMPT; currentExtendedMode = modes.PROMPT;
@@ -1180,13 +1221,14 @@ function CommandLine() //{{{
}, },
/** /**
* Get a multiline input from a user, up to but not including * Get a multiline input from a user, up to but not including the line
* the line which matches the given regular expression. Then * which matches the given regular expression. Then execute the
* execute the callback with that string as a parameter. * callback with that string as a parameter.
* *
* @param {RegExp} untilRegexp * @param {RegExp} untilRegexp
* @param {function(string)} callbackFunc * @param {function(string)} callbackFunc
*/ */
// FIXME: Buggy, especially when pasting. Shouldn't use a RegExp.
inputMultiline: function inputMultiline(untilRegexp, callbackFunc) inputMultiline: function inputMultiline(untilRegexp, callbackFunc)
{ {
// Kludge. // Kludge.
@@ -1207,11 +1249,12 @@ function CommandLine() //{{{
}, },
/** /**
* Handle events, the come from liberator when liberator.mode = modes.COMMAND_LINE * Handles all command-line events. All key events are passed here when
* but also takes blur/focus/input events raw from #liberator-commandline-command * COMMAND_LINE mode is active, as well as all input, keyup, focus, and
* in the XUL * blur events sent to the command-line XUL element.
* *
* @param {Event} event * @param {Event} event
* @private
*/ */
onEvent: function onEvent(event) onEvent: function onEvent(event)
{ {
@@ -1347,15 +1390,14 @@ function CommandLine() //{{{
}, },
/** /**
* Handle events when we are in multiline output mode, * Handle events when we are in multiline output mode, these come from
* these come from liberator when modes.extended & modes.MULTILINE_OUTPUT * liberator when modes.extended & modes.MULTILINE_OUTPUT and also from
* and also from #liberator-multiline-output in the XUL * #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 * @param {Event} event
*/ */
// FIXME: if 'more' is set and the MOW is not scrollable we should still
// allow a down motion after an up rather than closing
onMultilineOutputEvent: function onMultilineOutputEvent(event) onMultilineOutputEvent: function onMultilineOutputEvent(event)
{ {
let win = multilineOutputWidget.contentWindow; let win = multilineOutputWidget.contentWindow;
@@ -1374,8 +1416,8 @@ function CommandLine() //{{{
{ {
event.preventDefault(); event.preventDefault();
let target = event.button == 0 ? liberator.CURRENT_TAB : liberator.NEW_TAB; let target = event.button == 0 ? liberator.CURRENT_TAB : liberator.NEW_TAB;
if (event.target.href == "#") if (event.target.getAttribute("href") == "#")
liberator.open(String(event.target), target); liberator.open(event.target.textContent, target);
else else
liberator.open(event.target.href, target); liberator.open(event.target.href, target);
} }
@@ -1565,14 +1607,20 @@ function CommandLine() //{{{
} }
}, },
getSpaceNeeded: function getSpaceNeeded()
{
let rect = commandlineWidget.getBoundingClientRect();
let offset = rect.bottom - window.innerHeight;
return Math.max(0, offset);
},
/** /**
* Refresh or remove the prompt that displays when in multiline mode. * Update or remove the multiline output widget's "MORE" prompt.
* 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} force If true, "-- More --" is shown even if we're
* @param {boolean} showHelp * at the end of the output.
* @param {boolean} showHelp When true, show the valid key sequences
* and what they do.
*/ */
updateMorePrompt: function updateMorePrompt(force, showHelp) updateMorePrompt: function updateMorePrompt(force, showHelp)
{ {
@@ -1592,12 +1640,11 @@ function CommandLine() //{{{
}, },
/** /**
* Changes the height of the multilineOutputWidget to fit * Changes the height of the multilineOutputWidget to fit in the
* its contents, if <b>open</b> is true, it will cause the * available space.
* widget to uncollapse, if not it will leave the widget
* closed.
* *
* @param {boolean} open * @param {boolean} open If true, the widget will be opened if it's not
* already so.
*/ */
updateOutputHeight: function updateOutputHeight(open) updateOutputHeight: function updateOutputHeight(open)
{ {
@@ -1606,13 +1653,13 @@ function CommandLine() //{{{
let doc = multilineOutputWidget.contentDocument; let doc = multilineOutputWidget.contentDocument;
// The container needs to be collapsed for this calculation to work.
outputContainer.collapsed = true;
let availableHeight = 250; let availableHeight = 250;
try try
{ {
availableHeight = getBrowser().mPanelContainer ? availableHeight = getBrowser().mPanelContainer ?
getBrowser().mPanelContainer.boxObject.height : getBrowser().boxObject.height; getBrowser().mPanelContainer.boxObject.height : getBrowser().boxObject.height;
if (!outputContainer.collapsed)
availableHeight += parseFloat(outputContainer.height);
} }
catch (e) {} catch (e) {}
doc.body.style.minWidth = commandlineWidget.scrollWidth + "px"; doc.body.style.minWidth = commandlineWidget.scrollWidth + "px";
@@ -1621,15 +1668,8 @@ 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();
// liberator.dump("Resetting completions...");
if (completions) if (completions)
{ {
completions.context.cancelAll(); completions.context.cancelAll();
@@ -1644,11 +1684,12 @@ 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 {string} id The id of the XUL <iframe> which we want to fill it * @param {string} id The id of the <iframe> which will display the list. It
* MUST be inside a <vbox> (or any other html element, because otherwise * must be in its own container element, whose height it will update as
* setting the height does not work properly * necessary.
*/ */
function ItemList(id) //{{{ function ItemList(id) //{{{
{ {
@@ -1668,8 +1709,11 @@ function ItemList(id) //{{{
} }
function dom(xml, map) util.xmlToDom(xml, doc, map); function dom(xml, map) util.xmlToDom(xml, doc, map);
// Unused.
function elemToString(elem) elem.nodeType == elem.TEXT_NODE ? elem.data : function elemToString(elem) elem.nodeType == elem.TEXT_NODE ? elem.data :
"<" + [elem.localName].concat([a.name + "=" + a.value.quote() for ([i, a] in Iterator(elem.attributes))]).join(" ") + ">"; "<" + [elem.localName].concat([a.name + "=" + a.value.quote() for ([i, a] in Iterator(elem.attributes))]).join(" ") + ">";
var doc = iframe.contentDocument; var doc = iframe.contentDocument;
var container = iframe.parentNode; var container = iframe.parentNode;
@@ -1697,6 +1741,7 @@ function ItemList(id) //{{{
div.style.minWidth = ""; div.style.minWidth = "";
// FIXME: Belongs elsewhere. // FIXME: Belongs elsewhere.
commandline.updateOutputHeight(false); commandline.updateOutputHeight(false);
setTimeout(function () { container.height -= commandline.getSpaceNeeded() }, 0)
} }
function getCompletion(index) completionElements.snapshotItem(index - startIndex); function getCompletion(index) completionElements.snapshotItem(index - startIndex);
@@ -1717,6 +1762,7 @@ function ItemList(id) //{{{
</div> </div>
</div>, divNodes); </div>, divNodes);
doc.body.replaceChild(div, doc.body.firstChild); doc.body.replaceChild(div, doc.body.firstChild);
div.scrollIntoView(true);
items.contextList.forEach(function init_eachContext(context) { items.contextList.forEach(function init_eachContext(context) {
delete context.cache.nodes; delete context.cache.nodes;
@@ -1736,13 +1782,15 @@ function ItemList(id) //{{{
</div>, context.cache.nodes); </div>, context.cache.nodes);
divNodes.completions.appendChild(context.cache.nodes.root); divNodes.completions.appendChild(context.cache.nodes.root);
}); });
setTimeout(function () { autoSize(); }, 0);
} }
/** /**
* Uses the entries in "items" to fill the listbox and * Uses the entries in "items" to fill the listbox and does incremental
* does incremental filling to speed up things. * filling to speed up things.
* *
* @param {number} offset Start at this index and show maxItems * @param {number} offset Start at this index and show maxItems.
*/ */
function fill(offset) function fill(offset)
{ {
@@ -1760,7 +1808,7 @@ function ItemList(id) //{{{
function getRows(context) function getRows(context)
{ {
function fix(n) Math.max(0, Math.min(len, n)); function fix(n) Math.max(0, Math.min(len, n));
end -= context.message + context.incomplete; end -= !!context.message + context.incomplete;
let len = context.items.length; let len = context.items.length;
let start = off; let start = off;
off += len; off += len;
@@ -1820,7 +1868,6 @@ function ItemList(id) //{{{
completionElements = buffer.evaluateXPath("//xhtml:div[@liberator:highlight='CompItem']", doc); completionElements = buffer.evaluateXPath("//xhtml:div[@liberator:highlight='CompItem']", doc);
autoSize();
return true; return true;
} }
@@ -1896,7 +1943,10 @@ function ItemList(id) //{{{
getCompletion(sel).removeAttribute("selected"); getCompletion(sel).removeAttribute("selected");
fill(newOffset); fill(newOffset);
if (index >= 0) if (index >= 0)
{
getCompletion(index).setAttribute("selected", "true"); getCompletion(index).setAttribute("selected", "true");
getCompletion(index).scrollIntoView(false);
}
//if (index == 0) //if (index == 0)
// this.start = now; // this.start = now;
@@ -1945,14 +1995,11 @@ function StatusLine() //{{{
return value; return value;
}, },
completer: function completer(filter) completer: function completer(context) [
{
return [
["0", "Never display status line"], ["0", "Never display status line"],
["1", "Display status line only if there are multiple windows"], ["1", "Display status line only if there are multiple windows"],
["2", "Always display status line"] ["2", "Always display status line"]
]; ],
},
validator: Option.validateCompleter validator: Option.validateCompleter
}); });
@@ -1963,10 +2010,11 @@ function StatusLine() //{{{
return { return {
/** /**
* Update the status bar to indicate how secure the website is * Update the status bar to indicate how secure the website is:
* secure => https:// with valid certificate * secure - Secure connection with valid certificate.
* broken => https:// with invalid certificate * broken - Secure connection with invalid certificate, or
* insecure => http:// * mixed content.
* insecure - Insecure connection.
* *
* @param {'secure'|'broken'|'insecure'} type * @param {'secure'|'broken'|'insecure'} type
*/ */
@@ -1992,12 +2040,12 @@ function StatusLine() //{{{
}, },
/** /**
* Update which URL is displayed on the status line, * Update the URL displayed in the status line. Also displays status
* if url is omitted then buffer.URL is used instead and * icons, [+-♥], when there are next and previous pages in the
* status icons [+-❤] are updated to match whether one can * current tab's history, and when the current URL is bookmarked,
* go back/forwards in history/have bookmarked the page. * respectively.
* *
* @param {string} url * @param {string} url The URL to display. @default buffer.URL
*/ */
updateUrl: function updateUrl(url) updateUrl: function updateUrl(url)
{ {
@@ -2042,11 +2090,12 @@ function StatusLine() //{{{
}, },
/** /**
* Set the contents of the status line's input buffer * Set the contents of the status line's input buffer to the given
* to the given string. * string. Used primarily when a key press requires further input
* before being processed, including mapping counts and arguments,
* along with multi-key mappings.
* *
* Used for displaying partial key combinations in * @param {string} buffer
* normal mode.
*/ */
updateInputBuffer: function updateInputBuffer(buffer) updateInputBuffer: function updateInputBuffer(buffer)
{ {
@@ -2057,15 +2106,13 @@ function StatusLine() //{{{
}, },
/** /**
* Update the display of the progress bar. * Update the page load 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 * @param {string|number} progress The current progress, as follows:
* A string - Displayed literally.
* A ratio 0 < n < 1 - Displayed as a progress bar.
* A number n <= 0 - Displayed as a "Loading" message.
* Any other number - The progress is cleared.
*/ */
updateProgress: function updateProgress(progress) updateProgress: function updateProgress(progress)
{ {
@@ -2095,11 +2142,11 @@ function StatusLine() //{{{
}, },
/** /**
* Display the correct tabcount (e.g. [1/5]) on the status bar. * 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} currentIndex The 1-based index of the
* @param {number} totalTabs * currently selected tab. @optional
* @param {number} totalTabs The total number of tabs. @optional
*/ */
updateTabCount: function updateTabCount(currentIndex, totalTabs) updateTabCount: function updateTabCount(currentIndex, totalTabs)
{ {
@@ -2126,14 +2173,10 @@ function StatusLine() //{{{
}, },
/** /**
* Display the correct position on the status bar, if the * Display the main content's vertical scroll position in the status
* percent parameter is omitted it will be calculated. * bar.
* *
* Negative numbers are set to "All", Zero implies "Top" * @param {number} percent The position, as a percentage. @optional
* 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)
{ {

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -296,8 +296,8 @@ const util = { //{{{
/** /**
* Generates an Asciidoc help entry. * Generates an Asciidoc help entry.
* *
* @param {Object} obj A liberator <b>Command</b>, <b>Mapping</b> or * @param {Command|Mapping|Option} obj A liberator <b>Command</b>,
* <b>Option</b> object * <b>Mapping</b> or <b>Option</b> object
* @param {string} extraHelp Extra help text beyond the description. * @param {string} extraHelp Extra help text beyond the description.
* @returns {string} * @returns {string}
*/ */
@@ -359,8 +359,8 @@ const util = { //{{{
* argument. * argument.
* *
* @param {string} url * @param {string} url
* @param {function} callback * @param {function(XMLHttpRequest)} callback
* @returns {Object} * @returns {XMLHttpRequest}
*/ */
httpGet: function httpGet(url, callback) httpGet: function httpGet(url, callback)
{ {
@@ -426,10 +426,10 @@ const util = { //{{{
}, },
/** /**
* Converts a URI string into an URI object. * Converts a URI string into a URI object.
* *
* @param {string} uri * @param {string} uri
* @returns {Object} * @returns {nsIURI}
*/ */
// FIXME: createURI needed too? // FIXME: createURI needed too?
newURI: function (uri) newURI: function (uri)
@@ -611,7 +611,7 @@ const util = { //{{{
* ['www.google.com/search?q=bla', 'www.osnews.com'] * ['www.google.com/search?q=bla', 'www.osnews.com']
* *
* @param {string} str * @param {string} str
* @returns {Array} * @returns {string[]}
*/ */
stringToURLArray: function stringToURLArray(str) stringToURLArray: function stringToURLArray(str)
{ {
@@ -623,7 +623,7 @@ const util = { //{{{
// Try to find a matching file. // Try to find a matching file.
let file = io.getFile(url); let file = io.getFile(url);
if (file.exists() && file.isReadable()) if (file.exists() && file.isReadable())
return file.path; return services.get("io").newFileURI(file).spec;
} }
catch (e) {} catch (e) {}
@@ -638,14 +638,13 @@ const util = { //{{{
// Ok, not a valid proto. If it looks like URL-ish (foo.com/bar), // Ok, not a valid proto. If it looks like URL-ish (foo.com/bar),
// let Gecko figure it out. // let Gecko figure it out.
if (/[.]/.test(url) && !/\s/.test(url) || /^[\w.]+:\d+(?:\/|$)/.test(url)) if (/[.]/.test(url) && !/\s/.test(url) || /^[\w-.]+:\d+(?:\/|$)/.test(url))
return url; return url;
// TODO: it would be clearer if the appropriate call to // TODO: it would be clearer if the appropriate call to
// getSearchURL was made based on whether or not the first word was // getSearchURL was made based on whether or not the first word was
// indeed an SE alias rather than seeing if getSearchURL can // indeed an SE alias rather than seeing if getSearchURL can
// process the call usefully and trying again if it fails - much // process the call usefully and trying again if it fails
// like the comments below ;-)
// check for a search engine match in the string, then try to // check for a search engine match in the string, then try to
// search for the whole string in the default engine // search for the whole string in the default engine
@@ -663,7 +662,8 @@ const util = { //{{{
* *
* @param {Node} node * @param {Node} node
* @param {Document} doc * @param {Document} doc
* @param {Object} nodes * @param {Object} nodes If present, nodes with the "key" attribute are
* stored here, keyed to the value thereof.
* @returns {Node} * @returns {Node}
*/ */
xmlToDom: function xmlToDom(node, doc, nodes) xmlToDom: function xmlToDom(node, doc, nodes)
@@ -686,9 +686,6 @@ const util = { //{{{
} }
}; //}}} }; //}}}
// Struct is really slow, AT LEAST 5 times slower than using structs or simple Objects
// main reason is the function ConStructor(), which i couldn't get faster.
// Maybe it's a TraceMonkey problem, for now don't use it for anything which must be fast (like bookmarks or history)
function Struct() function Struct()
{ {
let self = this instanceof Struct ? this : new Struct(); let self = this instanceof Struct ? this : new Struct();

View File

@@ -51,6 +51,6 @@ do
) )
done done
cd $stage; zip -r "$top/$jar" * (cd $stage; zip -r "$top/$jar" *)
rm -rf "$stage" rm -rf "$stage"

View File

@@ -1,30 +1,9 @@
/***** BEGIN LICENSE BLOCK ***** {{{ /***** BEGIN LICENSE BLOCK ***** {{{
Version: MPL 1.1/GPL 2.0/LGPL 2.1 Copyright © 2008-2009 by Kris Maglione <maglione.k at Gmail>
Distributable under the terms of the MIT license, which allows
The contents of this file are subject to the Mozilla Public License Version for sublicensing under any compatible license, including the MPL,
1.1 (the "License"); you may not use this file except in compliance with GPL, and MPL. Anyone who changes this file is welcome to relicense
the License. You may obtain a copy of the License at it under any or all of those licenseses.
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
© 2008: Kris Maglione <maglione.k at Gmail>
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/ }}} ***** END LICENSE BLOCK *****/
var EXPORTED_SYMBOLS = ["storage", "Timer"]; var EXPORTED_SYMBOLS = ["storage", "Timer"];
@@ -80,10 +59,10 @@ function Timer(minInterval, maxInterval, callback)
{ {
timer.cancel(); timer.cancel();
this.doneAt = 0; this.doneAt = 0;
} };
this.flush = function () this.flush = function ()
{ {
if (this.latest) if (this.doneAt == -1)
this.notify(); this.notify();
}; };
} }

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -10,7 +10,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2008: Christian Dietrich <stettberger@dokucode.de> Copyright (c) 2008 by Christian Dietrich <stettberger@dokucode.de>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -13,7 +13,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -89,9 +89,9 @@ function Mail() //{{{
var notifyFlags = nsIFolderListener.intPropertyChanged | nsIFolderListener.event; var notifyFlags = nsIFolderListener.intPropertyChanged | nsIFolderListener.event;
mailSession.AddFolderListener(folderListener, notifyFlags); mailSession.AddFolderListener(folderListener, notifyFlags);
function getFolderCompletions(filter) function getFolderCompletions(context)
{ {
let folders = mail.getFolders(filter); let folders = mail.getFolders(context.filter);
context.completions = folders.map(function (folder) context.completions = folders.map(function (folder)
[folder.server.prettyName + ": " + folder.name, [folder.server.prettyName + ": " + folder.name,
"Unread: " + folder.getNumUnread(false)]); "Unread: " + folder.getNumUnread(false)]);

View File

@@ -13,7 +13,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -0,0 +1 @@
../../../common/Makefile.doc

View File

@@ -1,4 +1,7 @@
2009: 2009:
* InspireFocus
* Michael Fremont
* Kamil Dworakowski
* Jonathan Austin * Jonathan Austin
* Steven Romanow * Steven Romanow

View File

@@ -20,20 +20,19 @@ BUGS:
- http://cgiirc.blitzed.org?chan=%23debug is unusable after login in - http://cgiirc.blitzed.org?chan=%23debug is unusable after login in
(recent CVS regressions): (recent CVS regressions):
- visual caret mode is broken
- 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 - :set noflashblock seems broken (= :set fb? afterwards says "fb"), let's see if that's a
plugin or a vimp issue. plugin or a vimp issue.
- visual caret mode is broken, requires a manual page focus first anyway or
else it chucks, I haven't investigated --djk
- messages is still broken in several ways - needs testing.
=> :ls | :echomsg "Foobar" doesn't add "Foobar" to the already open MOW.
=> it often overwrites the open command-line while editing etc.
- <tags> and <keyword> autocmd 'keywords' are not available when adding a
bookmark - they're being set after the observer triggers the autocmd event.
- MOW is broken for multiple commands when open E.g. :ls | ls
- completion height is broken, try :a<tab>....<tab>, when it wraps it's totally off.
and even if it is not totally off, i had it jump by one pixel when wrapping around.
If that's unfixable, i propose reverting the new completion height stuff.
FEATURES: FEATURES:
9 finish :help TODOs 9 finish :help TODOs

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -792,9 +792,9 @@ function History() //{{{
function (args) { history.list(args.join(" "), args.bang, args["-max"] || 1000); }, function (args) { history.list(args.join(" "), args.bang, args["-max"] || 1000); },
{ {
bang: true, bang: true,
completer: function (context) { context.quote = null, completion.history(context); }, completer: function (context) { context.quote = null; completion.history(context); },
options: [[["-max", "-m"], options.OPTION_INT]]
// completer: function (filter) completion.history(filter) // completer: function (filter) completion.history(filter)
options: [[["-max", "-m"], options.OPTION_INT]]
}); });
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
@@ -962,7 +962,14 @@ function QuickMarks() //{{{
else else
quickmarks.remove(args.string); quickmarks.remove(args.string);
}, },
{ bang: true }); {
bang: true,
completer: function (context)
{
context.title = ["QuickMark", "URL"];
context.completions = qmarks;
}
});
commands.add(["qma[rk]"], commands.add(["qma[rk]"],
"Mark a URL with a letter for quick access", "Mark a URL with a letter for quick access",

View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -13,7 +13,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the for the specific language governing rights and limitations under the
License. License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net> Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@@ -0,0 +1 @@
../../../common/Makefile.doc

View File

@@ -40,19 +40,19 @@ The first URL is opened in the current tab, and all other URLs are
opened in new tabs. opened in new tabs.
Each token is analyzed and in this order: Each token is analyzed and in this order:
. Opened as a local file if it is an existing relative or absolute filename. 1. 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]
. Opened with the specified search engine if the token looks like a search 2. 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].
. Opened with the default search engine or keyword (specified with the 3. 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).
. Passed directly to Firefox in all other cases ([c]:open www.osnews.com, 4. 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).

View File

@@ -22,8 +22,10 @@ ________________________________________________________________________________
|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
(activated with [m]f[m]) but opens the link in a new tab. mode (activated with [m]f[m]) but opens the link in a new tab. The new
tab will be loaded in background according to the
\'browser.tabs.loadInBackground' Firefox preference.
________________________________________________________________________________ ________________________________________________________________________________
@@ -49,9 +51,9 @@ this hint mode. Then press [a]24[a] to copy the hint location.
* |;b| [m]b[m] to open its location in a new background tab * |;b| [m]b[m] to open its location in a new background tab
* |;w| [m]w[m] to open its destination in a new window * |;w| [m]w[m] to open its destination in a new window
* |;F| [m]F[m] to follow a sequence of [m]<CR>[m]-delimited hints in background tabs * |;F| [m]F[m] to follow a sequence of [m]<CR>[m]-delimited hints in background tabs
* |;O| [m]O[m] to preselect its location in an [c]:open[c] query * |;O| [m]O[m] to [c]:open[c] a URL based on hint location
* |;T| [m]T[m] to preselect its location in a [c]:tabopen[c] query * |;T| [m]T[m] to [c]:tabopen[c] a URL based on its location
* |;W| [m]W[m] to preselect its location in a [c]:winopen[c] query * |;W| [m]W[m] to [c]:winopen[c] a URL based on its location
* |;v| [m]v[m] to view its destination source * |;v| [m]v[m] to view its destination source
* |;V| [m]V[m] to view its destination source in the external editor * |;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 destination location
@@ -59,9 +61,6 @@ this hint mode. Then press [a]24[a] to copy the hint location.
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

@@ -330,7 +330,7 @@ properties, describing the completions and where the replacement is to start.
*start* is the index into the word being completed at which the returned values *start* is the index into the word being completed at which the returned values
should be applied and *completions* is a two dimensional array of the form: should be applied and *completions* is a two dimensional array of the form:
\[[arg1, description1], [arg2, description2], ...] [[arg1, description1], [arg2, description2], ...]
// TODO: add examples // TODO: add examples

View File

@@ -187,7 +187,7 @@ ________________________________________________________________________________
||:qma[rk] {a-zA-Z0-9} [a][url][a]|| + ||: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]
________________________________________________________________________________ ________________________________________________________________________________

View File

@@ -7,28 +7,28 @@ section:Initialization[initialization,startup]
At startup, Vimperator completes the following tasks in order. At startup, Vimperator completes the following tasks in order.
. Vimperator can perform user initialization commands. When 1. Vimperator can perform user initialization commands. When
one of the following is successfully located, it is executed, and no one of the following is successfully located, it is executed, and no
further locations are tried. further locations are tried.
.. |$VIMPERATOR_INIT| _$VIMPERATOR_INIT_ -- May contain a single ex a. |$VIMPERATOR_INIT| _$VIMPERATOR_INIT_ -- May contain a single ex
command (e.g., command (e.g.,
"[c]:source {file}[c]"). "[c]:source {file}[c]").
.. [a]\~/_vimperatorrc[a] -- Windows only. If this file exists, its b. [a]\~/_vimperatorrc[a] -- Windows only. If this file exists, its
contents are executed and contents are executed and
_$MY_VIMPERATORRC_ set to its path. _$MY_VIMPERATORRC_ set to its path.
.. [a]\~/.vimperatorrc[a] -- If this file exists, its contents are c. [a]\~/.vimperatorrc[a] -- If this file exists, its contents are
executed. executed.
. If 'exrc' is set, then any RC file in the current directory is also sourced. 2. If 'exrc' is set, then any RC file in the current directory is also sourced.
. All directories in 'runtimepath' are searched for a "plugin" 3. All directories in 'runtimepath' are searched for a "plugin"
subdirectory and all yet unloaded plugins are loaded. For each subdirectory and all yet unloaded plugins are loaded. For each
plugin directory, all *.\{js,vimp} files (including those in further plugin directory, all *.\{js,vimp} files (including those in further
subdirectories) are sourced alphabetically. No plugins will be sourced subdirectories) are sourced alphabetically. No plugins will be sourced
if 'noloadplugins' is set. Any particular plugin will not be loaded 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] if it has already been loaded (e.g., by an earlier [c]:loadplugins[c]
command). command).
The user's ~ (i.e., "home") directory is determined as follows: The user's ~ (i.e., "home") directory is determined as follows:

View File

@@ -94,7 +94,6 @@ function getBufferPosition()
function getLocation() window.content.document.location.href; function getLocation() window.content.document.location.href;
function echoLine(str, group) function echoLine(str, group)
{ {
if (!doc) if (!doc)