//////////////////////////////////////////////////////////////////////////////// // Lexer::Type::duration // <ISO8106p> | <Duration> bool Lexer::isDuration (std::string& token, Lexer::Type& type) { std::size_t marker = _cursor; ISO8601p iso; std::string extractedToken; Lexer::Type extractedType; if (isOperator(extractedToken, extractedType)) { _cursor = marker; return false; } marker = 0; if (iso.parse (_text.substr (_cursor), marker)) { type = Lexer::Type::duration; token = _text.substr (_cursor, marker); _cursor += marker; return true; } Duration dur; if (dur.parse (_text.substr (_cursor), marker)) { type = Lexer::Type::duration; token = _text.substr (_cursor, marker); _cursor += marker; return true; } return false; }
void CmdEdit::parseTask (Task& task, const std::string& after, const std::string& dateformat) { // project std::string value = findValue (after, "\n Project:"); if (task.get ("project") != value) { if (value != "") { context.footnote (STRING_EDIT_PROJECT_MOD); task.set ("project", value); } else { context.footnote (STRING_EDIT_PROJECT_DEL); task.remove ("project"); } } // tags value = findValue (after, "\n Tags:"); std::vector <std::string> tags; split (tags, value, ' '); task.remove ("tags"); task.addTags (tags); // description. value = findMultilineValue (after, "\n Description:", "\n Created:"); if (task.get ("description") != value) { if (value != "") { context.footnote (STRING_EDIT_DESC_MOD); task.set ("description", value); } else throw std::string (STRING_EDIT_DESC_REMOVE_ERR); } // entry value = findValue (after, "\n Created:"); if (value != "") { std::string formatted = formatDate (task, "entry", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_ENTRY_MOD); task.set ("entry", Date(value, dateformat).toEpochString ()); } } else throw std::string (STRING_EDIT_ENTRY_REMOVE_ERR); // start value = findValue (after, "\n Started:"); if (value != "") { if (task.get ("start") != "") { std::string formatted = formatDate (task, "start", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_START_MOD); task.set ("start", Date(value, dateformat).toEpochString ()); } } else { context.footnote (STRING_EDIT_START_MOD); task.set ("start", Date(value, dateformat).toEpochString ()); } } else { if (task.get ("start") != "") { context.footnote (STRING_EDIT_START_DEL); task.remove ("start"); } } // end value = findValue (after, "\n Ended:"); if (value != "") { if (task.get ("end") != "") { std::string formatted = formatDate (task, "end", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_END_MOD); task.set ("end", Date(value, dateformat).toEpochString ()); } } else if (task.getStatus () != Task::deleted) throw std::string (STRING_EDIT_END_SET_ERR); } else { if (task.get ("end") != "") { context.footnote (STRING_EDIT_END_DEL); task.setStatus (Task::pending); task.remove ("end"); } } // scheduled value = findValue (after, "\n Scheduled:"); if (value != "") { if (task.get ("scheduled") != "") { std::string formatted = formatDate (task, "scheduled", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_SCHED_MOD); task.set ("scheduled", Date(value, dateformat).toEpochString ()); } } else { context.footnote (STRING_EDIT_SCHED_MOD); task.set ("scheduled", Date(value, dateformat).toEpochString ()); } } else { if (task.get ("scheduled") != "") { context.footnote (STRING_EDIT_SCHED_DEL); task.setStatus (Task::pending); task.remove ("scheduled"); } } // due value = findValue (after, "\n Due:"); if (value != "") { if (task.get ("due") != "") { std::string formatted = formatDate (task, "due", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_DUE_MOD); task.set ("due", Date(value, dateformat).toEpochString ()); } } else { context.footnote (STRING_EDIT_DUE_MOD); task.set ("due", Date(value, dateformat).toEpochString ()); } } else { if (task.get ("due") != "") { if (task.getStatus () == Task::recurring || task.get ("parent") != "") { context.footnote (STRING_EDIT_DUE_DEL_ERR); } else { context.footnote (STRING_EDIT_DUE_DEL); task.remove ("due"); } } } // until value = findValue (after, "\n Until:"); if (value != "") { if (task.get ("until") != "") { std::string formatted = formatDate (task, "until", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_UNTIL_MOD); task.set ("until", Date(value, dateformat).toEpochString ()); } } else { context.footnote (STRING_EDIT_UNTIL_MOD); task.set ("until", Date(value, dateformat).toEpochString ()); } } else { if (task.get ("until") != "") { context.footnote (STRING_EDIT_UNTIL_DEL); task.remove ("until"); } } // recur value = findValue (after, "\n Recur:"); if (value != task.get ("recur")) { if (value != "") { Duration d; std::string::size_type idx = 0; if (d.parse (value, idx)) { context.footnote (STRING_EDIT_RECUR_MOD); if (task.get ("due") != "") { task.set ("recur", value); task.setStatus (Task::recurring); } else throw std::string (STRING_EDIT_RECUR_DUE_ERR); } else throw std::string (STRING_EDIT_RECUR_ERR); } else { context.footnote (STRING_EDIT_RECUR_DEL); task.setStatus (Task::pending); task.remove ("recur"); task.remove ("until"); task.remove ("mask"); task.remove ("imask"); } } // wait value = findValue (after, "\n Wait until:"); if (value != "") { if (task.get ("wait") != "") { std::string formatted = formatDate (task, "wait", dateformat); if (formatted != value) { context.footnote (STRING_EDIT_WAIT_MOD); task.set ("wait", Date(value, dateformat).toEpochString ()); task.setStatus (Task::waiting); } } else { context.footnote (STRING_EDIT_WAIT_MOD); task.set ("wait", Date(value, dateformat).toEpochString ()); task.setStatus (Task::waiting); } } else { if (task.get ("wait") != "") { context.footnote (STRING_EDIT_WAIT_DEL); task.remove ("wait"); task.setStatus (Task::pending); } } // parent value = findValue (after, "\n Parent:"); if (value != task.get ("parent")) { if (value != "") { context.footnote (STRING_EDIT_PARENT_MOD); task.set ("parent", value); } else { context.footnote (STRING_EDIT_PARENT_DEL); task.remove ("parent"); } } // Annotations std::map <std::string, std::string> annotations; std::string::size_type found = 0; while ((found = after.find ("\n Annotation:", found)) != std::string::npos) { found += 14; // Length of "\n Annotation:". std::string::size_type eol = after.find ("\n", found + 1); if (eol != std::string::npos) { std::string value = trim (after.substr ( found, eol - found), "\t "); std::string::size_type gap = value.find (" -- "); if (gap != std::string::npos) { // TODO keeping the initial dates even if dateformat approximates them // is complex as finding the correspondence between each original line // and edited line may be impossible (bug #705). It would be simpler if // each annotation was put on a line with a distinguishable id (then // for each line: if the annotation is the same, then it is copied; if // the annotation is modified, then its original date may be kept; and // if there is no corresponding id, then a new unique date is created). Date when (value.substr (0, gap), dateformat); // This guarantees that if more than one annotation has the same date, // that the seconds will be different, thus unique, thus not squashed. // Bug #249 when += (const int) annotations.size (); std::stringstream name; name << "annotation_" << when.toEpoch (); std::string text = trim (value.substr (gap + 4), "\t "); annotations.insert (std::make_pair (name.str (), text)); } } } task.setAnnotations (annotations); // Dependencies value = findValue (after, "\n Dependencies:"); std::vector <std::string> dependencies; split (dependencies, value, ","); task.remove ("depends"); std::vector <std::string>::iterator dep; for (dep = dependencies.begin (); dep != dependencies.end (); ++dep) { if (dep->length () >= 7) task.addDependency (*dep); else task.addDependency ((int) strtol (dep->c_str (), NULL, 10)); } // UDAs std::map <std::string, Column*>::iterator col; for (col = context.columns.begin (); col != context.columns.end (); ++col) { std::string type = context.config.get ("uda." + col->first + ".type"); if (type != "") { std::string value = findValue (after, "\n UDA " + col->first + ":"); if ((task.get (col->first) != value) && (type != "date" || (task.get (col->first) != Date (value, dateformat).toEpochString ())) && (type != "duration" || (task.get (col->first) != (std::string) Duration (value) ))) { if (value != "") { context.footnote (format (STRING_EDIT_UDA_MOD, col->first)); if (type == "string") { task.set (col->first, value); } else if (type == "numeric") { Nibbler n (value); double d; if (n.getNumber (d) && n.depleted ()) task.set (col->first, value); else throw format (STRING_UDA_NUMERIC, value); } else if (type == "date") { Date d (value, dateformat); task.set (col->first, d.toEpochString ()); } else if (type == "duration") { Duration d (value); task.set (col->first, (time_t) d); } } else { context.footnote (format (STRING_EDIT_UDA_DEL, col->first)); task.remove (col->first); } } } } // UDA orphans std::vector <std::string> orphanValues = findValues (after, "\n UDA Orphan "); std::vector <std::string>::iterator orphan; for (orphan = orphanValues.begin (); orphan != orphanValues.end (); ++orphan) { std::string::size_type colon = orphan->find (':'); if (colon != std::string::npos) { std::string name = trim (orphan->substr (0, colon), "\t "); std::string value = trim (orphan->substr (colon + 1), "\t "); if (value != "") task.set (name, value); else task.remove (name); } } }