mirror of
https://github.com/walles/moar.git
synced 2024-09-11 12:15:43 +03:00
commit
1b0a214bb3
@ -30,6 +30,7 @@ Doing the right thing includes:
|
||||
- The position in the file is always shown
|
||||
- Supports **word wrapping** (on actual word boundaries) if requested using
|
||||
`--wrap` or by pressing <kbd>w</kbd>
|
||||
- **Follows output** as long as you are on the last line, just like `tail -f`
|
||||
|
||||
[For compatibility reasons](https://github.com/walles/moar/issues/14), `moar`
|
||||
uses the formats declared in these environment variables when viewing man pages:
|
||||
|
42
m/pager.go
42
m/pager.go
@ -55,6 +55,7 @@ type Pager struct {
|
||||
searchString string
|
||||
searchPattern *regexp.Regexp
|
||||
gotoLineString string
|
||||
Following bool
|
||||
|
||||
isShowingHelp bool
|
||||
preHelpState *_PreHelpState
|
||||
@ -82,6 +83,7 @@ type _PreHelpState struct {
|
||||
reader *Reader
|
||||
scrollPosition scrollPosition
|
||||
leftColumnZeroBased int
|
||||
following bool
|
||||
}
|
||||
|
||||
const _EofMarkerFormat = "\x1b[7m" // Reverse video
|
||||
@ -133,6 +135,10 @@ Source Code
|
||||
Available at https://github.com/walles/moar/.
|
||||
`)
|
||||
|
||||
func (pm _PagerMode) isViewing() bool {
|
||||
return pm == _Viewing || pm == _NotFound
|
||||
}
|
||||
|
||||
// NewPager creates a new Pager
|
||||
func NewPager(r *Reader) *Pager {
|
||||
var name string
|
||||
@ -189,6 +195,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.preHelpState = nil
|
||||
}
|
||||
|
||||
@ -211,6 +218,14 @@ func (p *Pager) moveRight(delta int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pager) handleScrolledUp() {
|
||||
p.Following = false
|
||||
}
|
||||
|
||||
func (p *Pager) handleScrolledDown() {
|
||||
p.Following = p.isScrolledToEnd()
|
||||
}
|
||||
|
||||
func (p *Pager) onKey(keyCode twin.KeyCode) {
|
||||
if p.mode == _Searching {
|
||||
p.onSearchKey(keyCode)
|
||||
@ -234,10 +249,12 @@ func (p *Pager) onKey(keyCode twin.KeyCode) {
|
||||
case twin.KeyUp:
|
||||
// Clipping is done in _Redraw()
|
||||
p.scrollPosition = p.scrollPosition.PreviousLine(1)
|
||||
p.handleScrolledUp()
|
||||
|
||||
case twin.KeyDown, twin.KeyEnter:
|
||||
// Clipping is done in _Redraw()
|
||||
p.scrollPosition = p.scrollPosition.NextLine(1)
|
||||
p.handleScrolledDown()
|
||||
|
||||
case twin.KeyRight:
|
||||
p.moveRight(16)
|
||||
@ -247,17 +264,20 @@ func (p *Pager) onKey(keyCode twin.KeyCode) {
|
||||
|
||||
case twin.KeyHome:
|
||||
p.scrollPosition = newScrollPosition("Pager scroll position")
|
||||
p.handleScrolledUp()
|
||||
|
||||
case twin.KeyEnd:
|
||||
p.scrollToEnd()
|
||||
|
||||
case twin.KeyPgDown:
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.NextLine(height - 1)
|
||||
|
||||
case twin.KeyPgUp:
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.PreviousLine(height - 1)
|
||||
p.handleScrolledUp()
|
||||
|
||||
case twin.KeyPgDown:
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.NextLine(height - 1)
|
||||
p.handleScrolledDown()
|
||||
|
||||
default:
|
||||
log.Debugf("Unhandled key event %v", keyCode)
|
||||
@ -287,10 +307,12 @@ func (p *Pager) onRune(char rune) {
|
||||
reader: p.reader,
|
||||
scrollPosition: p.scrollPosition,
|
||||
leftColumnZeroBased: p.leftColumnZeroBased,
|
||||
following: p.Following,
|
||||
}
|
||||
p.reader = _HelpReader
|
||||
p.scrollPosition = newScrollPosition("Pager scroll position")
|
||||
p.leftColumnZeroBased = 0
|
||||
p.Following = false
|
||||
p.isShowingHelp = true
|
||||
}
|
||||
|
||||
@ -300,10 +322,12 @@ func (p *Pager) onRune(char rune) {
|
||||
case 'k', 'y':
|
||||
// Clipping is done in _Redraw()
|
||||
p.scrollPosition = p.scrollPosition.PreviousLine(1)
|
||||
p.handleScrolledUp()
|
||||
|
||||
case 'j', 'e':
|
||||
// Clipping is done in _Redraw()
|
||||
p.scrollPosition = p.scrollPosition.NextLine(1)
|
||||
p.handleScrolledDown()
|
||||
|
||||
case 'l':
|
||||
// vim right
|
||||
@ -315,6 +339,7 @@ func (p *Pager) onRune(char rune) {
|
||||
|
||||
case '<':
|
||||
p.scrollPosition = newScrollPosition("Pager scroll position")
|
||||
p.handleScrolledUp()
|
||||
|
||||
case '>', 'G':
|
||||
p.scrollToEnd()
|
||||
@ -322,22 +347,26 @@ func (p *Pager) onRune(char rune) {
|
||||
case 'f', ' ':
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.NextLine(height - 1)
|
||||
p.handleScrolledDown()
|
||||
|
||||
case 'b':
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.PreviousLine(height - 1)
|
||||
p.handleScrolledUp()
|
||||
|
||||
// '\x15' = CTRL-u, should work like just 'u'.
|
||||
// Ref: https://github.com/walles/moar/issues/90
|
||||
case 'u', '\x15':
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.PreviousLine(height / 2)
|
||||
p.handleScrolledUp()
|
||||
|
||||
// '\x04' = CTRL-d, should work like just 'd'.
|
||||
// Ref: https://github.com/walles/moar/issues/90
|
||||
case 'd', '\x04':
|
||||
_, height := p.screen.Size()
|
||||
p.scrollPosition = p.scrollPosition.NextLine(height / 2)
|
||||
p.handleScrolledDown()
|
||||
|
||||
case '/':
|
||||
p.mode = _Searching
|
||||
@ -458,8 +487,9 @@ func (p *Pager) StartPaging(screen twin.Screen) {
|
||||
// We'll be implicitly redrawn just by taking another lap in the loop
|
||||
|
||||
case eventMoreLinesAvailable:
|
||||
// Doing nothing here is fine; screen will be refreshed on the next
|
||||
// iteration of the main loop.
|
||||
if p.mode.isViewing() && p.Following {
|
||||
p.scrollToEnd()
|
||||
}
|
||||
|
||||
case eventSpinnerUpdate:
|
||||
spinner = event.spinner
|
||||
|
@ -277,6 +277,8 @@ func (p *Pager) scrollToEnd() {
|
||||
// Scroll down enough. We know for sure the last line won't wrap into more
|
||||
// lines than the number of characters it contains.
|
||||
p.scrollPosition.internalDontTouch.deltaScreenLines = len(lastInputLine.raw)
|
||||
|
||||
p.Following = true
|
||||
}
|
||||
|
||||
// Can be either because Pager.scrollToEnd() was just called or because the user
|
||||
|
@ -115,6 +115,9 @@ func (p *Pager) scrollToNextSearchHit() {
|
||||
return
|
||||
}
|
||||
p.scrollPosition = *firstHitPosition
|
||||
|
||||
// Don't let any search hit scroll out of sight
|
||||
p.Following = false
|
||||
}
|
||||
|
||||
func (p *Pager) scrollToPreviousSearchHit() {
|
||||
@ -150,6 +153,9 @@ func (p *Pager) scrollToPreviousSearchHit() {
|
||||
return
|
||||
}
|
||||
p.scrollPosition = *firstHitPosition
|
||||
|
||||
// Don't let any search hit scroll out of sight
|
||||
p.Following = false
|
||||
}
|
||||
|
||||
func (p *Pager) updateSearchPattern() {
|
||||
|
Loading…
Reference in New Issue
Block a user