1
1
mirror of https://github.com/walles/moar.git synced 2024-11-13 11:14:30 +03:00
Commit Graph

285 Commits

Author SHA1 Message Date
Johan Walles
ebf28a5cce Fix test running problem
By not highlighting text files.

Fixes #29.
2020-11-17 18:20:58 +01:00
Johan Walles
ac6fcadb12 Improve diagnostics on a test failure 2020-11-17 17:16:57 +01:00
Johan Walles
9c91399309 Advertise px / ptop and riff 2020-11-17 08:44:29 +01:00
Johan Walles
36bdd69372 Make moar.sh runnable from any directory 2020-11-07 13:57:50 +01:00
Johan Walles
7ee8844a1f Add support for ANSI SGR codes 2 and 22
Fixes #27
2020-10-29 15:48:56 +01:00
Johan Walles
453ad0fd91 Update screenshot to match code 2020-09-05 20:40:33 +02:00
Johan Walles
64b2fd4b73 "h" and "l" for moving left and right
vim inspired.

Fixes #25.
2020-09-05 20:31:21 +02:00
Johan Walles
6ec7df0d52 Ask for help with Debian packaging 2020-04-23 06:32:45 +02:00
Johan Walles
8b0bc846fc Brighten the bright colors
This makes moar match less and cat with TERM=screen-256color.
2020-04-23 06:28:55 +02:00
Johan Walles
a9ee2fae9d Support SGR codes 90-97, bright colors
We just treat them as their plain counterparts.

After testing vs less and cat on iTerm2 3.3.9 / macOS Catalina 10.15.4
that's how they seem to handle this. Counter examples welcome.

Fixes #24
2020-04-22 21:39:58 +02:00
Johan Walles
46881e4519 Add support for italics 2020-04-13 16:43:56 +02:00
Johan Walles
8a3056685c Upgrade tcell to a version supporting italics 2020-04-13 16:39:48 +02:00
Johan Walles
a174d86180 Support both kinds of bullet point patterns 2020-03-31 09:36:53 +02:00
Johan Walles
97906da4b0 Fix bullet pattern 2020-03-31 09:24:29 +02:00
Johan Walles
9a81e5ee62 Merge branch 'walles/stderr-in-reader-error'
If the filter fails, the error message reported will now contain the
contents of the filter's stderr.
2020-03-28 10:57:34 +01:00
Johan Walles
815fe8d6c8 Report filter stderr on non-zero exit code 2020-03-28 10:56:18 +01:00
Johan Walles
b2d01b4ad4 Test filter-stderr in error report 2020-03-28 10:10:38 +01:00
Johan Walles
70a21f097f Enable a disabled-by-mistake test
Having had a linter find this for me earlier would have been nice.
2020-03-25 21:42:18 +01:00
Johan Walles
3c7d017138 Implement SGI 24 "Underline off"
Ref: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters

Fixes #23
2020-03-25 08:55:35 +01:00
Johan Walles
ad767671eb Condition some log messages on --debug flag
With this change, to get some log messages (about unsupported keys
mostly), you have to pass --debug on the command line.

Fixes #20
2019-12-06 19:36:31 +01:00
Johan Walles
64015a0f90 CTRL-l to refresh screen
Useful if the screen has become garbled, this can happen when piping in
from something writing to both stdout and stderr.
2019-11-28 18:14:09 +01:00
Johan Walles
212ff0efa7 Fix rendering of man page bullet points 2019-11-27 21:20:50 +01:00
Johan Walles
e7ae84c1aa Rewrite man page formatting
To make it easier to extend.
2019-11-27 20:59:27 +01:00
Johan Walles
1fa52b9bc7 Use a global logger
This saves us from a lot of passing-a-logger-around and makes the code
generally easier to read and to work with.
2019-11-27 18:43:46 +01:00
Johan Walles
69c007eab4 Make search find formatted text
Fixes #19
2019-11-26 21:20:09 +01:00
Johan Walles
114e9c8aa5 We're using Go 1.13 features
Change-Id: I6675fbfeea9700ff7c6fa88a1dd3befeddb7bc53
2019-11-19 17:37:57 +01:00
Johan Walles
b2cfdf63c3 Fix a broken test
Why isn't this caught by the compiler?

