From 8a27ed168f8ef74548f0da328d5bbcb6ddaa9db7 Mon Sep 17 00:00:00 2001 From: Johan Walles Date: Sun, 27 Oct 2024 09:28:48 +0100 Subject: [PATCH] Move help printing into a file of its own --- moar.go | 236 ---------------------------------------------------- usage.go | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 236 deletions(-) create mode 100644 usage.go diff --git a/moar.go b/moar.go index 23ed7e4..4719ecf 100644 --- a/moar.go +++ b/moar.go @@ -5,11 +5,8 @@ import ( "fmt" "io" "os" - "os/exec" - "path/filepath" "runtime" "runtime/debug" - "sort" "strconv" "strings" "time" @@ -39,239 +36,6 @@ const defaultLightTheme = "tango" var versionString = "" -func renderLessTermcapEnvVar(envVarName string, description string, colors twin.ColorCount) string { - value := os.Getenv(envVarName) - if len(value) == 0 { - return "" - } - - style, err := m.TermcapToStyle(value) - if err != nil { - bold := twin.StyleDefault.WithAttr(twin.AttrBold).RenderUpdateFrom(twin.StyleDefault, colors) - notBold := twin.StyleDefault.RenderUpdateFrom(twin.StyleDefault.WithAttr(twin.AttrBold), colors) - return fmt.Sprintf(" %s (%s): %s %s<- Error: %v%s\n", - envVarName, - description, - strings.ReplaceAll(value, "\x1b", "ESC"), - bold, - err, - notBold, - ) - } - - prefix := style.RenderUpdateFrom(twin.StyleDefault, colors) - suffix := twin.StyleDefault.RenderUpdateFrom(style, colors) - return fmt.Sprintf(" %s (%s): %s\n", - envVarName, - description, - prefix+strings.ReplaceAll(value, "\x1b", "ESC")+suffix, - ) -} - -func renderPagerEnvVar(name string, colors twin.ColorCount) string { - bold := twin.StyleDefault.WithAttr(twin.AttrBold).RenderUpdateFrom(twin.StyleDefault, colors) - notBold := twin.StyleDefault.RenderUpdateFrom(twin.StyleDefault.WithAttr(twin.AttrBold), colors) - - value, isSet := os.LookupEnv(name) - if value == "" { - what := "unset" - if isSet { - what = "empty" - } - - return fmt.Sprintf(" %s is %s %s<- Should be %s%s\n", - name, - what, - bold, - getMoarPath(), - notBold, - ) - } - - absMoarPath, err := absLookPath(os.Args[0]) - if err != nil { - log.Warn("Unable to find absolute moar path: ", err) - return "" - } - - absEnvValue, err := absLookPath(value) - if err != nil { - // This can happen if this is set to some outdated value - absEnvValue = value - } - - if absEnvValue == absMoarPath { - return fmt.Sprintf(" %s=%s\n", name, value) - } - - return fmt.Sprintf(" %s=%s %s<- Should be %s%s\n", - name, - value, - bold, - getMoarPath(), - notBold, - ) -} - -// If the environment variable is set, render it as APA=bepa indented two -// spaces, plus a newline at the end. Otherwise, return an empty string. -func renderPlainEnvVar(envVarName string) string { - value := os.Getenv(envVarName) - if value == "" { - return "" - } - - return fmt.Sprintf(" %s=%s\n", envVarName, value) -} - -func printCommandline(output io.Writer) { - fmt.Fprintln(output, "Commandline: moar", strings.Join(os.Args[1:], " ")) - fmt.Fprintf(output, "Environment: MOAR=\"%v\"\n", os.Getenv("MOAR")) - fmt.Fprintln(output) -} - -func heading(text string, colors twin.ColorCount) string { - style := twin.StyleDefault.WithAttr(twin.AttrItalic) - prefix := style.RenderUpdateFrom(twin.StyleDefault, colors) - suffix := twin.StyleDefault.RenderUpdateFrom(style, colors) - return prefix + text + suffix -} - -func printUsage(flagSet *flag.FlagSet, colors twin.ColorCount) { - // This controls where PrintDefaults() prints, see below - flagSet.SetOutput(os.Stdout) - - // FIXME: Log if any printouts fail? - - fmt.Println(heading("Usage", colors)) - fmt.Println(" moar [options] ") - fmt.Println(" ... | moar") - fmt.Println(" moar < file") - fmt.Println() - fmt.Println("Shows file contents. Compressed files will be transparently decompressed.") - fmt.Println("Input is expected to be (possibly compressed) UTF-8 encoded text. Invalid /") - fmt.Println("non-printable characters are by default rendered as '?'.") - fmt.Println() - fmt.Println("More information + source code:") - fmt.Println(" ") - fmt.Println() - fmt.Println(heading("Environment", colors)) - - moarEnv := os.Getenv("MOAR") - if len(moarEnv) == 0 { - fmt.Println(" Additional options are read from the MOAR environment variable if set.") - fmt.Println(" But currently, the MOAR environment variable is not set.") - } else { - fmt.Println(" Additional options are read from the MOAR environment variable.") - fmt.Printf(" Current setting: MOAR=\"%s\"\n", moarEnv) - } - - envSection := "" - envSection += renderLessTermcapEnvVar("LESS_TERMCAP_md", "man page bold style", colors) - envSection += renderLessTermcapEnvVar("LESS_TERMCAP_us", "man page underline style", colors) - envSection += renderLessTermcapEnvVar("LESS_TERMCAP_so", "search hits and footer style", colors) - - envSection += renderPagerEnvVar("PAGER", colors) - envVars := os.Environ() - sort.Strings(envVars) - for _, env := range envVars { - split := strings.SplitN(env, "=", 2) - if len(split) != 2 { - continue - } - - name := split[0] - if name == "PAGER" { - // Already done above - continue - } - if !strings.HasSuffix(name, "PAGER") { - continue - } - - envSection += renderPagerEnvVar(name, colors) - } - - envSection += renderPlainEnvVar("TERM") - envSection += renderPlainEnvVar("TERM_PROGRAM") - envSection += renderPlainEnvVar("COLORTERM") - - // Requested here: https://github.com/walles/moar/issues/170#issuecomment-1891154661 - envSection += renderPlainEnvVar("MANROFFOPT") - - if envSection != "" { - fmt.Println() - - // Not Println since the section already ends with a newline - fmt.Print(envSection) - } - - absMoarPath, err := absLookPath(os.Args[0]) - if err == nil { - absPagerValue, err := absLookPath(os.Getenv("PAGER")) - if err != nil { - absPagerValue = "" - } - if absPagerValue != absMoarPath { - // We're not the default pager - fmt.Println() - fmt.Println(heading("Making moar Your Default Pager", colors)) - fmt.Println(" Put the following line in your ~/.bashrc, ~/.bash_profile or ~/.zshrc") - fmt.Println(" and moar will be used as the default pager in all new terminal windows:") - fmt.Println() - fmt.Printf(" export PAGER=%s\n", getMoarPath()) - } - } else { - log.Warn("Unable to find moar binary ", err) - } - - fmt.Println() - fmt.Println(heading("Options", colors)) - - flagSet.PrintDefaults() - - fmt.Println(" +1234") - fmt.Println(" \tImmediately scroll to line 1234") -} - -// "moar" if we're in the $PATH, otherwise an absolute path -func getMoarPath() string { - moarPath := os.Args[0] - if filepath.IsAbs(moarPath) { - return moarPath - } - - if strings.Contains(moarPath, string(os.PathSeparator)) { - // Relative path - moarPath, err := filepath.Abs(moarPath) - if err != nil { - panic(err) - } - return moarPath - } - - // Neither absolute nor relative, try PATH - _, err := exec.LookPath(moarPath) - if err != nil { - panic("Unable to find in $PATH: " + moarPath) - } - return moarPath -} - -func absLookPath(path string) (string, error) { - lookedPath, err := exec.LookPath(path) - if err != nil { - return "", err - } - - absLookedPath, err := filepath.Abs(lookedPath) - if err != nil { - return "", err - } - - return absLookedPath, err -} - // printProblemsHeader prints bug reporting information to stderr func printProblemsHeader() { fmt.Fprintln(os.Stderr, "Please post the following report at ,") diff --git a/usage.go b/usage.go new file mode 100644 index 0000000..750c428 --- /dev/null +++ b/usage.go @@ -0,0 +1,249 @@ +package main + +import ( + "flag" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + + log "github.com/sirupsen/logrus" + "github.com/walles/moar/m" + "github.com/walles/moar/twin" +) + +func renderLessTermcapEnvVar(envVarName string, description string, colors twin.ColorCount) string { + value := os.Getenv(envVarName) + if len(value) == 0 { + return "" + } + + style, err := m.TermcapToStyle(value) + if err != nil { + bold := twin.StyleDefault.WithAttr(twin.AttrBold).RenderUpdateFrom(twin.StyleDefault, colors) + notBold := twin.StyleDefault.RenderUpdateFrom(twin.StyleDefault.WithAttr(twin.AttrBold), colors) + return fmt.Sprintf(" %s (%s): %s %s<- Error: %v%s\n", + envVarName, + description, + strings.ReplaceAll(value, "\x1b", "ESC"), + bold, + err, + notBold, + ) + } + + prefix := style.RenderUpdateFrom(twin.StyleDefault, colors) + suffix := twin.StyleDefault.RenderUpdateFrom(style, colors) + return fmt.Sprintf(" %s (%s): %s\n", + envVarName, + description, + prefix+strings.ReplaceAll(value, "\x1b", "ESC")+suffix, + ) +} + +func renderPagerEnvVar(name string, colors twin.ColorCount) string { + bold := twin.StyleDefault.WithAttr(twin.AttrBold).RenderUpdateFrom(twin.StyleDefault, colors) + notBold := twin.StyleDefault.RenderUpdateFrom(twin.StyleDefault.WithAttr(twin.AttrBold), colors) + + value, isSet := os.LookupEnv(name) + if value == "" { + what := "unset" + if isSet { + what = "empty" + } + + return fmt.Sprintf(" %s is %s %s<- Should be %s%s\n", + name, + what, + bold, + getMoarPath(), + notBold, + ) + } + + absMoarPath, err := absLookPath(os.Args[0]) + if err != nil { + log.Warn("Unable to find absolute moar path: ", err) + return "" + } + + absEnvValue, err := absLookPath(value) + if err != nil { + // This can happen if this is set to some outdated value + absEnvValue = value + } + + if absEnvValue == absMoarPath { + return fmt.Sprintf(" %s=%s\n", name, value) + } + + return fmt.Sprintf(" %s=%s %s<- Should be %s%s\n", + name, + value, + bold, + getMoarPath(), + notBold, + ) +} + +// If the environment variable is set, render it as APA=bepa indented two +// spaces, plus a newline at the end. Otherwise, return an empty string. +func renderPlainEnvVar(envVarName string) string { + value := os.Getenv(envVarName) + if value == "" { + return "" + } + + return fmt.Sprintf(" %s=%s\n", envVarName, value) +} + +func printCommandline(output io.Writer) { + fmt.Fprintln(output, "Commandline: moar", strings.Join(os.Args[1:], " ")) + fmt.Fprintf(output, "Environment: MOAR=\"%v\"\n", os.Getenv("MOAR")) + fmt.Fprintln(output) +} + +func heading(text string, colors twin.ColorCount) string { + style := twin.StyleDefault.WithAttr(twin.AttrItalic) + prefix := style.RenderUpdateFrom(twin.StyleDefault, colors) + suffix := twin.StyleDefault.RenderUpdateFrom(style, colors) + return prefix + text + suffix +} + +func printUsage(flagSet *flag.FlagSet, colors twin.ColorCount) { + // This controls where PrintDefaults() prints, see below + flagSet.SetOutput(os.Stdout) + + // FIXME: Log if any printouts fail? + + fmt.Println(heading("Usage", colors)) + fmt.Println(" moar [options] ") + fmt.Println(" ... | moar") + fmt.Println(" moar < file") + fmt.Println() + fmt.Println("Shows file contents. Compressed files will be transparently decompressed.") + fmt.Println("Input is expected to be (possibly compressed) UTF-8 encoded text. Invalid /") + fmt.Println("non-printable characters are by default rendered as '?'.") + fmt.Println() + fmt.Println("More information + source code:") + fmt.Println(" ") + fmt.Println() + fmt.Println(heading("Environment", colors)) + + moarEnv := os.Getenv("MOAR") + if len(moarEnv) == 0 { + fmt.Println(" Additional options are read from the MOAR environment variable if set.") + fmt.Println(" But currently, the MOAR environment variable is not set.") + } else { + fmt.Println(" Additional options are read from the MOAR environment variable.") + fmt.Printf(" Current setting: MOAR=\"%s\"\n", moarEnv) + } + + envSection := "" + envSection += renderLessTermcapEnvVar("LESS_TERMCAP_md", "man page bold style", colors) + envSection += renderLessTermcapEnvVar("LESS_TERMCAP_us", "man page underline style", colors) + envSection += renderLessTermcapEnvVar("LESS_TERMCAP_so", "search hits and footer style", colors) + + envSection += renderPagerEnvVar("PAGER", colors) + envVars := os.Environ() + sort.Strings(envVars) + for _, env := range envVars { + split := strings.SplitN(env, "=", 2) + if len(split) != 2 { + continue + } + + name := split[0] + if name == "PAGER" { + // Already done above + continue + } + if !strings.HasSuffix(name, "PAGER") { + continue + } + + envSection += renderPagerEnvVar(name, colors) + } + + envSection += renderPlainEnvVar("TERM") + envSection += renderPlainEnvVar("TERM_PROGRAM") + envSection += renderPlainEnvVar("COLORTERM") + + // Requested here: https://github.com/walles/moar/issues/170#issuecomment-1891154661 + envSection += renderPlainEnvVar("MANROFFOPT") + + if envSection != "" { + fmt.Println() + + // Not Println since the section already ends with a newline + fmt.Print(envSection) + } + + absMoarPath, err := absLookPath(os.Args[0]) + if err == nil { + absPagerValue, err := absLookPath(os.Getenv("PAGER")) + if err != nil { + absPagerValue = "" + } + if absPagerValue != absMoarPath { + // We're not the default pager + fmt.Println() + fmt.Println(heading("Making moar Your Default Pager", colors)) + fmt.Println(" Put the following line in your ~/.bashrc, ~/.bash_profile or ~/.zshrc") + fmt.Println(" and moar will be used as the default pager in all new terminal windows:") + fmt.Println() + fmt.Printf(" export PAGER=%s\n", getMoarPath()) + } + } else { + log.Warn("Unable to find moar binary ", err) + } + + fmt.Println() + fmt.Println(heading("Options", colors)) + + flagSet.PrintDefaults() + + fmt.Println(" +1234") + fmt.Println(" \tImmediately scroll to line 1234") +} + +// "moar" if we're in the $PATH, otherwise an absolute path +func getMoarPath() string { + moarPath := os.Args[0] + if filepath.IsAbs(moarPath) { + return moarPath + } + + if strings.Contains(moarPath, string(os.PathSeparator)) { + // Relative path + moarPath, err := filepath.Abs(moarPath) + if err != nil { + panic(err) + } + return moarPath + } + + // Neither absolute nor relative, try PATH + _, err := exec.LookPath(moarPath) + if err != nil { + panic("Unable to find in $PATH: " + moarPath) + } + return moarPath +} + +func absLookPath(path string) (string, error) { + lookedPath, err := exec.LookPath(path) + if err != nil { + return "", err + } + + absLookedPath, err := filepath.Abs(lookedPath) + if err != nil { + return "", err + } + + return absLookedPath, err +}