import type { MarkdownDocument } from "model/format/markdown" ; import type { ReadOnlyReference } from "model/ref" ; import { Reminder } from "model/reminder" ; import { DateTime } from "model/time" ; import { Todo } from "./markdown" ; export type ReminderEdit = { time ? : DateTime ; rawTime ? : string ; checked ? : boolean ; } ; export interface ReminderModel { getTitle ( ) : string | null ; getTime ( ) : DateTime | null ; setTime ( time ) : void ; /** return false when this reminder doesn't support raw time. */ setRawTime ( rawTime ) : boolean ; toMarkdown ( ) : string ; } export class ReminderFormatParameterKey < T > { static readonly now = new ReminderFormatParameterKey < DateTime > ( "now" , DateTime . now ( ) ) ; static readonly useCustomEmojiForTasksPlugin = new ReminderFormatParameterKey < boolean > ( "useCustomEmojiForTasksPlugin" , false ) ; static readonly linkDatesToDailyNotes = new ReminderFormatParameterKey < boolean > ( "linkDatesToDailyNotes" , false ) ; static readonly strictDateFormat = new ReminderFormatParameterKey < boolean > ( "strictDateFormat" , false ) ; constructor ( public readonly key , public readonly defaultValue ) { } } type ReminderFormatParameterSource < T > = ( ) => T ; export class ReminderFormatConfig { private parameters : Map < string , ReminderFormatParameterSource < any > > = new Map ( ) ; constructor ( ) { } param key setParameter < T > ( key , value ) { this . parameters . set ( key . key , ( ) => value . value ) ; } param key setParameterFunc < T > ( key , f ) { this . parameters . set ( key . key , f ) ; } setParameterValue < T > ( key , value ) { this . parameters . set ( key . key , ( ) => value ) ; } getParameter < T > ( key ) { const value = this . parameters . get ( key . key ) ; if ( value == null ) { return key . defaultValue ; } return value ( ) ; } } export interface ReminderFormat { setConfig ( config ) : void ; /**
     * Parse given line if possible.
     */ parse ( doc ) : Array < Reminder > | null ; param doc param reminder param edit returns modify ( doc , reminder , edit ) : Promise < boolean > ; param line param time appendReminder ( line , time ) : string | null ; } export abstract class TodoBasedReminderFormat < E extends ReminderModel > implements ReminderFormat { protected config : ReminderFormatConfig = new ReminderFormatConfig ( ) ; setConfig ( config ) { this . config = config ; } parse ( doc ) { return doc . getTodos ( ) . map ( todo => { const parsed = this . parseValidReminder ( todo ) ; if ( parsed == null ) { return null ; } const title = parsed . getTitle ( ) ; if ( title == null ) { return null ; } const time = parsed . getTime ( ) ; if ( time == null ) { return null ; } return new Reminder ( doc . file , title , time , todo . lineIndex , todo . isChecked ( ) ) ; } ) . filter ( ( reminder ) : reminder is Reminder => reminder != null ) ; } async modify ( doc , reminder , edit ) { const todo = doc . getTodo ( reminder . rowNumber ) ; if ( todo === null ) { console . warn ( "Not a todo: reminder=%o" , reminder ) ; return false ; } const parsed = this . parseValidReminder ( todo ) ; if ( parsed === null ) { return false ; } if ( ! this . modifyReminder ( doc , todo , parsed , edit ) ) { return false ; } todo . body = parsed . toMarkdown ( ) ; return true ; } private parseValidReminder ( todo ) { const parsed = this . parseReminder ( todo ) ; if ( parsed === null ) { return null ; } if ( ! this . isValidReminder ( parsed ) ) { return null ; } return parsed ; } isValidReminder ( reminder ) { return reminder . getTime ( ) !== null ; } modifyReminder ( doc , todo , parsed , edit ) { if ( edit . rawTime !== undefined ) { if ( ! parsed . setRawTime ( edit . rawTime ) ) { console . warn ( "The reminder doesn't support raw time: parsed=%o" , parsed ) ; return false ; } } else if ( edit . time !== undefined ) { parsed . setTime ( edit . time ) ; } if ( edit . checked !== undefined ) { todo . setChecked ( edit . checked ) ; } return true ; } appendReminder ( line , time ) { const todo = Todo . parse ( 0 , line ) ; if ( todo == null ) { return null ; } let parsed = this . parseReminder ( todo ) ; if ( parsed != null ) { parsed . setTime ( time ) ; } else { parsed = this . newReminder ( todo . body , time ) ; parsed . setTime ( time ) ; } todo . body = parsed . toMarkdown ( ) ; return todo . toMarkdown ( ) ; } abstract parseReminder ( todo ) ; abstract newReminder ( title , time ) ; protected isStrictDateFormat ( ) { return this . config . getParameter ( ReminderFormatParameterKey . strictDateFormat ) ; } } export class CompositeReminderFormat implements ReminderFormat { private config ? : ReminderFormatConfig ; private formats : Array < ReminderFormat > = [ ] ; setConfig ( config ) { this . config = config ; this . syncConfig ( ) ; } parse ( doc ) { const reminders = [ ] ; for ( const format of this . formats ) { const parsed = format . parse ( doc ) ; if ( parsed == null ) { continue ; } reminders . push ( ... parsed ) ; } return reminders ; } async modify ( doc , reminder , edit ) { for ( const format of this . formats ) { const modified = await format . modify ( doc , reminder , edit ) ; if ( modified ) { return true ; } } return false ; } resetFormat ( formats ) { this . formats = formats ; this . syncConfig ( ) ; } private syncConfig ( ) { if ( this . config == null ) { return ; } this . formats . forEach ( f => f . setConfig ( this . config ! ) ) ; } appendReminder ( line , time ) { if ( this . formats [ 0 ] == null ) { return null ; } return this . formats [ 0 ] . appendReminder ( line , time ) ; } }