2019-06-09 08:47:55 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2019-07-07 19:18:29 +03:00
|
|
|
"flag"
|
2019-06-09 20:40:35 +03:00
|
|
|
"fmt"
|
2019-06-09 20:34:52 +03:00
|
|
|
"io"
|
|
|
|
"os"
|
2022-04-18 19:41:48 +03:00
|
|
|
"os/exec"
|
2022-04-18 19:49:25 +03:00
|
|
|
"path/filepath"
|
2019-07-08 07:42:48 +03:00
|
|
|
"runtime"
|
2019-06-16 11:02:19 +03:00
|
|
|
"strings"
|
2021-04-06 17:22:40 +03:00
|
|
|
"time"
|
2019-06-09 20:34:52 +03:00
|
|
|
|
2022-12-29 10:28:27 +03:00
|
|
|
"github.com/alecthomas/chroma/v2"
|
|
|
|
"github.com/alecthomas/chroma/v2/formatters"
|
|
|
|
"github.com/alecthomas/chroma/v2/styles"
|
2020-10-30 10:19:13 +03:00
|
|
|
log "github.com/sirupsen/logrus"
|
2021-04-15 16:16:06 +03:00
|
|
|
"golang.org/x/term"
|
2020-10-30 10:19:13 +03:00
|
|
|
|
2019-06-10 22:50:31 +03:00
|
|
|
"github.com/walles/moar/m"
|
2021-04-15 16:16:06 +03:00
|
|
|
"github.com/walles/moar/twin"
|
2019-06-09 08:47:55 +03:00
|
|
|
)
|
|
|
|
|
2019-07-07 19:34:05 +03:00
|
|
|
var versionString = "Should be set when building, please use build.sh to build"
|
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
func printUsage(output io.Writer, flagSet *flag.FlagSet, printCommandline bool) {
|
2019-07-15 23:14:36 +03:00
|
|
|
// This controls where PrintDefaults() prints, see below
|
2021-05-13 20:00:53 +03:00
|
|
|
flagSet.SetOutput(output)
|
2019-07-15 23:14:36 +03:00
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
// FIXME: Log if any printouts fail?
|
2021-06-04 07:15:09 +03:00
|
|
|
moarEnv := os.Getenv("MOAR")
|
2021-05-13 20:00:53 +03:00
|
|
|
if printCommandline {
|
|
|
|
_, _ = fmt.Fprintln(output, "Commandline: moar", strings.Join(os.Args[1:], " "))
|
2021-06-04 07:15:09 +03:00
|
|
|
_, _ = fmt.Fprintf(output, "Environment: MOAR=\"%v\"\n", moarEnv)
|
2021-05-13 20:00:53 +03:00
|
|
|
_, _ = fmt.Fprintln(output)
|
|
|
|
}
|
2021-04-20 09:43:37 +03:00
|
|
|
|
|
|
|
_, _ = fmt.Fprintln(output, "Usage:")
|
|
|
|
_, _ = fmt.Fprintln(output, " moar [options] <file>")
|
|
|
|
_, _ = fmt.Fprintln(output, " ... | moar")
|
|
|
|
_, _ = fmt.Fprintln(output, " moar < file")
|
2022-07-19 18:07:11 +03:00
|
|
|
_, _ = fmt.Fprintln(output)
|
2021-07-01 20:21:42 +03:00
|
|
|
_, _ = fmt.Fprintln(output, "Shows file contents. Compressed files will be transparently decompressed.")
|
2022-08-07 20:26:51 +03:00
|
|
|
_, _ = fmt.Fprintln(output, "Input is expected to be (possibly compressed) UTF-8 encoded text. Invalid /")
|
|
|
|
_, _ = fmt.Fprintln(output, "non-printable characters are by default rendered as '?'.")
|
2021-04-20 09:43:37 +03:00
|
|
|
_, _ = fmt.Fprintln(output)
|
2022-07-19 18:07:11 +03:00
|
|
|
_, _ = fmt.Fprintln(output, "More information + source code:")
|
|
|
|
_, _ = fmt.Fprintln(output, " <https://github.com/walles/moar#readme>")
|
|
|
|
_, _ = fmt.Fprintln(output)
|
2021-05-13 20:00:53 +03:00
|
|
|
_, _ = fmt.Fprintln(output, "Environment:")
|
2021-06-04 07:15:09 +03:00
|
|
|
if len(moarEnv) == 0 {
|
|
|
|
_, _ = fmt.Fprintln(output, " Additional options are read from the MOAR environment variable if set.")
|
|
|
|
_, _ = fmt.Fprintln(output, " But currently, the MOAR environment variable is not set.")
|
|
|
|
} else {
|
|
|
|
_, _ = fmt.Fprintln(output, " Additional options are read from the MOAR environment variable.")
|
|
|
|
_, _ = fmt.Fprintf(output, " Current setting: MOAR=\"%s\"\n", moarEnv)
|
|
|
|
}
|
2019-07-15 23:14:36 +03:00
|
|
|
|
2022-04-18 19:49:25 +03:00
|
|
|
absMoarPath, err := absLookPath(os.Args[0])
|
2019-07-15 23:27:41 +03:00
|
|
|
if err == nil {
|
2022-04-18 19:49:25 +03:00
|
|
|
absPagerValue, err := absLookPath(os.Getenv("PAGER"))
|
2019-07-15 23:47:36 +03:00
|
|
|
if err != nil {
|
2022-04-18 19:41:48 +03:00
|
|
|
absPagerValue = ""
|
2019-07-15 23:47:36 +03:00
|
|
|
}
|
2022-04-18 19:41:48 +03:00
|
|
|
if absPagerValue != absMoarPath {
|
2019-07-15 23:43:27 +03:00
|
|
|
// We're not the default pager
|
2021-04-20 09:43:37 +03:00
|
|
|
_, _ = fmt.Fprintln(output)
|
2022-04-20 08:09:42 +03:00
|
|
|
_, _ = fmt.Fprintln(output, "Making moar your default pager:")
|
|
|
|
_, _ = fmt.Fprintln(output, " Put the following line in your ~/.bashrc, ~/.bash_profile or ~/.zshrc")
|
|
|
|
_, _ = fmt.Fprintln(output, " and moar will be used as the default pager in all new terminal windows:")
|
|
|
|
_, _ = fmt.Fprintln(output)
|
|
|
|
_, _ = fmt.Fprintf(output, " export PAGER=%s\n", getMoarPath())
|
2019-07-15 23:43:27 +03:00
|
|
|
}
|
2019-07-15 23:27:41 +03:00
|
|
|
} else {
|
2021-04-19 21:29:05 +03:00
|
|
|
log.Warn("Unable to find moar binary ", err)
|
2019-07-15 23:27:41 +03:00
|
|
|
}
|
2022-04-20 08:09:42 +03:00
|
|
|
|
|
|
|
_, _ = fmt.Fprintln(output)
|
|
|
|
_, _ = fmt.Fprintln(output, "Options:")
|
|
|
|
|
|
|
|
flagSet.PrintDefaults()
|
2019-07-15 23:14:36 +03:00
|
|
|
}
|
|
|
|
|
2022-04-18 20:05:49 +03:00
|
|
|
// "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
|
|
|
|
}
|
|
|
|
|
2022-04-18 19:49:25 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-12-30 00:57:44 +03:00
|
|
|
// printProblemsHeader prints bug reporting information to stderr
|
|
|
|
func printProblemsHeader() {
|
Print bug reporting info on log messages
diff --git moar.go moar.go
index 46b2898..906b310 100644
--- moar.go
+++ moar.go
@@ -58,6 +58,23 @@ func _PrintUsage(output io.Writer) {
}
}
+// PrintProblemsHeader prints bug reporting information to stderr
+func PrintProblemsHeader() {
+ fmt.Fprintln(os.Stderr, "Please post the following report at <https://github.com/walles/moar/issues>,")
+ fmt.Fprintln(os.Stderr, "or e-mail it to johan.walles@gmail.com.")
+ fmt.Fprintln(os.Stderr)
+ fmt.Fprintln(os.Stderr, "Version:", versionString)
+ fmt.Fprintln(os.Stderr, "LANG :", os.Getenv("LANG"))
+ fmt.Fprintln(os.Stderr, "TERM :", os.Getenv("TERM"))
+ fmt.Fprintln(os.Stderr)
+ fmt.Fprintln(os.Stderr, "GOOS :", runtime.GOOS)
+ fmt.Fprintln(os.Stderr, "GOARCH :", runtime.GOARCH)
+ fmt.Fprintln(os.Stderr, "Compiler:", runtime.Compiler)
+ fmt.Fprintln(os.Stderr, "NumCPU :", runtime.NumCPU())
+
+ fmt.Fprintln(os.Stderr)
+}
+
func main() {
// FIXME: If we get a CTRL-C, get terminal back into a useful state before terminating
@@ -67,21 +84,7 @@ func main() {
return
}
- // On any panic or warnings, also print system info and how to report bugs
- fmt.Fprintln(os.Stderr, "Please post the following crash report at <https://github.com/walles/moar/issues>,")
- fmt.Fprintln(os.Stderr, "or e-mail it to johan.walles@gmail.com.")
- fmt.Fprintln(os.Stderr)
- fmt.Fprintln(os.Stderr, "Version:", versionString)
- fmt.Fprintln(os.Stderr, "LANG :", os.Getenv("LANG"))
- fmt.Fprintln(os.Stderr, "TERM :", os.Getenv("TERM"))
- fmt.Fprintln(os.Stderr)
- fmt.Fprintln(os.Stderr, "GOOS :", runtime.GOOS)
- fmt.Fprintln(os.Stderr, "GOARCH :", runtime.GOARCH)
- fmt.Fprintln(os.Stderr, "Compiler:", runtime.Compiler)
- fmt.Fprintln(os.Stderr, "NumCPU :", runtime.NumCPU())
-
- fmt.Fprintln(os.Stderr)
-
+ PrintProblemsHeader()
panic(err)
}()
@@ -161,6 +164,8 @@ func _StartPaging(reader *m.Reader) {
}
if len(loglines.String()) > 0 {
+ PrintProblemsHeader()
+
// FIXME: Don't print duplicate log messages more than once,
// maybe invent our own logger for this?
fmt.Fprintf(os.Stderr, "%s", loglines.String())
Change-Id: If41c17e98daf9f05909ab7e3c31dc84e946cbbf5
2019-11-19 17:33:00 +03:00
|
|
|
fmt.Fprintln(os.Stderr, "Please post the following report at <https://github.com/walles/moar/issues>,")
|
|
|
|
fmt.Fprintln(os.Stderr, "or e-mail it to johan.walles@gmail.com.")
|
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
fmt.Fprintln(os.Stderr, "Version:", versionString)
|
|
|
|
fmt.Fprintln(os.Stderr, "LANG :", os.Getenv("LANG"))
|
|
|
|
fmt.Fprintln(os.Stderr, "TERM :", os.Getenv("TERM"))
|
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
fmt.Fprintln(os.Stderr, "GOOS :", runtime.GOOS)
|
|
|
|
fmt.Fprintln(os.Stderr, "GOARCH :", runtime.GOARCH)
|
|
|
|
fmt.Fprintln(os.Stderr, "Compiler:", runtime.Compiler)
|
|
|
|
fmt.Fprintln(os.Stderr, "NumCPU :", runtime.NumCPU())
|
|
|
|
|
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
}
|
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
func parseStyleOption(styleOption string, flagSet *flag.FlagSet) chroma.Style {
|
2021-05-13 08:37:34 +03:00
|
|
|
style, ok := styles.Registry[styleOption]
|
|
|
|
if !ok {
|
|
|
|
fmt.Fprintf(os.Stderr,
|
|
|
|
"ERROR: Unrecognized style \"%s\", pick a style from here: https://xyproto.github.io/splash/docs/longer/all.html\n",
|
|
|
|
styleOption)
|
|
|
|
fmt.Fprintln(os.Stderr)
|
2021-05-13 20:00:53 +03:00
|
|
|
printUsage(os.Stderr, flagSet, true)
|
2021-05-13 08:37:34 +03:00
|
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return *style
|
|
|
|
}
|
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
func parseColorsOption(colorsOption string, flagSet *flag.FlagSet) chroma.Formatter {
|
2022-04-01 21:24:00 +03:00
|
|
|
if strings.ToLower(colorsOption) == "auto" {
|
|
|
|
colorsOption = "16M"
|
|
|
|
if strings.Contains(os.Getenv("TERM"), "256") {
|
|
|
|
// Covers "xterm-256color" as used by the macOS Terminal
|
|
|
|
colorsOption = "256"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-13 08:37:34 +03:00
|
|
|
switch strings.ToUpper(colorsOption) {
|
|
|
|
case "8":
|
|
|
|
return formatters.TTY8
|
|
|
|
case "16":
|
|
|
|
return formatters.TTY16
|
|
|
|
case "256":
|
|
|
|
return formatters.TTY256
|
|
|
|
case "16M":
|
|
|
|
return formatters.TTY16m
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "ERROR: Invalid color count \"%s\", valid counts are 8, 16, 256 or 16M.\n", colorsOption)
|
|
|
|
fmt.Fprintln(os.Stderr)
|
2021-05-13 20:00:53 +03:00
|
|
|
printUsage(os.Stderr, flagSet, true)
|
2021-05-13 08:37:34 +03:00
|
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
panic("We just did os.Exit(), why are we still executing?")
|
|
|
|
}
|
|
|
|
|
2022-02-18 21:09:05 +03:00
|
|
|
func parseStatusBarStyle(styleOption string, flagSet *flag.FlagSet) m.StatusBarStyle {
|
|
|
|
if styleOption == "inverse" {
|
|
|
|
return m.STATUSBAR_STYLE_INVERSE
|
|
|
|
}
|
|
|
|
if styleOption == "plain" {
|
|
|
|
return m.STATUSBAR_STYLE_PLAIN
|
|
|
|
}
|
|
|
|
if styleOption == "bold" {
|
|
|
|
return m.STATUSBAR_STYLE_BOLD
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr,
|
|
|
|
"ERROR: Unrecognized status bar style \"%s\", good ones are inverse, plain and bold.\n",
|
|
|
|
styleOption)
|
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
printUsage(os.Stderr, flagSet, true)
|
|
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
panic("os.Exit(1) just failed")
|
|
|
|
}
|
|
|
|
|
2022-02-27 11:39:16 +03:00
|
|
|
func parseUnprintableStyle(styleOption string, flagSet *flag.FlagSet) m.UnprintableStyle {
|
|
|
|
if styleOption == "highlight" {
|
|
|
|
return m.UNPRINTABLE_STYLE_HIGHLIGHT
|
|
|
|
}
|
|
|
|
if styleOption == "whitespace" {
|
|
|
|
return m.UNPRINTABLE_STYLE_WHITESPACE
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr,
|
|
|
|
"ERROR: Unrecognized invalid UTF8 rendering style \"%s\", good ones are highlight or whitespace.\n",
|
|
|
|
styleOption)
|
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
printUsage(os.Stderr, flagSet, true)
|
|
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
panic("os.Exit(1) just failed")
|
|
|
|
}
|
|
|
|
|
2022-08-07 18:43:29 +03:00
|
|
|
func parseScrollHint(scrollHint string, flagSet *flag.FlagSet) twin.Cell {
|
|
|
|
scrollHint = strings.ReplaceAll(scrollHint, "ESC", "\x1b")
|
|
|
|
hintParser := m.NewLine(scrollHint)
|
2022-10-27 17:51:17 +03:00
|
|
|
parsedTokens := hintParser.HighlightedTokens(nil).Cells
|
2022-08-07 18:43:29 +03:00
|
|
|
if len(parsedTokens) == 1 {
|
|
|
|
return parsedTokens[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintln(os.Stderr,
|
2022-08-07 18:57:13 +03:00
|
|
|
"ERROR: Scroll hint must be exactly one (optionally highlighted) character. For example: 'ESC[2m…'")
|
2022-08-07 18:43:29 +03:00
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
printUsage(os.Stderr, flagSet, true)
|
|
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
panic("os.Exit(1) just failed")
|
|
|
|
}
|
|
|
|
|
2019-06-09 08:47:55 +03:00
|
|
|
func main() {
|
2019-07-11 19:52:20 +03:00
|
|
|
// FIXME: If we get a CTRL-C, get terminal back into a useful state before terminating
|
|
|
|
|
2019-07-08 07:42:48 +03:00
|
|
|
defer func() {
|
|
|
|
err := recover()
|
|
|
|
if err == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-12-30 00:57:44 +03:00
|
|
|
printProblemsHeader()
|
2019-07-08 07:42:48 +03:00
|
|
|
panic(err)
|
|
|
|
}()
|
2019-06-29 12:20:48 +03:00
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
flagSet := flag.NewFlagSet("", flag.ExitOnError)
|
|
|
|
flagSet.Usage = func() {
|
|
|
|
printUsage(os.Stdout, flagSet, false)
|
|
|
|
}
|
|
|
|
printVersion := flagSet.Bool("version", false, "Prints the moar version number")
|
|
|
|
debug := flagSet.Bool("debug", false, "Print debug logs after exiting")
|
|
|
|
trace := flagSet.Bool("trace", false, "Print trace logs after exiting")
|
2021-05-22 16:56:55 +03:00
|
|
|
wrap := flagSet.Bool("wrap", false, "Wrap long lines")
|
2022-11-28 21:09:17 +03:00
|
|
|
follow := flagSet.Bool("follow", false, "Follow piped input just like \"tail -f\"")
|
2021-05-13 20:00:53 +03:00
|
|
|
styleOption := flagSet.String("style", "native",
|
|
|
|
"Highlighting style from https://xyproto.github.io/splash/docs/longer/all.html")
|
2022-04-01 21:24:00 +03:00
|
|
|
colorsOption := flagSet.String("colors", "auto", "Highlighting palette size: 8, 16, 256, 16M, auto")
|
2021-06-03 22:49:02 +03:00
|
|
|
noLineNumbers := flagSet.Bool("no-linenumbers", false, "Hide line numbers on startup, press left arrow key to show")
|
2022-07-20 23:16:33 +03:00
|
|
|
noStatusBar := flagSet.Bool("no-statusbar", false, "Hide the status bar, toggle with '='")
|
2021-11-09 20:56:02 +03:00
|
|
|
noClearOnExit := flagSet.Bool("no-clear-on-exit", false, "Retain screen contents when exiting moar")
|
2022-02-18 21:09:05 +03:00
|
|
|
statusBarStyleOption := flagSet.String("statusbar", "inverse", "Status bar style: inverse, plain or bold")
|
2022-08-07 18:43:29 +03:00
|
|
|
UnprintableStyleOption := flagSet.String("render-unprintable", "highlight",
|
|
|
|
"How unprintable characters are rendered: highlight or whitespace")
|
2022-08-07 18:57:13 +03:00
|
|
|
scrollLeftHintOption := flagSet.String("scroll-left-hint", "ESC[7m<",
|
2022-08-07 18:43:29 +03:00
|
|
|
"Shown when view can scroll left. One character with optional ANSI highlighting.")
|
2022-08-07 18:57:13 +03:00
|
|
|
scrollRightHintOption := flagSet.String("scroll-right-hint", "ESC[7m>",
|
2022-08-07 18:43:29 +03:00
|
|
|
"Shown when view can scroll right. One character with optional ANSI highlighting.")
|
2021-05-13 20:00:53 +03:00
|
|
|
|
|
|
|
// Combine flags from environment and from command line
|
|
|
|
flags := os.Args[1:]
|
|
|
|
moarEnv := strings.Trim(os.Getenv("MOAR"), " ")
|
|
|
|
if len(moarEnv) > 0 {
|
|
|
|
// FIXME: It would be nice if we could debug log that we're doing this,
|
|
|
|
// but logging is not yet set up and depends on command line parameters.
|
|
|
|
flags = append(strings.Split(moarEnv, " "), flags...)
|
|
|
|
}
|
|
|
|
|
|
|
|
err := flagSet.Parse(flags)
|
|
|
|
if err != nil {
|
|
|
|
printProblemsHeader()
|
|
|
|
fmt.Fprintln(os.Stderr, "ERROR: Command line parsing failed:", err.Error())
|
|
|
|
fmt.Fprintln(os.Stderr)
|
|
|
|
printUsage(os.Stderr, flagSet, true)
|
|
|
|
|
|
|
|
os.Exit(1)
|
2019-07-15 23:14:36 +03:00
|
|
|
}
|
2019-07-07 19:18:29 +03:00
|
|
|
|
2019-07-07 19:34:05 +03:00
|
|
|
if *printVersion {
|
|
|
|
fmt.Println(versionString)
|
2019-07-07 19:18:29 +03:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
style := parseStyleOption(*styleOption, flagSet)
|
|
|
|
formatter := parseColorsOption(*colorsOption, flagSet)
|
2022-02-18 21:09:05 +03:00
|
|
|
statusBarStyle := parseStatusBarStyle(*statusBarStyleOption, flagSet)
|
2022-02-27 11:39:16 +03:00
|
|
|
unprintableStyle := parseUnprintableStyle(*UnprintableStyleOption, flagSet)
|
2021-05-13 08:37:34 +03:00
|
|
|
|
2022-08-07 18:43:29 +03:00
|
|
|
scrollLeftHint := parseScrollHint(*scrollLeftHintOption, flagSet)
|
|
|
|
scrollRightHint := parseScrollHint(*scrollRightHintOption, flagSet)
|
|
|
|
|
2019-12-06 21:36:31 +03:00
|
|
|
log.SetLevel(log.InfoLevel)
|
2021-04-15 16:16:06 +03:00
|
|
|
if *trace {
|
|
|
|
log.SetLevel(log.TraceLevel)
|
|
|
|
} else if *debug {
|
2019-12-06 21:36:31 +03:00
|
|
|
log.SetLevel(log.DebugLevel)
|
|
|
|
}
|
|
|
|
|
2021-04-06 17:22:40 +03:00
|
|
|
log.SetFormatter(&log.TextFormatter{
|
|
|
|
TimestampFormat: time.RFC3339Nano,
|
|
|
|
})
|
|
|
|
|
2021-05-13 20:00:53 +03:00
|
|
|
if len(flagSet.Args()) > 1 {
|
|
|
|
fmt.Fprintln(os.Stderr, "ERROR: Expected exactly one filename, or data piped from stdin, got:", flagSet.Args())
|
2021-04-20 10:18:02 +03:00
|
|
|
fmt.Fprintln(os.Stderr)
|
2021-05-13 20:00:53 +03:00
|
|
|
printUsage(os.Stderr, flagSet, true)
|
2021-04-20 10:18:02 +03:00
|
|
|
|
|
|
|
os.Exit(1)
|
2019-06-09 20:34:52 +03:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:18:02 +03:00
|
|
|
stdinIsRedirected := !term.IsTerminal(int(os.Stdin.Fd()))
|
|
|
|
stdoutIsRedirected := !term.IsTerminal(int(os.Stdout.Fd()))
|
|
|
|
var inputFilename *string
|
2021-05-13 20:00:53 +03:00
|
|
|
if len(flagSet.Args()) == 1 {
|
|
|
|
word := flagSet.Arg(0)
|
2021-04-20 10:18:02 +03:00
|
|
|
inputFilename = &word
|
2019-06-09 22:58:12 +03:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:18:02 +03:00
|
|
|
if inputFilename == nil && !stdinIsRedirected {
|
|
|
|
fmt.Fprintln(os.Stderr, "ERROR: Filename or input pipe required")
|
2022-07-19 18:07:11 +03:00
|
|
|
fmt.Fprintln(os.Stderr)
|
2021-05-13 20:00:53 +03:00
|
|
|
printUsage(os.Stderr, flagSet, true)
|
2019-06-09 20:40:35 +03:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:18:02 +03:00
|
|
|
if inputFilename != nil && stdoutIsRedirected {
|
|
|
|
// Pump file to stdout.
|
|
|
|
//
|
|
|
|
// If we get both redirected stdin and an input filename, we must prefer
|
|
|
|
// to copy the file, because that's how less works.
|
|
|
|
inputFile, err := os.Open(*inputFilename)
|
2019-06-09 22:52:27 +03:00
|
|
|
if err != nil {
|
2021-04-20 10:18:02 +03:00
|
|
|
fmt.Fprintln(os.Stderr, "ERROR: Failed to open", inputFile, ": ")
|
2019-06-09 22:52:27 +03:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
2021-04-20 10:18:02 +03:00
|
|
|
|
|
|
|
_, err = io.Copy(os.Stdout, inputFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Failed to copy ", inputFilename, " to stdout: ", err)
|
|
|
|
}
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
if stdinIsRedirected && stdoutIsRedirected {
|
|
|
|
// Must be done after trying to pump the input filename to stdout to be
|
|
|
|
// compatible with less, see above.
|
|
|
|
_, err := io.Copy(os.Stdout, os.Stdin)
|
2021-04-20 09:43:37 +03:00
|
|
|
if err != nil {
|
2021-04-20 10:18:02 +03:00
|
|
|
log.Fatal("Failed to copy stdin to stdout: ", err)
|
2021-04-20 09:43:37 +03:00
|
|
|
}
|
2019-06-09 22:58:12 +03:00
|
|
|
os.Exit(0)
|
2019-06-09 20:55:49 +03:00
|
|
|
}
|
2019-06-09 22:58:12 +03:00
|
|
|
|
2021-04-20 10:18:02 +03:00
|
|
|
// INVARIANT: At this point, stdoutIsRedirected is false and we should
|
|
|
|
// proceed with paging.
|
|
|
|
|
2023-01-03 01:07:04 +03:00
|
|
|
var reader *m.Reader
|
2021-04-20 10:18:02 +03:00
|
|
|
if stdinIsRedirected {
|
|
|
|
// Display input pipe contents
|
2023-01-03 01:07:04 +03:00
|
|
|
reader = m.NewReaderFromStream("", os.Stdin)
|
|
|
|
} else {
|
|
|
|
reader, err = m.NewReaderFromFilename(*inputFilename, style, formatter)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2021-04-20 10:18:02 +03:00
|
|
|
}
|
|
|
|
|
2019-06-10 22:50:31 +03:00
|
|
|
// Display the input file contents
|
2023-01-03 01:07:04 +03:00
|
|
|
pager := m.NewPager(reader)
|
|
|
|
pager.WrapLongLines = *wrap
|
|
|
|
pager.Following = *follow
|
|
|
|
pager.ShowLineNumbers = !*noLineNumbers
|
|
|
|
pager.ShowStatusBar = !*noStatusBar
|
|
|
|
pager.DeInit = !*noClearOnExit
|
|
|
|
pager.StatusBarStyle = statusBarStyle
|
|
|
|
pager.UnprintableStyle = unprintableStyle
|
|
|
|
pager.ScrollLeftHint = scrollLeftHint
|
|
|
|
pager.ScrollRightHint = scrollRightHint
|
|
|
|
startPaging(pager)
|
2019-06-16 11:02:19 +03:00
|
|
|
}
|
2019-06-15 09:10:56 +03:00
|
|
|
|
2023-01-03 01:07:04 +03:00
|
|
|
func startPaging(pager *m.Pager) {
|
2021-04-15 16:16:06 +03:00
|
|
|
screen, e := twin.NewScreen()
|
2019-06-30 23:11:26 +03:00
|
|
|
if e != nil {
|
2019-07-08 07:42:48 +03:00
|
|
|
panic(e)
|
2019-06-30 23:11:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var loglines strings.Builder
|
2021-11-09 20:56:02 +03:00
|
|
|
log.SetOutput(&loglines)
|
|
|
|
|
2019-06-29 23:27:18 +03:00
|
|
|
defer func() {
|
|
|
|
// Restore screen...
|
2021-04-15 16:16:06 +03:00
|
|
|
screen.Close()
|
2019-06-29 23:27:18 +03:00
|
|
|
|
|
|
|
// ... before printing panic() output, otherwise the output will have
|
|
|
|
// broken linefeeds and be hard to follow.
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2023-01-03 01:07:04 +03:00
|
|
|
if !pager.DeInit {
|
2021-11-09 20:56:02 +03:00
|
|
|
err := pager.ReprintAfterExit()
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed reprinting pager view after exit", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-30 23:11:26 +03:00
|
|
|
if len(loglines.String()) > 0 {
|
2020-12-30 00:57:44 +03:00
|
|
|
printProblemsHeader()
|
Print bug reporting info on log messages
diff --git moar.go moar.go
index 46b2898..906b310 100644
--- moar.go
+++ moar.go
@@ -58,6 +58,23 @@ func _PrintUsage(output io.Writer) {
}
}
+// PrintProblemsHeader prints bug reporting information to stderr
+func PrintProblemsHeader() {
+ fmt.Fprintln(os.Stderr, "Please post the following report at <https://github.com/walles/moar/issues>,")
+ fmt.Fprintln(os.Stderr, "or e-mail it to johan.walles@gmail.com.")
+ fmt.Fprintln(os.Stderr)
+ fmt.Fprintln(os.Stderr, "Version:", versionString)
+ fmt.Fprintln(os.Stderr, "LANG :", os.Getenv("LANG"))
+ fmt.Fprintln(os.Stderr, "TERM :", os.Getenv("TERM"))
+ fmt.Fprintln(os.Stderr)
+ fmt.Fprintln(os.Stderr, "GOOS :", runtime.GOOS)
+ fmt.Fprintln(os.Stderr, "GOARCH :", runtime.GOARCH)
+ fmt.Fprintln(os.Stderr, "Compiler:", runtime.Compiler)
+ fmt.Fprintln(os.Stderr, "NumCPU :", runtime.NumCPU())
+
+ fmt.Fprintln(os.Stderr)
+}
+
func main() {
// FIXME: If we get a CTRL-C, get terminal back into a useful state before terminating
@@ -67,21 +84,7 @@ func main() {
return
}
- // On any panic or warnings, also print system info and how to report bugs
- fmt.Fprintln(os.Stderr, "Please post the following crash report at <https://github.com/walles/moar/issues>,")
- fmt.Fprintln(os.Stderr, "or e-mail it to johan.walles@gmail.com.")
- fmt.Fprintln(os.Stderr)
- fmt.Fprintln(os.Stderr, "Version:", versionString)
- fmt.Fprintln(os.Stderr, "LANG :", os.Getenv("LANG"))
- fmt.Fprintln(os.Stderr, "TERM :", os.Getenv("TERM"))
- fmt.Fprintln(os.Stderr)
- fmt.Fprintln(os.Stderr, "GOOS :", runtime.GOOS)
- fmt.Fprintln(os.Stderr, "GOARCH :", runtime.GOARCH)
- fmt.Fprintln(os.Stderr, "Compiler:", runtime.Compiler)
- fmt.Fprintln(os.Stderr, "NumCPU :", runtime.NumCPU())
-
- fmt.Fprintln(os.Stderr)
-
+ PrintProblemsHeader()
panic(err)
}()
@@ -161,6 +164,8 @@ func _StartPaging(reader *m.Reader) {
}
if len(loglines.String()) > 0 {
+ PrintProblemsHeader()
+
// FIXME: Don't print duplicate log messages more than once,
// maybe invent our own logger for this?
fmt.Fprintf(os.Stderr, "%s", loglines.String())
Change-Id: If41c17e98daf9f05909ab7e3c31dc84e946cbbf5
2019-11-19 17:33:00 +03:00
|
|
|
|
2019-07-08 07:42:48 +03:00
|
|
|
// FIXME: Don't print duplicate log messages more than once,
|
|
|
|
// maybe invent our own logger for this?
|
2019-06-30 23:11:26 +03:00
|
|
|
fmt.Fprintf(os.Stderr, "%s", loglines.String())
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}()
|
2019-06-15 09:10:56 +03:00
|
|
|
|
2021-05-22 16:56:55 +03:00
|
|
|
pager.StartPaging(screen)
|
2019-06-09 08:47:55 +03:00
|
|
|
}
|