Skip to content

Commit

Permalink
Merge pull request #157 from walles/johan/start-at-line
Browse files Browse the repository at this point in the history
Add support for +1234 command line option
  • Loading branch information
walles authored Sep 27, 2023
2 parents 4b7c112 + 1209010 commit 822bd80
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 24 deletions.
48 changes: 33 additions & 15 deletions m/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package m

import (
"fmt"
"math"
"regexp"
"time"

Expand Down Expand Up @@ -59,7 +60,9 @@ type Pager struct {
searchString string
searchPattern *regexp.Regexp
gotoLineString string
Following bool

// We used to have a "Following" field here. If you want to follow, set
// TargetLineNumberOneBased to math.MaxInt instead, see below.

isShowingHelp bool
preHelpState *_PreHelpState
Expand All @@ -83,16 +86,20 @@ type Pager struct {

SideScrollAmount int // Should be positive

// If non-zero, scroll to this line number as soon as possible. Set to
// math.MaxInt to follow the end of the input (tail).
TargetLineNumberOneBased int

// If true, pager will clear the screen on return. If false, pager will
// clear the last line, and show the cursor.
DeInit bool
}

type _PreHelpState struct {
reader *Reader
scrollPosition scrollPosition
leftColumnZeroBased int
following bool
reader *Reader
scrollPosition scrollPosition
leftColumnZeroBased int
targetLineNumberOneBased int
}

const _EofMarkerFormat = "\x1b[7m" // Reverse video
Expand Down Expand Up @@ -210,7 +217,7 @@ func (p *Pager) Quit() {
p.reader = p.preHelpState.reader
p.scrollPosition = p.preHelpState.scrollPosition
p.leftColumnZeroBased = p.preHelpState.leftColumnZeroBased
p.Following = p.preHelpState.following
p.TargetLineNumberOneBased = p.preHelpState.targetLineNumberOneBased
p.preHelpState = nil
}

Expand All @@ -235,11 +242,15 @@ func (p *Pager) moveRight(delta int) {
}

func (p *Pager) handleScrolledUp() {
p.Following = false
p.TargetLineNumberOneBased = 0
}

func (p *Pager) handleScrolledDown() {
p.Following = p.isScrolledToEnd()
if p.isScrolledToEnd() {
p.TargetLineNumberOneBased = math.MaxInt
} else {
p.TargetLineNumberOneBased = 0
}
}

func (p *Pager) onKey(keyCode twin.KeyCode) {
Expand Down Expand Up @@ -326,15 +337,15 @@ func (p *Pager) onRune(char rune) {
case '?':
if !p.isShowingHelp {
p.preHelpState = &_PreHelpState{
reader: p.reader,
scrollPosition: p.scrollPosition,
leftColumnZeroBased: p.leftColumnZeroBased,
following: p.Following,
reader: p.reader,
scrollPosition: p.scrollPosition,
leftColumnZeroBased: p.leftColumnZeroBased,
targetLineNumberOneBased: p.TargetLineNumberOneBased,
}
p.reader = _HelpReader
p.scrollPosition = newScrollPosition("Pager scroll position")
p.leftColumnZeroBased = 0
p.Following = false
p.TargetLineNumberOneBased = 0
p.isShowingHelp = true
}

Expand Down Expand Up @@ -539,8 +550,15 @@ func (p *Pager) StartPaging(screen twin.Screen) {
return

case eventMoreLinesAvailable:
if p.mode.isViewing() && p.Following {
p.scrollToEnd()
if p.mode.isViewing() && p.TargetLineNumberOneBased > 0 {
// The user wants to scroll down to a specific line number
if p.reader.GetLineCount() >= p.TargetLineNumberOneBased {
p.scrollPosition = NewScrollPositionFromLineNumberOneBased(p.TargetLineNumberOneBased, "goToTargetLineNumber")
p.TargetLineNumberOneBased = 0
} else {
// Not there yet, keep scrolling
p.scrollToEnd()
}
}

case eventMaybeDone:
Expand Down
13 changes: 11 additions & 2 deletions m/scrollPosition.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package m

import "fmt"
import (
"fmt"
"math"
)

// Please create using newScrollPosition(name)
type scrollPosition struct {
Expand Down Expand Up @@ -305,7 +308,13 @@ func (p *Pager) scrollToEnd() {
// lines than the number of characters it contains.
p.scrollPosition.internalDontTouch.deltaScreenLines = len(lastInputLine.raw)

p.Following = true
if p.TargetLineNumberOneBased == 0 {
// Start following the end of the file
//
// Otherwise, if we're already aiming for some place, don't overwrite
// that.
p.TargetLineNumberOneBased = math.MaxInt
}
}

// Can be either because Pager.scrollToEnd() was just called or because the user
Expand Down
4 changes: 2 additions & 2 deletions m/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (p *Pager) scrollToNextSearchHit() {
p.scrollPosition = *firstHitPosition

// Don't let any search hit scroll out of sight
p.Following = false
p.TargetLineNumberOneBased = 0
}

func (p *Pager) scrollToPreviousSearchHit() {
Expand Down Expand Up @@ -155,7 +155,7 @@ func (p *Pager) scrollToPreviousSearchHit() {
p.scrollPosition = *firstHitPosition

// Don't let any search hit scroll out of sight
p.Following = false
p.TargetLineNumberOneBased = 0
}

func (p *Pager) updateSearchPattern() {
Expand Down
4 changes: 4 additions & 0 deletions moar.1
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ Print trace logs after exiting, more verbose than
\fB\-\-wrap\fR
Wrap long lines, toggle with
.B w
.TP
\fB\+\1234\fR
Immediately scroll to line
.B 1234
.SH ENVIRONMENT
Having
.B PAGER=moar
Expand Down
53 changes: 49 additions & 4 deletions moar.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"io"
"math"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -80,6 +81,9 @@ func printUsage(output io.Writer, flagSet *flag.FlagSet, printCommandline bool)
_, _ = fmt.Fprintln(output, "Options:")

flagSet.PrintDefaults()

_, _ = fmt.Fprintln(output, " +1234")
_, _ = fmt.Fprintln(output, " \tImmediately scroll to line 1234")
}

// "moar" if we're in the $PATH, otherwise an absolute path
Expand Down Expand Up @@ -271,6 +275,40 @@ func tryOpen(filename string) error {
return err
}

// Parses an argument like "+123" anywhere on the command line into a one-based
// line number, and returns the remaining args.
//
// Returns 0 on no target line number specified.
func getTargetLineNumberOneBased(flagSet *flag.FlagSet) (int, []string) {
args := flagSet.Args()
for i, arg := range args {
if !strings.HasPrefix(arg, "+") {
continue
}

lineNumber, err := strconv.ParseInt(arg[1:], 10, 32)
if err != nil {
// Let's pretend this is a file name
continue
}
if lineNumber < 1 {
// Pretend this is a file name
continue
}

// Remove the target line number from the args
//
// Ref: https://stackoverflow.com/a/57213476/473672
remainingArgs := make([]string, 0)
remainingArgs = append(remainingArgs, args[:i]...)
remainingArgs = append(remainingArgs, args[i+1:]...)

return int(lineNumber), remainingArgs
}

return 0, args
}

func main() {
// FIXME: If we get a CTRL-C, get terminal back into a useful state before terminating

Expand Down Expand Up @@ -370,8 +408,10 @@ func main() {
TimestampFormat: time.StampMicro,
})

if len(flagSet.Args()) > 1 {
fmt.Fprintln(os.Stderr, "ERROR: Expected exactly one filename, or data piped from stdin, got:", flagSet.Args())
targetLineNumberOneBased, remainingArgs := getTargetLineNumberOneBased(flagSet)

if len(remainingArgs) > 1 {
fmt.Fprintln(os.Stderr, "ERROR: Expected exactly one filename, or data piped from stdin, got:", remainingArgs)
fmt.Fprintln(os.Stderr)
printUsage(os.Stderr, flagSet, true)

Expand All @@ -381,7 +421,7 @@ func main() {
stdinIsRedirected := !term.IsTerminal(int(os.Stdin.Fd()))
stdoutIsRedirected := !term.IsTerminal(int(os.Stdout.Fd()))
var inputFilename *string
if len(flagSet.Args()) == 1 {
if len(remainingArgs) == 1 {
word := flagSet.Arg(0)
inputFilename = &word

Expand Down Expand Up @@ -444,7 +484,6 @@ func main() {

pager := m.NewPager(reader)
pager.WrapLongLines = *wrap
pager.Following = *follow
pager.ShowLineNumbers = !*noLineNumbers
pager.ShowStatusBar = !*noStatusBar
pager.DeInit = !*noClearOnExit
Expand All @@ -454,6 +493,12 @@ func main() {
pager.ScrollLeftHint = *scrollLeftHint
pager.ScrollRightHint = *scrollRightHint
pager.SideScrollAmount = int(*shift)

pager.TargetLineNumberOneBased = targetLineNumberOneBased
if *follow && pager.TargetLineNumberOneBased == 0 {
pager.TargetLineNumberOneBased = math.MaxInt
}

startPaging(pager, screen)
}

Expand Down
2 changes: 1 addition & 1 deletion test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ echo Test --version...
diff -u <(./moar --version) <(git describe --tags --dirty --always)

echo Test that the man page and --help document the same set of options...
MAN_OPTIONS="$(grep -E '^\\fB' moar.1 | cut -d\\ -f4- | sed 's/fR.*//' | sed 's/\\//g')"
MAN_OPTIONS="$(grep -E '^\\fB\\-' moar.1 | cut -d\\ -f4- | sed 's/fR.*//' | sed 's/\\//g')"
MOAR_OPTIONS="$(./moar --help | grep -E '^ -' | cut -d' ' -f3 | grep -v -- -version)"
diff -u <(echo "${MAN_OPTIONS}") <(echo "${MOAR_OPTIONS}")

Expand Down

0 comments on commit 822bd80

Please sign in to comment.