add ascii-code-bind-option-and-find-current-word-end
This commit is contained in:
parent
de51277535
commit
6a9503cb3a
@ -97,7 +97,7 @@ func (b *Buffer) CursorLeft(count int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorRight move to right on the current line.
|
// CursorLineEnd move to right on the current line.
|
||||||
func (b *Buffer) CursorRight(count int) {
|
func (b *Buffer) CursorRight(count int) {
|
||||||
l := b.Document().GetCursorRightPosition(count)
|
l := b.Document().GetCursorRightPosition(count)
|
||||||
b.CursorPosition += l
|
b.CursorPosition += l
|
||||||
|
52
document.go
52
document.go
@ -4,6 +4,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
"io/ioutil"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Document has text displayed in terminal and cursor position.
|
// Document has text displayed in terminal and cursor position.
|
||||||
@ -55,6 +57,13 @@ func (d *Document) GetWordBeforeCursor() string {
|
|||||||
return x[d.FindStartOfPreviousWord():]
|
return x[d.FindStartOfPreviousWord():]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWordAfterCursor returns the word after the cursor.
|
||||||
|
// If we have whitespace after the cursor this returns an empty string.
|
||||||
|
func (d *Document) GetWordAfterCursor() string {
|
||||||
|
x := d.TextAfterCursor()
|
||||||
|
return x[:d.FindEndOfCurrentWord()]
|
||||||
|
}
|
||||||
|
|
||||||
// GetWordBeforeCursorWithSpace returns the word before the cursor.
|
// GetWordBeforeCursorWithSpace returns the word before the cursor.
|
||||||
// Unlike GetWordBeforeCursor, it returns string containing space
|
// Unlike GetWordBeforeCursor, it returns string containing space
|
||||||
func (d *Document) GetWordBeforeCursorWithSpace() string {
|
func (d *Document) GetWordBeforeCursorWithSpace() string {
|
||||||
@ -62,6 +71,13 @@ func (d *Document) GetWordBeforeCursorWithSpace() string {
|
|||||||
return x[d.FindStartOfPreviousWordWithSpace():]
|
return x[d.FindStartOfPreviousWordWithSpace():]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWordAfterCursorWithSpace returns the word after the cursor.
|
||||||
|
// Unlike GetWordAfterCursor, it returns string containing space
|
||||||
|
func (d *Document) GetWordAfterCursorWithSpace() string {
|
||||||
|
x := d.TextAfterCursor()
|
||||||
|
return x[:d.FindEndOfCurrentWordWithSpace()]
|
||||||
|
}
|
||||||
|
|
||||||
// FindStartOfPreviousWord returns an index relative to the cursor position
|
// FindStartOfPreviousWord returns an index relative to the cursor position
|
||||||
// pointing to the start of the previous word. Return `None` if nothing was found.
|
// pointing to the start of the previous word. Return `None` if nothing was found.
|
||||||
func (d *Document) FindStartOfPreviousWord() int {
|
func (d *Document) FindStartOfPreviousWord() int {
|
||||||
@ -76,6 +92,20 @@ func (d *Document) FindStartOfPreviousWord() int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindEndOfCurrentWord returns an index relative to the cursor position
|
||||||
|
// pointing to the end of the current word. Return `None` if nothing was found.
|
||||||
|
func (d *Document) FindEndOfCurrentWord() int {
|
||||||
|
// Reverse the text before the cursor, in order to do an efficient backwards search.
|
||||||
|
x := d.TextAfterCursor()
|
||||||
|
l := len(x)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
if x[i:i+1] == " " {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// FindStartOfPreviousWordWithSpace is almost the same as FindStartOfPreviousWord.
|
// FindStartOfPreviousWordWithSpace is almost the same as FindStartOfPreviousWord.
|
||||||
// The only difference is to ignore contiguous spaces.
|
// The only difference is to ignore contiguous spaces.
|
||||||
func (d *Document) FindStartOfPreviousWordWithSpace() int {
|
func (d *Document) FindStartOfPreviousWordWithSpace() int {
|
||||||
@ -94,6 +124,28 @@ func (d *Document) FindStartOfPreviousWordWithSpace() int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindEndOfCurrentWordWithSpace is almost the same as FindEndOfCurrentWord.
|
||||||
|
// The only difference is to ignore contiguous spaces.
|
||||||
|
func (d *Document) FindEndOfCurrentWordWithSpace() int {
|
||||||
|
// Reverse the text before the cursor, in order to do an efficient backwards search.
|
||||||
|
x := d.TextAfterCursor()
|
||||||
|
ioutil.WriteFile("/tmp/fff", []byte(fmt.Sprintf("[%s]", x)), 0644)
|
||||||
|
l := len(x)
|
||||||
|
appear := false
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
if x[i:i+1] != " " {
|
||||||
|
appear = true
|
||||||
|
}
|
||||||
|
if x[i:i+1] == " " && appear {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
if i == l-1 {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// CurrentLineBeforeCursor returns the text from the start of the line until the cursor.
|
// CurrentLineBeforeCursor returns the text from the start of the line until the cursor.
|
||||||
func (d *Document) CurrentLineBeforeCursor() string {
|
func (d *Document) CurrentLineBeforeCursor() string {
|
||||||
s := strings.Split(d.TextBeforeCursor(), "\n")
|
s := strings.Split(d.TextBeforeCursor(), "\n")
|
||||||
|
32
key_bind.go
32
key_bind.go
@ -9,6 +9,12 @@ type KeyBind struct {
|
|||||||
Fn KeyBindFunc
|
Fn KeyBindFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ASCIICodeBind represents which []byte should do what operation
|
||||||
|
type ASCIICodeBind struct {
|
||||||
|
ASCIICode []byte
|
||||||
|
Fn KeyBindFunc
|
||||||
|
}
|
||||||
|
|
||||||
// KeyBindMode to switch a key binding flexibly.
|
// KeyBindMode to switch a key binding flexibly.
|
||||||
type KeyBindMode string
|
type KeyBindMode string
|
||||||
|
|
||||||
@ -23,45 +29,31 @@ var commonKeyBindings = []KeyBind{
|
|||||||
// Go to the End of the line
|
// Go to the End of the line
|
||||||
{
|
{
|
||||||
Key: End,
|
Key: End,
|
||||||
Fn: func(buf *Buffer) {
|
Fn: GoLineEnd,
|
||||||
x := []rune(buf.Document().TextAfterCursor())
|
|
||||||
buf.CursorRight(len(x))
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// Go to the beginning of the line
|
// Go to the beginning of the line
|
||||||
{
|
{
|
||||||
Key: Home,
|
Key: Home,
|
||||||
Fn: func(buf *Buffer) {
|
Fn: GoLineBeginning,
|
||||||
x := []rune(buf.Document().TextBeforeCursor())
|
|
||||||
buf.CursorLeft(len(x))
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// Delete character under the cursor
|
// Delete character under the cursor
|
||||||
{
|
{
|
||||||
Key: Delete,
|
Key: Delete,
|
||||||
Fn: func(buf *Buffer) {
|
Fn: DeleteChar,
|
||||||
buf.Delete(1)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// Backspace
|
// Backspace
|
||||||
{
|
{
|
||||||
Key: Backspace,
|
Key: Backspace,
|
||||||
Fn: func(buf *Buffer) {
|
Fn: DeleteBeforeChar,
|
||||||
buf.DeleteBeforeCursor(1)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// Right allow: Forward one character
|
// Right allow: Forward one character
|
||||||
{
|
{
|
||||||
Key: Right,
|
Key: Right,
|
||||||
Fn: func(buf *Buffer) {
|
Fn: GoRightChar,
|
||||||
buf.CursorRight(1)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// Left allow: Backward one character
|
// Left allow: Backward one character
|
||||||
{
|
{
|
||||||
Key: Left,
|
Key: Left,
|
||||||
Fn: func(buf *Buffer) {
|
Fn: GoLeftChar,
|
||||||
buf.CursorLeft(1)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,14 @@ func OptionAddKeyBind(b ...KeyBind) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OptionAddKeyBind to set a custom key bind.
|
||||||
|
func OptionAddASCIICodeBind(b ...ASCIICodeBind) Option {
|
||||||
|
return func(p *Prompt) error {
|
||||||
|
p.ASCIICodeBindings = append(p.ASCIICodeBindings, b...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a Prompt with powerful auto-completion.
|
// New returns a Prompt with powerful auto-completion.
|
||||||
func New(executor Executor, completer Completer, opts ...Option) *Prompt {
|
func New(executor Executor, completer Completer, opts ...Option) *Prompt {
|
||||||
pt := &Prompt{
|
pt := &Prompt{
|
||||||
|
16
prompt.go
16
prompt.go
@ -5,6 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
"bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -26,6 +27,7 @@ type Prompt struct {
|
|||||||
history *History
|
history *History
|
||||||
completion *CompletionManager
|
completion *CompletionManager
|
||||||
keyBindings []KeyBind
|
keyBindings []KeyBind
|
||||||
|
ASCIICodeBindings []ASCIICodeBind
|
||||||
keyBindMode KeyBindMode
|
keyBindMode KeyBindMode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +142,9 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case NotDefined:
|
case NotDefined:
|
||||||
|
if p.handleASCIICodeBinding(b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
p.buf.InsertText(string(b), false, true)
|
p.buf.InsertText(string(b), false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +204,17 @@ func (p *Prompt) handleKeyBinding(key Key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Prompt) handleASCIICodeBinding(b []byte) bool {
|
||||||
|
checked := false
|
||||||
|
for _, kb := range p.ASCIICodeBindings {
|
||||||
|
if bytes.Compare(kb.ASCIICode, b) == 0 {
|
||||||
|
kb.Fn(p.buf)
|
||||||
|
checked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checked
|
||||||
|
}
|
||||||
|
|
||||||
// Input just returns user input text.
|
// Input just returns user input text.
|
||||||
func (p *Prompt) Input() string {
|
func (p *Prompt) Input() string {
|
||||||
if l := os.Getenv(envDebugLogPath); l == "" {
|
if l := os.Getenv(envDebugLogPath); l == "" {
|
||||||
|
Loading…
Reference in New Issue
Block a user