โ– humdrum codex / glint v1.0.2
license AGPL-3.0
3.1 KB raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// 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"
)

// version is the build version, overridden at release time via
// -ldflags "-X main.version=<v>" (the Homebrew formula sets it).
var version = "dev"

func main() {
	// Version is the one long-only flag (-v means --vault).
	if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "-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)
	}
}