grimoir/main.go
2026-07-04 13:04:33 +03:00

150 lines
No EOL
4.3 KiB
Go
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"flag"
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
)
func main() {
var filePath string
var configPath string
var writeConfig bool
flag.StringVar(&filePath, "f", "", "File to edit")
flag.StringVar(&configPath, "config", "", "Path to config file (overrides auto-search)")
flag.BoolVar(&writeConfig, "write-config", false, "Write default config to standard location and exit")
flag.Parse()
// Позиционный аргумент: grimoir file.txt или grimoir https://...
if filePath == "" && flag.NArg() > 0 {
filePath = flag.Arg(0)
}
// Загружаем конфиг
var cfg Config
if configPath != "" {
data, err := os.ReadFile(configPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading config %s: %v\n", configPath, err)
os.Exit(1)
}
cfg = DefaultConfig()
if err := parseConfig(data, &cfg); err != nil {
fmt.Fprintf(os.Stderr, "Error parsing config %s: %v\n", configPath, err)
os.Exit(1)
}
cfg.LoadedFrom = configPath
} else {
cfg = LoadConfig()
}
// --write-config
if writeConfig {
paths := ConfigPaths()
target := ""
for _, p := range paths {
if p != paths[0] {
target = p
break
}
}
if target == "" {
target = "grimoir.conf"
}
if err := WriteDefaultConfig(target); err != nil {
fmt.Fprintf(os.Stderr, "Error writing config: %v\n", err)
os.Exit(1)
}
fmt.Printf("Default config written to: %s\n", target)
os.Exit(0)
}
// === Если файл не передан — показываем стартовое меню ===
if filePath == "" {
result := RunMenu()
if result == nil {
// Пользователь закрыл меню без выбора
os.Exit(0)
}
switch result.Action {
case menuQuit:
os.Exit(0)
case menuHelp:
// Открываем редактор с пустым файлом и сразу показываем help
runEditor("untitled.md", cfg, true)
return
case menuNewFile:
// Гарантированно пустой буфер — даже если untitled.md уже существует
// на диске от прошлой сессии, не подгружаем его содержимое.
runNewEditor(cfg)
return
case menuOpenFile:
filePath = result.FilePath
case menuFetchURL:
filePath = result.URL
}
}
// === URL — скачиваем и конвертируем ===
if IsURL(filePath) {
fmt.Fprintf(os.Stderr, "Fetching: %s\n", filePath)
result, err := FetchAndConvert(filePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error fetching URL: %v\n", err)
os.Exit(1)
}
savedPath, err := SaveFetchResult(result, "")
if err != nil {
fmt.Fprintf(os.Stderr, "Error saving file: %v\n", err)
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "Saved as: %s\n", savedPath)
filePath = savedPath
}
runEditor(filePath, cfg, false)
}
// runNewEditor запускает редактор с гарантированно пустым буфером,
// не читая существующий файл с диска (используется для "Новый файл" в меню).
// Имя файла остаётся "untitled.md" — пользователь сохранит его явным :w/:saveas,
// что не перезапишет существующий файл, так как save() запросит подтверждение
// только при явном указании того же имени.
func runNewEditor(cfg Config) {
model := NewEditor("untitled.md", "md", "", cfg)
p := tea.NewProgram(model, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
// runEditor загружает файл и запускает редактор.
// showHelp=true открывает справку сразу при старте.
func runEditor(filePath string, cfg Config, showHelp bool) {
content, err := LoadFile(filePath)
if err != nil && !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "Error loading file: %v\n", err)
os.Exit(1)
}
fileType := DetectFileType(filePath)
model := NewEditor(filePath, fileType, content, cfg)
if showHelp {
model.showHelp = true
}
p := tea.NewProgram(model, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}