todotxt_reminder/lib/parser/todotxt.dart

81 lines
3.0 KiB
Dart

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();
static List<TaskExtra> parse(List<String> input) {
final List<TaskExtra> ret = [];
var line=1;
for (var element in input) {
var parsed = _todoParser.parse(element);
if (parsed.isSuccess) {
ret.add(TaskExtra.fromTask(parsed.value, lineNumber: line));
} else {
debugPrint(parsed.message);
debugPrint(element);
}
line++;
}
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])));
}