diff --git a/content/bookmarks.js b/content/bookmarks.js index f05c4554..666ab86e 100644 --- a/content/bookmarks.js +++ b/content/bookmarks.js @@ -280,8 +280,15 @@ function Bookmarks() //{{{ }, { argCount: "0" }); - function tags() util.Array.uniq(util.Array.flatten([b.tags for ([k, b] in Iterator(cache.bookmarks))])) - .map(function (tag) [tag, tag]); + function tags(context, args) + { + let filter = args.completeFilter; + let have = filter.split(","); + args.completeFilter = have.pop(); + let prefix = filter.substr(0, filter.length - args.completeFilter.length); + let tags = util.Array.uniq(util.Array.flatten([b.tags for ([k, b] in Iterator(cache.bookmarks))])); + return [[prefix + tag, tag] for ([i, tag] in Iterator(tags)) if (have.indexOf(tag) < 0)]; + } commands.add(["bma[rk]"], "Add a bookmark", @@ -318,13 +325,7 @@ function Bookmarks() //{{{ }, { bang: true, - completer: function (context, args) - { - if (args.completeOpt) - return; - context.advance(args.completeStart); // TODO: Move this to completion.ex? - completion.url(context, "b"); - }, + completer: function (context, args) completion.url(context, "b"), options: [[["-tags", "-T"], commands.OPTION_LIST, null, tags]] }); diff --git a/content/commands.js b/content/commands.js index 15c70c3b..ba8a4436 100644 --- a/content/commands.js +++ b/content/commands.js @@ -438,23 +438,22 @@ function Commands() //{{{ var arg = null; var count = 0; // the length of the argument var i = 0; + var completeOpts; // XXX function matchOpts(arg) { // Push possible option matches into completions - if (!onlyArgumentsRemaining && !quote) - args.completions = [[opt[0][0], opt[0][0]] for ([i, opt] in Iterator(options)) if (opt[0][0].indexOf(arg) == 0)]; - //args.completions = util.Array.flatten( - // options.map(function ([names]) names.filter( - // function (name) name.indexOf(arg) == 0))); + if (complete && !onlyArgumentsRemaining) + completeOpts = [[opt[0][0], opt[0][0]] for ([i, opt] in Iterator(options)) if (opt[0][0].indexOf(arg) == 0)]; } function resetCompletions() { + completeOpts = null; args.completeArg = null; args.completeOpt = null; + args.completeFilter = null; args.completeStart = i; - args.completions = []; args.quote = quoteArg[""]; } if (complete) @@ -471,11 +470,10 @@ function Commands() //{{{ resetCompletions(); // skip whitespace - if (/\s/.test(str[i])) - { + while (/\s/.test(str[i]) && i < str.length) i++; - continue; - } + if (i == str.length && !complete) + break; var sub = str.substr(i); //liberator.dump(i + ": " + sub + " - " + onlyArgumentsRemaining + "\n"); @@ -486,6 +484,8 @@ function Commands() //{{{ continue; } + matchOpts(sub); + var optname = ""; if (!onlyArgumentsRemaining) { @@ -532,29 +532,22 @@ function Commands() //{{{ invalid = true; } - if (complete) - { - if (quote || !invalid && count && i + optname.length + 1 + arg.length == str.length) - { - args.completeStart += optname.length + 1; - args.completeOpt = opt[0][0]; - args.quote = quoteArg[quote] || quoteArg[""]; - if (typeof opt[3] == "function") - var compl = opt[3](); - else - compl = opt[3] || []; - args.completions = completion.filter(compl.map(function ([k, v]) [args.quote(k), v]), arg);; - return args; - } - } - else if (quote) + let context = null; + if (!complete && quote) { liberator.echoerr("Invalid argument for option " + optname); return null; } - if (!invalid && (!complete || count)) + if (!invalid) { + if (complete && count > 0) + { + args.completeStart += optname.length + 1; + args.completeOpt = opt; + args.completeFilter = arg; + args.quote = quoteArg[quote] || quoteArg[""]; + } let type = argTypes[opt[1]]; if (type) { @@ -562,10 +555,12 @@ function Commands() //{{{ if (arg == null || arg == NaN) { if (complete) - commandline.highlight(completions.completeStart, arg.length, "SPELLCHECK"); + complete.highlight(args.completeStart, count - 1, "SPELLCHECK"); else + { liberator.echoerr("Invalid argument for " + type.description + "option: " + optname); - return null; + return null; + } } } @@ -575,10 +570,12 @@ function Commands() //{{{ if (opt[2].call(this, arg) == false) { if (complete) - commandline.highlight(completions.completeStart, arg.length, "SPELLCHECK"); + complete.highlight(args.completeStart, count - 1, "SPELLCHECK"); else + { liberator.echoerr("Invalid argument for option: " + optname); - return null; + return null; + } } } @@ -597,18 +594,14 @@ function Commands() //{{{ args.literalArg = sub; args.arguments.push(sub); if (complete) - args.completeArg = args.arguments.length; + args.completeArg = args.arguments.length - 1; break; } // if not an option, treat this token as an argument var [count, arg, quote] = getNextArg(sub); if (complete) - { args.quote = quoteArg[quote] || quoteArg[""]; - args.completeArg = args.arguments.length; - matchOpts(arg); - } else if (count == -1) { liberator.echoerr("Error parsing arguments: " + arg); @@ -623,13 +616,32 @@ function Commands() //{{{ if (arg != null) args.arguments.push(arg); if (complete) - args.completeArg = args.arguments.length; + args.completeArg = args.arguments.length - 1; if (count <= 0) - throw Error("count <= 0"); // Shouldn't happen. + break; i += count; } + if (complete) + { + if (args.completeOpt) + { + let opt = args.completeOpt; + let context = complete.fork(opt[0][0], args.completeStart); + if (typeof opt[3] == "function") + var compl = opt[3](context, args); + else + compl = opt[3] || []; + context.title = [opt[0][0]]; + context.items = completion.filter(compl.map(function ([k, v]) [args.quote(k), v]), args.completeFilter);; + } + complete.advance(args.completeStart); + complete.title = ["Options"]; + if (completeOpts) + complete.items = completeOpts; + } + // check for correct number of arguments if (args.arguments.length == 0 && (argCount == "1" || argCount == "+") && !complete) { diff --git a/content/completion.js b/content/completion.js index fe0d6759..669576de 100644 --- a/content/completion.js +++ b/content/completion.js @@ -1078,24 +1078,23 @@ function Completion() //{{{ { [prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/); context = context.fork(cmd, prefix.length); - args = command.parseArgs(context.filter, true); + let argContext = context.fork("args", args.completeStart); + args = command.parseArgs(context.filter, argContext); if (args) { // XXX, XXX, XXX - let argContext = context.fork("args", args.completeStart); - compObject = command.completer.call(command, context, args, special, count); - if (compObject instanceof Array) // for now at least, let completion functions return arrays instead of objects - compObject = { start: compObject[0], items: compObject[1] }; - if (args.completions) + if (!args.completeOpt) { - argContext.title = [args.completeOpt || "Options"]; - argContext.items = args.completions; - } - if (compObject != null) - { - context.advance(compObject.start); - context.title = ["Completions"]; - context.items = compObject.items; + context.advance(args.completeStart); + compObject = command.completer.call(command, context, args, special, count); + if (compObject instanceof Array) // for now at least, let completion functions return arrays instead of objects + compObject = { start: compObject[0], items: compObject[1] }; + if (compObject != null) + { + context.advance(compObject.start); + context.title = ["Completions"]; + context.items = compObject.items; + } } } //liberator.dump([[v.name, v.offset, v.items.length, v.hasItems] for each (v in context.contexts)]); diff --git a/content/style.js b/content/style.js index 92f4894c..fd79ae7a 100644 --- a/content/style.js +++ b/content/style.js @@ -441,9 +441,8 @@ liberator.registerObserver("load_commands", function () } catch (e) {} compl = compl.concat([[s, ""] for each (s in styles.sites)]) - return [0, completion.filter(compl, args.arguments[0])]; + context.items = completion.filter(compl, args.arguments[0]); } - return [0, []]; }, hereDoc: true, literal: true, diff --git a/content/ui.js b/content/ui.js index 0f391bac..dcdeef62 100644 --- a/content/ui.js +++ b/content/ui.js @@ -1362,22 +1362,23 @@ function ItemList(id) //{{{ } let xml =
+
{ - items.allItems.items.length == 0 && -
+ items.allItems.items.length == 0 ? No Completions -
|| <> + : <> } { - template.map(items.contextList, function (context) context.hasItems && -
+ template.map(items.contextList, function (context) context.hasItems ? + <> { context.createRow(context, context.title || {}, "hl-CompTitle") } { template.map(range(context), function (i) context.createRow(context, context.items[i])) } -
- || undefined) + + : undefined) } +
{ // Hmm. The problem with not making this a CompItem is that