package main import ( "bufio" "fmt" "os" "strconv" "strings" ) // ─── ANSI цвета ─────────────────────────────────────────────────────────────── const ( reset = "\033[0m" bold = "\033[1m" dim = "\033[2m" red = "\033[31m" green = "\033[32m" yellow = "\033[33m" blue = "\033[34m" magenta = "\033[35m" cyan = "\033[36m" white = "\033[37m" ) func clr(color, text string) string { return color + text + reset } func bld(text string) string { return bold + text + reset } // ─── Ввод ───────────────────────────────────────────────────────────────────── var reader = bufio.NewReader(os.Stdin) func readLine() string { line, _ := reader.ReadString('\n') return strings.TrimSpace(line) } // ask выводит подсказку и читает строку. Пустая строка → "_не указано_" func ask(prompt string) string { fmt.Printf(" %s %s ", clr(cyan, "→"), prompt) val := readLine() if val == "" { return "_не указано_" } return val } // askDefault выводит подсказку с дефолтным значением. func askDefault(prompt, defaultVal string) string { fmt.Printf(" %s %s %s ", clr(cyan, "→"), prompt, clr(dim, "(Enter = "+defaultVal+")")) val := readLine() if val == "" { return defaultVal } return val } // choose выводит нумерованное меню и возвращает выбранный вариант. func choose(prompt string, options []string) string { fmt.Printf("\n %s %s\n", clr(magenta, "▸"), bld(prompt)) for i, opt := range options { fmt.Printf(" %s %s\n", clr(yellow, fmt.Sprintf("[%d]", i+1)), opt) } for { fmt.Printf(" %s Выберите (1-%d): ", clr(cyan, "→"), len(options)) input := readLine() n, err := strconv.Atoi(input) if err == nil && n >= 1 && n <= len(options) { fmt.Printf(" %s %s\n", clr(green, "✔"), options[n-1]) return options[n-1] } fmt.Printf(" %s Введите число от 1 до %d\n", clr(red, "✘"), len(options)) } } // section печатает визуальный разделитель с заголовком. func section(title string) { fmt.Printf("\n%s\n%s\n%s\n", clr(blue, strings.Repeat("─", 60)), clr(bold+blue, " "+title), clr(blue, strings.Repeat("─", 60)), ) } // ─── Коллекторы списков ─────────────────────────────────────────────────────── func collectList(prompt, itemLabel string) []string { fmt.Printf("\n %s %s %s\n", clr(magenta, "▸"), bld(prompt), clr(dim, "(пустая строка = завершить)")) var items []string for i := 1; ; i++ { fmt.Printf(" %s %s %d: ", clr(cyan, "→"), itemLabel, i) val := readLine() if val == "" { break } items = append(items, val) } if len(items) == 0 { return []string{"_не указано_"} } return items } func collectTimeline() []TimelineEvent { fmt.Printf("\n %s %s %s\n", clr(magenta, "▸"), bld("Хронология событий"), clr(dim, "(пустое время = завершить)")) var events []TimelineEvent for i := 1; ; i++ { fmt.Printf(" %s Событие %d — время (напр. 14:32): ", clr(cyan, "→"), i) t := readLine() if t == "" { break } fmt.Printf(" %s Событие %d — описание: ", clr(cyan, "→"), i) desc := readLine() if desc == "" { desc = "—" } events = append(events, TimelineEvent{Time: t, Event: desc}) } if len(events) == 0 { events = append(events, TimelineEvent{Time: "—", Event: "_не указано_"}) } return events } func collectWhyAnalysis() []WhyItem { fmt.Printf("\n %s %s %s\n", clr(magenta, "▸"), bld("Анализ «5 Почему»"), clr(dim, "(пустой ввод = завершить, макс. 5)")) var items []WhyItem for i := 1; i <= 5; i++ { fmt.Printf(" %s Почему #%d: ", clr(cyan, "→"), i) why := readLine() if why == "" { break } fmt.Printf(" %s Ответ #%d: ", clr(cyan, "→"), i) answer := readLine() items = append(items, WhyItem{Why: why, Answer: answer}) } if len(items) == 0 { items = append(items, WhyItem{Why: "_не указано_", Answer: "—"}) } return items } func collectActionItems() []ActionItem { fmt.Printf("\n %s %s %s\n", clr(magenta, "▸"), bld("Action Items"), clr(dim, "(пустая задача = завершить)")) var items []ActionItem for i := 1; ; i++ { fmt.Printf("\n %s Задача %d (Enter = завершить): ", clr(cyan, "→"), i) task := readLine() if task == "" { break } fmt.Printf(" %s Ответственный (@имя): ", clr(cyan, "→")) assignee := readLine() if assignee == "" { assignee = "@tbd" } fmt.Printf(" %s Дедлайн (ДД.ММ): ", clr(cyan, "→")) deadline := readLine() if deadline == "" { deadline = "—" } items = append(items, ActionItem{Task: task, Assignee: assignee, Deadline: deadline}) } if len(items) == 0 { items = append(items, ActionItem{Task: "_не указано_", Assignee: "@tbd", Deadline: "—"}) } return items }