Skip to content

Commit 5c71c2e

Browse files
author
redsti
committed
Autocomplete support for multiple cursors
1 parent d38f0df commit 5c71c2e

2 files changed

Lines changed: 48 additions & 17 deletions

File tree

internal/action/actions.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -916,16 +916,6 @@ func (h *BufPane) Autocomplete() bool {
916916
return true
917917
}
918918

919-
if h.Cursor.X == 0 {
920-
return false
921-
}
922-
r := h.Cursor.RuneUnder(h.Cursor.X)
923-
prev := h.Cursor.RuneUnder(h.Cursor.X - 1)
924-
if !util.IsAutocomplete(prev) || util.IsWordChar(r) {
925-
// don't autocomplete if cursor is within a word
926-
return false
927-
}
928-
929919
return b.Autocomplete(buffer.BufferComplete)
930920
}
931921

internal/buffer/autocomplete.go

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ func (b *Buffer) GetSuggestions() {
2525

2626
// Autocomplete starts the autocomplete process
2727
func (b *Buffer) Autocomplete(c Completer) bool {
28+
if !b.GetActiveCursor().CanAutocomplete() {
29+
return false
30+
}
2831
b.Completions, b.Suggestions = c(b)
2932
if len(b.Completions) != len(b.Suggestions) || len(b.Completions) == 0 {
3033
return false
@@ -49,23 +52,57 @@ func (b *Buffer) CycleAutocomplete(forward bool) {
4952
b.CurSuggestion = len(b.Suggestions) - 1
5053
}
5154

52-
c := b.GetActiveCursor()
55+
// cycle autocomplete for all except active cursors
56+
for i, c := range b.cursors {
57+
if i == b.curCursor || !c.CanAutocomplete() {
58+
continue
59+
}
60+
61+
activeWord, _ := b.GetWordCursor(b.GetActiveCursor())
62+
word, _ := b.GetWordCursor(c);
63+
if !bytes.Equal(word, activeWord) {
64+
continue
65+
}
66+
67+
b.AutocompleteSingle(c, prevSuggestion)
68+
}
69+
70+
// cycle autocomplete for active cursor
71+
b.AutocompleteSingle(b.GetActiveCursor(), prevSuggestion)
72+
73+
if len(b.Suggestions) > 1 {
74+
b.HasSuggestions = true
75+
}
76+
}
77+
78+
func (b *Buffer) AutocompleteSingle(c *Cursor, prevSuggestion int) {
5379
start := c.Loc
5480
end := c.Loc
81+
5582
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
5683
start = end.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b)
5784
}
5885

5986
b.Replace(start, end, b.Completions[b.CurSuggestion])
60-
if len(b.Suggestions) > 1 {
61-
b.HasSuggestions = true
87+
}
88+
89+
func (c *Cursor) CanAutocomplete() bool {
90+
if c.X == 0 {
91+
return false
6292
}
93+
94+
r := c.RuneUnder(c.X)
95+
prev := c.RuneUnder(c.X - 1)
96+
if !util.IsAutocomplete(prev) || util.IsWordChar(r) {
97+
// don't autocomplete if cursor is within a word
98+
return false
99+
}
100+
return true
63101
}
64102

65-
// GetWord gets the most recent word separated by any separator
103+
// GetWordCursor gets the most recent word separated by any separator
66104
// (whitespace, punctuation, any non alphanumeric character)
67-
func (b *Buffer) GetWord() ([]byte, int) {
68-
c := b.GetActiveCursor()
105+
func (b *Buffer) GetWordCursor(c *Cursor) ([]byte, int) {
69106
l := b.LineBytes(c.Y)
70107
l = util.SliceStart(l, c.X)
71108

@@ -82,6 +119,10 @@ func (b *Buffer) GetWord() ([]byte, int) {
82119
return input, c.X - util.CharacterCount(input)
83120
}
84121

122+
func (b *Buffer) GetWord() ([]byte, int) {
123+
return b.GetWordCursor(b.GetActiveCursor())
124+
}
125+
85126
// GetArg gets the most recent word (separated by ' ' only)
86127
func (b *Buffer) GetArg() (string, int) {
87128
c := b.GetActiveCursor()
@@ -153,7 +194,7 @@ func FileComplete(b *Buffer) ([]string, []string) {
153194
// BufferComplete autocompletes based on previous words in the buffer
154195
func BufferComplete(b *Buffer) ([]string, []string) {
155196
c := b.GetActiveCursor()
156-
input, argstart := b.GetWord()
197+
input, argstart := b.GetWordCursor(c)
157198

158199
if argstart == -1 {
159200
return []string{}, []string{}

0 commit comments

Comments
 (0)