2023-01-09 16:27:04 +00:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:petitparser/petitparser.dart';
|
|
|
|
import 'package:nextcloud_reminder/types/tasks.dart';
|
|
|
|
import 'package:tuple/tuple.dart';
|
|
|
|
|
|
|
|
abstract class TodoParser {
|
|
|
|
|
|
|
|
static final _definition = TodoTxtEvaluatorDefinition();
|
|
|
|
|
|
|
|
static final _todoParser = _definition.build();
|
|
|
|
|
2023-01-10 22:55:38 +00:00
|
|
|
static List<TaskExtra> parse(List<String> input) {
|
|
|
|
final List<TaskExtra> ret = [];
|
|
|
|
var line=1;
|
2023-01-09 16:27:04 +00:00
|
|
|
for (var element in input) {
|
|
|
|
var parsed = _todoParser.parse(element);
|
|
|
|
if (parsed.isSuccess) {
|
2023-01-10 22:55:38 +00:00
|
|
|
ret.add(TaskExtra.fromTask(parsed.value, lineNumber: line));
|
2023-01-09 16:27:04 +00:00
|
|
|
} else {
|
|
|
|
debugPrint(parsed.message);
|
|
|
|
debugPrint(element);
|
|
|
|
}
|
2023-01-10 22:55:38 +00:00
|
|
|
line++;
|
2023-01-09 16:27:04 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class TodoTxtEvaluatorDefinition extends TodoTxtDefinition {
|
|
|
|
|
|
|
|
@override
|
|
|
|
Parser todoLine() => super.todoLine().map((value) =>
|
|
|
|
//parser gives the following structure:
|
|
|
|
//0: completed? (null | true)
|
|
|
|
//1: priority? (null | uppercase letter)
|
|
|
|
//2: range? (null | [begin-date, (null | end-date)]
|
|
|
|
//3: description: Tuple5<original text, list<projects>, list<contexts>, map<meta>, text without meta>
|
|
|
|
Task( title: value[3].item5,
|
|
|
|
done: value[0] ?? false,
|
|
|
|
priority: value[1],
|
|
|
|
begin: (value[2] == null ? null : value[2][0]),
|
|
|
|
end: (value[2] == null ? null : value[2][1]),
|
|
|
|
projects: value[3].item2,
|
|
|
|
contexts: value[3].item3,
|
|
|
|
meta: value[3].item4,
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
class TodoTxtDefinition extends GrammarDefinition {
|
|
|
|
|
|
|
|
Tuple5<String,List<String>,List<String>, Map<String,String>, String> _extract_project_and_context(String input) {
|
|
|
|
final projectPattern = RegExp(r'\+([^ ]+)');
|
|
|
|
final contextPattern = RegExp(r'@([^ ]+)');
|
|
|
|
final metaPattern = RegExp(r'([^ ]+):([^ ]+)');
|
|
|
|
var projects = projectPattern.allMatches(input).map((Match m) => m[1]!);
|
|
|
|
var contexts = contextPattern.allMatches(input).map((Match m) => m[1]!);
|
|
|
|
var meta = metaPattern.allMatches(input).map((Match m) => MapEntry(m[1]!, m[2]!));
|
|
|
|
var cleanInput = input//.replaceAll(projectPattern, '')
|
|
|
|
//.replaceAll(contextPattern, '')
|
|
|
|
.replaceAll(metaPattern, '');
|
|
|
|
return Tuple5(input, List.of(projects), List.of(contexts), Map.fromEntries(meta), cleanInput.trim());
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Parser start() => ref0(todoLine).end();
|
|
|
|
|
|
|
|
Parser todoLine() => ref0(completed).trim().optional()
|
|
|
|
& ref0(priority).trim().optional()
|
|
|
|
& (ref0(date).trim() & ref0(date).trim().optional()).optional() // completion date + optional creation date
|
|
|
|
& any().plus().flatten().map(_extract_project_and_context)
|
|
|
|
;
|
|
|
|
|
|
|
|
Parser completed() => char('x').map((_) => true);
|
|
|
|
|
|
|
|
Parser priority() => (char('(') & pattern('A-Z') & char(')')).map((values) => values[1]);
|
|
|
|
|
|
|
|
Parser date() => (digit().plus().flatten() & char('-') & digit().plus().flatten() & char('-') & digit().plus().flatten())
|
|
|
|
.map((values) => DateTime(int.parse(values[0]),int.parse(values[2]),int.parse(values[4])));
|
|
|
|
}
|