Skip to content

Commit

Permalink
Added line number mode. (#8)
Browse files Browse the repository at this point in the history
* Added line number mode.

The command line option is "-n" for line number mode.
The keyboard shortcut key is "G".

Change the specifications to apply the background color alternately.
Add a background color from the beginning to the end of the screen.
It also adds a background color to blank lines.
  • Loading branch information
noborus authored May 10, 2020
1 parent 93327b0 commit d388725
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 65 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OV - Oviewer
# ov - Oviewer

[![Actions Status](https://github.com/noborus/ov/workflows/Go/badge.svg)](https://github.com/noborus/ov/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/noborus/ov)](https://goreportcard.com/report/github.com/noborus/ov)
Expand Down Expand Up @@ -137,6 +137,8 @@ Flags:

![header](https://raw.githubusercontent.com/noborus/ov/master/docs/ov-header.gif)

### line number (<kbd>G</kbd>)

### psql

Set environment variable `PSQL_PAGER`(PostgreSQL 11 or later).
Expand Down Expand Up @@ -193,6 +195,7 @@ pager=ov -w=f -H3 -F -C -d "|"
* <kbd>w</kbd> - wrap/nowrap toggle
* <kbd>c</kbd> - column mode enable/disable toggle
* <kbd>C</kbd> - color to alternate rows enable/disable toggle
* <kbd>G</kbd> - line number toogle

### Input Mode

Expand Down
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ require (
github.com/spf13/cobra v1.0.0
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.3
github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.5.1 // indirect
github.com/ulikunitz/xz v0.5.7
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
golang.org/x/text v0.3.2 // indirect
gopkg.in/ini.v1 v1.55.0 // indirect
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f // indirect
gopkg.in/ini.v1 v1.56.0 // indirect
)
165 changes: 155 additions & 10 deletions go.sum

Large diffs are not rendered by default.

99 changes: 54 additions & 45 deletions internal/oviewer/draw.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,7 @@ func (root *Root) Draw() {
return
}

space := Content{
mainc: ' ',
combc: nil,
width: 1,
style: tcell.StyleDefault.Normal(),
}
for y := 0; y < m.vHight; y++ {
for x := 0; x < m.vWidth; x++ {
screen.SetContent(x, y, space.mainc, space.combc, space.style)
}
}
root.ResetScreen()

bottom := root.bottomLineNum(m.BufEndNum()) - root.Header
if m.lineNum > bottom+1 {
Expand All @@ -43,11 +33,10 @@ func (root *Root) Draw() {
searchWord = root.input
}

// Header
lY := 0
lX := 0
hy := 0
for lY < root.Header {
// Header
for hy := 0; lY < root.Header; hy++ {
line := m.GetLine(lY)
lc, err := m.lineToContents(lY, root.TabWidth)
if err != nil {
Expand All @@ -68,7 +57,6 @@ func (root *Root) Draw() {
} else {
lX, lY = root.noWrapContents(hy, m.x, lY, contents)
}
hy++
}

// Body
Expand All @@ -77,26 +65,16 @@ func (root *Root) Draw() {
lc, err := m.lineToContents(m.lineNum+lY, root.TabWidth)
if err != nil {
// EOF
root.Screen.SetContent(0, y, '~', nil, tcell.StyleDefault.Foreground(tcell.ColorGray))
screen.SetContent(0, y, '~', nil, tcell.StyleDefault.Foreground(tcell.ColorGray))
continue
}

line := m.GetLine(m.lineNum + lY)

// alternate background color
if root.AlternateRows {
bgColor := normalBgColor
if (root.Model.lineNum+lY)%2 == 1 {
bgColor = root.ColorAlternate
}
for n := range lc.contents {
lc.contents[n].style = lc.contents[n].style.Background(bgColor)
}
}

for n := range lc.contents {
lc.contents[n].style = lc.contents[n].style.Reverse(false)
}

// search highlight
if searchWord != "" {
poss := searchPosition(line, searchWord, root.CaseSensitive)
Expand All @@ -111,11 +89,31 @@ func (root *Root) Draw() {
reverseContents(lc, r)
}

// line number mode
if root.LineNumMode {
lineNum := strToContents(fmt.Sprintf("%*d", root.startPos-1, root.Model.lineNum+lY-root.Header+1), root.TabWidth)
root.setContentString(0, y, lineNum, tcell.StyleDefault.Bold(true))
}

var nextY int
if root.WrapMode {
lX, lY = root.wrapContents(y, lX, lY, lc.contents)
lX, nextY = root.wrapContents(y, lX, lY, lc.contents)
} else {
lX, lY = root.noWrapContents(y, m.x, lY, lc.contents)
lX, nextY = root.noWrapContents(y, m.x, lY, lc.contents)
}

// alternate background color
if root.AlternateRows {
bgColor := normalBgColor
if (m.lineNum+lY)%2 == 1 {
bgColor = root.ColorAlternate
}
for x := 0; x < m.vWidth; x++ {
r, c, style, _ := root.GetContent(x, y)
root.SetContent(x, y, r, c, style.Background(bgColor))
}
}
lY = nextY
}

if lY > 0 {
Expand All @@ -128,51 +126,62 @@ func (root *Root) Draw() {
root.Show()
}

// ResetScreen initializes the screen with a blank
func (root *Root) ResetScreen() {
space := Content{
mainc: ' ',
combc: nil,
width: 1,
style: tcell.StyleDefault.Normal(),
}
for y := 0; y < root.Model.vHight; y++ {
for x := 0; x < root.Model.vWidth; x++ {
root.Screen.SetContent(x, y, space.mainc, space.combc, space.style)
}
}
}

// reverses the specified range.
func reverseContents(lc lineContents, r rangePos) {
for n := lc.cMap[r.start]; n < lc.cMap[r.end]; n++ {
lc.contents[n].style = lc.contents[n].style.Reverse(true)
}
}

// wrapContents returns the wrapped content.
func (root *Root) wrapContents(y int, lX int, lY int, contents []Content) (rX int, rY int) {
wX := 0
for {
if lX+wX >= len(contents) {
// wrapContents wraps and draws the contents and returns the next drawing position.
func (root *Root) wrapContents(y int, lX int, lY int, contents []Content) (int, int) {
for x := 0; ; x++ {
if lX+x >= len(contents) {
// EOL
lX = 0
lY++
break
}
content := contents[lX+wX]
if wX+content.width > root.Model.vWidth {
content := contents[lX+x]
if x+content.width+root.startPos > root.Model.vWidth {
// next line
lX += wX
lX += x
break
}
style := content.style
root.Screen.SetContent(wX, y, content.mainc, content.combc, style)
wX++
root.Screen.SetContent(x+root.startPos, y, content.mainc, content.combc, content.style)
}
return lX, lY
}

// returns unwrapped contents.
func (root *Root) noWrapContents(y int, lX int, lY int, contents []Content) (rX int, rY int) {
// noWrapContents draws contents without wrapping and returns the next drawing position.
func (root *Root) noWrapContents(y int, lX int, lY int, contents []Content) (int, int) {
if lX < root.minStartPos {
lX = root.minStartPos
}
for x := 0; x < root.Model.vWidth; x++ {
for x := 0; x+root.startPos < root.Model.vWidth; x++ {
if lX+x < 0 {
continue
}
if lX+x >= len(contents) {
break
}
content := contents[lX+x]
style := content.style
root.Screen.SetContent(x, y, content.mainc, content.combc, style)
root.Screen.SetContent(x+root.startPos, y, content.mainc, content.combc, content.style)
}
lY++
return lX, lY
Expand Down
2 changes: 2 additions & 0 deletions internal/oviewer/keybind.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ func (root *Root) defaultEvent(ev *tcell.EventKey) bool {
root.input = ""
root.setMode(goline)
return true
case 'G':
root.toggleLineNumMode()
case 'H':
root.input = ""
root.setMode(header)
Expand Down
6 changes: 3 additions & 3 deletions internal/oviewer/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ func (m *Model) GetContents(lineNum int, tabWidth int) []Content {
// NewCache creates a new cache.
func (m *Model) NewCache() error {
cache, err := ristretto.NewCache(&ristretto.Config{
NumCounters: 1e7, // number of keys to track frequency of (10M).
MaxCost: 1 << 30, // maximum cost of cache (1GB).
BufferItems: 64, // number of keys per Get buffer.
NumCounters: 10000, // number of keys to track frequency of (10M).
MaxCost: 1000, // maximum cost of cache (1GB).
BufferItems: 64, // number of keys per Get buffer.
})
if err != nil {
return err
Expand Down
27 changes: 26 additions & 1 deletion internal/oviewer/oviewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ type Root struct {
AlternateRows bool
ColumnMode bool
ColumnDelimiter string
LineNumMode bool

Model *Model
wrapHeaderLen int
startPos int
bottomPos int
statusPos int
fileName string
Expand Down Expand Up @@ -69,6 +71,7 @@ func New() *Root {
root.ColorAlternate = tcell.ColorGray
root.ColumnDelimiter = ""
root.columnNum = 0
root.startPos = 0
return root
}

Expand Down Expand Up @@ -141,6 +144,15 @@ func (root *Root) toggleAlternateRows() {
}
}

func (root *Root) toggleLineNumMode() {
if root.LineNumMode {
root.LineNumMode = false
} else {
root.LineNumMode = true
}
root.updateEndNum()
}

func (root *Root) setMode(mode Mode) {
root.mode = mode
}
Expand Down Expand Up @@ -203,6 +215,7 @@ func (root *Root) Resize() {

// Sync redraws the whole thing.
func (root *Root) Sync() {
root.PreparelineNum()
root.PrepareView()
root.Draw()
}
Expand All @@ -220,6 +233,18 @@ loop:
timer.Stop()
}

func (root *Root) PreparelineNum() {
root.startPos = 0
if root.LineNumMode {
root.startPos = len(fmt.Sprintf("%d", root.Model.BufEndNum())) + 1
}
}

func (root *Root) updateEndNum() {
root.PreparelineNum()
root.statusDraw()
}

// main is manages and executes events in the main routine.
func (root *Root) main() {
screen := root.Screen
Expand All @@ -230,7 +255,7 @@ loop:
ev := screen.PollEvent()
switch ev := ev.(type) {
case *eventTimer:
root.statusDraw()
root.updateEndNum()
case *eventAppQuit:
break loop
case *tcell.EventKey:
Expand Down
8 changes: 7 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

var (
// Version represents the version
Version string = "v0.1.1"
Version string = "dev"
// Revision set "git rev-parse --short HEAD"
Revision string = "HEAD"
)
Expand Down Expand Up @@ -43,6 +43,8 @@ type Config struct {
ColumnMode bool
// Column Delimiter
ColumnDelimiter string
// Line Number
LineNumMode bool
// Debug is enable debug display.
Debug bool

Expand Down Expand Up @@ -83,6 +85,7 @@ It supports various compressed files(gzip, bzip2, zstd, lz4, and xz).
root.CaseSensitive = config.CaseSensitive
root.AlternateRows = config.AlternateRows
root.ColumnMode = config.ColumnMode
root.LineNumMode = config.LineNumMode
root.ColumnDelimiter = strings.ReplaceAll(config.ColumnDelimiter, "\\t", "\t")
if config.ColorAlternate != "" {
color := tcell.GetColor(config.ColorAlternate)
Expand Down Expand Up @@ -132,6 +135,9 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&config.ColumnDelimiter, "column-delimiter", "d", ",", "column delimiter")
_ = viper.BindPFlag("ColumnDelimiter", rootCmd.PersistentFlags().Lookup("column-delimiter"))

rootCmd.PersistentFlags().BoolVarP(&config.LineNumMode, "line-number", "n", false, "line number")
_ = viper.BindPFlag("LineNumMode", rootCmd.PersistentFlags().Lookup("line-number"))

rootCmd.PersistentFlags().BoolVarP(&config.Debug, "debug", "", false, "debug mode")
}

Expand Down

0 comments on commit d388725

Please sign in to comment.