Change-Id: I70e6c0bfb48542a2ac13abd04adbd28e47535eb0
2019-11-19 17:30:41 +01:00
Johan Walles
a438439c11 Improve long-lines performance
diff --git m/ansiTokenizer.go m/ansiTokenizer.go
index d5a5272..601b939 100644
--- m/ansiTokenizer.go
+++ m/ansiTokenizer.go
@@ -92,10 +92,12 @@ func TokensFromString(logger *log.Logger, s string) ([]Token, *string) {
 		}
 	}

-	plainString := ""
+	var stringBuilder strings.Builder
+	stringBuilder.Grow(len(tokens))
 	for _, token := range tokens {
-		plainString += string(token.Rune)
+		stringBuilder.WriteRune(token.Rune)
 	}
+	plainString := stringBuilder.String()
 	return tokens, &plainString
 }

Change-Id: Ieb2c3aa9f1daa18ab2280f499025994b561266e1
2019-11-19 17:28:58 +01:00
Johan Walles
3744165d8b Merge branch 'walles/longlines'
This makes us handle long lines without errors.

Performance is bad, but now we at least do the right thing.

Change-Id: I73fbfbdee24e2b3739452dec53213228ac22e05f
2019-11-19 17:02:06 +01:00
Johan Walles
d36cb1c561 Fix an off-by-one error in a test
Change-Id: I425bc33a611ba96b4d95676b6231e7bc46a87463
2019-11-19 16:58:01 +01:00
Johan Walles
0fc6ee65f5 Fix long-lines-reading bug
Change-Id: Ic93d70cef771527c212cdf02b40e41a0f9e0b350
2019-11-19 16:55:49 +01:00
Johan Walles
9a2ab6df98 Add test for reading long lines
Change-Id: Ib24518c681f1ffc93192a985cd573fa37006d1f8
2019-11-19 16:53:17 +01:00
Johan Walles
d5a0b7df63 Use a bufio.Reader to read the input stream
Because the scanner cannot handle too long lines.

Change-Id: I45f1777537795772ae741816ba095a4939ce4f67
2019-11-19 16:27:14 +01:00
Johan Walles
b25cfc692e Make start of line identifiable
Change-Id: I1fa4b4fa5b25ec58b418a53dbb4d38b6f473d172
2019-11-19 16:21:58 +01:00
Johan Walles
8dd45b7b1c Clarify where an error printout is coming from
Change-Id: Ic263afa23e647fcf8a62c45bf80969d6c85f9436
2019-11-19 15:46:04 +01:00
Johan Walles
0ccbd6a2b3 Deal with broken commit messages
Our git commit messages have been screwed up by VSCode 1.40.1, probably
in conjunction with using Git in Swedish.
diff --git release.sh release.sh
index 1cc1f6c..1b6805c 100755
--- release.sh
+++ release.sh
@@ -30,7 +30,7 @@ echo

 # FIXME: Make this part of the editable tagging message
 echo "Changes since last release:"
-git log --first-parent --pretty="format:* %s" "$LAST_VERSION"..HEAD | cat
+git log --first-parent --pretty="format:* %s" "$LAST_VERSION"..HEAD | sed 's/ diff.*//'
 echo
 echo

Change-Id: Iedaecf17a69c8cfe22f29714907e599ff2b86689
2019-11-19 15:36:21 +01:00
Johan Walles
aaa25b74f3 Add sample file with a long line
This file breaks the test suite.

Change-Id: I510e1ddf98dadb02d1848702e9e83aaacf0f6e78
2019-11-19 15:33:50 +01:00
Johan Walles
d96bb923a1 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 15:33:00 +01:00
Johan Walles
2df60227cf Tell user about Reader errors
diff --git m/pager.go m/pager.go
index 51a007a..070e39d 100644
--- m/pager.go
+++ m/pager.go
@@ -763,5 +763,7 @@ func (p *Pager) StartPaging(logger *log.Logger, screen tcell.Screen) {
 		p._Redraw(logger, spinner)
 	}

