diff --git a/oviewer/control.go b/oviewer/control.go index ea9de057..e318506e 100644 --- a/oviewer/control.go +++ b/oviewer/control.go @@ -237,6 +237,17 @@ func (m *Document) requestLoad(chunkNum int) { }() } +// requestLoadSync sends instructions to load chunks into memory. +func (m *Document) requestLoadSync(chunkNum int) bool { + sc := controlSpecifier{ + request: requestLoad, + chunkNum: chunkNum, + done: make(chan bool), + } + m.ctlCh <- sc + return <-sc.done +} + // requestSearch sends instructions to load chunks into memory. func (m *Document) requestSearch(chunkNum int, searcher Searcher) bool { sc := controlSpecifier{ diff --git a/oviewer/document_test.go b/oviewer/document_test.go index bc441579..a606c59c 100644 --- a/oviewer/document_test.go +++ b/oviewer/document_test.go @@ -14,7 +14,7 @@ func docHelper(t *testing.T, str string) *Document { if err != nil { t.Fatal(err) } - if err := m.ReadAll(bytes.NewBufferString(str)); err != nil { + if err := m.ControlReader(bytes.NewBufferString(str), nil); err != nil { t.Fatal(err) } for !m.BufEOF() { diff --git a/oviewer/draw.go b/oviewer/draw.go index 92fadd32..79f1f482 100644 --- a/oviewer/draw.go +++ b/oviewer/draw.go @@ -312,8 +312,8 @@ func (root *Root) applyMarkStyle(lN int, y int, width int) { // applyStyleToRange applies the style from the start to the end of the physical line. func (root *Root) applyStyleToRange(y int, s OVStyle, start int, end int) { for x := start; x < end; x++ { - r, c, ts, _ := root.GetContent(x, y) - root.Screen.SetContent(x, y, r, c, applyStyle(ts, s)) + mainc, combc, style, _ := root.GetContent(x, y) + root.Screen.SetContent(x, y, mainc, combc, applyStyle(style, s)) } } diff --git a/oviewer/event.go b/oviewer/event.go index 460eafb7..e3e3a552 100644 --- a/oviewer/event.go +++ b/oviewer/event.go @@ -141,7 +141,9 @@ func (root *Root) everyUpdate(ctx context.Context) { // This process is executed when temporary read is switched to normal read. if n := atomic.SwapInt32(&root.Doc.tmpLN, 0); n > 0 { tmpN := int(n) - root.Doc.topLN - root.Doc.topLN = root.Doc.BufEndNum() - tmpN + if tmpN > 0 { + root.Doc.topLN = root.Doc.BufEndNum() - tmpN + } } root.Doc.width = root.scr.vWidth - root.scr.startX diff --git a/oviewer/example_test.go b/oviewer/example_test.go index 24da5f15..ee2cd65a 100644 --- a/oviewer/example_test.go +++ b/oviewer/example_test.go @@ -35,7 +35,7 @@ func ExampleNewOviewer() { panic(err) } s := "Hello, World!" - if err := doc.ReadAll(bytes.NewBufferString(s)); err != nil { + if err := doc.ControlReader(bytes.NewBufferString(s), nil); err != nil { panic(err) } @@ -65,7 +65,7 @@ func ExampleSearch() { panic(err) } s := "Hello, World!" - if err := doc.ReadAll(bytes.NewBufferString(s)); err != nil { + if err := doc.ControlReader(bytes.NewBufferString(s), nil); err != nil { panic(err) } diff --git a/oviewer/move_vertical.go b/oviewer/move_vertical.go index f871bc06..a79b9d13 100644 --- a/oviewer/move_vertical.go +++ b/oviewer/move_vertical.go @@ -36,7 +36,11 @@ func (m *Document) moveBottom() { m.requestBottom() } - m.topLX, m.topLN = m.bottomLineNum(m.BufEndNum()-1, m.height-lastLineMargin) + lN := m.BufEndNum() - 1 + height := m.height - lastLineMargin + chunkNum, _ := chunkLineNum(lN - height) + m.requestLoadSync(chunkNum) + m.topLX, m.topLN = m.bottomLineNum(lN, height) } // Move to the nth wrapping line of the specified line. @@ -101,9 +105,9 @@ func (m *Document) limitMoveDown(lX int, lN int) { } } -// numOfWrap returns the number of wrap from lX and lY. -func (m *Document) numOfWrap(lX int, lY int) int { - listX := m.leftMostX(lY) +// numOfWrap returns the number of wrap from lX and lN. +func (m *Document) numOfWrap(lX int, lN int) int { + listX := m.leftMostX(lN) if len(listX) == 0 { return 0 } diff --git a/oviewer/reader.go b/oviewer/reader.go index b26d5ed0..ace46467 100644 --- a/oviewer/reader.go +++ b/oviewer/reader.go @@ -2,7 +2,6 @@ package oviewer import ( "bufio" - "context" "errors" "fmt" "io" @@ -404,72 +403,3 @@ func (m *Document) close() error { atomic.StoreInt32(&m.store.changed, 1) return nil } - -// ReadFile reads file. -// If the file name is empty, read from standard input. -// -// Deprecated: Use ControlFile instead. -func (m *Document) ReadFile(fileName string) error { - r, err := m.openFileReader(fileName) - if err != nil { - return err - } - return m.ReadAll(r) -} - -// ContinueReadAll continues to read even if it reaches EOF. -// -// Deprecated: Use ControlFile instead. -func (m *Document) ContinueReadAll(_ context.Context, r io.Reader) error { - return m.ReadAll(r) -} - -// ReadReader reads reader. -// A wrapper for ReadAll. -// -// Deprecated: Use ControlReader instead. -func (m *Document) ReadReader(r io.Reader) error { - return m.ReadAll(r) -} - -// ReadAll reads all from the reader. -// And store it in the lines of the Document. -// ReadAll needs to be notified on eofCh. -// -// Deprecated: Use ControlReader instead. -func (m *Document) ReadAll(r io.Reader) error { - reader := bufio.NewReader(r) - go func() { - if m.checkClose() { - return - } - - if err := m.readAll(reader); err != nil { - if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, os.ErrClosed) { - m.store.offset = m.store.size - atomic.StoreInt32(&m.store.eof, 1) - return - } - log.Printf("error: %v\n", err) - return - } - }() - return nil -} - -// readAll reads to the end. -// The read lines are stored in the lines of the Document. -func (m *Document) readAll(reader *bufio.Reader) error { - chunk := m.store.chunkForAdd(m.seekable, m.store.size) - start := len(chunk.lines) - for { - if err := m.store.readLines(chunk, reader, start, ChunkSize, true); err != nil { - return err - } - chunk = NewChunk(m.store.size) - m.store.mu.Lock() - m.store.chunks = append(m.store.chunks, chunk) - m.store.mu.Unlock() - start = 0 - } -} diff --git a/oviewer/reader_test.go b/oviewer/reader_test.go index e18fe063..0cb39627 100644 --- a/oviewer/reader_test.go +++ b/oviewer/reader_test.go @@ -3,98 +3,11 @@ package oviewer import ( "bufio" "bytes" - "io" "path/filepath" - "strings" "sync/atomic" "testing" ) -func TestDocument_ReadFile(t *testing.T) { - t.Parallel() - type args struct { - args string - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "testNoFile", - args: args{ - "noFile", - }, - wantErr: true, - }, - { - name: "testSTDIN", - args: args{ - "", - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - m, err := NewDocument() - if err != nil { - t.Fatal(err) - } - if err := m.ReadFile(tt.args.args); (err != nil) != tt.wantErr { - t.Errorf("Document.ReadFile() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestDocument_ReadAll(t *testing.T) { - t.Parallel() - type args struct { - r io.Reader - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "test1", - args: args{ - r: bytes.NewBufferString("foo\nbar\n"), - }, - wantErr: false, - }, - { - name: "testOverChunkSize", - args: args{ - r: bytes.NewBufferString(strings.Repeat("a\n", ChunkSize+1)), - }, - wantErr: false, - }, - { - name: "testLongLine", - args: args{ - r: bytes.NewBufferString(strings.Repeat("a", 4097)), - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - m, err := NewDocument() - if err != nil { - t.Fatal(err) - } - if err := m.ReadAll(tt.args.r); (err != nil) != tt.wantErr { - t.Errorf("Document.ReadAll() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - func TestDocument_reset(t *testing.T) { t.Parallel() type fields struct {