diff --git a/main.go b/main.go index 71226939..e7860739 100644 --- a/main.go +++ b/main.go @@ -361,6 +361,9 @@ func init() { rootCmd.PersistentFlags().IntP("section-start", "", 0, "section start position") _ = viper.BindPFlag("general.SectionStartPosition", rootCmd.PersistentFlags().Lookup("section-start")) + rootCmd.PersistentFlags().BoolP("section-header", "", false, "enable section-delimiter line as Header") + _ = viper.BindPFlag("general.SectionHeader", rootCmd.PersistentFlags().Lookup("section-header")) + rootCmd.PersistentFlags().BoolP("follow-mode", "f", false, "follow mode") _ = viper.BindPFlag("general.FollowMode", rootCmd.PersistentFlags().Lookup("follow-mode")) diff --git a/oviewer/document.go b/oviewer/document.go index c991e1b3..d00cd9aa 100644 --- a/oviewer/document.go +++ b/oviewer/document.go @@ -87,6 +87,8 @@ type Document struct { // columnCursor is the number of columns. columnCursor int + // sectionHeaderNum is the number of lines in the section header. + sectionHeaderNum int // jumpTargetNum is the display position of search results. jumpTargetNum int // jumpTargetSection is the display position of search results. @@ -170,14 +172,12 @@ func NewDocument() (*Document, error) { ColumnDelimiter: "", TabWidth: 8, MarkStyleWidth: 1, - PlainMode: false, }, - ctlCh: make(chan controlSpecifier), - memoryLimit: 100, - seekable: true, - reopenable: true, - preventReload: false, - store: NewStore(), + ctlCh: make(chan controlSpecifier), + memoryLimit: 100, + seekable: true, + reopenable: true, + store: NewStore(), } if err := m.NewCache(); err != nil { return nil, err @@ -458,6 +458,10 @@ func (m *Document) setDelimiter(delm string) { func (m *Document) setSectionDelimiter(delm string) { m.SectionDelimiter = delm m.SectionDelimiterReg = regexpCompile(delm, true) + m.sectionHeaderNum = 0 + if m.SectionHeader && m.SectionDelimiter != "" { + m.sectionHeaderNum = 1 + } } // setMultiColorWords set multiple strings to highlight with multiple colors. diff --git a/oviewer/draw.go b/oviewer/draw.go index 5943fec2..d583c4eb 100644 --- a/oviewer/draw.go +++ b/oviewer/draw.go @@ -35,6 +35,10 @@ func (root *Root) draw() { } lN = m.topLN + lN + + // Section header + lN = root.sectionHeader(lN) + // Body lX, lN = root.drawBody(lX, lN) @@ -102,6 +106,35 @@ func (root *Root) drawHeader() int { return lN } +// sectionHeader draws section header. +func (root *Root) sectionHeader(lN int) int { + m := root.Doc + if !m.SectionHeader || m.SectionDelimiter == "" { + return lN + } + log.Println(m.SectionHeader) + sectionLN, err := root.Doc.prevSection(lN) + if err != nil { + log.Println(err) + return lN + } + + if m.Header > sectionLN { + return lN + } + + if lN > sectionLN { + sx, sn := 0, sectionLN + line, _ := m.getLineC(sn, m.TabWidth) + for y := m.headerLen; sn <= sectionLN; y++ { + sx, sn = root.drawLine(y, sx, sn, line.lc) + root.sectionLineHighlight(y, line.str) + m.headerLen += 1 + } + } + return lN +} + // drawBody draws body. func (root *Root) drawBody(lX int, lN int) (int, int) { m := root.Doc diff --git a/oviewer/input_savebuffer.go b/oviewer/input_savebuffer.go index 975002a5..540203a6 100644 --- a/oviewer/input_savebuffer.go +++ b/oviewer/input_savebuffer.go @@ -5,7 +5,7 @@ import "github.com/gdamore/tcell/v2" // setSaveBuffer is a wrapper to move to setSaveBufferMode. func (root *Root) setSaveBuffer() { if root.Doc.seekable { - root.setMessage("Saving regular files is not supported") + root.setMessage("Does not support saving regular files") return } root.setSaveBufferMode() diff --git a/oviewer/move.go b/oviewer/move.go index f53f0b73..12b81610 100644 --- a/oviewer/move.go +++ b/oviewer/move.go @@ -260,6 +260,10 @@ func (m *Document) searchGoSection(lN int, x int) { if err != nil { sN = 0 } + if m.SectionHeader { + sN = (sN - m.firstLine() + m.sectionHeaderNum) + m.SectionStartPosition + sN = max(sN, m.BufStartNum()) + } y := 0 if sN < m.firstLine() { // topLN is negative if the section is less than header + skip. diff --git a/oviewer/move_vertical.go b/oviewer/move_vertical.go index c91226dd..18e8ee35 100644 --- a/oviewer/move_vertical.go +++ b/oviewer/move_vertical.go @@ -256,7 +256,7 @@ func (m *Document) moveNextSection() error { m.movePgDn() return ErrNoDelimiter } - m.moveLine((lN - m.firstLine()) + m.SectionStartPosition) + m.moveLine((lN - m.firstLine() + m.sectionHeaderNum) + m.SectionStartPosition) return nil } @@ -266,11 +266,7 @@ func (m *Document) nextSection(n int) (int, error) { searcher := NewSearcher(m.SectionDelimiter, m.SectionDelimiterReg, true, true) ctx := context.Background() defer ctx.Done() - n, err := m.SearchLine(ctx, searcher, lN) - if err != nil { - return n, err - } - return n, nil + return m.SearchLine(ctx, searcher, lN) } // movePrevSection moves to the previous section. @@ -281,12 +277,14 @@ func (m *Document) movePrevSection() error { return nil } - lN, err := m.prevSection(m.topLN + m.firstLine()) + lN, err := m.prevSection(m.topLN + m.firstLine() - m.sectionHeaderNum) if err != nil { m.moveTop() return err } - m.moveLine(lN) + lN = (lN - m.firstLine()) + m.SectionStartPosition + lN = max(lN, m.BufStartNum()) + m.moveLine(lN + m.sectionHeaderNum) return nil } @@ -296,13 +294,7 @@ func (m *Document) prevSection(n int) (int, error) { searcher := NewSearcher(m.SectionDelimiter, m.SectionDelimiterReg, true, true) ctx := context.Background() defer ctx.Done() - n, err := m.BackSearchLine(ctx, searcher, lN) - if err != nil { - return 0, err - } - n = (n - m.firstLine()) + m.SectionStartPosition - n = max(n, m.BufStartNum()) - return n, nil + return m.BackSearchLine(ctx, searcher, lN) } // moveLastSection moves to the last section. diff --git a/oviewer/oviewer.go b/oviewer/oviewer.go index 91cc65ff..f1a7abe1 100644 --- a/oviewer/oviewer.go +++ b/oviewer/oviewer.go @@ -151,6 +151,8 @@ type general struct { FollowName bool // PlainMode is whether to enable the original character decoration. PlainMode bool + // SectionHeader is whether to display the section header. + SectionHeader bool } // OVPromptConfigNormal is the normal prompt setting. diff --git a/oviewer/search.go b/oviewer/search.go index bd859bec..0579ff8b 100644 --- a/oviewer/search.go +++ b/oviewer/search.go @@ -288,6 +288,9 @@ func (root *Root) setSearcher(word string, caseSensitive bool) Searcher { // searchMove searches forward/backward and moves to the nearest matching line. func (root *Root) searchMove(ctx context.Context, forward bool, lN int, searcher Searcher) { if searcher == nil { + if root.Doc.jumpTargetSection { + root.Doc.jumpTargetNum = 0 + } return } word := root.searcher.String()