-	// FIXME: Log p.reader.err if it's non-nil
+	if p.reader.err != nil {
+		logger.Printf("Reader reported an error: %s", p.reader.err.Error())
+	}
 }

Change-Id: Ia848d1daced793c39ebd4518fa144627a2598ecd
2019-11-19 15:18:40 +01:00
Johan Walles
08d3fbfaa8 Add some timeouts
diff --git m/reader.go m/reader.go
index 339de9c..2427094 100644
--- m/reader.go
+++ m/reader.go
@@ -12,6 +12,7 @@ import (
 	"regexp"
 	"strings"
 	"sync"
+	"time"
 )

 // Reader reads a file into an array of strings.
@@ -54,9 +55,18 @@ func _ReadStream(stream io.Reader, reader *Reader, fromFilter *exec.Cmd) {
 			return
 		}

-		// FIXME: Can Wait()ing here stall? Should we release the lock while Wait()ing?
+		// Give the filter a little time to go away
+		timer := time.AfterFunc(2*time.Second, func() {
+			fromFilter.Process.Kill()
+		})
+
 		err := fromFilter.Wait()
+		timer.Stop()
+
 		if reader.err == nil {
+			// NOTE: This could mean that our Wait()ing on the filter above
+			// timed out.
+			//
 			// FIXME: Add filter stderr contents to the error reported here
 			reader.err = err
 		}
diff --git test.sh test.sh
index 677c5db..6d0b6b9 100755
--- test.sh
+++ test.sh
@@ -3,7 +3,7 @@
 set -e -o pipefail

 # Unit tests first
-go test github.com/walles/moar/m
+go test -timeout 20s github.com/walles/moar/m

 # Ensure we can cross compile
 # NOTE: Make sure this list matches the one in release.sh

