9593c2a720
Add HistorySearchUp and HistorySearchDown actions which are similar to HistoryUp and HistoryDown but search for the prev/next history item whose beginning matches the currently entered text in the infobuffer (more precisely, the text before cursor). Also fixed the following issue: if we scrolled to an older history item and then edit the infobuffer, this older item gets modified. We should not edit old history entries. So in this case set HistoryNum to the last (newly added) item and modify the last item.
155 lines
3.9 KiB
Go
155 lines
3.9 KiB
Go
package info
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/zyedidia/micro/v2/internal/config"
|
|
"github.com/zyedidia/micro/v2/internal/util"
|
|
)
|
|
|
|
// LoadHistory attempts to load user history from configDir/buffers/history
|
|
// into the history map
|
|
// The savehistory option must be on
|
|
func (i *InfoBuf) LoadHistory() {
|
|
if config.GetGlobalOption("savehistory").(bool) {
|
|
file, err := os.Open(filepath.Join(config.ConfigDir, "buffers", "history"))
|
|
var decodedMap map[string][]string
|
|
if err == nil {
|
|
defer file.Close()
|
|
decoder := gob.NewDecoder(file)
|
|
err = decoder.Decode(&decodedMap)
|
|
|
|
if err != nil {
|
|
i.Error("Error loading history:", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if decodedMap != nil {
|
|
i.History = decodedMap
|
|
} else {
|
|
i.History = make(map[string][]string)
|
|
}
|
|
} else {
|
|
i.History = make(map[string][]string)
|
|
}
|
|
}
|
|
|
|
// SaveHistory saves the user's command history to configDir/buffers/history
|
|
// only if the savehistory option is on
|
|
func (i *InfoBuf) SaveHistory() {
|
|
if config.GetGlobalOption("savehistory").(bool) {
|
|
// Don't save history past 100
|
|
for k, v := range i.History {
|
|
if len(v) > 100 {
|
|
i.History[k] = v[len(i.History[k])-100:]
|
|
}
|
|
}
|
|
|
|
file, err := os.Create(filepath.Join(config.ConfigDir, "buffers", "history"))
|
|
if err == nil {
|
|
defer file.Close()
|
|
encoder := gob.NewEncoder(file)
|
|
|
|
err = encoder.Encode(i.History)
|
|
if err != nil {
|
|
i.Error("Error saving history:", err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// AddToHistory adds a new item to the history for the prompt type `ptype`.
|
|
// This function is not used by micro itself. It is useful for plugins
|
|
// which add their own items to the history, bypassing the infobar command line.
|
|
func (i *InfoBuf) AddToHistory(ptype string, item string) {
|
|
if i.HasPrompt && i.PromptType == ptype {
|
|
return
|
|
}
|
|
|
|
if _, ok := i.History[ptype]; !ok {
|
|
i.History[ptype] = []string{item}
|
|
} else {
|
|
i.History[ptype] = append(i.History[ptype], item)
|
|
|
|
// avoid duplicates
|
|
h := i.History[ptype]
|
|
for j := len(h) - 2; j >= 0; j-- {
|
|
if h[j] == h[len(h)-1] {
|
|
i.History[ptype] = append(h[:j], h[j+1:]...)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// UpHistory fetches the previous item in the history
|
|
func (i *InfoBuf) UpHistory(history []string) {
|
|
if i.HistoryNum > 0 && i.HasPrompt && !i.HasYN {
|
|
i.HistoryNum--
|
|
i.Replace(i.Start(), i.End(), history[i.HistoryNum])
|
|
i.Buffer.GetActiveCursor().GotoLoc(i.End())
|
|
}
|
|
}
|
|
|
|
// DownHistory fetches the next item in the history
|
|
func (i *InfoBuf) DownHistory(history []string) {
|
|
if i.HistoryNum < len(history)-1 && i.HasPrompt && !i.HasYN {
|
|
i.HistoryNum++
|
|
i.Replace(i.Start(), i.End(), history[i.HistoryNum])
|
|
i.Buffer.GetActiveCursor().GotoLoc(i.End())
|
|
}
|
|
}
|
|
|
|
// SearchUpHistory fetches the previous item in the history
|
|
// beginning with the text in the infobuffer before cursor
|
|
func (i *InfoBuf) SearchUpHistory(history []string) {
|
|
if i.HistoryNum > 0 && i.HasPrompt && !i.HasYN {
|
|
i.searchHistory(history, false)
|
|
}
|
|
}
|
|
|
|
// SearchDownHistory fetches the next item in the history
|
|
// beginning with the text in the infobuffer before cursor
|
|
func (i *InfoBuf) SearchDownHistory(history []string) {
|
|
if i.HistoryNum < len(history)-1 && i.HasPrompt && !i.HasYN {
|
|
i.searchHistory(history, true)
|
|
}
|
|
}
|
|
|
|
func (i *InfoBuf) searchHistory(history []string, down bool) {
|
|
line := string(i.LineBytes(0))
|
|
c := i.Buffer.GetActiveCursor()
|
|
|
|
if !i.HistorySearch || !strings.HasPrefix(line, i.HistorySearchPrefix) {
|
|
i.HistorySearch = true
|
|
i.HistorySearchPrefix = util.SliceStartStr(line, c.X)
|
|
}
|
|
|
|
found := -1
|
|
if down {
|
|
for j := i.HistoryNum + 1; j < len(history); j++ {
|
|
if strings.HasPrefix(history[j], i.HistorySearchPrefix) {
|
|
found = j
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
for j := i.HistoryNum - 1; j >= 0; j-- {
|
|
if strings.HasPrefix(history[j], i.HistorySearchPrefix) {
|
|
found = j
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if found != -1 {
|
|
i.HistoryNum = found
|
|
i.Replace(i.Start(), i.End(), history[found])
|
|
c.GotoLoc(i.End())
|
|
}
|
|
}
|