diff options
author | Benjamin Chausse <benjamin.chausse@goto.com> | 2025-03-26 10:52:14 -0400 |
---|---|---|
committer | Benjamin Chausse <benjamin.chausse@goto.com> | 2025-03-26 10:52:14 -0400 |
commit | 04213e975c46b0d6bfecc8695801b85c3f3dd0ab (patch) | |
tree | 73d39c5f614c83baad5eb6ad8669a27750770e2a /internal | |
parent | cd9338e0d6cf582f9ea8028661ac3729e408f3bf (diff) |
charmbracelet/glamour for help + man page generate
Diffstat (limited to 'internal')
-rw-r--r-- | internal/app/app.go | 67 | ||||
-rw-r--r-- | internal/app/flags.go | 21 | ||||
-rw-r--r-- | internal/app/keybindings.md | 24 | ||||
-rw-r--r-- | internal/documentation/documentation.go | 44 | ||||
-rw-r--r-- | internal/logging/discard.go | 25 | ||||
-rw-r--r-- | internal/logging/logging.go | 8 |
6 files changed, 182 insertions, 7 deletions
diff --git a/internal/app/app.go b/internal/app/app.go new file mode 100644 index 0000000..b17f32a --- /dev/null +++ b/internal/app/app.go @@ -0,0 +1,67 @@ +package app + +import ( + "context" + _ "embed" + "fmt" + "io" + "log/slog" + + "github.com/ChausseBenjamin/termpicker/internal/logging" + "github.com/ChausseBenjamin/termpicker/internal/switcher" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/glamour" + docs "github.com/urfave/cli-docs/v3" + "github.com/urfave/cli/v3" +) + +//go:embed keybindings.md +var KeybindingDocs string + +// Set by the build system +var version = "compiled" + +func AppAction(ctx context.Context, cmd *cli.Command) error { + logfile := logging.Setup(cmd.String("logfile")) + defer logfile.Close() + + slog.Info("Starting Termpicker") + + sw := switcher.New() + + if colorStr := cmd.String("color"); colorStr != "" { + sw.NewNotice(sw.SetColorFromText(colorStr)) + } + + p := tea.NewProgram(sw) + if _, err := p.Run(); err != nil { + return err + } + return nil +} + +func Command() *cli.Command { + cmd := &cli.Command{ + Name: "termpicker", + Usage: "A terminal-based color picker", + Action: AppAction, + Authors: []any{"Benjamin Chausse <benjamin@chausse.xyz>"}, + Version: version, + Flags: AppFlags, + EnableShellCompletion: true, + } + + cli.HelpPrinter = func(w io.Writer, _ string, _ any) { + docs.MarkdownDocTemplate = fmt.Sprintf("%s\n\n\n%s", + docs.MarkdownDocTemplate, + KeybindingDocs, + ) + + helpRaw, _ := docs.ToMarkdown(cmd) + helpCute, _ := glamour.Render(helpRaw, "dark") + + w.Write([]byte(helpCute)) + } + + return cmd +} diff --git a/internal/app/flags.go b/internal/app/flags.go new file mode 100644 index 0000000..fae403b --- /dev/null +++ b/internal/app/flags.go @@ -0,0 +1,21 @@ +package app + +import "github.com/urfave/cli/v3" + +const ( + flagLogfile = "logfile" +) + +var AppFlags []cli.Flag = []cli.Flag{ + &cli.StringFlag{ + Name: flagLogfile, + Aliases: []string{"l"}, + Usage: "Log file", + }, + &cli.StringFlag{ + Name: "color", + Aliases: []string{"c"}, + Usage: "Initial color", + Value: "", + }, +} diff --git a/internal/app/keybindings.md b/internal/app/keybindings.md new file mode 100644 index 0000000..03f8201 --- /dev/null +++ b/internal/app/keybindings.md @@ -0,0 +1,24 @@ +# KEYBINDINGS + +**Normal mode**: + +- `h`,`l`: coarse decrease/increase the current slider by 5% +- `H`,`L`: fine decrease/increase the current slider by 1 +- `j`,`k`: select the slider below/above +- `<Tab>`,`<S-Tab>`: move to the next/previous tab +- `f`,`b`: copy the color as an ANSI escape code for the foreground/background +- `x`,`r`,`s`,`c`: copy the color as a hex/rgb/hsl/cmyk +- `?`: expand/shrink the help menu +- `i`,`<cmd>`: enter Insert mode +- `q`/`<C-c>`: quit the application + +**Insert mode**: + +Manually type a color. Pressing <Esc> will cancel/leave insert mode. +Anything in the following formats will be used as a color input when +pressing enter: + +- Hex values: `#rrggbb` +- RGB values: `rgb( r, g, b)` +- CMYK values: `cmyk(c, m, y, k)` +- HSL values: `hsl(h, s, l)` diff --git a/internal/documentation/documentation.go b/internal/documentation/documentation.go new file mode 100644 index 0000000..af4b302 --- /dev/null +++ b/internal/documentation/documentation.go @@ -0,0 +1,44 @@ +/* + * This package isn't the actual termpicker app. + * To avoid importing packages which aren't needed at runtime, + * some auto-generation functionnalities is offloaded to here so + * it can be done with access to the rest of the code-base but + * without bloating the final binary. For example, + * generating bash+zsh auto-completion scripts isn't needed in + * the final binary if those script are generated before hand. + * Same gose for manpages. This file is meant to be run automatically + * to easily package new releases. Same goes for manpages which is the + * only feature currently in here. + */ +package main + +import ( + _ "embed" + "log/slog" + "os" + "strings" + + "github.com/ChausseBenjamin/termpicker/internal/app" + docs "github.com/urfave/cli-docs/v3" +) + +func main() { + a := app.Command() + + docs.MarkdownDocTemplate = strings.Join( + []string{ + docs.MarkdownDocTemplate, + app.KeybindingDocs, + }, + "\n", + ) + + man, err := docs.ToManWithSection(a, 1) + if err != nil { + slog.Error("failed to generate man page", + slog.Any("error_message", err), + ) + os.Exit(1) + } + os.Stdout.Write([]byte(man)) +} diff --git a/internal/logging/discard.go b/internal/logging/discard.go new file mode 100644 index 0000000..e827287 --- /dev/null +++ b/internal/logging/discard.go @@ -0,0 +1,25 @@ +package logging + +import ( + "context" + "log/slog" +) + +// DiscardHandler discards all log output. DiscardHandler.Enabled returns false for all Levels. +type DiscardHandler struct{} + +func (d DiscardHandler) Enabled(ctx context.Context, level slog.Level) bool { + return false +} + +func (d DiscardHandler) Handle(ctx context.Context, record slog.Record) error { + return nil +} + +func (d DiscardHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return d +} + +func (d DiscardHandler) WithGroup(name string) slog.Handler { + return d +} diff --git a/internal/logging/logging.go b/internal/logging/logging.go index 71f0334..054b303 100644 --- a/internal/logging/logging.go +++ b/internal/logging/logging.go @@ -7,12 +7,6 @@ import ( "github.com/ChausseBenjamin/termpicker/internal/util" ) -type logSink struct{} - -func (l logSink) Write(p []byte) (n int, err error) { - return len(p), nil -} - func Setup(filepath string) *os.File { if filepath != "" { logFile, err := os.Create(filepath) @@ -28,7 +22,7 @@ func Setup(filepath string) *os.File { } else { // Since app is a TUI, logging to stdout/stderr would break the UI // So we disable it by default - handler := slog.NewJSONHandler(logSink{}, nil) + handler := DiscardHandler{} slog.SetDefault(slog.New(handler)) return nil } |