Files
steampipe/pkg/interactive/interactive_helpers.go
Nathan Wallace 152420d278 Fix getQueryInfo() 'from ' detection closes #4810 (rebased) (#4884)
* Add test for #4810: getQueryInfo() fails to detect 'from ' correctly

This test demonstrates that getQueryInfo("from ") incorrectly returns
EditingTable = false when it should return true. This prevents autocomplete
from suggesting tables after users type "from ".

The test currently fails as expected, proving the bug exists.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix #4810: Correct getQueryInfo() 'from ' detection for autocomplete

This commit fixes a bug where getQueryInfo("from ") incorrectly returned
EditingTable = false, preventing autocomplete from suggesting tables after
users type "from ".

The fix involves two changes:

1. Modified getPreviousWord() to correctly return "from" when the input is
   "from " (single word followed by space). Previously, it returned an empty
   string because it couldn't find a space before "from".

2. Modified isEditingTable() to check that the text ends with a space. This
   ensures we only enable table suggestions when the user has typed "from "
   (ready for a table name), not when they're in the middle of typing "from"
   or after they've already started typing a table name like "from my_table".

The combination of these changes ensures:
- "from " → EditingTable = true (autocomplete shows tables)
- "from my_table" → EditingTable = false (autocomplete doesn't interfere)
- "from" → EditingTable = false (no space yet, not ready for table name)

All existing tests pass, and the new test from the previous commit now passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-16 08:50:25 -05:00

99 lines
2.3 KiB
Go

package interactive
import (
"strings"
"github.com/turbot/go-kit/helpers"
)
type queryCompletionInfo struct {
Table string
EditingTable bool
}
func getQueryInfo(text string) *queryCompletionInfo {
table := getTable(text)
prevWord := getPreviousWord(text)
return &queryCompletionInfo{
Table: table,
EditingTable: isEditingTable(text, prevWord),
}
}
func isEditingTable(text string, prevWord string) bool {
// Only consider it editing table if:
// 1. The previous word is "from"
// 2. The text ends with a space (meaning cursor is after "from ", not in the middle of typing a table name)
endsWithSpace := len(text) > 0 && text[len(text)-1] == ' '
var editingTable = prevWord == "from" && endsWithSpace
return editingTable
}
func getTable(text string) string {
// split on space and remove empty results - they occur if there is a double space
split := helpers.RemoveFromStringSlice(strings.Split(text, " "), "")
for idx, word := range split {
if word == "from" {
if idx+1 < len(split) {
return split[idx+1]
}
}
}
return ""
}
func getPreviousWord(text string) string {
// create a new document up the previous space
finalSpace := strings.LastIndex(text, " ")
if finalSpace == -1 {
return ""
}
lastNotSpace := lastIndexByteNot(text[:finalSpace], ' ')
if lastNotSpace == -1 {
return ""
}
prevSpace := strings.LastIndex(text[:lastNotSpace], " ")
if prevSpace == -1 {
// No space before the word, so return from the beginning to lastNotSpace
return text[0 : lastNotSpace+1]
}
return text[prevSpace+1 : lastNotSpace+1]
}
func lastIndexByteNot(s string, c byte) int {
for i := len(s) - 1; i >= 0; i-- {
if s[i] != c {
return i
}
}
return -1
}
// if there are no spaces this is the first word
func isFirstWord(text string) bool {
return strings.LastIndex(text, " ") == -1
}
// split the string by spaces and return the last segment
func lastWord(text string) string {
idx := strings.LastIndex(text, " ")
if idx == -1 {
return text
}
return text[idx:]
}
//
// keeping this around because we may need
// to revisit exit on non-darwin platforms.
// as per line #128
//
//
// https://github.com/c-bata/go-prompt/issues/59
// func exit(_ *prompt.Buffer) {
// fmt.Println("Ctrl+D :: exitCallback")
// panic(utils.ExitCode(0))
// }