Merge branch 'text-find' of sloum/bombadillo into develop
This commit is contained in:
commit
b551138c75
11
bombadillo.1
11
bombadillo.1
|
@ -88,6 +88,13 @@ k
|
||||||
Scroll up a single line.
|
Scroll up a single line.
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
|
n
|
||||||
|
Jump to next found text item.
|
||||||
|
.TP
|
||||||
|
.B
|
||||||
|
Jump to previous found text item.
|
||||||
|
.TP
|
||||||
|
.B
|
||||||
q
|
q
|
||||||
Quit \fBbombadillo\fP.
|
Quit \fBbombadillo\fP.
|
||||||
.TP
|
.TP
|
||||||
|
@ -100,6 +107,10 @@ u
|
||||||
Scroll up an amount corresponding to 75% of your terminal window height in the current document.
|
Scroll up an amount corresponding to 75% of your terminal window height in the current document.
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
|
/
|
||||||
|
Search for text within current document. / followed by a text query will highlight and allow navigation of found text. / with an empty query will clear the current query.
|
||||||
|
.TP
|
||||||
|
.B
|
||||||
<tab>
|
<tab>
|
||||||
Toggle the scroll focus between the bookmarks panel and the document panel. Only has an effect if the bookmarks panel is open.
|
Toggle the scroll focus between the bookmarks panel and the document panel. Only has an effect if the bookmarks panel is open.
|
||||||
.TP
|
.TP
|
||||||
|
|
115
client.go
115
client.go
|
@ -90,9 +90,8 @@ func (c *client) Draw() {
|
||||||
var re *regexp.Regexp
|
var re *regexp.Regexp
|
||||||
if c.Options["theme"] == "inverse" {
|
if c.Options["theme"] == "inverse" {
|
||||||
screen.WriteString("\033[7m")
|
screen.WriteString("\033[7m")
|
||||||
} else if c.Options["theme"] == "color" {
|
|
||||||
re = regexp.MustCompile(`\033\[(?:\d*;?)+[A-Za-z]`)
|
|
||||||
}
|
}
|
||||||
|
re = regexp.MustCompile(`\033\[(?:\d*;?)+[A-Za-z]`)
|
||||||
if c.BookMarks.IsOpen {
|
if c.BookMarks.IsOpen {
|
||||||
bm := c.BookMarks.Render(c.Width, c.Height)
|
bm := c.BookMarks.Render(c.Width, c.Height)
|
||||||
bmWidth := len([]rune(bm[0]))
|
bmWidth := len([]rune(bm[0]))
|
||||||
|
@ -137,11 +136,9 @@ func (c *client) Draw() {
|
||||||
for i := 0; i < c.Height-3; i++ {
|
for i := 0; i < c.Height-3; i++ {
|
||||||
if i < len(pageContent) {
|
if i < len(pageContent) {
|
||||||
extra := 0
|
extra := 0
|
||||||
if c.Options["theme"] == "color" {
|
escapes := re.FindAllString(pageContent[i], -1)
|
||||||
escapes := re.FindAllString(pageContent[i], -1)
|
for _, esc := range escapes {
|
||||||
for _, esc := range escapes {
|
extra += len(esc)
|
||||||
extra += len(esc)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width+extra, c.Width+extra, pageContent[i]))
|
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width+extra, c.Width+extra, pageContent[i]))
|
||||||
screen.WriteString("\n")
|
screen.WriteString("\n")
|
||||||
|
@ -235,6 +232,45 @@ func (c *client) TakeControlInput() {
|
||||||
// Toggle bookmark browser focus on/off
|
// Toggle bookmark browser focus on/off
|
||||||
c.BookMarks.ToggleFocused()
|
c.BookMarks.ToggleFocused()
|
||||||
c.Draw()
|
c.Draw()
|
||||||
|
case 'n':
|
||||||
|
// Next search item
|
||||||
|
c.ClearMessage()
|
||||||
|
err := c.NextSearchItem(1)
|
||||||
|
if err != nil {
|
||||||
|
c.SetMessage(err.Error(), false)
|
||||||
|
c.DrawMessage()
|
||||||
|
}
|
||||||
|
case 'N':
|
||||||
|
// Previous search item
|
||||||
|
c.ClearMessage()
|
||||||
|
err := c.NextSearchItem(-1)
|
||||||
|
if err != nil {
|
||||||
|
c.SetMessage(err.Error(), false)
|
||||||
|
c.DrawMessage()
|
||||||
|
}
|
||||||
|
case '/':
|
||||||
|
// Search for text
|
||||||
|
c.ClearMessage()
|
||||||
|
c.ClearMessageLine()
|
||||||
|
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
|
||||||
|
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
|
||||||
|
}
|
||||||
|
entry, err := cui.GetLine("/")
|
||||||
|
c.ClearMessageLine()
|
||||||
|
if err != nil {
|
||||||
|
c.SetMessage(err.Error(), true)
|
||||||
|
c.DrawMessage()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = c.find(entry)
|
||||||
|
if err != nil {
|
||||||
|
c.SetMessage(err.Error(), true)
|
||||||
|
c.DrawMessage()
|
||||||
|
}
|
||||||
|
err = c.NextSearchItem(0)
|
||||||
|
if err != nil {
|
||||||
|
c.Draw()
|
||||||
|
}
|
||||||
case ':', ' ':
|
case ':', ' ':
|
||||||
// Process a command
|
// Process a command
|
||||||
c.ClearMessage()
|
c.ClearMessage()
|
||||||
|
@ -242,7 +278,7 @@ func (c *client) TakeControlInput() {
|
||||||
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
|
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
|
||||||
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
|
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
|
||||||
}
|
}
|
||||||
entry, err := cui.GetLine()
|
entry, err := cui.GetLine(": ")
|
||||||
c.ClearMessageLine()
|
c.ClearMessageLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.SetMessage(err.Error(), true)
|
c.SetMessage(err.Error(), true)
|
||||||
|
@ -644,7 +680,7 @@ func (c *client) search(query, url, question string) {
|
||||||
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
|
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
|
||||||
}
|
}
|
||||||
fmt.Print(question)
|
fmt.Print(question)
|
||||||
entry, err = cui.GetLine()
|
entry, err = cui.GetLine("? ")
|
||||||
c.ClearMessageLine()
|
c.ClearMessageLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.SetMessage(err.Error(), true)
|
c.SetMessage(err.Error(), true)
|
||||||
|
@ -1051,6 +1087,67 @@ func (c *client) handleWeb(u Url) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) find(s string) error {
|
||||||
|
c.PageState.History[c.PageState.Position].SearchTerm = s
|
||||||
|
c.PageState.History[c.PageState.Position].FindText()
|
||||||
|
if s == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(c.PageState.History[c.PageState.Position].FoundLinkLines) == 0 {
|
||||||
|
return fmt.Errorf("No text matching %q was found", s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) NextSearchItem(dir int) error {
|
||||||
|
page := c.PageState.History[c.PageState.Position]
|
||||||
|
if len(page.FoundLinkLines) == 0 {
|
||||||
|
return fmt.Errorf("The search is over before it has begun")
|
||||||
|
}
|
||||||
|
c.PageState.History[c.PageState.Position].SearchIndex += dir
|
||||||
|
page.SearchIndex += dir
|
||||||
|
if page.SearchIndex < 0 {
|
||||||
|
c.PageState.History[c.PageState.Position].SearchIndex = 0
|
||||||
|
page.SearchIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if page.SearchIndex >= len(page.FoundLinkLines) {
|
||||||
|
c.PageState.History[c.PageState.Position].SearchIndex = len(page.FoundLinkLines) - 1
|
||||||
|
return fmt.Errorf("The search path goes no further")
|
||||||
|
} else if page.SearchIndex < 0 {
|
||||||
|
c.PageState.History[c.PageState.Position].SearchIndex = 0
|
||||||
|
return fmt.Errorf("You are at the beginning of the search path")
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := page.FoundLinkLines[page.SearchIndex] - page.ScrollPosition
|
||||||
|
c.ScrollForSearch(diff)
|
||||||
|
c.Draw()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) ScrollForSearch(amount int) {
|
||||||
|
var percentRead int
|
||||||
|
page := c.PageState.History[c.PageState.Position]
|
||||||
|
bottom := len(page.WrappedContent) - c.Height + 3 // 3 for the three bars: top, msg, bottom
|
||||||
|
|
||||||
|
newScrollPosition := page.ScrollPosition + amount
|
||||||
|
if newScrollPosition < 0 {
|
||||||
|
newScrollPosition = 0
|
||||||
|
} else if newScrollPosition > bottom {
|
||||||
|
newScrollPosition = bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
c.PageState.History[c.PageState.Position].ScrollPosition = newScrollPosition
|
||||||
|
|
||||||
|
if len(page.WrappedContent) < c.Height-3 {
|
||||||
|
percentRead = 100
|
||||||
|
} else {
|
||||||
|
percentRead = int(float32(newScrollPosition+c.Height-3) / float32(len(page.WrappedContent)) * 100.0)
|
||||||
|
}
|
||||||
|
c.FootBar.SetPercentRead(percentRead)
|
||||||
|
c.Draw()
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------\\
|
//------------------------------------------------\\
|
||||||
// + + + F U N C T I O N S + + + \\
|
// + + + F U N C T I O N S + + + \\
|
||||||
//--------------------------------------------------\\
|
//--------------------------------------------------\\
|
||||||
|
|
|
@ -96,11 +96,11 @@ func Getch() rune {
|
||||||
return char
|
return char
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLine() (string, error) {
|
func GetLine(prefix string) (string, error) {
|
||||||
SetLineMode()
|
SetLineMode()
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
fmt.Print(": ")
|
fmt.Print(prefix)
|
||||||
text, err := reader.ReadString('\n')
|
text, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
49
page.go
49
page.go
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,6 +18,9 @@ type Page struct {
|
||||||
Links []string
|
Links []string
|
||||||
Location Url
|
Location Url
|
||||||
ScrollPosition int
|
ScrollPosition int
|
||||||
|
FoundLinkLines []int
|
||||||
|
SearchTerm string
|
||||||
|
SearchIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------\\
|
//------------------------------------------------\\
|
||||||
|
@ -95,7 +99,7 @@ func (p *Page) WrapContent(width int, color bool) {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
if counter < width {
|
if counter <= width {
|
||||||
content.WriteRune(ch)
|
content.WriteRune(ch)
|
||||||
counter++
|
counter++
|
||||||
} else {
|
} else {
|
||||||
|
@ -112,6 +116,47 @@ func (p *Page) WrapContent(width int, color bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.WrappedContent = strings.Split(content.String(), "\n")
|
p.WrappedContent = strings.Split(content.String(), "\n")
|
||||||
|
p.HighlightFoundText()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Page) HighlightFoundText() {
|
||||||
|
if p.SearchTerm == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, ln := range p.WrappedContent {
|
||||||
|
found := strings.Index(ln, p.SearchTerm)
|
||||||
|
if found < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
format := "\033[7m%s\033[27m"
|
||||||
|
if bombadillo.Options["theme"] == "inverse" {
|
||||||
|
format = "\033[27m%s\033[7m"
|
||||||
|
}
|
||||||
|
ln = strings.ReplaceAll(ln, p.SearchTerm, fmt.Sprintf(format, p.SearchTerm))
|
||||||
|
p.WrappedContent[i] = ln
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Page) FindText() {
|
||||||
|
p.FoundLinkLines = make([]int, 0, 10)
|
||||||
|
s := p.SearchTerm
|
||||||
|
p.SearchIndex = 0
|
||||||
|
if s == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
format := "\033[7m%s\033[27m"
|
||||||
|
if bombadillo.Options["theme"] == "inverse" {
|
||||||
|
format = "\033[27m%s\033[7m"
|
||||||
|
}
|
||||||
|
for i, ln := range p.WrappedContent {
|
||||||
|
found := strings.Index(ln, s)
|
||||||
|
if found < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ln = strings.ReplaceAll(ln, s, fmt.Sprintf(format, s))
|
||||||
|
p.WrappedContent[i] = ln
|
||||||
|
p.FoundLinkLines = append(p.FoundLinkLines, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------\\
|
//------------------------------------------------\\
|
||||||
|
@ -120,6 +165,6 @@ func (p *Page) WrapContent(width int, color bool) {
|
||||||
|
|
||||||
// MakePage returns a Page struct with default values
|
// MakePage returns a Page struct with default values
|
||||||
func MakePage(url Url, content string, links []string) Page {
|
func MakePage(url Url, content string, links []string) Page {
|
||||||
p := Page{make([]string, 0), content, links, url, 0}
|
p := Page{make([]string, 0), content, links, url, 0, make([]int, 0), "", 0}
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue