mirror of
https://github.com/makew0rld/amfora.git
synced 2025-02-02 15:07:34 -05:00
adding tabModeSearch to search in page (#240)
* adding tabModeSearch to search in page * skipping tag regions in text search * formatted and fixed linter errors * fixed non-exhaustive switch case * adding keybindings to default-config.toml and help.go * change search keybindings to vim/less defaults * updated tag regex and compiled it once globally * use existing bottomBar for search * adding resetSearch helper function * remove redundant bool * go fmt --------- Co-authored-by: Robin Schubert <robin.schubert@ghi-muenster.de> Co-authored-by: makeworld <makeworld@protonmail.com>
This commit is contained in:
parent
a8f2e0f638
commit
509d7892fc
@ -254,6 +254,9 @@ func Init() error {
|
||||
viper.SetDefault("keybindings.bind_copy_target_url", "c")
|
||||
viper.SetDefault("keybindings.bind_beginning", []string{"Home", "g"})
|
||||
viper.SetDefault("keybindings.bind_end", []string{"End", "G"})
|
||||
viper.SetDefault("keybindings.bind_search", "/")
|
||||
viper.SetDefault("keybindings.bind_next_match", "n")
|
||||
viper.SetDefault("keybindings.bind_prev_match", "N")
|
||||
viper.SetDefault("keybindings.shift_numbers", "")
|
||||
viper.SetDefault("keybindings.bind_url_handler_open", "Ctrl-U")
|
||||
viper.SetDefault("url-handlers.other", "default")
|
||||
|
@ -190,6 +190,11 @@ underline = true
|
||||
# bind_end: same but the for the end (bottom left)
|
||||
# bind_url_handler_open: Open highlighted URL with URL handler (#143)
|
||||
|
||||
# Search
|
||||
# bind_search = "/"
|
||||
# bind_next_match = "n"
|
||||
# bind_prev_match = "N"
|
||||
|
||||
[url-handlers]
|
||||
# Allows setting the commands to run for various URL schemes.
|
||||
# E.g. to open FTP URLs with FileZilla set the following key:
|
||||
|
@ -62,6 +62,9 @@ const (
|
||||
CmdBeginning
|
||||
CmdEnd
|
||||
CmdURLHandlerOpen // See #143
|
||||
CmdSearch
|
||||
CmdNextMatch
|
||||
CmdPrevMatch
|
||||
)
|
||||
|
||||
type keyBinding struct {
|
||||
@ -200,6 +203,9 @@ func KeyInit() {
|
||||
CmdBeginning: "keybindings.bind_beginning",
|
||||
CmdEnd: "keybindings.bind_end",
|
||||
CmdURLHandlerOpen: "keybindings.bind_url_handler_open",
|
||||
CmdSearch: "keybindings.bind_search",
|
||||
CmdNextMatch: "keybindings.bind_next_match",
|
||||
CmdPrevMatch: "keybindings.bind_prev_match",
|
||||
}
|
||||
// This is split off to allow shift_numbers to override bind_tab[1-90]
|
||||
// (This is needed for older configs so that the default bind_tab values
|
||||
|
@ -187,6 +187,11 @@ underline = true
|
||||
# bind_end: same but the for the end (bottom left)
|
||||
# bind_url_handler_open: Open highlighted URL with URL handler (#143)
|
||||
|
||||
# Search
|
||||
# bind_search = "/"
|
||||
# bind_next_match = "n"
|
||||
# bind_prev_match = "N"
|
||||
|
||||
[url-handlers]
|
||||
# Allows setting the commands to run for various URL schemes.
|
||||
# E.g. to open FTP URLs with FileZilla set the following key:
|
||||
|
@ -29,6 +29,14 @@ var termH int
|
||||
// The user input and URL display bar at the bottom
|
||||
var bottomBar = cview.NewInputField()
|
||||
|
||||
var originalText []byte
|
||||
var tagsRegex = regexp.MustCompile(`\[[a-zA-Z0-9_,;: \-\."#]+[^\[]*\]`)
|
||||
var searchMode = false
|
||||
var searchString = ""
|
||||
var bottomBarText = ""
|
||||
var matches = 0
|
||||
var curMatch = 0
|
||||
|
||||
// When the bottom bar string has a space, this regex decides whether it's
|
||||
// a non-encoded URL or a search string.
|
||||
// See this comment for details:
|
||||
@ -139,6 +147,9 @@ func Init(version, commit, builtBy string) {
|
||||
// Reset func to set the bottomBar back to what it was before
|
||||
// Use for errors.
|
||||
reset := func() {
|
||||
if searchMode {
|
||||
resetSearch()
|
||||
}
|
||||
bottomBar.SetLabel("")
|
||||
tabs[tab].applyAll()
|
||||
App.SetFocus(tabs[tab].view)
|
||||
@ -147,6 +158,63 @@ func Init(version, commit, builtBy string) {
|
||||
//nolint:exhaustive
|
||||
switch key {
|
||||
case tcell.KeyEnter:
|
||||
|
||||
if searchMode {
|
||||
// Escape the search string to not find regexp symbols
|
||||
searchString = regexp.QuoteMeta(bottomBar.GetText())
|
||||
|
||||
if strings.TrimSpace(searchString) == "" {
|
||||
// Ignore
|
||||
reset()
|
||||
return
|
||||
}
|
||||
|
||||
if tabs[tab].mode != tabModeSearch {
|
||||
originalText = tabs[curTab].view.GetBytes(false)
|
||||
}
|
||||
tabs[tab].mode = tabModeSearch
|
||||
|
||||
// find all positions of the search string
|
||||
searchRegex := regexp.MustCompile(searchString)
|
||||
searchIdx := searchRegex.FindAllIndex(originalText, -1)
|
||||
|
||||
// find all positions of tags
|
||||
tagsIdx := tagsRegex.FindAllIndex(originalText, -1)
|
||||
|
||||
text := make([]byte, 0)
|
||||
matches = 0
|
||||
lastMatch := 0
|
||||
|
||||
// loops through all occurrences and check if they
|
||||
// discard if they lie within tags.
|
||||
// []byte text is build from the original text buffer
|
||||
// with the actual search strings replaced by tagged regions
|
||||
// to highlight.
|
||||
for i, match := range searchIdx {
|
||||
for _, tag := range tagsIdx {
|
||||
if match[0] >= tag[0] && match[1] <= tag[1] {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
matches++
|
||||
text = append(text, originalText[lastMatch:match[0]]...)
|
||||
replacement := []byte(fmt.Sprint(`["search-`, i, `"]`, searchString, `[""]`))
|
||||
text = append(text, replacement...)
|
||||
lastMatch = match[0] + len(searchString)
|
||||
}
|
||||
text = append(text, originalText[lastMatch:]...)
|
||||
|
||||
tabs[curTab].view.SetBytes(text)
|
||||
|
||||
curMatch = 0
|
||||
tabs[curTab].view.Highlight(fmt.Sprint("search-", "0"))
|
||||
tabs[curTab].view.ScrollToHighlight()
|
||||
App.SetFocus(tabs[tab].view)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Figure out whether it's a URL, link number, or search
|
||||
// And send out a request
|
||||
|
||||
@ -305,6 +373,31 @@ func Init(version, commit, builtBy string) {
|
||||
// keybinding in config/config.go and update the help panel in display/help.go
|
||||
|
||||
cmd := config.TranslateKeyEvent(event)
|
||||
if tabs[curTab].mode == tabModeSearch {
|
||||
switch cmd {
|
||||
case config.CmdNextMatch:
|
||||
if curMatch < (matches - 1) {
|
||||
curMatch++
|
||||
tabs[curTab].view.Highlight(fmt.Sprint("search-", curMatch))
|
||||
}
|
||||
tabs[curTab].view.ScrollToHighlight()
|
||||
return nil
|
||||
case config.CmdPrevMatch:
|
||||
if curMatch > 0 {
|
||||
curMatch--
|
||||
tabs[curTab].view.Highlight(fmt.Sprint("search-", curMatch))
|
||||
}
|
||||
tabs[curTab].view.ScrollToHighlight()
|
||||
return nil
|
||||
case config.CmdInvalid:
|
||||
if event.Key() == tcell.KeyEsc {
|
||||
resetSearch()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
if tabs[curTab].mode == tabModeDone {
|
||||
// All the keys and operations that can only work while NOT loading
|
||||
//nolint:exhaustive
|
||||
@ -322,6 +415,13 @@ func Init(version, commit, builtBy string) {
|
||||
// Don't save bottom bar, so that whenever you switch tabs, it's not in that mode
|
||||
App.SetFocus(bottomBar)
|
||||
return nil
|
||||
case config.CmdSearch:
|
||||
bottomBar.SetLabel("[::b]Search: [::-]")
|
||||
bottomBarText = bottomBar.GetText()
|
||||
bottomBar.SetText("")
|
||||
searchMode = true
|
||||
App.SetFocus(bottomBar)
|
||||
return nil
|
||||
case config.CmdEdit:
|
||||
// Letter e allows to edit current URL
|
||||
bottomBar.SetLabel("[::b]Edit URL: [::-]")
|
||||
@ -578,3 +678,11 @@ func renderPageFromString(str string) *structs.Page {
|
||||
func NumTabs() int {
|
||||
return len(tabs)
|
||||
}
|
||||
|
||||
func resetSearch() {
|
||||
tabs[curTab].view.SetBytes(originalText)
|
||||
tabs[curTab].mode = tabModeDone
|
||||
searchMode = false
|
||||
bottomBar.SetLabel("")
|
||||
bottomBar.SetText(bottomBarText)
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ var helpCells = strings.TrimSpace(
|
||||
"%s\tSave the current page to your downloads.\n" +
|
||||
"%s\tView subscriptions\n" +
|
||||
"%s\tAdd or update a subscription\n" +
|
||||
"%s\tSearch the page content for a string\n" +
|
||||
"%s\tFind next search match\n" +
|
||||
"%s\tFind previous search match\n" +
|
||||
"%s\tQuit\n")
|
||||
|
||||
var helpTable = cview.NewTextView()
|
||||
@ -110,6 +113,9 @@ func helpInit() {
|
||||
config.GetKeyBinding(config.CmdSave),
|
||||
config.GetKeyBinding(config.CmdSub),
|
||||
config.GetKeyBinding(config.CmdAddSub),
|
||||
config.GetKeyBinding(config.CmdSearch),
|
||||
config.GetKeyBinding(config.CmdNextMatch),
|
||||
config.GetKeyBinding(config.CmdPrevMatch),
|
||||
config.GetKeyBinding(config.CmdQuit),
|
||||
)
|
||||
|
||||
|
@ -19,6 +19,7 @@ type tabMode int
|
||||
const (
|
||||
tabModeDone tabMode = iota
|
||||
tabModeLoading
|
||||
tabModeSearch
|
||||
)
|
||||
|
||||
// tabHistoryPageCache is fields from the Page struct, cached here to solve #122
|
||||
|
@ -1,4 +1,4 @@
|
||||
//nolint
|
||||
// nolint
|
||||
package display
|
||||
|
||||
//go:generate ./thanks.sh
|
||||
|
Loading…
x
Reference in New Issue
Block a user