This commit is contained in:
Neko Box Coder 2025-05-27 11:10:27 +02:00 committed by GitHub
commit e4b34b99f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 88 additions and 39 deletions

View File

@ -906,27 +906,22 @@ func (h *BufPane) OutdentSelection() bool {
// Autocomplete cycles the suggestions and performs autocompletion if there are suggestions // Autocomplete cycles the suggestions and performs autocompletion if there are suggestions
func (h *BufPane) Autocomplete() bool { func (h *BufPane) Autocomplete() bool {
b := h.Buf b := h.Buf
cc := buffer.AutocompleteCursorCheck(h.Cursor)
rc := buffer.AutocompleteRuneCheck(h.Cursor)
if h.Cursor.HasSelection() { // Don't autocomplete at all if the active cursor cannot be autocomplete
if !b.HasSuggestions && (!rc || !cc || !b.StartAutocomplete(buffer.BufferComplete)) {
return false return false
} }
if b.HasSuggestions { prevSuggestion := b.CycleAutocomplete(true)
b.CycleAutocomplete(true) for i := 0; i < b.NumCursors(); i++ {
return true if buffer.AutocompleteCursorCheck(b.GetCursor(i)) {
b.PerformSingleAutocomplete(prevSuggestion, b.GetCursor(i))
}
} }
if h.Cursor.X == 0 { return true
return false
}
r := h.Cursor.RuneUnder(h.Cursor.X)
prev := h.Cursor.RuneUnder(h.Cursor.X - 1)
if !util.IsAutocomplete(prev) || util.IsWordChar(r) {
// don't autocomplete if cursor is within a word
return false
}
return b.Autocomplete(buffer.BufferComplete)
} }
// CycleAutocompleteBack cycles back in the autocomplete suggestion list // CycleAutocompleteBack cycles back in the autocomplete suggestion list
@ -935,8 +930,14 @@ func (h *BufPane) CycleAutocompleteBack() bool {
return false return false
} }
if h.Buf.HasSuggestions { b := h.Buf
h.Buf.CycleAutocomplete(false) if b.HasSuggestions {
prevSuggestion := b.CycleAutocomplete(false)
for i := 0; i < b.NumCursors(); i++ {
if buffer.AutocompleteCursorCheck(b.GetCursor(i)) {
b.PerformSingleAutocomplete(prevSuggestion, b.GetCursor(i))
}
}
return true return true
} }
return false return false

View File

@ -191,30 +191,52 @@ func (h *InfoPane) HistorySearchDown() {
// Autocomplete begins autocompletion // Autocomplete begins autocompletion
func (h *InfoPane) CommandComplete() { func (h *InfoPane) CommandComplete() {
b := h.Buf b := h.Buf
if b.HasSuggestions { c := b.GetActiveCursor()
b.CycleAutocomplete(true)
cc := buffer.AutocompleteCursorCheck(c)
rc := buffer.AutocompleteRuneCheck(c)
// Cycling commands
if !b.HasSuggestions && !cc && !rc {
return return
} }
c := b.GetActiveCursor() if b.HasSuggestions {
if !cc {
return
}
prevSuggestion := b.CycleAutocomplete(true)
b.PerformSingleAutocomplete(prevSuggestion, c)
return
}
// Otherwise start autocomplete
l := b.LineBytes(0) l := b.LineBytes(0)
l = util.SliceStart(l, c.X) l = util.SliceStart(l, c.X)
args := bytes.Split(l, []byte{' '}) args := bytes.Split(l, []byte{' '})
cmd := string(args[0]) cmd := string(args[0])
var completer buffer.Completer = nil
if h.PromptType == "Command" { if h.PromptType == "Command" {
if len(args) == 1 { if len(args) == 1 {
b.Autocomplete(CommandComplete) completer = CommandComplete
} else if action, ok := commands[cmd]; ok { } else if action, ok := commands[cmd]; ok {
if action.completer != nil { completer = action.completer
b.Autocomplete(action.completer)
}
} }
} else { } else {
// by default use filename autocompletion // by default use filename autocompletion
b.Autocomplete(buffer.FileComplete) completer = buffer.FileComplete
} }
if completer == nil {
return
}
if !b.StartAutocomplete(completer) {
return
}
prevSuggestion := b.CycleAutocomplete(true)
b.PerformSingleAutocomplete(prevSuggestion, c)
} }
// ExecuteCommand completes the prompt // ExecuteCommand completes the prompt

View File

@ -23,19 +23,37 @@ func (b *Buffer) GetSuggestions() {
} }
// Autocomplete starts the autocomplete process func AutocompleteRuneCheck(cursor *Cursor) bool {
func (b *Buffer) Autocomplete(c Completer) bool { r := cursor.RuneUnder(cursor.X)
prev := cursor.RuneUnder(cursor.X - 1)
if !util.IsAutocomplete(prev) || util.IsWordChar(r) {
// don't autocomplete if cursor is within a word
return false
}
return true
}
func AutocompleteCursorCheck(cursor *Cursor) bool {
if cursor.HasSelection() {
return false
}
if cursor.X == 0 {
return false
}
return true
}
func (b *Buffer) StartAutocomplete(c Completer) bool {
b.Completions, b.Suggestions = c(b) b.Completions, b.Suggestions = c(b)
if len(b.Completions) != len(b.Suggestions) || len(b.Completions) == 0 { if len(b.Completions) != len(b.Suggestions) || len(b.Completions) == 0 {
return false return false
} }
b.CurSuggestion = -1 b.CurSuggestion = -1
b.CycleAutocomplete(true)
return true return true
} }
// CycleAutocomplete moves to the next suggestion // CycleAutocomplete moves to the next suggestion and return the previous suggestion
func (b *Buffer) CycleAutocomplete(forward bool) { func (b *Buffer) CycleAutocomplete(forward bool) int {
prevSuggestion := b.CurSuggestion prevSuggestion := b.CurSuggestion
if forward { if forward {
@ -49,17 +67,25 @@ func (b *Buffer) CycleAutocomplete(forward bool) {
b.CurSuggestion = len(b.Suggestions) - 1 b.CurSuggestion = len(b.Suggestions) - 1
} }
c := b.GetActiveCursor()
start := c.Loc
end := c.Loc
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
start = end.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b)
}
b.Replace(start, end, b.Completions[b.CurSuggestion])
if len(b.Suggestions) > 1 { if len(b.Suggestions) > 1 {
b.HasSuggestions = true b.HasSuggestions = true
} }
return prevSuggestion
}
func (b *Buffer) PerformSingleAutocomplete(prevSuggestion int, cursor *Cursor) {
curLoc := cursor.Loc
curStart := curLoc
curEnd := curLoc
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
curStart = curEnd.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b)
}
hasSuggestions := b.HasSuggestions
b.Replace(curStart, curEnd, b.Completions[b.CurSuggestion])
b.HasSuggestions = hasSuggestions
} }
// GetWord gets the most recent word separated by any separator // GetWord gets the most recent word separated by any separator