start = _ @(task / line) _ /**************************************************************************************************************************************/ line = data:.* { return { type: "line", data: data.join("") } } /**************************************************************************************************************************************/ task = "-" _ "[" status:. "]" _ label:label meta:meta* { return { type: "task", data: { status, label, meta } }; } /**************************************************************************************************************************************/ label = spans:(tag / labelWord / labelWhitespace)* { return spans; } labelWord = word:[^ \t\r⏬🔽🔼⏫🔺➕⏳🛫📅✅❌🔁🏁🆔⛔⏰]+ { return { span: "word", value: word.join("") } } labelWhitespace = whitespace:[ \t\r]+ { return { span: "whitespace", value: whitespace.join("") } } tag = "#" tag:[a-zA-Z0-9-]+ { return { span: "tag", value: tag.join("") } } /**************************************************************************************************************************************/ meta = _ @(date / recurrence / delete / priority / dependency / reminder) _ /**************************************************************************************************************************************/ priority = priority:priorityIcon { return { feature: "priority", priority } } /**************************************************************************************************************************************/ delete = type:deleteIcon _ action:[a-zA-Z]+ { return { feature: "delete", action: action.join("").trim() } } /**************************************************************************************************************************************/ reminder = reminderIcon _ time:(longTime / shortTime)? { return { feature: "reminder", time } } longTime = hour:[0-9]|1..2| ":" minute:[0-9]|1..2| { return `${hour.join("").padStart(2, '0')}:${minute.join("").padStart(2, '0')}`; } shortTime = hour:[0-9]|1..2| { return `${hour.join("").padStart(2, '0')}:00`; } /**************************************************************************************************************************************/ recurrence = type:recurrenceIcon _ rec:[a-zA-Z0-9 ]+ { return { feature: "recurrence", rule: rec.join("").trim() } } /**************************************************************************************************************************************/ date = type:dateIcon _ date:dateLiteral { return { feature: "date", type, date }; } dateLiteral = year:([0-9]|4|) "-" month:([0-9]|1..2|) "-" day:([0-9]|1..2|) { return `${year.join("")}-${month.join("").padStart(2, '0')}-${day.join("").padStart(2, '0')}`; } /**************************************************************************************************************************************/ dependency = type:dependencyIcon _ deps:([a-zA-Z0-9-]+)|..,(_ "," _)| { return { feature: "dependency", type, deps: deps.map(x => x.join("")) } } /**************************************************************************************************************************************/ allIcons = dependencyIcon / recurrenceIcon / deleteIcon / reminderIcon / dateIcon / priority dependencyIcon = "🆔" / "⛔" recurrenceIcon = "🔁" deleteIcon = "🏁" reminderIcon = "⏰" dateIcon = "➕" /"⏳" /"🛫" /"📅" /"✅" /"❌" priorityIcon = "⏬" /"🔽" /"🔼" /"⏫" /"🔺" _ "whitespace" = [ \t\r]*