// Command glint is a modeless terminal markdown editor with live styling. package main import ( "flag" "fmt" "os" "glint/internal/app" "glint/internal/config" "glint/internal/configui" "glint/internal/keyprobe" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/muesli/termenv" ) func init() { // Render glint's exact theme hexes regardless of the terminal's detected // profile or OS appearance — never downsample or adapt to the system. lipgloss.SetColorProfile(termenv.TrueColor) } // version is the build version, overridden at release time via // -ldflags "-X main.version=" (the Homebrew formula sets it). var version = "dev" const helpText = `glint — a modeless terminal markdown editor USAGE glint [file] open a file, or the fuzzy picker when no file is given glint COMMANDS (each takes a short letter or the full word, one or two dashes: -n / --n / -new / --new all work) -n, --new [name] new note in the current directory combine with -i or -v to target the inbox or vault -t, --today open today's daily note (in the vault) -d, --daily browse the daily-notes folder -v, --vault fuzzy picker over your vault, from anywhere -i, --inbox fuzzy picker over your inbox -c, --config interactive setup walkthrough (writes the config file) -h, --help show this help --version print the version EDITOR KEYS Ctrl+S save (an unnamed buffer prompts for a name) Ctrl+P toggle the read preview Ctrl+F fuzzy file picker Ctrl+D today's daily note Ctrl+N new note in the current directory Ctrl+B new note in the inbox Ctrl+T cycle theme (flexoki-light / flexoki-dark / charm) Ctrl+C / Ctrl+X / Ctrl+V copy / cut / paste (system clipboard) Shift+arrows select text (Ctrl+Shift+left/right by word) Alt+left / Alt+right move by word Ctrl+U / Ctrl+K delete to start / end of line Ctrl+W delete the word before the cursor Ctrl+Z / Ctrl+Y undo / redo Ctrl+Q quit (press twice if there are unsaved changes) Esc back to the editor CONFIG ~/.config/glint/config.toml (run 'glint -c' to set it up) ` func main() { // Help and version short-circuit before flag parsing (-v means --vault, so // version is long-only). if len(os.Args) > 1 { switch os.Args[1] { case "-h", "--h", "-help", "--help": fmt.Print(helpText) return case "--version", "-version": fmt.Println("glint", version) return } } cfg, err := config.Load() if err != nil { fmt.Fprintln(os.Stderr, "glint: config:", err) } // Every command is a flag; both -x and --x (letter or word) work. flagNew := boolFlag("n", "new") flagToday := boolFlag("t", "today") flagDaily := boolFlag("d", "daily") flagVault := boolFlag("v", "vault") flagConfig := boolFlag("c", "config") flagInbox := boolFlag("i", "inbox") flagKeys := flag.Bool("keys", false, "show what the terminal sends for each key") flag.Parse() isNew := *flagNew[0] || *flagNew[1] isToday := *flagToday[0] || *flagToday[1] isDaily := *flagDaily[0] || *flagDaily[1] isVault := *flagVault[0] || *flagVault[1] isConfig := *flagConfig[0] || *flagConfig[1] isInbox := *flagInbox[0] || *flagInbox[1] // Standalone commands (no editor TUI). if isConfig { runOrDie(configui.Run()) return } if *flagKeys { runOrDie(keyprobe.Run()) return } name := "" if args := flag.Args(); len(args) > 0 { name = args[0] } a := app.New(cfg) var startErr error switch { case isNew: // New note in the current dir, or the inbox/vault when combined. dir := cfg.WorkingDir() if isInbox { dir = cfg.InboxRoot() } if isVault { dir = cfg.Vault() } startErr = a.StartNewIn(dir, name) case isToday: startErr = a.Start("", true) // today's daily note case isVault: startErr = a.StartPickerIn(cfg.Vault()) case isInbox: startErr = a.StartPickerIn(cfg.InboxRoot()) case isDaily: startErr = a.StartPickerIn(cfg.DailyDir()) // browse the daily folder case name != "": startErr = a.Start(name, false) // open a file default: startErr = a.Start("", false) // bare → fuzzy picker over the current dir } if startErr != nil { fmt.Fprintln(os.Stderr, "glint:", startErr) os.Exit(1) } run(a) } // boolFlag registers a short and long name for the same command and returns both // pointers; either being set means the command was given (e.g. -n / --n / -new / // --new). Go's flag package accepts both single- and double-dash for each name. func boolFlag(short, long string) [2]*bool { return [2]*bool{ flag.Bool(short, false, "command: -"+short+" / --"+long), flag.Bool(long, false, ""), } } func runOrDie(err error) { if err != nil { fmt.Fprintln(os.Stderr, "glint:", err) os.Exit(1) } } // run drives the Bubbletea program in the alternate screen. func run(a *app.App) { if _, err := tea.NewProgram(a, tea.WithAltScreen(), tea.WithMouseCellMotion()).Run(); err != nil { fmt.Fprintln(os.Stderr, "glint:", err) os.Exit(1) } }