81 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			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])));
 | |
| } |