feat: new command parser
It's not fully hooked up to the react app, and it's not quite complete
either, but it's a start.
Currently, it will parse filter implicitly, and there's also the done
and add command. For now, all commands must place the command name in
the right location.
Additionally, I've hooked up the react table's selection state to the
command parser. Filter based on _ids_ explicitly does work. Manually
selecting an ID will also place it in the input field for
discoverability. It does not remove ids that were manually deselected
yet, nor does filter based on any other attribute work.
The command parser also parses times, but it does so very poorly
currently. More work will need to go into that, for now it's basically a
stub. I'll also need to convert the parser to Go.
The react table conviently handles virtual tables based on it's internal
`row.id`. I'm still wondering how to implement virtual ids, but at least
on the web app, they are constantly updated since the view is always
visible, which is different to the CLI (though perhaps the same as a
TUI?)
Notably, there's no semantics for the difference between selection and
filtering. I think perhaps the implicit filter command should default to
selection, but the explicit filter command should be handled
differently, and actually execute filtering. I haven't yet looked into
how the TanStack Table handles filtering, but I am aware that it does.
I think for an MVP, once done is implemented, I can deploy this, the web
socket server, and try and start using it.
2024-11-10 02:15:10 -08:00
|
|
|
// @generated by Peggy 4.1.1.
|
|
|
|
//
|
|
|
|
// https://peggyjs.org/
|
|
|
|
|
|
|
|
|
|
|
|
function peg$subclass(child, parent) {
|
|
|
|
function C() { this.constructor = child; }
|
|
|
|
C.prototype = parent.prototype;
|
|
|
|
child.prototype = new C();
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$SyntaxError(message, expected, found, location) {
|
|
|
|
var self = Error.call(this, message);
|
|
|
|
// istanbul ignore next Check is a necessary evil to support older environments
|
|
|
|
if (Object.setPrototypeOf) {
|
|
|
|
Object.setPrototypeOf(self, peg$SyntaxError.prototype);
|
|
|
|
}
|
|
|
|
self.expected = expected;
|
|
|
|
self.found = found;
|
|
|
|
self.location = location;
|
|
|
|
self.name = "SyntaxError";
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
peg$subclass(peg$SyntaxError, Error);
|
|
|
|
|
|
|
|
function peg$padEnd(str, targetLength, padString) {
|
|
|
|
padString = padString || " ";
|
|
|
|
if (str.length > targetLength) { return str; }
|
|
|
|
targetLength -= str.length;
|
|
|
|
padString += padString.repeat(targetLength);
|
|
|
|
return str + padString.slice(0, targetLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
peg$SyntaxError.prototype.format = function(sources) {
|
|
|
|
var str = "Error: " + this.message;
|
|
|
|
if (this.location) {
|
|
|
|
var src = null;
|
|
|
|
var k;
|
|
|
|
for (k = 0; k < sources.length; k++) {
|
|
|
|
if (sources[k].source === this.location.source) {
|
|
|
|
src = sources[k].text.split(/\r\n|\n|\r/g);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var s = this.location.start;
|
|
|
|
var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))
|
|
|
|
? this.location.source.offset(s)
|
|
|
|
: s;
|
|
|
|
var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;
|
|
|
|
if (src) {
|
|
|
|
var e = this.location.end;
|
|
|
|
var filler = peg$padEnd("", offset_s.line.toString().length, ' ');
|
|
|
|
var line = src[s.line - 1];
|
|
|
|
var last = s.line === e.line ? e.column : line.length + 1;
|
|
|
|
var hatLen = (last - s.column) || 1;
|
|
|
|
str += "\n --> " + loc + "\n"
|
|
|
|
+ filler + " |\n"
|
|
|
|
+ offset_s.line + " | " + line + "\n"
|
|
|
|
+ filler + " | " + peg$padEnd("", s.column - 1, ' ')
|
|
|
|
+ peg$padEnd("", hatLen, "^");
|
|
|
|
} else {
|
|
|
|
str += "\n at " + loc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
};
|
|
|
|
|
|
|
|
peg$SyntaxError.buildMessage = function(expected, found) {
|
|
|
|
var DESCRIBE_EXPECTATION_FNS = {
|
|
|
|
literal: function(expectation) {
|
|
|
|
return "\"" + literalEscape(expectation.text) + "\"";
|
|
|
|
},
|
|
|
|
|
|
|
|
class: function(expectation) {
|
|
|
|
var escapedParts = expectation.parts.map(function(part) {
|
|
|
|
return Array.isArray(part)
|
|
|
|
? classEscape(part[0]) + "-" + classEscape(part[1])
|
|
|
|
: classEscape(part);
|
|
|
|
});
|
|
|
|
|
|
|
|
return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
|
|
|
|
},
|
|
|
|
|
|
|
|
any: function() {
|
|
|
|
return "any character";
|
|
|
|
},
|
|
|
|
|
|
|
|
end: function() {
|
|
|
|
return "end of input";
|
|
|
|
},
|
|
|
|
|
|
|
|
other: function(expectation) {
|
|
|
|
return expectation.description;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
function hex(ch) {
|
|
|
|
return ch.charCodeAt(0).toString(16).toUpperCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
function literalEscape(s) {
|
|
|
|
return s
|
|
|
|
.replace(/\\/g, "\\\\")
|
|
|
|
.replace(/"/g, "\\\"")
|
|
|
|
.replace(/\0/g, "\\0")
|
|
|
|
.replace(/\t/g, "\\t")
|
|
|
|
.replace(/\n/g, "\\n")
|
|
|
|
.replace(/\r/g, "\\r")
|
|
|
|
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
|
|
|
|
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
|
|
|
|
}
|
|
|
|
|
|
|
|
function classEscape(s) {
|
|
|
|
return s
|
|
|
|
.replace(/\\/g, "\\\\")
|
|
|
|
.replace(/\]/g, "\\]")
|
|
|
|
.replace(/\^/g, "\\^")
|
|
|
|
.replace(/-/g, "\\-")
|
|
|
|
.replace(/\0/g, "\\0")
|
|
|
|
.replace(/\t/g, "\\t")
|
|
|
|
.replace(/\n/g, "\\n")
|
|
|
|
.replace(/\r/g, "\\r")
|
|
|
|
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
|
|
|
|
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
|
|
|
|
}
|
|
|
|
|
|
|
|
function describeExpectation(expectation) {
|
|
|
|
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
|
|
|
|
}
|
|
|
|
|
|
|
|
function describeExpected(expected) {
|
|
|
|
var descriptions = expected.map(describeExpectation);
|
|
|
|
var i, j;
|
|
|
|
|
|
|
|
descriptions.sort();
|
|
|
|
|
|
|
|
if (descriptions.length > 0) {
|
|
|
|
for (i = 1, j = 1; i < descriptions.length; i++) {
|
|
|
|
if (descriptions[i - 1] !== descriptions[i]) {
|
|
|
|
descriptions[j] = descriptions[i];
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
descriptions.length = j;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (descriptions.length) {
|
|
|
|
case 1:
|
|
|
|
return descriptions[0];
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
return descriptions[0] + " or " + descriptions[1];
|
|
|
|
|
|
|
|
default:
|
|
|
|
return descriptions.slice(0, -1).join(", ")
|
|
|
|
+ ", or "
|
|
|
|
+ descriptions[descriptions.length - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function describeFound(found) {
|
|
|
|
return found ? "\"" + literalEscape(found) + "\"" : "end of input";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
|
|
|
|
};
|
|
|
|
|
|
|
|
function peg$parse(input, options) {
|
|
|
|
options = options !== undefined ? options : {};
|
|
|
|
|
|
|
|
var peg$FAILED = {};
|
|
|
|
var peg$source = options.grammarSource;
|
|
|
|
|
|
|
|
var peg$startRuleFunctions = { Start: peg$parseStart };
|
|
|
|
var peg$startRuleFunction = peg$parseStart;
|
|
|
|
|
|
|
|
var peg$c0 = "add";
|
|
|
|
var peg$c1 = "done";
|
|
|
|
var peg$c2 = "filter";
|
|
|
|
var peg$c3 = "-";
|
|
|
|
var peg$c4 = ",";
|
|
|
|
var peg$c5 = "@";
|
|
|
|
var peg$c6 = "pro:";
|
|
|
|
var peg$c7 = "project:";
|
|
|
|
var peg$c8 = "+";
|
|
|
|
var peg$c9 = "priority:";
|
|
|
|
var peg$c10 = "#";
|
|
|
|
var peg$c11 = "am";
|
|
|
|
var peg$c12 = "pm";
|
|
|
|
|
|
|
|
var peg$r0 = /^[HML]/;
|
|
|
|
var peg$r1 = /^[0-9]/;
|
|
|
|
var peg$r2 = /^[0-9:]/;
|
|
|
|
var peg$r3 = /^[a-zA-Z0-9_\-]/;
|
|
|
|
var peg$r4 = /^[ \t]/;
|
|
|
|
|
|
|
|
var peg$e0 = peg$literalExpectation("add", false);
|
|
|
|
var peg$e1 = peg$literalExpectation("done", false);
|
|
|
|
var peg$e2 = peg$literalExpectation("filter", false);
|
|
|
|
var peg$e3 = peg$literalExpectation("-", false);
|
|
|
|
var peg$e4 = peg$literalExpectation(",", false);
|
|
|
|
var peg$e5 = peg$literalExpectation("@", false);
|
|
|
|
var peg$e6 = peg$literalExpectation("pro:", false);
|
|
|
|
var peg$e7 = peg$literalExpectation("project:", false);
|
|
|
|
var peg$e8 = peg$literalExpectation("+", false);
|
|
|
|
var peg$e9 = peg$literalExpectation("priority:", false);
|
|
|
|
var peg$e10 = peg$classExpectation(["H", "M", "L"], false, false);
|
|
|
|
var peg$e11 = peg$literalExpectation("#", false);
|
|
|
|
var peg$e12 = peg$classExpectation([["0", "9"]], false, false);
|
|
|
|
var peg$e13 = peg$classExpectation([["0", "9"], ":"], false, false);
|
|
|
|
var peg$e14 = peg$literalExpectation("am", false);
|
|
|
|
var peg$e15 = peg$literalExpectation("pm", false);
|
|
|
|
var peg$e16 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false);
|
|
|
|
var peg$e17 = peg$classExpectation([" ", "\t"], false, false);
|
|
|
|
var peg$e18 = peg$anyExpectation();
|
|
|
|
|
|
|
|
var peg$f0 = function(parts) {
|
|
|
|
return makeCommand('add', null, parts.filter(p => p !== null));
|
|
|
|
};
|
|
|
|
var peg$f1 = function(filters) {
|
|
|
|
return makeCommand('done', filters, null);
|
|
|
|
};
|
|
|
|
var peg$f2 = function(filters, moreFilters) {
|
|
|
|
return makeCommand('filter', [...filters, ...moreFilters], null);
|
|
|
|
};
|
|
|
|
var peg$f3 = function(filters) {
|
|
|
|
return makeCommand('filter', filters, null);
|
|
|
|
};
|
|
|
|
var peg$f4 = function(first, rest) {
|
|
|
|
return [first, ...rest.map(r => r[1])];
|
|
|
|
};
|
|
|
|
var peg$f5 = function(start, end) {
|
|
|
|
const ids = [];
|
|
|
|
for (let i = start; i <= end; i++) {
|
|
|
|
ids.push(i);
|
|
|
|
}
|
|
|
|
return ids;
|
|
|
|
};
|
|
|
|
var peg$f6 = function(id) {
|
|
|
|
return [id];
|
|
|
|
};
|
|
|
|
var peg$f7 = function(first, rest, trailing) {
|
|
|
|
const ids = [first, ...rest.map(r => r[1])].flat();
|
|
|
|
return {
|
|
|
|
type: 'id',
|
|
|
|
ids: ids,
|
|
|
|
reconstruct: function() { return this.ids.join(','); }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var peg$f8 = function(chars) {
|
|
|
|
return {
|
|
|
|
type: "text",
|
|
|
|
value: chars,
|
|
|
|
reconstruct: function() { return this.value; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var peg$f9 = function(value) {
|
|
|
|
return {
|
|
|
|
type: "due",
|
|
|
|
value: value,
|
|
|
|
reconstruct: function() { return `@${this.value}`; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var peg$f10 = function(value) {
|
|
|
|
return {
|
|
|
|
type: "project",
|
|
|
|
value: value,
|
|
|
|
reconstruct: function() { return `+${this.value}`; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var peg$f11 = function(value) {
|
|
|
|
return {
|
|
|
|
type: "priority",
|
|
|
|
value: value,
|
|
|
|
reconstruct: function() { return `priority:${this.value}`; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var peg$f12 = function(value) {
|
|
|
|
return {
|
|
|
|
type: "tag",
|
|
|
|
value: value,
|
|
|
|
reconstruct: function() { return `#${this.value}`; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var peg$f13 = function(digits) {
|
|
|
|
return parseInt(digits.join(''), 10);
|
|
|
|
};
|
|
|
|
var peg$f14 = function(chars) {
|
|
|
|
return chars.join('') + (text() || '');
|
|
|
|
};
|
|
|
|
var peg$f15 = function(chars) {
|
|
|
|
return chars.join('');
|
|
|
|
};
|
|
|
|
var peg$f16 = function() {
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
var peg$currPos = options.peg$currPos | 0;
|
|
|
|
var peg$savedPos = peg$currPos;
|
|
|
|
var peg$posDetailsCache = [{ line: 1, column: 1 }];
|
|
|
|
var peg$maxFailPos = peg$currPos;
|
|
|
|
var peg$maxFailExpected = options.peg$maxFailExpected || [];
|
|
|
|
var peg$silentFails = options.peg$silentFails | 0;
|
|
|
|
|
|
|
|
var peg$result;
|
|
|
|
|
|
|
|
if (options.startRule) {
|
|
|
|
if (!(options.startRule in peg$startRuleFunctions)) {
|
|
|
|
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
|
|
|
|
}
|
|
|
|
|
|
|
|
peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
|
|
|
|
}
|
|
|
|
|
|
|
|
function text() {
|
|
|
|
return input.substring(peg$savedPos, peg$currPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
function offset() {
|
|
|
|
return peg$savedPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
function range() {
|
|
|
|
return {
|
|
|
|
source: peg$source,
|
|
|
|
start: peg$savedPos,
|
|
|
|
end: peg$currPos
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function location() {
|
|
|
|
return peg$computeLocation(peg$savedPos, peg$currPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
function expected(description, location) {
|
|
|
|
location = location !== undefined
|
|
|
|
? location
|
|
|
|
: peg$computeLocation(peg$savedPos, peg$currPos);
|
|
|
|
|
|
|
|
throw peg$buildStructuredError(
|
|
|
|
[peg$otherExpectation(description)],
|
|
|
|
input.substring(peg$savedPos, peg$currPos),
|
|
|
|
location
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function error(message, location) {
|
|
|
|
location = location !== undefined
|
|
|
|
? location
|
|
|
|
: peg$computeLocation(peg$savedPos, peg$currPos);
|
|
|
|
|
|
|
|
throw peg$buildSimpleError(message, location);
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$literalExpectation(text, ignoreCase) {
|
|
|
|
return { type: "literal", text: text, ignoreCase: ignoreCase };
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$classExpectation(parts, inverted, ignoreCase) {
|
|
|
|
return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$anyExpectation() {
|
|
|
|
return { type: "any" };
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$endExpectation() {
|
|
|
|
return { type: "end" };
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$otherExpectation(description) {
|
|
|
|
return { type: "other", description: description };
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$computePosDetails(pos) {
|
|
|
|
var details = peg$posDetailsCache[pos];
|
|
|
|
var p;
|
|
|
|
|
|
|
|
if (details) {
|
|
|
|
return details;
|
|
|
|
} else {
|
|
|
|
if (pos >= peg$posDetailsCache.length) {
|
|
|
|
p = peg$posDetailsCache.length - 1;
|
|
|
|
} else {
|
|
|
|
p = pos;
|
|
|
|
while (!peg$posDetailsCache[--p]) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
details = peg$posDetailsCache[p];
|
|
|
|
details = {
|
|
|
|
line: details.line,
|
|
|
|
column: details.column
|
|
|
|
};
|
|
|
|
|
|
|
|
while (p < pos) {
|
|
|
|
if (input.charCodeAt(p) === 10) {
|
|
|
|
details.line++;
|
|
|
|
details.column = 1;
|
|
|
|
} else {
|
|
|
|
details.column++;
|
|
|
|
}
|
|
|
|
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
peg$posDetailsCache[pos] = details;
|
|
|
|
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$computeLocation(startPos, endPos, offset) {
|
|
|
|
var startPosDetails = peg$computePosDetails(startPos);
|
|
|
|
var endPosDetails = peg$computePosDetails(endPos);
|
|
|
|
|
|
|
|
var res = {
|
|
|
|
source: peg$source,
|
|
|
|
start: {
|
|
|
|
offset: startPos,
|
|
|
|
line: startPosDetails.line,
|
|
|
|
column: startPosDetails.column
|
|
|
|
},
|
|
|
|
end: {
|
|
|
|
offset: endPos,
|
|
|
|
line: endPosDetails.line,
|
|
|
|
column: endPosDetails.column
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (offset && peg$source && (typeof peg$source.offset === "function")) {
|
|
|
|
res.start = peg$source.offset(res.start);
|
|
|
|
res.end = peg$source.offset(res.end);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$fail(expected) {
|
|
|
|
if (peg$currPos < peg$maxFailPos) { return; }
|
|
|
|
|
|
|
|
if (peg$currPos > peg$maxFailPos) {
|
|
|
|
peg$maxFailPos = peg$currPos;
|
|
|
|
peg$maxFailExpected = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
peg$maxFailExpected.push(expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$buildSimpleError(message, location) {
|
|
|
|
return new peg$SyntaxError(message, null, null, location);
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$buildStructuredError(expected, found, location) {
|
|
|
|
return new peg$SyntaxError(
|
|
|
|
peg$SyntaxError.buildMessage(expected, found),
|
|
|
|
expected,
|
|
|
|
found,
|
|
|
|
location
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseStart() {
|
|
|
|
var s0;
|
|
|
|
|
|
|
|
s0 = peg$parseAddCommand();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseDoneCommand();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseExplicitFilterCommand();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseImplicitFilterCommand();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseAddCommand() {
|
|
|
|
var s0, s1, s2, s3, s4;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
if (input.substr(peg$currPos, 3) === peg$c0) {
|
|
|
|
s1 = peg$c0;
|
|
|
|
peg$currPos += 3;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e0); }
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parse_();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
s3 = [];
|
|
|
|
s4 = peg$parsePart();
|
|
|
|
if (s4 === peg$FAILED) {
|
|
|
|
s4 = peg$parse_();
|
|
|
|
}
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
while (s4 !== peg$FAILED) {
|
|
|
|
s3.push(s4);
|
|
|
|
s4 = peg$parsePart();
|
|
|
|
if (s4 === peg$FAILED) {
|
|
|
|
s4 = peg$parse_();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
if (s3 !== peg$FAILED) {
|
|
|
|
s4 = peg$parseEOF();
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f0(s3);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseDoneCommand() {
|
|
|
|
var s0, s1, s2, s3, s4;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseFilters();
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parse_();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
if (input.substr(peg$currPos, 4) === peg$c1) {
|
|
|
|
s3 = peg$c1;
|
|
|
|
peg$currPos += 4;
|
|
|
|
} else {
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e1); }
|
|
|
|
}
|
|
|
|
if (s3 !== peg$FAILED) {
|
|
|
|
s4 = peg$parseEOF();
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f1(s1);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseExplicitFilterCommand() {
|
|
|
|
var s0, s1, s2, s3, s4, s5, s6;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseFilters();
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parse_();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
if (input.substr(peg$currPos, 6) === peg$c2) {
|
|
|
|
s3 = peg$c2;
|
|
|
|
peg$currPos += 6;
|
|
|
|
} else {
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e2); }
|
|
|
|
}
|
|
|
|
if (s3 !== peg$FAILED) {
|
|
|
|
s4 = [];
|
|
|
|
s5 = peg$parse_();
|
|
|
|
while (s5 !== peg$FAILED) {
|
|
|
|
s4.push(s5);
|
|
|
|
s5 = peg$parse_();
|
|
|
|
}
|
|
|
|
s5 = [];
|
|
|
|
s6 = peg$parseFilters();
|
|
|
|
while (s6 !== peg$FAILED) {
|
|
|
|
s5.push(s6);
|
|
|
|
s6 = peg$parseFilters();
|
|
|
|
}
|
|
|
|
s6 = peg$parseEOF();
|
|
|
|
if (s6 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f2(s1, s5);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseImplicitFilterCommand() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = [];
|
|
|
|
s2 = peg$parseFilters();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
while (s2 !== peg$FAILED) {
|
|
|
|
s1.push(s2);
|
|
|
|
s2 = peg$parseFilters();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parseEOF();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f3(s1);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseFilters() {
|
|
|
|
var s0, s1, s2, s3, s4, s5;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseFilter();
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = [];
|
|
|
|
s3 = peg$currPos;
|
|
|
|
s4 = peg$parse_();
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
s5 = peg$parseFilter();
|
|
|
|
if (s5 !== peg$FAILED) {
|
|
|
|
s4 = [s4, s5];
|
|
|
|
s3 = s4;
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
while (s3 !== peg$FAILED) {
|
|
|
|
s2.push(s3);
|
|
|
|
s3 = peg$currPos;
|
|
|
|
s4 = peg$parse_();
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
s5 = peg$parseFilter();
|
|
|
|
if (s5 !== peg$FAILED) {
|
|
|
|
s4 = [s4, s5];
|
|
|
|
s3 = s4;
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f4(s1, s2);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseIdRange() {
|
|
|
|
var s0, s1, s2, s3;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseInteger();
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
if (input.charCodeAt(peg$currPos) === 45) {
|
|
|
|
s2 = peg$c3;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e3); }
|
|
|
|
}
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
s3 = peg$parseInteger();
|
|
|
|
if (s3 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f5(s1, s3);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseSingleId() {
|
|
|
|
var s0, s1;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseInteger();
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s1 = peg$f6(s1);
|
|
|
|
}
|
|
|
|
s0 = s1;
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseFilter() {
|
|
|
|
var s0;
|
|
|
|
|
|
|
|
s0 = peg$parseIdFilter();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseTag();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseProject();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parsePriority();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseDue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseIdFilter() {
|
|
|
|
var s0, s1, s2, s3, s4, s5;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseIdRange();
|
|
|
|
if (s1 === peg$FAILED) {
|
|
|
|
s1 = peg$parseSingleId();
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = [];
|
|
|
|
s3 = peg$currPos;
|
|
|
|
if (input.charCodeAt(peg$currPos) === 44) {
|
|
|
|
s4 = peg$c4;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s4 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e4); }
|
|
|
|
}
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
s5 = peg$parseIdRange();
|
|
|
|
if (s5 === peg$FAILED) {
|
|
|
|
s5 = peg$parseSingleId();
|
|
|
|
}
|
|
|
|
if (s5 !== peg$FAILED) {
|
|
|
|
s4 = [s4, s5];
|
|
|
|
s3 = s4;
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
while (s3 !== peg$FAILED) {
|
|
|
|
s2.push(s3);
|
|
|
|
s3 = peg$currPos;
|
|
|
|
if (input.charCodeAt(peg$currPos) === 44) {
|
|
|
|
s4 = peg$c4;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s4 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e4); }
|
|
|
|
}
|
|
|
|
if (s4 !== peg$FAILED) {
|
|
|
|
s5 = peg$parseIdRange();
|
|
|
|
if (s5 === peg$FAILED) {
|
|
|
|
s5 = peg$parseSingleId();
|
|
|
|
}
|
|
|
|
if (s5 !== peg$FAILED) {
|
|
|
|
s4 = [s4, s5];
|
|
|
|
s3 = s4;
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s3;
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (input.charCodeAt(peg$currPos) === 44) {
|
|
|
|
s3 = peg$c4;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s3 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e4); }
|
|
|
|
}
|
|
|
|
if (s3 === peg$FAILED) {
|
|
|
|
s3 = null;
|
|
|
|
}
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f7(s1, s2, s3);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parsePart() {
|
|
|
|
var s0;
|
|
|
|
|
|
|
|
s0 = peg$parseAttribute();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseTextPart();
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseTextPart() {
|
|
|
|
var s0, s1;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = peg$parseWord();
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s1 = peg$f8(s1);
|
|
|
|
}
|
|
|
|
s0 = s1;
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseAttribute() {
|
|
|
|
var s0;
|
|
|
|
|
|
|
|
s0 = peg$parseDue();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseTag();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parseProject();
|
|
|
|
if (s0 === peg$FAILED) {
|
|
|
|
s0 = peg$parsePriority();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseDue() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
if (input.charCodeAt(peg$currPos) === 64) {
|
|
|
|
s1 = peg$c5;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e5); }
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parseTimeValue();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f9(s2);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseProject() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
if (input.substr(peg$currPos, 4) === peg$c6) {
|
|
|
|
s1 = peg$c6;
|
|
|
|
peg$currPos += 4;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e6); }
|
|
|
|
}
|
|
|
|
if (s1 === peg$FAILED) {
|
|
|
|
if (input.substr(peg$currPos, 8) === peg$c7) {
|
|
|
|
s1 = peg$c7;
|
|
|
|
peg$currPos += 8;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e7); }
|
|
|
|
}
|
|
|
|
if (s1 === peg$FAILED) {
|
|
|
|
if (input.charCodeAt(peg$currPos) === 43) {
|
|
|
|
s1 = peg$c8;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e8); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parseWord();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f10(s2);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parsePriority() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
if (input.substr(peg$currPos, 9) === peg$c9) {
|
|
|
|
s1 = peg$c9;
|
|
|
|
peg$currPos += 9;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e9); }
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r0.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e10); }
|
|
|
|
}
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f11(s2);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseTag() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
if (input.charCodeAt(peg$currPos) === 35) {
|
|
|
|
s1 = peg$c10;
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e11); }
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
s2 = peg$parseWord();
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f12(s2);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseInteger() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = [];
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r1.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e12); }
|
|
|
|
}
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
while (s2 !== peg$FAILED) {
|
|
|
|
s1.push(s2);
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r1.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e12); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s1 = peg$f13(s1);
|
|
|
|
}
|
|
|
|
s0 = s1;
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseTimeValue() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = [];
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r2.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e13); }
|
|
|
|
}
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
while (s2 !== peg$FAILED) {
|
|
|
|
s1.push(s2);
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r2.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e13); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
if (input.substr(peg$currPos, 2) === peg$c11) {
|
|
|
|
s2 = peg$c11;
|
|
|
|
peg$currPos += 2;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e14); }
|
|
|
|
}
|
|
|
|
if (s2 === peg$FAILED) {
|
|
|
|
if (input.substr(peg$currPos, 2) === peg$c12) {
|
|
|
|
s2 = peg$c12;
|
|
|
|
peg$currPos += 2;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e15); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (s2 === peg$FAILED) {
|
|
|
|
s2 = null;
|
|
|
|
}
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s0 = peg$f14(s1);
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseWord() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = [];
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r3.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e16); }
|
|
|
|
}
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
while (s2 !== peg$FAILED) {
|
|
|
|
s1.push(s2);
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r3.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e16); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s1 = peg$f15(s1);
|
|
|
|
}
|
|
|
|
s0 = s1;
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parse_() {
|
|
|
|
var s0, s1, s2;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
s1 = [];
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r4.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e17); }
|
|
|
|
}
|
|
|
|
if (s2 !== peg$FAILED) {
|
|
|
|
while (s2 !== peg$FAILED) {
|
|
|
|
s1.push(s2);
|
|
|
|
s2 = input.charAt(peg$currPos);
|
|
|
|
if (peg$r4.test(s2)) {
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s2 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e17); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
}
|
|
|
|
if (s1 !== peg$FAILED) {
|
|
|
|
peg$savedPos = s0;
|
|
|
|
s1 = peg$f16();
|
|
|
|
}
|
|
|
|
s0 = s1;
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function peg$parseEOF() {
|
|
|
|
var s0, s1;
|
|
|
|
|
|
|
|
s0 = peg$currPos;
|
|
|
|
peg$silentFails++;
|
|
|
|
if (input.length > peg$currPos) {
|
|
|
|
s1 = input.charAt(peg$currPos);
|
|
|
|
peg$currPos++;
|
|
|
|
} else {
|
|
|
|
s1 = peg$FAILED;
|
|
|
|
if (peg$silentFails === 0) { peg$fail(peg$e18); }
|
|
|
|
}
|
|
|
|
peg$silentFails--;
|
|
|
|
if (s1 === peg$FAILED) {
|
|
|
|
s0 = undefined;
|
|
|
|
} else {
|
|
|
|
peg$currPos = s0;
|
|
|
|
s0 = peg$FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function makeCommand(type, filters, parts) {
|
|
|
|
|
|
|
|
const validParts = parts || [];
|
|
|
|
// Extract pure description (without attributes)
|
|
|
|
const description = validParts
|
feat: parse multiple commands
basically at MVP now
the react app can now add, complete and reactively filter tasks
The filter command doesn't have a enter action, it should probably do
something. maybe I do need the default to be select, instead of filter,
and filter should _actually filter_.
Syncing is next. I'll need to look at the vcln starter template to
understand how they set up, and then maintain different databases for
each user.
What needs to be done is setting up rooms, and the backend such that
everybody gets their own lil sql database, and the syncer can identify
them. we don't really have any notion of security, which is uhhh, not
great.
After that we can look at some malleable features that lend themself to
discoverability. ideally, I don't need to have a tutorial at all.
reactivity needs to exist for almost every command. I want to save the
command, to a dirty state sql table, and then restore it on load. that
should cause all the elements to re-render the proposed change.
this actually unlocks a thought for me: executing filters, sets them as
a "context". a context makes up a view. reports are literally just
saved contexts then. this allows the tanstack table to handle virtual
ids for us!
Then, for the malleable input, all we need some kind of triple scroll
wheel that can be typed, for each of the three segments. ideally with
desired autocomplete 🤔
i think i'm reimagining the CLI for the web almost!
2024-11-10 18:15:20 -08:00
|
|
|
.filter(part => part.type === 'text')
|
|
|
|
.map(part => part.value)
|
feat: new command parser
It's not fully hooked up to the react app, and it's not quite complete
either, but it's a start.
Currently, it will parse filter implicitly, and there's also the done
and add command. For now, all commands must place the command name in
the right location.
Additionally, I've hooked up the react table's selection state to the
command parser. Filter based on _ids_ explicitly does work. Manually
selecting an ID will also place it in the input field for
discoverability. It does not remove ids that were manually deselected
yet, nor does filter based on any other attribute work.
The command parser also parses times, but it does so very poorly
currently. More work will need to go into that, for now it's basically a
stub. I'll also need to convert the parser to Go.
The react table conviently handles virtual tables based on it's internal
`row.id`. I'm still wondering how to implement virtual ids, but at least
on the web app, they are constantly updated since the view is always
visible, which is different to the CLI (though perhaps the same as a
TUI?)
Notably, there's no semantics for the difference between selection and
filtering. I think perhaps the implicit filter command should default to
selection, but the explicit filter command should be handled
differently, and actually execute filtering. I haven't yet looked into
how the TanStack Table handles filtering, but I am aware that it does.
I think for an MVP, once done is implemented, I can deploy this, the web
socket server, and try and start using it.
2024-11-10 02:15:10 -08:00
|
|
|
.join(' ')
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
// Collect all attributes
|
|
|
|
const attributes = validParts
|
feat: parse multiple commands
basically at MVP now
the react app can now add, complete and reactively filter tasks
The filter command doesn't have a enter action, it should probably do
something. maybe I do need the default to be select, instead of filter,
and filter should _actually filter_.
Syncing is next. I'll need to look at the vcln starter template to
understand how they set up, and then maintain different databases for
each user.
What needs to be done is setting up rooms, and the backend such that
everybody gets their own lil sql database, and the syncer can identify
them. we don't really have any notion of security, which is uhhh, not
great.
After that we can look at some malleable features that lend themself to
discoverability. ideally, I don't need to have a tutorial at all.
reactivity needs to exist for almost every command. I want to save the
command, to a dirty state sql table, and then restore it on load. that
should cause all the elements to re-render the proposed change.
this actually unlocks a thought for me: executing filters, sets them as
a "context". a context makes up a view. reports are literally just
saved contexts then. this allows the tanstack table to handle virtual
ids for us!
Then, for the malleable input, all we need some kind of triple scroll
wheel that can be typed, for each of the three segments. ideally with
desired autocomplete 🤔
i think i'm reimagining the CLI for the web almost!
2024-11-10 18:15:20 -08:00
|
|
|
.filter(part => part.type !== 'text')
|
feat: new command parser
It's not fully hooked up to the react app, and it's not quite complete
either, but it's a start.
Currently, it will parse filter implicitly, and there's also the done
and add command. For now, all commands must place the command name in
the right location.
Additionally, I've hooked up the react table's selection state to the
command parser. Filter based on _ids_ explicitly does work. Manually
selecting an ID will also place it in the input field for
discoverability. It does not remove ids that were manually deselected
yet, nor does filter based on any other attribute work.
The command parser also parses times, but it does so very poorly
currently. More work will need to go into that, for now it's basically a
stub. I'll also need to convert the parser to Go.
The react table conviently handles virtual tables based on it's internal
`row.id`. I'm still wondering how to implement virtual ids, but at least
on the web app, they are constantly updated since the view is always
visible, which is different to the CLI (though perhaps the same as a
TUI?)
Notably, there's no semantics for the difference between selection and
filtering. I think perhaps the implicit filter command should default to
selection, but the explicit filter command should be handled
differently, and actually execute filtering. I haven't yet looked into
how the TanStack Table handles filtering, but I am aware that it does.
I think for an MVP, once done is implemented, I can deploy this, the web
socket server, and try and start using it.
2024-11-10 02:15:10 -08:00
|
|
|
.filter(part => part !== null);
|
feat: parse multiple commands
basically at MVP now
the react app can now add, complete and reactively filter tasks
The filter command doesn't have a enter action, it should probably do
something. maybe I do need the default to be select, instead of filter,
and filter should _actually filter_.
Syncing is next. I'll need to look at the vcln starter template to
understand how they set up, and then maintain different databases for
each user.
What needs to be done is setting up rooms, and the backend such that
everybody gets their own lil sql database, and the syncer can identify
them. we don't really have any notion of security, which is uhhh, not
great.
After that we can look at some malleable features that lend themself to
discoverability. ideally, I don't need to have a tutorial at all.
reactivity needs to exist for almost every command. I want to save the
command, to a dirty state sql table, and then restore it on load. that
should cause all the elements to re-render the proposed change.
this actually unlocks a thought for me: executing filters, sets them as
a "context". a context makes up a view. reports are literally just
saved contexts then. this allows the tanstack table to handle virtual
ids for us!
Then, for the malleable input, all we need some kind of triple scroll
wheel that can be typed, for each of the three segments. ideally with
desired autocomplete 🤔
i think i'm reimagining the CLI for the web almost!
2024-11-10 18:15:20 -08:00
|
|
|
|
|
|
|
const project = validParts
|
|
|
|
.filter(part => part.type === 'project')
|
|
|
|
.map(part => part.value)
|
|
|
|
.join('')
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
const tags = validParts
|
|
|
|
.filter(part => part.type === 'tag')
|
|
|
|
.map(part => part.value);
|
|
|
|
|
feat: new command parser
It's not fully hooked up to the react app, and it's not quite complete
either, but it's a start.
Currently, it will parse filter implicitly, and there's also the done
and add command. For now, all commands must place the command name in
the right location.
Additionally, I've hooked up the react table's selection state to the
command parser. Filter based on _ids_ explicitly does work. Manually
selecting an ID will also place it in the input field for
discoverability. It does not remove ids that were manually deselected
yet, nor does filter based on any other attribute work.
The command parser also parses times, but it does so very poorly
currently. More work will need to go into that, for now it's basically a
stub. I'll also need to convert the parser to Go.
The react table conviently handles virtual tables based on it's internal
`row.id`. I'm still wondering how to implement virtual ids, but at least
on the web app, they are constantly updated since the view is always
visible, which is different to the CLI (though perhaps the same as a
TUI?)
Notably, there's no semantics for the difference between selection and
filtering. I think perhaps the implicit filter command should default to
selection, but the explicit filter command should be handled
differently, and actually execute filtering. I haven't yet looked into
how the TanStack Table handles filtering, but I am aware that it does.
I think for an MVP, once done is implemented, I can deploy this, the web
socket server, and try and start using it.
2024-11-10 02:15:10 -08:00
|
|
|
|
|
|
|
// Store original parts for reconstruction
|
|
|
|
const originalParts = validParts.filter(part => part !== null);
|
feat: parse multiple commands
basically at MVP now
the react app can now add, complete and reactively filter tasks
The filter command doesn't have a enter action, it should probably do
something. maybe I do need the default to be select, instead of filter,
and filter should _actually filter_.
Syncing is next. I'll need to look at the vcln starter template to
understand how they set up, and then maintain different databases for
each user.
What needs to be done is setting up rooms, and the backend such that
everybody gets their own lil sql database, and the syncer can identify
them. we don't really have any notion of security, which is uhhh, not
great.
After that we can look at some malleable features that lend themself to
discoverability. ideally, I don't need to have a tutorial at all.
reactivity needs to exist for almost every command. I want to save the
command, to a dirty state sql table, and then restore it on load. that
should cause all the elements to re-render the proposed change.
this actually unlocks a thought for me: executing filters, sets them as
a "context". a context makes up a view. reports are literally just
saved contexts then. this allows the tanstack table to handle virtual
ids for us!
Then, for the malleable input, all we need some kind of triple scroll
wheel that can be typed, for each of the three segments. ideally with
desired autocomplete 🤔
i think i'm reimagining the CLI for the web almost!
2024-11-10 18:15:20 -08:00
|
|
|
let validFilters;
|
|
|
|
if (!!filters) {
|
|
|
|
validFilters = filters.flat();
|
|
|
|
} else {
|
|
|
|
validFilters = [];
|
|
|
|
}
|
feat: new command parser
It's not fully hooked up to the react app, and it's not quite complete
either, but it's a start.
Currently, it will parse filter implicitly, and there's also the done
and add command. For now, all commands must place the command name in
the right location.
Additionally, I've hooked up the react table's selection state to the
command parser. Filter based on _ids_ explicitly does work. Manually
selecting an ID will also place it in the input field for
discoverability. It does not remove ids that were manually deselected
yet, nor does filter based on any other attribute work.
The command parser also parses times, but it does so very poorly
currently. More work will need to go into that, for now it's basically a
stub. I'll also need to convert the parser to Go.
The react table conviently handles virtual tables based on it's internal
`row.id`. I'm still wondering how to implement virtual ids, but at least
on the web app, they are constantly updated since the view is always
visible, which is different to the CLI (though perhaps the same as a
TUI?)
Notably, there's no semantics for the difference between selection and
filtering. I think perhaps the implicit filter command should default to
selection, but the explicit filter command should be handled
differently, and actually execute filtering. I haven't yet looked into
how the TanStack Table handles filtering, but I am aware that it does.
I think for an MVP, once done is implemented, I can deploy this, the web
socket server, and try and start using it.
2024-11-10 02:15:10 -08:00
|
|
|
|
|
|
|
return {
|
|
|
|
type: type,
|
|
|
|
description: description || [],
|
|
|
|
attributes: attributes || [],
|
feat: parse multiple commands
basically at MVP now
the react app can now add, complete and reactively filter tasks
The filter command doesn't have a enter action, it should probably do
something. maybe I do need the default to be select, instead of filter,
and filter should _actually filter_.
Syncing is next. I'll need to look at the vcln starter template to
understand how they set up, and then maintain different databases for
each user.
What needs to be done is setting up rooms, and the backend such that
everybody gets their own lil sql database, and the syncer can identify
them. we don't really have any notion of security, which is uhhh, not
great.
After that we can look at some malleable features that lend themself to
discoverability. ideally, I don't need to have a tutorial at all.
reactivity needs to exist for almost every command. I want to save the
command, to a dirty state sql table, and then restore it on load. that
should cause all the elements to re-render the proposed change.
this actually unlocks a thought for me: executing filters, sets them as
a "context". a context makes up a view. reports are literally just
saved contexts then. this allows the tanstack table to handle virtual
ids for us!
Then, for the malleable input, all we need some kind of triple scroll
wheel that can be typed, for each of the three segments. ideally with
desired autocomplete 🤔
i think i'm reimagining the CLI for the web almost!
2024-11-10 18:15:20 -08:00
|
|
|
filters: validFilters,
|
|
|
|
project: project,
|
|
|
|
tags: JSON.stringify(tags),
|
feat: new command parser
It's not fully hooked up to the react app, and it's not quite complete
either, but it's a start.
Currently, it will parse filter implicitly, and there's also the done
and add command. For now, all commands must place the command name in
the right location.
Additionally, I've hooked up the react table's selection state to the
command parser. Filter based on _ids_ explicitly does work. Manually
selecting an ID will also place it in the input field for
discoverability. It does not remove ids that were manually deselected
yet, nor does filter based on any other attribute work.
The command parser also parses times, but it does so very poorly
currently. More work will need to go into that, for now it's basically a
stub. I'll also need to convert the parser to Go.
The react table conviently handles virtual tables based on it's internal
`row.id`. I'm still wondering how to implement virtual ids, but at least
on the web app, they are constantly updated since the view is always
visible, which is different to the CLI (though perhaps the same as a
TUI?)
Notably, there's no semantics for the difference between selection and
filtering. I think perhaps the implicit filter command should default to
selection, but the explicit filter command should be handled
differently, and actually execute filtering. I haven't yet looked into
how the TanStack Table handles filtering, but I am aware that it does.
I think for an MVP, once done is implemented, I can deploy this, the web
socket server, and try and start using it.
2024-11-10 02:15:10 -08:00
|
|
|
parts: parts || [],
|
|
|
|
reconstruct: function() {
|
|
|
|
const filterStr = this.filters.map(f => f.reconstruct()).join(',');
|
|
|
|
const partsStr = this.parts.map(p => p.reconstruct()).join(' ');
|
|
|
|
return [filterStr, this.type, partsStr].filter(Boolean).join(' ');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
peg$result = peg$startRuleFunction();
|
|
|
|
|
|
|
|
if (options.peg$library) {
|
|
|
|
return /** @type {any} */ ({
|
|
|
|
peg$result,
|
|
|
|
peg$currPos,
|
|
|
|
peg$FAILED,
|
|
|
|
peg$maxFailExpected,
|
|
|
|
peg$maxFailPos
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (peg$result !== peg$FAILED && peg$currPos === input.length) {
|
|
|
|
return peg$result;
|
|
|
|
} else {
|
|
|
|
if (peg$result !== peg$FAILED && peg$currPos < input.length) {
|
|
|
|
peg$fail(peg$endExpectation());
|
|
|
|
}
|
|
|
|
|
|
|
|
throw peg$buildStructuredError(
|
|
|
|
peg$maxFailExpected,
|
|
|
|
peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
|
|
|
|
peg$maxFailPos < input.length
|
|
|
|
? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
|
|
|
|
: peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const peg$allowedStartRules = [
|
|
|
|
"Start"
|
|
|
|
];
|
|
|
|
|
|
|
|
export {
|
|
|
|
peg$allowedStartRules as StartRules,
|
|
|
|
peg$SyntaxError as SyntaxError,
|
|
|
|
peg$parse as parse
|
|
|
|
};
|