Skip to content

Commit

Permalink
Separate run from prepareRun
Browse files Browse the repository at this point in the history
Separate run from prepareRun to make it testable.
Changed main.go to set only the QuitSmallFilter flag.
  • Loading branch information
noborus committed Jul 17, 2024
1 parent 7e1506e commit 5686801
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 56 deletions.
5 changes: 1 addition & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,7 @@ func RunOviewer(args []string) error {
}

if ov.QuitSmall && (filter != "" || nonMatchFilter != "") {
// UpdateInterval(50 * time.Millisecond) * 10 = 500ms.
// Quit if it fits on the screen within 500ms.
ov.QuitSmallCount = 10
ov.QuitSmall = false
ov.QuitSmallFilter = true
}

if err := ov.Run(); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions oviewer/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ func (root *Root) everyUpdate(ctx context.Context) {
root.watchControl()
}

if root.QuitSmallCount > 0 {
root.QuitSmallCount--
if root.Doc.documentType == DocFilter && root.docSmall() {
if root.quitSmallCountDown > 0 {
root.quitSmallCountDown--
if root.DocumentLen() == 2 && root.Doc.documentType == DocFilter && root.docSmall() {
root.WriteQuit(ctx)
}
}
Expand Down
128 changes: 79 additions & 49 deletions oviewer/oviewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ type Root struct {
// minStartX is the minimum start position of x.
minStartX int

// quitSmallCountDown is the countdown to quit if the output fits on one screen.
quitSmallCountDown int

// mu controls the RWMutex.
mu sync.RWMutex

Expand Down Expand Up @@ -261,8 +264,8 @@ type Config struct {
IsWriteOriginal bool
// QuitSmall Quit if the output fits on one screen.
QuitSmall bool
// QuitSmallCount is the number of times to check if the output fits on one screen.
QuitSmallCount int
// QuitSmallFilter Quit if the output fits on one screen and the filter is applied.
QuitSmallFilter bool
// CaseSensitive is case-sensitive if true.
CaseSensitive bool
// SmartCaseSensitive is lowercase search ignores case, if true.
Expand Down Expand Up @@ -347,6 +350,10 @@ var (
// Does not track mouse movements except when dragging.
const MouseFlags = tcell.MouseDragEvents

// QuitSmallCountDown is the countdown to quit if the output fits on one screen.
// UpdateInterval(50 * time.Millisecond) * 10 = 500ms.
const QuitSmallCountDown = 10

// MaxWriteLog is the maximum number of lines to output to the log
// when the debug flag is enabled.
const MaxWriteLog int = 10
Expand Down Expand Up @@ -616,67 +623,28 @@ func (root *Root) Run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()

defer root.Close()

watcher, err := fsnotify.NewWatcher()
if err != nil {
return fmt.Errorf("failed to create watcher: %w", err)
}
defer watcher.Close()
root.SetWatcher(watcher)

// Do not set the key bindings in NewOviewer
// because it is done after loading the config.
keyBind, err := root.setKeyConfig(ctx)
if err != nil {
return err
}
help, err := NewHelp(keyBind)
if err != nil {
if err := root.prepareRun(ctx); err != nil {
return err
}
root.helpDoc = help

if !root.Config.DisableMouse {
root.Screen.EnableMouse(MouseFlags)
}

root.optimizedMan()
if root.General.Caption != "" {
root.Doc.Caption = root.General.Caption
}

root.setModeConfig()
for n, doc := range root.DocList {
doc.general = root.Config.General
doc.regexpCompile()

if doc.FollowName {
doc.FollowMode = true
}
if doc.ColumnWidth {
doc.ColumnMode = true
}
w := ""
if doc.general.WatchInterval > 0 {
doc.watchMode()
w = "(watch)"
}
log.Printf("open [%d]%s%s", n, doc.FileName, w)
}

root.ViewSync(ctx)
// Exit if fits on screen
// Quit if fits on screen.
if root.QuitSmall && root.DocumentLen() == 1 && root.docSmall() {
root.IsWriteOriginal = true
return nil
}

sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT)

sigSuspend := registerSIGTSTP()

quitChan := make(chan struct{})

go func() {
Expand All @@ -699,8 +667,45 @@ func (root *Root) Run() error {
}
}

// optimizedMan optimizes execution with the Man command.
func (root *Root) optimizedMan() {
// prepareRun prepares to run the oviewer.
func (root *Root) prepareRun(ctx context.Context) error {
// Do not set the key bindings in NewOviewer
// because it is done after loading the config.
keyBind, err := root.setKeyConfig(ctx)
if err != nil {
return err
}
help, err := NewHelp(keyBind)
if err != nil {
return err
}
root.helpDoc = help

if !root.Config.DisableMouse {
root.Screen.EnableMouse(MouseFlags)
}

root.setCaption()

root.setViewModeConfig()
root.prepareAllDocuments()
// Quit by filter result. This is evaluated lazily.
if root.QuitSmallFilter {
root.quitSmallCountDown = QuitSmallCountDown
root.QuitSmall = false
}
root.ViewSync(ctx)
return nil
}

// setCaption sets the caption.
// optimizes execution with the Man command.
func (root *Root) setCaption() {
if root.General.Caption != "" {
root.Doc.Caption = root.General.Caption
return
}

// Call from man command.
manPN := os.Getenv("MAN_PN")
if len(manPN) == 0 {
Expand All @@ -710,8 +715,8 @@ func (root *Root) optimizedMan() {
root.Doc.Caption = manPN
}

// setModeConfig sets mode config.
func (root *Root) setModeConfig() {
// setViewModeConfig sets view mode config.
func (root *Root) setViewModeConfig() {
list := make([]string, 0, len(root.Config.Mode)+1)
list = append(list, "general")
for name := range root.Config.Mode {
Expand All @@ -720,6 +725,27 @@ func (root *Root) setModeConfig() {
root.input.ModeCandidate.list = list
}

// prepareAllDocuments prepares all documents.
func (root *Root) prepareAllDocuments() {
for n, doc := range root.DocList {
doc.general = root.Config.General
doc.regexpCompile()

if doc.FollowName {
doc.FollowMode = true
}
if doc.ColumnWidth {
doc.ColumnMode = true
}
w := ""
if doc.general.WatchInterval > 0 {
doc.watchMode()
w = "(watch)"
}
log.Printf("open [%d]%s%s", n, doc.FileName, w)
}
}

// Close closes the oviewer.
func (root *Root) Close() {
root.Screen.Fini()
Expand Down Expand Up @@ -995,10 +1021,14 @@ func (root *Root) writeOriginal(output io.Writer) {

// WriteLog write to the log terminal.
func (root *Root) WriteLog() {
root.writeLog(os.Stdout)
}

func (root *Root) writeLog(w io.Writer) {
m := root.logDoc
start := max(0, m.BufEndNum()-MaxWriteLog)
end := m.BufEndNum()
if err := m.Export(os.Stdout, start, end); err != nil {
if err := m.Export(w, start, end); err != nil {
log.Println(err)
}
}
Expand Down
135 changes: 135 additions & 0 deletions oviewer/oviewer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"io"
"os"
"path/filepath"
"reflect"
"testing"
Expand Down Expand Up @@ -495,3 +496,137 @@ func Test_mergeGeneral(t *testing.T) {
})
}
}

func TestRoot_setCaption(t *testing.T) {
type fields struct {
caption string
manpn string
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "testnil",
fields: fields{
caption: "",
manpn: "",
},
want: "",
},
{
name: "test1",
fields: fields{
caption: "test",
manpn: "",
},
want: "test",
},
{
name: "testMan",
fields: fields{
caption: "",
manpn: "man",
},
want: "man",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
os.Setenv("MAN_PN", tt.fields.manpn)
root := rootHelper(t)
root.General.Caption = tt.fields.caption
root.setCaption()
if got := root.Doc.Caption; got != tt.want {
t.Errorf("Root.setCaption() = %v, want %v", got, "test")
}
os.Setenv("MAN_PN", "")
})
}
}

func TestRoot_setViewModeConfig(t *testing.T) {
type fields struct {
viewMode map[string]general
}
tests := []struct {
name string
fields fields
wantList []string
}{
{
name: "test1",
fields: fields{
viewMode: map[string]general{
"view1": {},
},
},
wantList: []string{"general", "view1"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
root := rootHelper(t)
root.Config.Mode = tt.fields.viewMode
root.setViewModeConfig()
if !reflect.DeepEqual(root.input.ModeCandidate.list, tt.wantList) {
t.Errorf("Root.setViewModeConfig() = %v, want %v", root.input.ModeCandidate.list, tt.wantList)
}
})
}
}

func TestRoot_prepareRun(t *testing.T) {
type fields struct {
QuitSmall bool
QuitSmallFilter bool
}
tests := []struct {
name string
fields fields
wantErr bool
wantQuit bool
}{
{
name: "test1",
fields: fields{
QuitSmall: false,
QuitSmallFilter: false,
},
wantErr: false,
wantQuit: false,
},
{
name: "test2",
fields: fields{
QuitSmall: true,
QuitSmallFilter: true,
},
wantErr: false,
wantQuit: false,
},
{
name: "test2",
fields: fields{
QuitSmall: true,
QuitSmallFilter: false,
},
wantErr: false,
wantQuit: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
root := rootHelper(t)
root.QuitSmall = tt.fields.QuitSmall
root.QuitSmallFilter = tt.fields.QuitSmallFilter
if err := root.prepareRun(context.Background()); (err != nil) != tt.wantErr {
t.Errorf("Root.prepareRun() error = %v, wantErr %v", err, tt.wantErr)
}
if got := root.QuitSmall; got != tt.wantQuit {
t.Errorf("Root.prepareRun() = %v, want %v", got, tt.wantQuit)
}
})
}
}

0 comments on commit 5686801

Please sign in to comment.