package main import ( "regexp" "strings" ) // reminderMarker — the words that open a reminder. Stripped because they are // the instruction, not the thing to say at the hour. var reminderMarker = regexp.MustCompile(`(?i)^\s*(?:напомни(?:те)?|напомнить|remind)\s*(?:мне|me)?[\s,:—-]*`) // reminderTimeWords — the time expressions a reminder carries, removed from // the body because the fire time is already a column. Ordered longest-first // where two could match the same words, so "через полтора часа" does not leave // "полтора" behind. // // Go's \b is ASCII-only and never fires next to a Cyrillic letter, so the word // boundaries here are written out as whitespace or an end of string — the same // trap the agenda grammars hit. var reminderTimeWords = []*regexp.Regexp{ regexp.MustCompile(`(?i)(^|\s)через\s+\S+(\s+(часа?|часов|минут[уы]?|секунд[уы]?|дня|дней|недел[юи]))?(\s|$)`), regexp.MustCompile(`(?i)(^|\s)(в|во)\s+\d{1,2}(:\d{2})?(\s*(часа?|часов))?(\s*(утра|вечера|дня|ночи))?(\s|$)`), regexp.MustCompile(`(?i)(^|\s)(завтра|послезавтра|сегодня|вечером|утром|днём|днем|ночью)(\s|$)`), regexp.MustCompile(`(?i)(^|\s)(at|in)\s+\d{1,2}(:\d{2})?\s*(am|pm)?(\s|$)`), regexp.MustCompile(`(?i)(^|\s)(tomorrow|today|tonight)(\s|$)`), } // reminderBody is what she says at the hour. // // The whole utterance used to be stored, so /reminders read "напомни завтра в // 9 утра выпить таблетки" where it should read "выпить таблетки", and the // agenda recited the marker back at him (Vikunja #469). The fire time is // already a column, and the marker is an instruction that was carried out. // // Falls back to the fuller text whenever stripping would leave nothing: an // empty body is a reminder that fires and says nothing, which is worse than a // wordy one. func reminderBody(utterance, text string) string { body := strings.TrimSpace(text) if body == "" { body = strings.TrimSpace(utterance) } stripped := reminderMarker.ReplaceAllString(body, "") for _, re := range reminderTimeWords { stripped = re.ReplaceAllString(stripped, " ") } stripped = strings.TrimSpace(strings.Join(strings.Fields(stripped), " ")) stripped = strings.Trim(stripped, " ,;:—-") if stripped == "" { return body } return stripped }