summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorBenjamin Chausse <benjamin@chausse.xyz>2025-03-26 17:28:58 -0400
committerGitHub <noreply@github.com>2025-03-26 17:28:58 -0400
commitd2fdcbc0d4f8b4c184ba2b1c3c4b00da3918521f (patch)
tree6f4ba628fffb5e6d84f2eaa756345d3307abab77 /internal
parentcd9338e0d6cf582f9ea8028661ac3729e408f3bf (diff)
Stylish `--help` + generate manpages (#27)v1.3.7
* man page generation * generate VHS Gifs manually * goreleaser packages manpage
Diffstat (limited to 'internal')
-rw-r--r--internal/app/app.go50
-rw-r--r--internal/app/description.txt23
-rw-r--r--internal/app/flags.go25
-rw-r--r--internal/documentation/documentation.go38
-rw-r--r--internal/logging/discard.go25
-rw-r--r--internal/logging/logging.go8
6 files changed, 162 insertions, 7 deletions
diff --git a/internal/app/app.go b/internal/app/app.go
new file mode 100644
index 0000000..d0b168d
--- /dev/null
+++ b/internal/app/app.go
@@ -0,0 +1,50 @@
+package app
+
+import (
+ "context"
+ _ "embed"
+ "log/slog"
+
+ "github.com/ChausseBenjamin/termpicker/internal/logging"
+ "github.com/ChausseBenjamin/termpicker/internal/switcher"
+ tea "github.com/charmbracelet/bubbletea"
+ "github.com/urfave/cli/v3"
+)
+
+//go:embed description.txt
+var Desc string
+
+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(version string) *cli.Command {
+ cmd := &cli.Command{
+ Name: "termpicker",
+ Usage: "A terminal-based color picker",
+ Action: AppAction,
+ ArgsUsage: "",
+ Description: Desc,
+ Authors: []any{"Benjamin Chausse <benjamin@chausse.xyz>"},
+ Version: version,
+ Flags: AppFlags,
+ EnableShellCompletion: true,
+ }
+
+ return cmd
+}
diff --git a/internal/app/description.txt b/internal/app/description.txt
new file mode 100644
index 0000000..cf58bd6
--- /dev/null
+++ b/internal/app/description.txt
@@ -0,0 +1,23 @@
+Termpicker is a terminal-based application designed to help users select and manipulate colors efficiently. Its keybindings are meant to be intuitive to vim users as it behaves in a modal way:
+
+Normal mode:
+
+ - h,l: decrease/increase the current slider coarsely by 5%
+ - H,L: decrease/increase the current slider finely 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 foreground/background escape code
+ - x,r,s,c: copy the color as a hex, rgb, hsl, or cmyk value
+ - ?: expand/shrink the help menu
+ - i,<cmd>: enter Insert mode
+ - q,<C-c>: quit the application
+
+Insert mode:
+
+ Manually type a color. Pressing will cancel/leave insert mode. Anything in
+ the following formats will be used as a color input when pressing enter:
+
+ - Hex: #rrggbb
+ - RGB: rgb( r, g, b)
+ - CMYK: cmyk(c, m, y, k)
+ - HSL: hsl(h, s, l)
diff --git a/internal/app/flags.go b/internal/app/flags.go
new file mode 100644
index 0000000..7b3ab5a
--- /dev/null
+++ b/internal/app/flags.go
@@ -0,0 +1,25 @@
+package app
+
+import "github.com/urfave/cli/v3"
+
+const (
+ flagLogfile = "log-file"
+)
+
+var AppFlags []cli.Flag = []cli.Flag{
+ &cli.StringFlag{
+ Name: "color",
+ Aliases: []string{"c"},
+ Usage: "Initial color",
+ Value: "",
+ DefaultText: "#b7416e",
+ },
+ &cli.StringFlag{
+ Name: flagLogfile,
+ Aliases: []string{"l"},
+ Usage: "Log file",
+ Sources: cli.EnvVars("TERMPICKER_LOG_FILE"),
+ DefaultText: "/path/to/termpicker-logs.txt",
+ },
+ cli.VersionFlag,
+}
diff --git a/internal/documentation/documentation.go b/internal/documentation/documentation.go
new file mode 100644
index 0000000..3744eb0
--- /dev/null
+++ b/internal/documentation/documentation.go
@@ -0,0 +1,38 @@
+/*
+ * This package isn't the actual termpicker app.
+ * To avoid importing packages which aren't needed at runtime,
+ * some auto-generation functionalities 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 goes 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
+
+//go:generate go run . > termpicker.1
+
+import (
+ _ "embed"
+ "log/slog"
+ "os"
+
+ "github.com/ChausseBenjamin/termpicker/internal/app"
+ docs "github.com/urfave/cli-docs/v3"
+)
+
+func main() {
+ // version doesn't show up in the man page...
+ a := app.Command("")
+
+ 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.WriteFile("termpicker.1", []byte(man), 0644)
+}
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
}