1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 16:12:26 +01:00

Add the beginings of completion support to parseArgs

This commit is contained in:
Kris Maglione
2008-10-10 19:03:38 +00:00
parent c5f8f5e581
commit 56dde515a0
2 changed files with 76 additions and 68 deletions

View File

@@ -318,44 +318,50 @@ liberator.Commands = function () //{{{
// @param allowUnknownOptions: -foo won't result in an error, if -foo isn't // @param allowUnknownOptions: -foo won't result in an error, if -foo isn't
// specified in "options" // specified in "options"
// TODO: should it handle comments? // TODO: should it handle comments?
parseArgs: function (str, options, argCount, allowUnknownOptions) //{{{ parseArgs: function (str, options, argCount, allowUnknownOptions, complete) //{{{
{ {
function quoteArg(quote)
{
switch (quote)
{
case "'":
return function (str) "'" + str.substitute(/[\\']/g, "\\$&") + "'";
case '"':
return function (str) '"' + str.substitute(/[\\"\t\n]/g,
function (c) (c == "\n" ? "\\n" : c == "\t" ? "\\t" : "\\" + c));
default:
return function (str) str.substitute(/[\\ ]/g, "\\$&");
}
}
// returns [count, parsed_argument] // returns [count, parsed_argument]
function getNextArg(str) // {{{ function getNextArg(str) // {{{
{ {
var inSingleString = false; var stringDelimiter = null;
var inDoubleString = false; var escapeNext = false;
var inEscapeKey = false;
var arg = ""; var arg = "";
outer: outer:
for (let i = 0; i < str.length; i++) for (let i = 0; i < str.length; i++)
{ {
inner:
switch (str[i]) switch (str[i])
{ {
case "\"": case '"':
if (inEscapeKey)
{
inEscapeKey = false;
break;
}
if (!inSingleString)
{
inDoubleString = !inDoubleString;
continue outer;
}
break;
case "'": case "'":
if (inEscapeKey) if (escapeNext)
{ {
inEscapeKey = false; escapeNext = false;
break; break;
} }
if (!inDoubleString) switch (stringDelimiter)
{ {
inSingleString = !inSingleString; case str[i]:
stringDelimiter = null;
continue outer;
case null:
stringDelimiter = str[i];
continue outer; continue outer;
} }
break; break;
@@ -363,59 +369,56 @@ liberator.Commands = function () //{{{
// \ is an escape key for non quoted or "-quoted strings // \ is an escape key for non quoted or "-quoted strings
// for '-quoted strings it is taken literally, apart from \' and \\ // for '-quoted strings it is taken literally, apart from \' and \\
case "\\": case "\\":
if (inEscapeKey) if (escapeNext)
{ {
inEscapeKey = false; escapeNext = false;
break; break;
} }
else else
{ {
// only escape "\\" and "\ " in non quoted strings // in non-quoted strings, only escape "\\" and "\ ", otherwise drop "\\"
if (!inSingleString && !inDoubleString && str[i + 1] != "\\" && str[i + 1] != " ") if (!stringDelimiter && str[i + 1] != "\\" && str[i + 1] != " ")
continue outer; continue outer;
// only escape "\\" and "\'" in single quoted strings // in single quoted strings, only escape "\\" and "\'", otherwise keep "\\"
else if (inSingleString && str[i + 1] != "\\" && str[i + 1] != "'") if (stringDelimiter == "'" && str[i + 1] != "\\" && str[i + 1] != "'")
break; break;
else escapeNext = true;
{
inEscapeKey = true;
continue outer; continue outer;
} }
}
break; break;
default: default:
if (inSingleString) if (stringDelimiter == "'")
{ {
inEscapeKey = false; escapeNext = false;
break; break;
} }
else if (inEscapeKey) if (escapeNext)
{ {
inEscapeKey = false; escapeNext = false;
switch (str[i]) switch (str[i])
{ {
case "n": arg += "\n"; continue outer; case "n": arg += "\n"; break;
case "t": arg += "\t"; continue outer; case "t": arg += "\t"; break;
default: default:
break; // this makes "a\fb" -> afb; wanted or should we return ab? --mst break inner; // this makes "a\fb" -> afb; wanted or should we return ab? --mst
} }
continue outer;
} }
else if (!inDoubleString && /\s/.test(str[i])) else if (stringDelimiter != '"' && /\s/.test(str[i]))
{ {
return [i, arg]; return [i, arg];
} }
else // a normal charcter
break; break;
} }
arg += str[i]; arg += str[i];
} }
// TODO: add parsing of a " comment here: // TODO: add parsing of a " comment here:
if (inDoubleString || inSingleString) if (stringDelimiter)
return [-1, "E114: Missing quote"]; return [str.length, arg, stringDelimiter];
if (inEscapeKey) if (escapeNext)
return [-1, "trailing \\"]; return [str.length, arg, "\\"];
else else
return [str.length, arg]; return [str.length, arg];
} // }}} } // }}}
@@ -459,15 +462,15 @@ liberator.Commands = function () //{{{
var optname = ""; var optname = "";
if (!onlyArgumentsRemaining) //{{{ if (!onlyArgumentsRemaining) //{{{
{ {
for (let opt = 0; opt < options.length; opt++) for (let [,opt] in Iterator(options))
{ {
for (let name = 0; name < options[opt][0].length; name++) for (let [,optname] in Iterator(opt[0]))
{ {
optname = options[opt][0][name];
if (sub.indexOf(optname) == 0) if (sub.indexOf(optname) == 0)
{ {
invalid = false; invalid = false;
arg = null; arg = null;
quote = null;
// no value to the option // no value to the option
if (optname.length >= sub.length) if (optname.length >= sub.length)
{ {
@@ -475,28 +478,19 @@ liberator.Commands = function () //{{{
} }
else if (sub[optname.length] == "=") else if (sub[optname.length] == "=")
{ {
[count, arg] = getNextArg(sub.substr(optname.length + 1)); [count, arg, quote] = getNextArg(sub.substr(optname.length + 1));
if (count == -1)
{
liberator.echoerr("Invalid argument for option " + optname);
return null;
}
count++; // to compensate the "=" character count++; // to compensate the "=" character
} }
else if (/\s/.test(sub[optname.length])) else if (/\s/.test(sub[optname.length]))
{ {
if (options[opt][1] != this.OPTION_NOARG) if (opt[1] != this.OPTION_NOARG)
{ {
[count, arg] = getNextArg(sub.substr(optname.length + 1)); [count, arg, quote] = getNextArg(sub.substr(optname.length + 1));
if (count == -1) if (count == -1)
{
liberator.echoerr("Invalid argument for option " + optname);
return null;
}
// if we add the argument to an option after a space, it MUST not be empty // if we add the argument to an option after a space, it MUST not be empty
if (arg.length == 0) if (!quote && arg.length == 0)
arg = null; arg = null;
count++; // to compensate the " " character count++; // to compensate the " " character
@@ -510,9 +504,23 @@ liberator.Commands = function () //{{{
invalid = true; invalid = true;
} }
if (quote)
{
if (!complete)
{
liberator.echoerr("Invalid argument for option " + optname);
return null;
}
let compl = opt[3] || [];
if (typeof compl == "function")
compl = compl();
let filter = quoteArg(sub[optname.length + 1])
return [i + optname.length + 1, liberator.completion.filter(compl.map(filter), filter(arg))];
}
if (!invalid) if (!invalid)
{ {
switch (options[opt][1]) // type switch (opt[1]) // type
{ {
case this.OPTION_NOARG: case this.OPTION_NOARG:
if (arg != null) if (arg != null)
@@ -566,16 +574,16 @@ liberator.Commands = function () //{{{
} }
// we have a validator function // we have a validator function
if (typeof options[opt][2] == "function") if (typeof opt[2] == "function")
{ {
if (options[opt][2].call(this, arg) == false) if (opt[2].call(this, arg) == false)
{ {
liberator.echoerr("Invalid argument for option: " + optname); liberator.echoerr("Invalid argument for option: " + optname);
return null; return null;
} }
} }
args[options[opt][0][0]] = arg; // always use the first name of the option args[opt[0][0]] = arg; // always use the first name of the option
i += optname.length + count; i += optname.length + count;
continue outer; continue outer;
} }

View File

@@ -191,7 +191,7 @@ liberator.Completion = function () //{{{
try try
{ {
// liberator.dump("eval(" + liberator.util.escapeString(arg) + ")\n"); // liberator.dump("eval(" + liberator.util.escapeString(arg) + ")\n");
return window.eval(arg); return liberator.eval(arg);
} }
catch (e) catch (e)
{ {