gotextlog

gotextlog
git clone https://git.ryansepassi.com/git/gotextlog.git
Log | Files | Refs | README

main.go (3232B)


      1 package main
      2 
      3 import (
      4 	"errors"
      5 	"fmt"
      6 	"io"
      7 	"net/http"
      8 	"os"
      9 	"os/exec"
     10 	"runtime"
     11 
     12 	"git.ryansepassi.com/git/gotextlog.git/internal/config"
     13 	"git.ryansepassi.com/git/gotextlog.git/internal/textlog"
     14 	"git.ryansepassi.com/git/gotextlog.git/internal/tui"
     15 	tea "github.com/charmbracelet/bubbletea"
     16 	"github.com/charmbracelet/x/term"
     17 )
     18 
     19 const version = "1.0.0"
     20 const help = `textlog 1.0.0
     21 
     22 Usage: textlog [options]
     23 
     24   --url <origin>              Textlog-compatible instance
     25   --theme <auto|light|dark>   Color theme
     26   --help                      Show help
     27   --version                   Show version
     28 
     29 Environment: TEXTLOG_URL, TEXTLOG_TOKEN, TEXTLOG_THEME, NO_COLOR`
     30 
     31 type arguments struct {
     32 	url           string
     33 	theme         config.Theme
     34 	help, version bool
     35 }
     36 
     37 func parseArgs(values []string) (arguments, error) {
     38 	var result arguments
     39 	for index := 0; index < len(values); index++ {
     40 		switch values[index] {
     41 		case "--help", "-h":
     42 			result.help = true
     43 		case "--version", "-v":
     44 			result.version = true
     45 		case "--url":
     46 			index++
     47 			if index >= len(values) {
     48 				return result, errors.New("--url requires a value")
     49 			}
     50 			normalized, err := config.NormalizeBaseURL(values[index])
     51 			if err != nil {
     52 				return result, err
     53 			}
     54 			result.url = normalized
     55 		case "--theme":
     56 			index++
     57 			if index >= len(values) {
     58 				return result, errors.New("--theme requires a value")
     59 			}
     60 			result.theme = config.Theme(values[index])
     61 			if result.theme != config.ThemeAuto && result.theme != config.ThemeLight && result.theme != config.ThemeDark {
     62 				return result, errors.New("--theme must be auto, light, or dark")
     63 			}
     64 		default:
     65 			return result, fmt.Errorf("Unknown option: %s", values[index])
     66 		}
     67 	}
     68 	return result, nil
     69 }
     70 func main() { os.Exit(run(os.Args[1:], os.Stdin, os.Stdout, os.Stderr)) }
     71 func run(values []string, stdin *os.File, stdout, stderr io.Writer) int {
     72 	args, err := parseArgs(values)
     73 	if err != nil {
     74 		fmt.Fprintln(stderr, err)
     75 		return 2
     76 	}
     77 	if args.help {
     78 		fmt.Fprintln(stdout, help)
     79 		return 0
     80 	}
     81 	if args.version {
     82 		fmt.Fprintln(stdout, version)
     83 		return 0
     84 	}
     85 	outFile, ok := stdout.(*os.File)
     86 	if !ok || !term.IsTerminal(stdin.Fd()) || !term.IsTerminal(outFile.Fd()) {
     87 		fmt.Fprintln(stderr, "textlog requires an interactive terminal")
     88 		return 1
     89 	}
     90 	env := config.Environment()
     91 	cfg, err := config.Load(env)
     92 	if err != nil {
     93 		fmt.Fprintln(stderr, err)
     94 		return 1
     95 	}
     96 	if args.url != "" {
     97 		cfg.BaseURL = args.url
     98 	}
     99 	if args.theme != "" {
    100 		cfg.Theme = args.theme
    101 	}
    102 	client := textlog.NewClient(cfg.BaseURL, cfg.Token, http.DefaultClient)
    103 	model := tui.New(tui.NewClientBackend(client), cfg, tui.Options{
    104 		SaveConfig: func(next config.Config) error { return config.Save(next, env) },
    105 		OpenURL:    openBrowser,
    106 	})
    107 	program := tea.NewProgram(model, tea.WithAltScreen(), tea.WithInput(stdin), tea.WithOutput(outFile))
    108 	if _, err := program.Run(); err != nil {
    109 		fmt.Fprintln(stderr, err)
    110 		return 1
    111 	}
    112 	return 0
    113 }
    114 func openBrowser(url string) error {
    115 	var command *exec.Cmd
    116 	switch runtime.GOOS {
    117 	case "darwin":
    118 		command = exec.Command("open", url)
    119 	case "windows":
    120 		command = exec.Command("cmd", "/c", "start", "", url)
    121 	default:
    122 		command = exec.Command("xdg-open", url)
    123 	}
    124 	return command.Start()
    125 }