▍ humdrum codex / glint v1.0.2
license AGPL-3.0
3.3 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
123
124
125
126
127
128
129
130
// 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=<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)
	}
}