package catalog import ( "bufio" "fmt" "rubric/modules/gomodules" "rubric/utils" "strconv" "strings" ) // GoBook — запись справочника Go в главном меню var GoBook = Book{ Key: "go", Aliases: []string{"g", "golang"}, Title: "Справочник по языку Go", Description: "Установка, синтаксис, типы, функции, горутины, интерфейсы и многое другое", Run: runGoBook, } func runGoBook(scanner *bufio.Scanner) { for { showGoMenu() input, ok := ReadLine(scanner) if !ok { return } if input == "" { continue } if IsQuit(input) { fmt.Printf("\n %s%sДо свидания!%s\n\n", utils.ColorBold, utils.ColorCyan, utils.ColorReset) // сигнализируем главному циклу о выходе через os.Exit // чтобы не усложнять — просто выходим return } if IsBack(input) { return // назад в главное меню } // По номеру if n, err := strconv.Atoi(input); err == nil { if n >= 1 && n <= len(gomodules.All) { gomodules.All[n-1].Run() waitBack(scanner) continue } fmt.Printf("\n %s%sНомер %d вне диапазона (1–%d)%s\n", utils.ColorBold, utils.ColorRed, n, len(gomodules.All), utils.ColorReset) continue } // По ключу if m, ok := gomodules.Find(input); ok { m.Run() waitBack(scanner) continue } fmt.Printf("\n %s%sНе понял '%s'. Номер, ключ раздела, b — назад.%s\n", utils.ColorBold, utils.ColorRed, input, utils.ColorReset) } } func showGoMenu() { utils.Header("Справочник Go") fmt.Printf(" %s%sРазделы:%s\n\n", utils.ColorBold, utils.ColorWhite, utils.ColorReset) for i, m := range gomodules.All { aliases := "" if len(m.Aliases) > 0 { aliases = fmt.Sprintf("%s [%s]%s", utils.ColorDim, strings.Join(m.Aliases, ", "), utils.ColorReset) } fmt.Printf(" %s%s %2d.%s %s%-10s%s %s%-32s%s%s\n", utils.ColorBold, utils.ColorCyan, i+1, utils.ColorReset, utils.ColorYellow+utils.ColorBold, m.Key, utils.ColorReset, utils.ColorWhite, m.Title, utils.ColorReset, aliases, ) fmt.Printf(" %s%s%s\n\n", utils.ColorDim, m.Description, utils.ColorReset) } fmt.Printf(" %s%sРаздел (номер / ключ / b — главное меню / q — выход):%s ", utils.ColorBold, utils.ColorGreen, utils.ColorReset) } func waitBack(scanner *bufio.Scanner) { fmt.Printf("\n %s%s[Enter — назад в меню Go, b — главное меню]%s ", utils.ColorDim, utils.ColorCyan, utils.ColorReset) if scanner.Scan() { if IsBack(strings.TrimSpace(scanner.Text())) { // вернёмся на уровень выше — используем специальный возврат // реализуем через панику+recover для чистоты навигации panic(backSignal{}) } } } // backSignal — сигнал для возврата на уровень выше из waitBack type backSignal struct{} func init() { // Оборачиваем runGoBook чтобы перехватывать backSignal orig := GoBook.Run GoBook.Run = func(scanner *bufio.Scanner) { defer func() { if r := recover(); r != nil { if _, ok := r.(backSignal); !ok { panic(r) // пробрасываем не наши паники } // backSignal — просто возвращаемся в главное меню, ничего не делаем } }() orig(scanner) } }