Skip to content
Permalink
Browse files

Reverse search through Ctrl+R, closes #206

This PR adds the ability to do reverse search in the ABS shell.
It works a little bit differently than the regular bash reverse search
as it's not multi-line.

Start typing the string you want to search for, then type ctrl + R:
Abs will show you the closes command that matches that search in the
history. At every Ctrl + R, ABS will go back and look for an older
matching command in the history.
  • Loading branch information
odino committed Aug 16, 2019
1 parent 0c5e950 commit 7a8ad9492ac95d305e056db5b6daeec703259f1c
Showing with 1,436 additions and 26 deletions.
  1. +5 −6 .travis.yml
  2. +1,330 −0 coverage.out
  3. +6 −4 go.mod
  4. +19 −13 go.sum
  5. +3 −0 object/environment.go
  6. +8 −3 repl/repl.go
  7. +65 −0 repl/reverse_search.go
@@ -9,15 +9,14 @@ go:
- "1.12.x"

before_script:
- go get github.com/c-bata/go-prompt
- go get -v github.com/mattn/go-colorable
- go get -v github.com/mattn/go-tty
- go get -u
- go get github.com/mattn/goveralls
- go get -d -v `go list ./... | grep -v "/js"`

env:
- CONTEXT=abs
global:
- GO111MODULE=on
- CONTEXT=abs

script:
- go test `go list ./... | grep -v "/js"` -vet=off -v -covermode=count -coverprofile=coverage.out
- $GOPATH/bin/goveralls -service=travis-ci -coverprofile=coverage.out
- $GOPATH/bin/goveralls -service=travis-ci -coverprofile=coverage.out
1,330 coverage.out

Large diffs are not rendered by default.

10 go.mod
@@ -3,11 +3,13 @@ module github.com/abs-lang/abs
go 1.12

require (
github.com/c-bata/go-prompt v0.2.3
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/c-bata/go-prompt v0.2.4-0
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-isatty v0.0.9 // indirect
github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859 // indirect
github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942 // indirect
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 // indirect
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
)

replace github.com/c-bata/go-prompt => github.com/odino/go-prompt v0.2.4-0.20190816001457-ea717205ca73412c085f2b2296f11c674f359f5c
32 go.sum
@@ -1,22 +1,28 @@
github.com/c-bata/go-prompt v0.2.3 h1:jjCS+QhG/sULBhAaBdjb2PlMRVaKXQgn+4yzaauvs2s=
github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859 h1:smQbSzmT3EHl4EUwtFwFGmGIpiYgIiiPeVv1uguIQEE=
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942 h1:A7GG7zcGjl3jqAqGPmcNjd/D9hzL95SuoOQAaFNdLU0=
github.com/odino/go-prompt v0.2.4-0.20190816001457-9305aa75823e h1:mTySyY/vV0hlz9FlqLIrBthNof8fjMqVZPDhn6v2jJs=
github.com/odino/go-prompt v0.2.4-0.20190816001457-9305aa75823e/go.mod h1:r3+2ndvD23nUkN89DAba+DuXLHnaDwNrpvmSl/eYGUU=
github.com/odino/go-prompt v0.2.4-0.20190816001457-ea717205ca73412c085f2b2296f11c674f359f5c h1:VifSDBOIAnbm1vrgm0/hkiXNEd9UgBjW++10L7PDoVM=
github.com/odino/go-prompt v0.2.4-0.20190816001457-ea717205ca73412c085f2b2296f11c674f359f5c/go.mod h1:r3+2ndvD23nUkN89DAba+DuXLHnaDwNrpvmSl/eYGUU=
github.com/pkg/term v0.0.0-20180423043932-cda20d4ac917/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20180620133508-ad87a3a340fa/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2,6 +2,7 @@ package object

import (
"io"
"sort"
)

// NewEnclosedEnvironment creates an environment
@@ -49,6 +50,8 @@ func (e *Environment) GetKeys() []string {
keys = append(keys, k)
}

sort.Strings(keys)

return keys
}

@@ -13,8 +13,8 @@ import (
"github.com/abs-lang/abs/object"
"github.com/abs-lang/abs/parser"
"github.com/abs-lang/abs/util"
"github.com/c-bata/go-prompt"

prompt "github.com/c-bata/go-prompt"
"golang.org/x/crypto/ssh/terminal"
)

@@ -50,7 +50,7 @@ func completer(d prompt.Document) []prompt.Suggest {
return nil
}

return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true)
return prompt.FilterContains(s, d.GetWordBeforeCursor(), true)
}

var LivePrefixState struct {
@@ -72,6 +72,9 @@ func Start(in io.Reader, out io.Writer) {
// get history file only when interactive REPL is running
historyFile, maxLines = getHistoryConfiguration()
history = getHistory(historyFile, maxLines)
// once we load the history we can setup reverse search
// which will need to go through the history itself
initReverseSearch()
// get prompt prefix template string
promptPrefix := util.GetEnvVar(env, "ABS_PROMPT_PREFIX", ABS_PROMPT_PREFIX)
// get live prompt boolean
@@ -95,7 +98,10 @@ func Start(in io.Reader, out io.Writer) {
prompt.OptionLivePrefix(changeLivePrefix),
prompt.OptionTitle("abs-repl"),
prompt.OptionHistory(history),
prompt.OptionAddKeyBind(reverseSearch()), // ControlR: reverse search
prompt.OptionBreakLineCallback(clearReverseSearch), // at every line break clear the reverse search
)

p.Run()
// we get here on ^D from the prompt
saveHistory(historyFile, maxLines, history)
@@ -130,7 +136,6 @@ func executor(line string) {

// record this line for posterity
history = addToHistory(history, maxLines, line)

Run(line, true)
}

@@ -0,0 +1,65 @@
package repl

import (
"strings"

"github.com/c-bata/go-prompt"
)

var reverseSearchStr string
var lastSearchPosition int

func clearReverseSearch() {
reverseSearchStr = ""
initReverseSearch()
}

func initReverseSearch() {
lastSearchPosition = len(history)
}

// Trigger a reverse search in the shell
// on Ctrl + R: we will go through the history
// and find a match for our search text
func reverseSearch() prompt.KeyBind {
return prompt.KeyBind{
Key: prompt.ControlR,
Fn: func(buf *prompt.Buffer) {
// Get the text on the repl
text := buf.Text()

// If there's text and the search string
// is not set, let's define our search string (ie. "curl")
if text != "" && reverseSearchStr == "" {
reverseSearchStr = text
}

// If our last search position is 0,
// it means we went through the entire
// history. At this point, it's useless
// to search more.
if lastSearchPosition == 0 {
return
}

// Let's go from the last entry in the history
// to the first: if we find an entry that matches
// our text, let's replace the input in the repl
// with the history, and break out. Let's also set
// the lastSearchPosition so that, if the user
// presses Ctrl + R once again, we start our search
// from the last position onward.
for i := lastSearchPosition - 1; i >= 0; i-- {
lastSearchPosition = i

if strings.Contains(history[i], reverseSearchStr) && text != history[i] {
buf.CursorRight(len(text))
buf.DeleteBeforeCursor(len(text))
buf.InsertText(history[i], false, false)
break
}
}
return
},
}
}

0 comments on commit 7a8ad94

Please sign in to comment.
You can’t perform that action at this time.