diff --git a/Donators b/Donators
index 74148a7a..b519261a 100644
--- a/Donators
+++ b/Donators
@@ -15,6 +15,7 @@
* Nathan Saper
* Albert Menkveld
* Ian Taylor
+* Thomas Svensen
I want to say a big THANK YOU for all people which supported this project in this way.
diff --git a/NEWS b/NEWS
index b77d186e..17a7dc62 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@
2007-xx-xx:
* version 0.6
* THIS VERSION ONLY WORKS WITH FIREFOX 3.0
+ * Tab-completion improvments for :javascript and :open
* IMPORTANT: changed semantics of :echo and :echoerr: Strings must be quoted with " or ' now,
but you can do things like :echo 3+2 or :echo window.document now
* statusline is now white on black with bold font by default (like in (g)vim)
diff --git a/chrome/content/vimperator/commands.js b/chrome/content/vimperator/commands.js
index ae3d1ac6..ca42fef4 100644
--- a/chrome/content/vimperator/commands.js
+++ b/chrome/content/vimperator/commands.js
@@ -523,7 +523,8 @@ function Commands() //{{{
short_help: "Display a string at the bottom of the window",
help: "Useful for showing informational messages. Multiple lines can be separated by \\n.
" +
"{expr} can either be a quoted string, or any expression which can be fed to eval() like 4+5. " +
- "You can also view the source code of objects and functions if the return value of {expr} is an object or function."
+ "You can also view the source code of objects and functions if the return value of {expr} is an object or function.",
+ completer: function(filter) { return vimperator.completion.javascript(filter); }
}
));
addDefaultCommand(new Command(["echoe[rr]"],
@@ -536,7 +537,8 @@ function Commands() //{{{
{
usage: ["echoe[rr] {expr}"],
short_help: "Display an error string at the bottom of the window",
- help: "Just like :ec[ho], but echoes the result highlighted in red. Useful for showing important messages."
+ help: "Just like :ec[ho], but echoes the result highlighted in red. Useful for showing important messages.",
+ completer: function(filter) { return vimperator.completion.javascript(filter); }
}
));
addDefaultCommand(new Command(["exe[cute]"],
@@ -643,7 +645,11 @@ function Commands() //{{{
help: "Acts as a JavaScript interpreter by passing the argument to eval().
" +
":javascript alert('Hello world') would show a dialog box with the text \"Hello world\".
" +
":javascript <<EOF would read all the lines until a line starting with 'EOF' is found, and will eval() them.
" +
- "The special version :javascript! will open the JavaScript console of Firefox."
+ "The special version :javascript! will open the JavaScript console of Firefox.
" +
+ "Rudimentary <Tab> completion is available for :javascript {cmd} (but not yet for the " +
+ ":js <<EOF multiline widget). Be aware that Vimperator needs to run {cmd} through eval() " +
+ "to get the completions, which could have unwanted side effects.",
+ completer: function(filter) { return vimperator.completion.javascript(filter); }
}
));
addDefaultCommand(new Command(["let"],
@@ -957,7 +963,7 @@ function Commands() //{{{
"" +
"You WILL be able to use :open [-T \"linux\"] torvalds<Tab> to complete bookmarks " +
"with tag \"linux\" and which contain \"torvalds\". Note that -T support is only available for tab completion, not for the actual command.
" +
- "The items which are completed on <Tab> are specified in the 'complete' option.
" +
+ "The items which are completed on <Tab> are specified in the 'complete' option.
" +
"Without argument, reloads the current page.
" +
"Without argument but with !, reloads the current page skipping the cache.",
completer: function(filter) { return vimperator.completion.get_url_completions(filter); }
diff --git a/chrome/content/vimperator/completion.js b/chrome/content/vimperator/completion.js
index 0c02f520..d8188411 100644
--- a/chrome/content/vimperator/completion.js
+++ b/chrome/content/vimperator/completion.js
@@ -479,6 +479,74 @@ vimperator.completion = (function() // {{{
return build_longest_common_substring(mapped, filter);
}, //}}}
+ javascript: function(str)
+ {
+ g_substrings = [];
+ var matches = str.match(/^(.*?)(\s*\.\s*)?(\w*)$/);
+ var object = "window";
+ var filter = matches[3] || "";
+ var start = matches[1].length-1;
+ if (matches[2])
+ {
+ var brackets = 0, parentheses = 0;
+ outer:
+ for (; start >= 0; start--)
+ {
+ dump(matches[1].substr(start) + ": " + start + "\n");
+ switch (matches[1][start])
+ {
+ case ";":
+ case "{":
+ break outer;
+
+ case "]":
+ brackets--;
+ break;
+ case "[":
+ brackets++;
+ break;
+ case ")":
+ parentheses--;
+ break;
+ case "(":
+ parentheses++;
+ break;
+ }
+ if (brackets > 0 || parentheses > 0)
+ break outer;
+ }
+ }
+ object = matches[1].substr(start+1) || "window";
+
+ var completions = [];
+ try
+ {
+ completions = eval(
+ "var comp = [];" +
+ "var type = '';" +
+ "var value = '';" +
+ "var obj = eval(" + object + ");" +
+ "for (var i in obj) {" +
+ " try { type = typeof(obj[i]); } catch (e) { type = 'unknown type'; };" +
+ " if (type == 'number' || type == 'string' || type == 'boolean') {" +
+ " value = obj[i];" +
+ " comp.push([[i], type + ': ' + value]); }" +
+ // The problem with that is that you complete vimperator.
+ // but can't press to complete sub items
+ // so it's better to complete vimperator and the user can do
+ // . to get the sub items
+ //" else if (type == 'function') {" +
+ //" comp.push([[i+'('], type]); }" +
+ //" else if (type == 'object') {" +
+ //" comp.push([[i+'.'], type]); }" +
+ " else {" +
+ " comp.push([[i], type]); }" +
+ "} comp;");
+ } catch (e) { completions = []; };
+
+ return build_longest_starting_substring(completions, filter);
+ },
+
exTabCompletion: function(str) //{{{
{
var [count, cmd, special, args] = vimperator.commands.parseCommand(str);
@@ -498,14 +566,27 @@ vimperator.completion = (function() // {{{
var command = vimperator.commands.get(cmd);
if (command && command.completer)
{
+ matches = str.match(/^:*\d*\w+\s+/);
+ start = matches ? matches[0].length : 0;
+
+ // TODO: maybe we should move these checks to the complete functions
+ if (command.hasName("open") || command.hasName("tabopen") || command.hasName("winopen"))
+ {
+ var skip = args.match(/^(.*,\s+)(.*)/); // start after the last ", "
+ if (skip)
+ {
+ start += skip[1].length;
+ args = skip[2];
+ }
+ }
+ else if (command.hasName("echo") || command.hasName("echoerr") || command.hasName("javascript"))
+ {
+ var skip = args.match(/^(.*?)(\w*)$/); // start after the last ", "
+ if (skip)
+ start += skip[1].length;
+ }
+
completions = command.completer.call(this, args);
- // if (command[0][0] == "open" ||
- // command[0][0] == "tabopen" ||
- // command[0][0] == "winopen")
- // start = str.search(/^:*\d*\w+(\s+|.*\|)/); // up to the last | or the first space
- // else
- matches = str.match(/^:*\d*\w+\s+/); // up to the first spaces only
- start = matches[0].length;
}
}
return [start, completions];