Change-Id: I3847aaa0942588c2d4129c7b2967d1d10aa95035
2019-11-19 15:08:22 +01:00
Johan Walles
b781d09a72 Add another test case
diff --git m/reader_test.go m/reader_test.go
index 176192b..bed1e33 100644
--- m/reader_test.go
+++ m/reader_test.go
@@ -30,6 +30,12 @@ func _TestGetLineCount(t *testing.T, reader *Reader) {
 	if err != nil {
 		t.Error("Error counting lines of", *reader.name, err)
 	}
+
+	if strings.HasSuffix(*reader.name, "/line-without-newline.txt") {
+		// "wc -l" thinks this file contains zero lines
+		fileLineCount = 1
+	}
+
 	if reader.GetLineCount() != fileLineCount {
 		t.Errorf("Got %d lines but expected %d: <%s>",
 			reader.GetLineCount(), fileLineCount, *reader.name)
diff --git sample-files/line-without-newline.txt sample-files/line-without-newline.txt
new file mode 100644
index 0000000..2260c57
--- /dev/null
+++ sample-files/line-without-newline.txt
@@ -0,0 +1 @@
+This file contains no newlines
\ No newline at end of file

Change-Id: Ic2801ce3477a7afd4537d340385c884c5f2b7438
2019-11-19 14:47:44 +01:00
Johan Walles
8d9155061a Merge branch 'walles/linenumbers'
Fixes #17

Change-Id: Iad01483b26128f2b782c19ee6092b73cfea7d962
2019-11-19 12:00:12 +01:00
Johan Walles
db048012fa Add line numbers to screenshot
diff --git screenshot.png screenshot.png
index 1a30f30..4ce4774 100644
Binary files screenshot.png and screenshot.png differ

Change-Id: I3bfeba25afcec9f7ce105d180989c78b56c3cfa6
2019-11-19 11:58:52 +01:00
Johan Walles
d3233845a6 Fix test failures
diff --git m/pager_test.go m/pager_test.go
index 5911cbc..ba18470 100644
--- m/pager_test.go
+++ m/pager_test.go
@@ -99,6 +99,7 @@ func TestBrokenUtf8(t *testing.T) {
 func _StartPaging(t *testing.T, reader *Reader) []tcell.SimCell {
 	screen := tcell.NewSimulationScreen("UTF-8")
 	pager := NewPager(reader)
+	pager.showLineNumbers = false
 	pager.Quit()

 	var loglines strings.Builder
@@ -267,12 +268,12 @@ func assertTokenRangesEqual(t *testing.T, actual []Token, expected []Token) {
 }

 func TestCreateScreenLineBase(t *testing.T) {
-	line := _CreateScreenLine(nil, 0, 0, 3, "", nil)
+	line := _CreateScreenLine(nil, 0, 3, "", nil)
 	assert.Assert(t, len(line) == 0)
 }

 func TestCreateScreenLineOverflowRight(t *testing.T) {
-	line := _CreateScreenLine(nil, 0, 0, 3, "012345", nil)
+	line := _CreateScreenLine(nil, 0, 3, "012345", nil)
 	assertTokenRangesEqual(t, line, []Token{
 		_CreateExpectedCell('0', tcell.StyleDefault),
 		_CreateExpectedCell('1', tcell.StyleDefault),
@@ -281,7 +282,7 @@ func TestCreateScreenLineOverflowRight(t *testing.T) {
 }

 func TestCreateScreenLineUnderflowLeft(t *testing.T) {
-	line := _CreateScreenLine(nil, 0, 1, 3, "012", nil)
+	line := _CreateScreenLine(nil, 1, 3, "012", nil)
 	assertTokenRangesEqual(t, line, []Token{
 		_CreateExpectedCell('<', tcell.StyleDefault.Reverse(true)),
 		_CreateExpectedCell('1', tcell.StyleDefault),
@@ -295,7 +296,7 @@ func TestCreateScreenLineSearchHit(t *testing.T) {
 		panic(err)
 	}

-	line := _CreateScreenLine(nil, 0, 0, 3, "abc", pattern)
+	line := _CreateScreenLine(nil, 0, 3, "abc", pattern)
 	assertTokenRangesEqual(t, line, []Token{
 		_CreateExpectedCell('a', tcell.StyleDefault),
 		_CreateExpectedCell('b', tcell.StyleDefault.Reverse(true)),
@@ -309,7 +310,7 @@ func TestCreateScreenLineUtf8SearchHit(t *testing.T) {
 		panic(err)
 	}

-	line := _CreateScreenLine(nil, 0, 0, 3, "åäö", pattern)
+	line := _CreateScreenLine(nil, 0, 3, "åäö", pattern)
 	assertTokenRangesEqual(t, line, []Token{
 		_CreateExpectedCell('å', tcell.StyleDefault),
 		_CreateExpectedCell('ä', tcell.StyleDefault.Reverse(true)),
@@ -320,7 +321,7 @@ func TestCreateScreenLineUtf8SearchHit(t *testing.T) {
 func TestCreateScreenLineScrolledUtf8SearchHit(t *testing.T) {
 	pattern := regexp.MustCompile("ä")

-	line := _CreateScreenLine(nil, 0, 1, 4, "ååäö", pattern)
+	line := _CreateScreenLine(nil, 1, 4, "ååäö", pattern)

 	assertTokenRangesEqual(t, line, []Token{
 		_CreateExpectedCell('<', tcell.StyleDefault.Reverse(true)),
@@ -333,7 +334,7 @@ func TestCreateScreenLineScrolledUtf8SearchHit(t *testing.T) {
 func TestCreateScreenLineScrolled2Utf8SearchHit(t *testing.T) {
 	pattern := regexp.MustCompile("ä")

-	line := _CreateScreenLine(nil, 0, 2, 4, "åååäö", pattern)
+	line := _CreateScreenLine(nil, 2, 4, "åååäö", pattern)

 	assertTokenRangesEqual(t, line, []Token{
 		_CreateExpectedCell('<', tcell.StyleDefault.Reverse(true)),

Change-Id: Ib85633c6d191a54ab8d34dcc29850bfb127eb0d3
2019-11-19 11:49:37 +01:00
Johan Walles
2e931b400c Scroll left / right to show / hide line numbers
diff --git m/pager.go m/pager.go
index 0e22e83..51a007a 100644
--- m/pager.go
+++ m/pager.go
@@ -504,6 +504,16 @@ func (p *Pager) _OnSearchKey(logger *log.Logger, key tcell.Key) {
 }

 func (p *Pager) _MoveRight(delta int) {
+	if p.showLineNumbers && delta > 0 {
+		p.showLineNumbers = false
+		return
+	}
+
+	if p.leftColumnZeroBased == 0 && delta < 0 {
+		p.showLineNumbers = true
+		return
+	}
+
 	result := p.leftColumnZeroBased + delta
 	if result < 0 {
 		p.leftColumnZeroBased = 0

Change-Id: I69040ac8da06e50b866fdb6b678a0ae54fe0a84f
2019-11-19 11:41:56 +01:00
Johan Walles
7de5025257 Extract sideways scrolling into its own method
diff --git m/pager.go m/pager.go
index ec81976..0e22e83 100644
--- m/pager.go
+++ m/pager.go
@@ -41,7 +41,7 @@ type Pager struct {
 	isShowingHelp bool
 	preHelpState  *_PreHelpState

-	lineNumbersWanted bool
+	showLineNumbers bool
 }

 type _PreHelpState struct {
@@ -101,7 +101,7 @@ func NewPager(r *Reader) *Pager {
 		reader:            r,
 		quit:              false,
 		firstLineOneBased: 1,
-		lineNumbersWanted: true,
+		showLineNumbers:   true,
 	}
 }

@@ -211,7 +211,7 @@ func (p *Pager) _AddLines(logger *log.Logger, spinner string) {
 	lastLineOneBased := lines.firstLineOneBased + len(lines.lines) - 1
 	maxPrefixLength := len(strconv.Itoa(lastLineOneBased)) + 1

-	if !p.lineNumbersWanted {
+	if !p.showLineNumbers {
 		maxPrefixLength = 0
 	}

@@ -503,6 +503,15 @@ func (p *Pager) _OnSearchKey(logger *log.Logger, key tcell.Key) {
 	}
 }

+func (p *Pager) _MoveRight(delta int) {
+	result := p.leftColumnZeroBased + delta
+	if result < 0 {
+		p.leftColumnZeroBased = 0
+	} else {
+		p.leftColumnZeroBased = result
+	}
+}
+
 func (p *Pager) _OnKey(logger *log.Logger, key tcell.Key) {
 	if p.mode == _Searching {
 		p._OnSearchKey(logger, key)
@@ -528,13 +537,10 @@ func (p *Pager) _OnKey(logger *log.Logger, key tcell.Key) {
 		p.firstLineOneBased++

 	case tcell.KeyRight:
-		p.leftColumnZeroBased += 16
+		p._MoveRight(16)

 	case tcell.KeyLeft:
-		p.leftColumnZeroBased -= 16
-		if p.leftColumnZeroBased < 0 {
-			p.leftColumnZeroBased = 0
-		}
+		p._MoveRight(-16)

 	case tcell.KeyHome:
 		p.firstLineOneBased = 1
@@ -718,13 +724,10 @@ func (p *Pager) StartPaging(logger *log.Logger, screen tcell.Screen) {
 				p.firstLineOneBased++

 			case tcell.WheelRight:
-				p.leftColumnZeroBased += 16
+				p._MoveRight(16)

 			case tcell.WheelLeft:
-				p.leftColumnZeroBased -= 16
-				if p.leftColumnZeroBased < 0 {
-					p.leftColumnZeroBased = 0
-				}
+				p._MoveRight(-16)
 			}

 		case *tcell.EventResize:

Change-Id: I5925876d42ec3cd7b8486bb96eb47b81c6855032
2019-11-19 11:38:41 +01:00
Johan Walles
47b34c3351 Make line number configurable through code
diff --git m/pager.go m/pager.go
index 2133057..ec81976 100644
--- m/pager.go
+++ m/pager.go
@@ -40,6 +40,8 @@ type Pager struct {

 	isShowingHelp bool
 	preHelpState  *_PreHelpState
+
+	lineNumbersWanted bool
 }

 type _PreHelpState struct {
@@ -60,6 +62,7 @@ Quitting
 Moving around
 -------------
 * Arrow keys
+* Left / right can be used to hide / show line numbers
 * PageUp / 'b' and PageDown / 'f'
 * Half page 'u'p / 'd'own
 * Home and End for start / end of the document
@@ -98,6 +101,7 @@ func NewPager(r *Reader) *Pager {
 		reader:            r,
 		quit:              false,
 		firstLineOneBased: 1,
+		lineNumbersWanted: true,
 	}
 }

@@ -106,7 +110,7 @@ func (p *Pager) _AddLine(logger *log.Logger, fileLineNumber *int, maxPrefixLengt

 	prefixLength := 0
 	lineNumberString := ""
-	if fileLineNumber != nil {
+	if maxPrefixLength > 0 && fileLineNumber != nil {
 		prefixLength = maxPrefixLength
 		lineNumberString = fmt.Sprintf("%*d ", prefixLength-1, *fileLineNumber)
 	}
@@ -207,6 +211,10 @@ func (p *Pager) _AddLines(logger *log.Logger, spinner string) {
 	lastLineOneBased := lines.firstLineOneBased + len(lines.lines) - 1
 	maxPrefixLength := len(strconv.Itoa(lastLineOneBased)) + 1

+	if !p.lineNumbersWanted {
+		maxPrefixLength = 0
+	}
+
 	screenLineNumber := 0
 	for i, line := range lines.lines {
 		lineNumber := p.firstLineOneBased + i

Change-Id: I79cd0d46e8590cfdcd9e0ee942eeb0098676d25d
2019-11-19 11:28:28 +01:00
Johan Walles
a14f756d99 Adaptive width of the line numbers column
diff --git m/pager.go m/pager.go
index 0c7c3a2..2133057 100644
--- m/pager.go
+++ m/pager.go
@@ -5,6 +5,7 @@ import (
 	"log"
 	"os"
 	"regexp"
+	"strconv"
 	"time"
 	"unicode"
 	"unicode/utf8"
@@ -100,13 +101,13 @@ func NewPager(r *Reader) *Pager {
 	}
 }

-func (p *Pager) _AddLine(logger *log.Logger, fileLineNumber *int, screenLineNumber int, line string) {
+func (p *Pager) _AddLine(logger *log.Logger, fileLineNumber *int, maxPrefixLength int, screenLineNumber int, line string) {
 	screenWidth, _ := p.screen.Size()

 	prefixLength := 0
 	lineNumberString := ""
 	if fileLineNumber != nil {
-		prefixLength = 3
+		prefixLength = maxPrefixLength
 		lineNumberString = fmt.Sprintf("%*d ", prefixLength-1, *fileLineNumber)
 	}

@@ -200,10 +201,16 @@ func (p *Pager) _AddLines(logger *log.Logger, spinner string) {
 	// display starts scrolling visibly.
 	p.firstLineOneBased = lines.firstLineOneBased

+	// Count the length of the last line number
+	//
+	// Offsets figured out through trial-and-error...
+	lastLineOneBased := lines.firstLineOneBased + len(lines.lines) - 1
+	maxPrefixLength := len(strconv.Itoa(lastLineOneBased)) + 1
+
 	screenLineNumber := 0
 	for i, line := range lines.lines {
 		lineNumber := p.firstLineOneBased + i
-		p._AddLine(logger, &lineNumber, screenLineNumber, line)
+		p._AddLine(logger, &lineNumber, maxPrefixLength, screenLineNumber, line)
 		screenLineNumber++
 	}

@@ -212,7 +219,7 @@ func (p *Pager) _AddLines(logger *log.Logger, spinner string) {
 		// This happens when we're done
 		eofSpinner = "---"
 	}
-	p._AddLine(logger, nil, screenLineNumber, _EofMarkerFormat+eofSpinner)
+	p._AddLine(logger, nil, 0, screenLineNumber, _EofMarkerFormat+eofSpinner)

 	switch p.mode {
 	case _Searching:

Change-Id: I7ab67a61048557fd11cd9a044dbae5c13264f492
2019-11-19 11:24:01 +01:00
Johan Walles
fd286d4004 Mandatory line numbers, badly formatted
diff --git m/pager.go m/pager.go
index 2c2736b..0c7c3a2 100644
--- m/pager.go
+++ m/pager.go
@@ -22,6 +22,9 @@ const (
 	_NotFound  _PagerMode = 2
 )

+// Styling of line numbers
+var _NumberStyle = tcell.StyleDefault.Dim(true)
+
 // Pager is the main on-screen pager
 type Pager struct {
 	reader              *Reader
@@ -97,17 +100,32 @@ func NewPager(r *Reader) *Pager {
 	}
 }

-func (p *Pager) _AddLine(logger *log.Logger, lineNumber int, line string) {
-	width, _ := p.screen.Size()
-	tokens := _CreateScreenLine(logger, lineNumber, p.leftColumnZeroBased, width, line, p.searchPattern)
+func (p *Pager) _AddLine(logger *log.Logger, fileLineNumber *int, screenLineNumber int, line string) {
+	screenWidth, _ := p.screen.Size()
+
+	prefixLength := 0
+	lineNumberString := ""
+	if fileLineNumber != nil {
+		prefixLength = 3
+		lineNumberString = fmt.Sprintf("%*d ", prefixLength-1, *fileLineNumber)
+	}
+
+	for column, digit := range lineNumberString {
+		if column >= prefixLength {
+			break
+		}
+
+		p.screen.SetContent(column, screenLineNumber, digit, nil, _NumberStyle)
+	}
+
+	tokens := _CreateScreenLine(logger, p.leftColumnZeroBased, screenWidth-prefixLength, line, p.searchPattern)
 	for column, token := range tokens {
-		p.screen.SetContent(column, lineNumber, token.Rune, nil, token.Style)
+		p.screen.SetContent(column+prefixLength, screenLineNumber, token.Rune, nil, token.Style)
 	}
 }

 func _CreateScreenLine(
 	logger *log.Logger,
-	lineNumber int,
 	stringIndexAtColumnZero int,
 	screenColumnsCount int,
 	line string,
@@ -183,8 +201,9 @@ func (p *Pager) _AddLines(logger *log.Logger, spinner string) {
 	p.firstLineOneBased = lines.firstLineOneBased

 	screenLineNumber := 0
-	for _, line := range lines.lines {
-		p._AddLine(logger, screenLineNumber, line)
+	for i, line := range lines.lines {
+		lineNumber := p.firstLineOneBased + i
+		p._AddLine(logger, &lineNumber, screenLineNumber, line)
 		screenLineNumber++
 	}

@@ -193,7 +212,7 @@ func (p *Pager) _AddLines(logger *log.Logger, spinner string) {
 		// This happens when we're done
 		eofSpinner = "---"
 	}
-	p._AddLine(logger, screenLineNumber, _EofMarkerFormat+eofSpinner)
+	p._AddLine(logger, nil, screenLineNumber, _EofMarkerFormat+eofSpinner)

 	switch p.mode {
 	case _Searching:

Change-Id: I2cafedb3e8a87c88564982f42819b16e911c6a1b
2019-11-19 11:12:23 +01:00
Johan Walles
8d37e9cfe8 Sideways mouse wheel scrolling
diff --git m/pager.go m/pager.go
index 16e91e7..2c2736b 100644
--- m/pager.go
+++ m/pager.go
@@ -682,6 +682,15 @@ func (p *Pager) StartPaging(logger *log.Logger, screen tcell.Screen) {
 			case tcell.WheelDown:
 				// Clipping is done in _AddLines()
 				p.firstLineOneBased++
+
+			case tcell.WheelRight:
+				p.leftColumnZeroBased += 16
+
+			case tcell.WheelLeft:
+				p.leftColumnZeroBased -= 16
+				if p.leftColumnZeroBased < 0 {
+					p.leftColumnZeroBased = 0
+				}
 			}

 		case *tcell.EventResize:

Change-Id: Ibe36c3d88392dda1f4d6e7be182cf5ea5d168703
2019-11-14 07:46:54 +01:00