Add option to customize insertion points for completions
This commit is contained in:
parent
c704dcd9d4
commit
d3ef529afd
|
@ -35,6 +35,7 @@ type CompletionManager struct {
|
|||
completer Completer
|
||||
|
||||
verticalScroll int
|
||||
wordSeparator string
|
||||
}
|
||||
|
||||
// GetSelectedSuggestion returns the selected item.
|
||||
|
|
202
document.go
202
document.go
|
@ -92,35 +92,48 @@ func (d *Document) GetWordAfterCursorWithSpace() string {
|
|||
return x[:d.FindEndOfCurrentWordWithSpace()]
|
||||
}
|
||||
|
||||
// FindStartOfPreviousWord returns an index relative to the cursor position
|
||||
// pointing to the start of the previous word. Return `None` if nothing was found.
|
||||
func (d *Document) FindStartOfPreviousWord() int {
|
||||
// Reverse the text before the cursor, in order to do an efficient backwards search.
|
||||
// GetWordBeforeCursorUntilSeparator returns the text before the cursor until next separator.
|
||||
func (d *Document) GetWordBeforeCursorUntilSeparator(sep string) string {
|
||||
x := d.TextBeforeCursor()
|
||||
if i := strings.LastIndexByte(x, ' '); i != -1 {
|
||||
return x[d.FindStartOfPreviousWordUntilSeparator(sep):]
|
||||
}
|
||||
|
||||
// GetWordAfterCursorUntilSeparator returns the text after the cursor until next separator.
|
||||
func (d *Document) GetWordAfterCursorUntilSeparator(sep string) string {
|
||||
x := d.TextAfterCursor()
|
||||
return x[:d.FindEndOfCurrentWordUntilSeparator(sep)]
|
||||
}
|
||||
|
||||
// GetWordBeforeCursorUntilSeparatorIgnoreNextToCursor returns the word before the cursor.
|
||||
// Unlike GetWordBeforeCursor, it returns string containing space
|
||||
func (d *Document) GetWordBeforeCursorUntilSeparatorIgnoreNextToCursor(sep string) string {
|
||||
x := d.TextBeforeCursor()
|
||||
return x[d.FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor(sep):]
|
||||
}
|
||||
|
||||
// GetWordAfterCursorUntilSeparatorIgnoreNextToCursor returns the word after the cursor.
|
||||
// Unlike GetWordAfterCursor, it returns string containing space
|
||||
func (d *Document) GetWordAfterCursorUntilSeparatorIgnoreNextToCursor(sep string) string {
|
||||
x := d.TextAfterCursor()
|
||||
return x[:d.FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor(sep)]
|
||||
}
|
||||
|
||||
// FindStartOfPreviousWord returns an index relative to the cursor position
|
||||
// pointing to the start of the previous word. Return 0 if nothing was found.
|
||||
func (d *Document) FindStartOfPreviousWord() int {
|
||||
x := d.TextBeforeCursor()
|
||||
i := strings.LastIndexByte(x, ' ')
|
||||
if i != -1 {
|
||||
return i + 1
|
||||
} else {
|
||||
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 {
|
||||
x := d.TextAfterCursor()
|
||||
if i := strings.IndexByte(x, ' '); i != -1 {
|
||||
return i
|
||||
} else {
|
||||
return len([]rune(x))
|
||||
}
|
||||
}
|
||||
|
||||
// FindStartOfPreviousWordWithSpace is almost the same as FindStartOfPreviousWord.
|
||||
// The only difference is to ignore contiguous spaces.
|
||||
func (d *Document) FindStartOfPreviousWordWithSpace() int {
|
||||
// Reverse the text before the cursor, in order to do an efficient backwards search.
|
||||
x := d.TextBeforeCursor()
|
||||
|
||||
end := lastIndexByteNot(x, ' ')
|
||||
if end == -1 {
|
||||
return 0
|
||||
|
@ -133,6 +146,53 @@ func (d *Document) FindStartOfPreviousWordWithSpace() int {
|
|||
return start + 1
|
||||
}
|
||||
|
||||
// FindStartOfPreviousWordUntilSeparator is almost the same as FindStartOfPreviousWord.
|
||||
// But this can specify Separator. Return 0 if nothing was found.
|
||||
func (d *Document) FindStartOfPreviousWordUntilSeparator(sep string) int {
|
||||
if sep == "" {
|
||||
return d.FindStartOfPreviousWord()
|
||||
}
|
||||
|
||||
x := d.TextBeforeCursor()
|
||||
i := strings.LastIndexAny(x, sep)
|
||||
if i != -1 {
|
||||
return i + 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor is almost the same as FindStartOfPreviousWordWithSpace.
|
||||
// But this can specify Separator. Return 0 if nothing was found.
|
||||
func (d *Document) FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor(sep string) int {
|
||||
if sep == "" {
|
||||
return d.FindStartOfPreviousWordWithSpace()
|
||||
}
|
||||
|
||||
x := d.TextBeforeCursor()
|
||||
end := lastIndexAnyNot(x, sep)
|
||||
if end == -1 {
|
||||
return 0
|
||||
}
|
||||
start := strings.LastIndexAny(x[:end], sep)
|
||||
if start == -1 {
|
||||
return 0
|
||||
}
|
||||
return start + 1
|
||||
}
|
||||
|
||||
// FindEndOfCurrentWord returns an index relative to the cursor position.
|
||||
// pointing to the end of the current word. Return 0 if nothing was found.
|
||||
func (d *Document) FindEndOfCurrentWord() int {
|
||||
x := d.TextAfterCursor()
|
||||
i := strings.IndexByte(x, ' ')
|
||||
if i != -1 {
|
||||
return i
|
||||
} else {
|
||||
return len(x)
|
||||
}
|
||||
}
|
||||
|
||||
// FindEndOfCurrentWordWithSpace is almost the same as FindEndOfCurrentWord.
|
||||
// The only difference is to ignore contiguous spaces.
|
||||
func (d *Document) FindEndOfCurrentWordWithSpace() int {
|
||||
|
@ -151,6 +211,44 @@ func (d *Document) FindEndOfCurrentWordWithSpace() int {
|
|||
return start + end
|
||||
}
|
||||
|
||||
// FindEndOfCurrentWordUntilSeparator is almost the same as FindEndOfCurrentWord.
|
||||
// But this can specify Separator. Return 0 if nothing was found.
|
||||
func (d *Document) FindEndOfCurrentWordUntilSeparator(sep string) int {
|
||||
if sep == "" {
|
||||
return d.FindEndOfCurrentWord()
|
||||
}
|
||||
|
||||
x := d.TextAfterCursor()
|
||||
i := strings.IndexAny(x, sep)
|
||||
if i != -1 {
|
||||
return i
|
||||
} else {
|
||||
return len(x)
|
||||
}
|
||||
}
|
||||
|
||||
// FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor is almost the same as FindEndOfCurrentWordWithSpace.
|
||||
// But this can specify Separator. Return 0 if nothing was found.
|
||||
func (d *Document) FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor(sep string) int {
|
||||
if sep == "" {
|
||||
return d.FindEndOfCurrentWordWithSpace()
|
||||
}
|
||||
|
||||
x := d.TextAfterCursor()
|
||||
|
||||
start := indexAnyNot(x, sep)
|
||||
if start == -1 {
|
||||
return len(x)
|
||||
}
|
||||
|
||||
end := strings.IndexAny(x[start:], sep)
|
||||
if end == -1 {
|
||||
return len(x)
|
||||
}
|
||||
|
||||
return start + end
|
||||
}
|
||||
|
||||
// CurrentLineBeforeCursor returns the text from the start of the line until the cursor.
|
||||
func (d *Document) CurrentLineBeforeCursor() string {
|
||||
s := strings.Split(d.TextBeforeCursor(), "\n")
|
||||
|
@ -369,3 +467,71 @@ func lastIndexByteNot(s string, c byte) int {
|
|||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
type asciiSet [8]uint32
|
||||
|
||||
func (as *asciiSet) notContains(c byte) bool {
|
||||
return (as[c>>5] & (1 << uint(c&31))) == 0
|
||||
}
|
||||
|
||||
func makeASCIISet(chars string) (as asciiSet, ok bool) {
|
||||
for i := 0; i < len(chars); i++ {
|
||||
c := chars[i]
|
||||
if c >= utf8.RuneSelf {
|
||||
return as, false
|
||||
}
|
||||
as[c>>5] |= 1 << uint(c&31)
|
||||
}
|
||||
return as, true
|
||||
}
|
||||
|
||||
func indexAnyNot(s, chars string) int {
|
||||
if len(chars) > 0 {
|
||||
if len(s) > 8 {
|
||||
if as, isASCII := makeASCIISet(chars); isASCII {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if as.notContains(s[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(s); {
|
||||
// I don't know why strings.IndexAny doesn't add rune count here.
|
||||
r, size := utf8.DecodeRuneInString(s[i:])
|
||||
i += size
|
||||
for _, c := range chars {
|
||||
if r != c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func lastIndexAnyNot(s, chars string) int {
|
||||
if len(chars) > 0 {
|
||||
if len(s) > 8 {
|
||||
if as, isASCII := makeASCIISet(chars); isASCII {
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if as.notContains(s[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
for i := len(s); i > 0; {
|
||||
r, size := utf8.DecodeLastRuneInString(s[:i])
|
||||
i -= size
|
||||
for _, c := range chars {
|
||||
if r != c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
|
287
document_test.go
287
document_test.go
|
@ -161,6 +161,7 @@ func TestDocument_GetWordBeforeCursor(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected string
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -169,6 +170,29 @@ func TestDocument_GetWordBeforeCursor(t *testing.T) {
|
|||
},
|
||||
expected: "bana",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ./file/foo.json"),
|
||||
},
|
||||
expected: "foo.json",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple banana orange",
|
||||
cursorPosition: len("apple ba"),
|
||||
},
|
||||
expected: "ba",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ./fi"),
|
||||
},
|
||||
expected: "fi",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple ",
|
||||
|
@ -193,9 +217,20 @@ func TestDocument_GetWordBeforeCursor(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, p := range pattern {
|
||||
ac := p.document.GetWordBeforeCursor()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", i, p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.GetWordBeforeCursor()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", i, p.expected, ac)
|
||||
}
|
||||
ac = p.document.GetWordBeforeCursorUntilSeparator("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", i, p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.GetWordBeforeCursorUntilSeparator(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", i, p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +239,7 @@ func TestDocument_GetWordBeforeCursorWithSpace(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected string
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -212,6 +248,14 @@ func TestDocument_GetWordBeforeCursorWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: "bana ",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f /path/to/file/",
|
||||
cursorPosition: len("apply -f /path/to/file/"),
|
||||
},
|
||||
expected: "file/",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple ",
|
||||
|
@ -219,6 +263,14 @@ func TestDocument_GetWordBeforeCursorWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: "apple ",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "path/",
|
||||
cursorPosition: len("path/"),
|
||||
},
|
||||
expected: "path/",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "あいうえお かきくけこ ",
|
||||
|
@ -236,9 +288,20 @@ func TestDocument_GetWordBeforeCursorWithSpace(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, p := range pattern {
|
||||
ac := p.document.GetWordBeforeCursorWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.GetWordBeforeCursorWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
ac = p.document.GetWordBeforeCursorUntilSeparatorIgnoreNextToCursor("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.GetWordBeforeCursorUntilSeparatorIgnoreNextToCursor(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +310,7 @@ func TestDocument_FindStartOfPreviousWord(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected int
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -255,6 +319,14 @@ func TestDocument_FindStartOfPreviousWord(t *testing.T) {
|
|||
},
|
||||
expected: len("apple "),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ./file/foo.json"),
|
||||
},
|
||||
expected: len("apply -f ./file/"),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple ",
|
||||
|
@ -262,6 +334,14 @@ func TestDocument_FindStartOfPreviousWord(t *testing.T) {
|
|||
},
|
||||
expected: len("apple "),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ./"),
|
||||
},
|
||||
expected: len("apply -f ./"),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "あいうえお かきくけこ さしすせそ",
|
||||
|
@ -279,9 +359,20 @@ func TestDocument_FindStartOfPreviousWord(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, p := range pattern {
|
||||
ac := p.document.FindStartOfPreviousWord()
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.FindStartOfPreviousWord()
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
ac = p.document.FindStartOfPreviousWordUntilSeparator("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.FindStartOfPreviousWordUntilSeparator(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +381,7 @@ func TestDocument_FindStartOfPreviousWordWithSpace(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected int
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -298,6 +390,14 @@ func TestDocument_FindStartOfPreviousWordWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: len("apple "),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f /file/foo/",
|
||||
cursorPosition: len("apply -f /file/foo/"),
|
||||
},
|
||||
expected: len("apply -f /file/"),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple ",
|
||||
|
@ -305,6 +405,14 @@ func TestDocument_FindStartOfPreviousWordWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: len(""),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "file/",
|
||||
cursorPosition: len("file/"),
|
||||
},
|
||||
expected: len(""),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "あいうえお かきくけこ ",
|
||||
|
@ -322,9 +430,20 @@ func TestDocument_FindStartOfPreviousWordWithSpace(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, p := range pattern {
|
||||
ac := p.document.FindStartOfPreviousWordWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.FindStartOfPreviousWordWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
ac = p.document.FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("Should be %#v, got %#v", p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -333,6 +452,7 @@ func TestDocument_GetWordAfterCursor(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected string
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -341,6 +461,14 @@ func TestDocument_GetWordAfterCursor(t *testing.T) {
|
|||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ./fi"),
|
||||
},
|
||||
expected: "le",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -355,6 +483,14 @@ func TestDocument_GetWordAfterCursor(t *testing.T) {
|
|||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ."),
|
||||
},
|
||||
expected: "",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -379,9 +515,20 @@ func TestDocument_GetWordAfterCursor(t *testing.T) {
|
|||
}
|
||||
|
||||
for k, p := range pattern {
|
||||
ac := p.document.GetWordAfterCursor()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.GetWordAfterCursor()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
ac = p.document.GetWordAfterCursorUntilSeparator("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.GetWordAfterCursorUntilSeparator(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,6 +537,7 @@ func TestDocument_GetWordAfterCursorWithSpace(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected string
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -405,6 +553,22 @@ func TestDocument_GetWordAfterCursorWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: "bana",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "/path/to",
|
||||
cursorPosition: len("/path/"),
|
||||
},
|
||||
expected: "to",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "/path/to/file",
|
||||
cursorPosition: len("/path/"),
|
||||
},
|
||||
expected: "to",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -412,6 +576,14 @@ func TestDocument_GetWordAfterCursorWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: " bana",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "path/to",
|
||||
cursorPosition: len("path"),
|
||||
},
|
||||
expected: "/to",
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -436,9 +608,20 @@ func TestDocument_GetWordAfterCursorWithSpace(t *testing.T) {
|
|||
}
|
||||
|
||||
for k, p := range pattern {
|
||||
ac := p.document.GetWordAfterCursorWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d]Should be %#v, got %#v", k, p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.GetWordAfterCursorWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
ac = p.document.GetWordAfterCursorUntilSeparatorIgnoreNextToCursor("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.GetWordAfterCursorUntilSeparatorIgnoreNextToCursor(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -447,6 +630,7 @@ func TestDocument_FindEndOfCurrentWord(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected int
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -462,6 +646,14 @@ func TestDocument_FindEndOfCurrentWord(t *testing.T) {
|
|||
},
|
||||
expected: len("bana"),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ./"),
|
||||
},
|
||||
expected: len("file"),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -469,6 +661,14 @@ func TestDocument_FindEndOfCurrentWord(t *testing.T) {
|
|||
},
|
||||
expected: len(""),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f ./file/foo.json",
|
||||
cursorPosition: len("apply -f ."),
|
||||
},
|
||||
expected: len(""),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -502,9 +702,20 @@ func TestDocument_FindEndOfCurrentWord(t *testing.T) {
|
|||
}
|
||||
|
||||
for k, p := range pattern {
|
||||
ac := p.document.FindEndOfCurrentWord()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.FindEndOfCurrentWord()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
ac = p.document.FindEndOfCurrentWordUntilSeparator("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.FindEndOfCurrentWordUntilSeparator(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -513,6 +724,7 @@ func TestDocument_FindEndOfCurrentWordWithSpace(t *testing.T) {
|
|||
pattern := []struct {
|
||||
document *Document
|
||||
expected int
|
||||
sep string
|
||||
}{
|
||||
{
|
||||
document: &Document{
|
||||
|
@ -528,6 +740,14 @@ func TestDocument_FindEndOfCurrentWordWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: len("bana"),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f /file/foo.json",
|
||||
cursorPosition: len("apply -f /"),
|
||||
},
|
||||
expected: len("file"),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -535,6 +755,14 @@ func TestDocument_FindEndOfCurrentWordWithSpace(t *testing.T) {
|
|||
},
|
||||
expected: len(" bana"),
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apply -f /path/to",
|
||||
cursorPosition: len("apply -f /path"),
|
||||
},
|
||||
expected: len("/to"),
|
||||
sep: " /",
|
||||
},
|
||||
{
|
||||
document: &Document{
|
||||
Text: "apple bana",
|
||||
|
@ -566,9 +794,20 @@ func TestDocument_FindEndOfCurrentWordWithSpace(t *testing.T) {
|
|||
}
|
||||
|
||||
for k, p := range pattern {
|
||||
ac := p.document.FindEndOfCurrentWordWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
if p.sep == "" {
|
||||
ac := p.document.FindEndOfCurrentWordWithSpace()
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
ac = p.document.FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor("")
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
} else {
|
||||
ac := p.document.FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor(p.sep)
|
||||
if ac != p.expected {
|
||||
t.Errorf("[%d] Should be %#v, got %#v", k, p.expected, ac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,14 @@ func OptionPrefix(x string) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// OptionCompletionWordSeparator to set word separators. Enable only ' ' if empty.
|
||||
func OptionCompletionWordSeparator(x string) Option {
|
||||
return func(p *Prompt) error {
|
||||
p.completion.wordSeparator = x
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// OptionLivePrefix to change the prefix dynamically by callback function
|
||||
func OptionLivePrefix(f func() (prefix string, useLivePrefix bool)) Option {
|
||||
return func(p *Prompt) error {
|
||||
|
|
|
@ -170,7 +170,7 @@ func (p *Prompt) handleCompletionKeyBinding(key Key, completing bool) {
|
|||
p.completion.Previous()
|
||||
default:
|
||||
if s, ok := p.completion.GetSelectedSuggestion(); ok {
|
||||
w := p.buf.Document().GetWordBeforeCursor()
|
||||
w := p.buf.Document().GetWordBeforeCursorUntilSeparator(p.completion.wordSeparator)
|
||||
if w != "" {
|
||||
p.buf.DeleteBeforeCursor(len([]rune(w)))
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
|
|||
|
||||
r.renderCompletion(buffer, completion)
|
||||
if suggest, ok := completion.GetSelectedSuggestion(); ok {
|
||||
cursor = r.backward(cursor, runewidth.StringWidth(buffer.Document().GetWordBeforeCursor()))
|
||||
cursor = r.backward(cursor, runewidth.StringWidth(buffer.Document().GetWordBeforeCursorUntilSeparator(completion.wordSeparator)))
|
||||
|
||||
r.out.SetColor(r.previewSuggestionTextColor, r.previewSuggestionBGColor, false)
|
||||
r.out.WriteStr(suggest.Text)
|
||||
|
|
Loading…
Reference in New Issue