fix: fixes issue where the autocomplete tui dialog flickers while typing (#11641)
This commit is contained in:
@@ -129,6 +129,16 @@ export function Autocomplete(props: {
|
|||||||
return props.input().getTextRange(store.index + 1, props.input().cursorOffset)
|
return props.input().getTextRange(store.index + 1, props.input().cursorOffset)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// filter() reads reactive props.value plus non-reactive cursor/text state.
|
||||||
|
// On keypress those can be briefly out of sync, so filter() may return an empty/partial string.
|
||||||
|
// Copy it into search in an effect because effects run after reactive updates have been rendered and painted
|
||||||
|
// so the input has settled and all consumers read the same stable value.
|
||||||
|
const [search, setSearch] = createSignal("")
|
||||||
|
createEffect(() => {
|
||||||
|
const next = filter()
|
||||||
|
setSearch(next ? next : "");
|
||||||
|
})
|
||||||
|
|
||||||
// When the filter changes due to how TUI works, the mousemove might still be triggered
|
// When the filter changes due to how TUI works, the mousemove might still be triggered
|
||||||
// via a synthetic event as the layout moves underneath the cursor. This is a workaround to make sure the input mode remains keyboard so
|
// via a synthetic event as the layout moves underneath the cursor. This is a workaround to make sure the input mode remains keyboard so
|
||||||
// that the mouseover event doesn't trigger when filtering.
|
// that the mouseover event doesn't trigger when filtering.
|
||||||
@@ -208,7 +218,7 @@ export function Autocomplete(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [files] = createResource(
|
const [files] = createResource(
|
||||||
() => filter(),
|
() => search(),
|
||||||
async (query) => {
|
async (query) => {
|
||||||
if (!store.visible || store.visible === "/") return []
|
if (!store.visible || store.visible === "/") return []
|
||||||
|
|
||||||
@@ -378,9 +388,9 @@ export function Autocomplete(props: {
|
|||||||
const mixed: AutocompleteOption[] =
|
const mixed: AutocompleteOption[] =
|
||||||
store.visible === "@" ? [...agentsValue, ...(filesValue || []), ...mcpResources()] : [...commandsValue]
|
store.visible === "@" ? [...agentsValue, ...(filesValue || []), ...mcpResources()] : [...commandsValue]
|
||||||
|
|
||||||
const currentFilter = filter()
|
const searchValue = search()
|
||||||
|
|
||||||
if (!currentFilter) {
|
if (!searchValue) {
|
||||||
return mixed
|
return mixed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +398,7 @@ export function Autocomplete(props: {
|
|||||||
return prev
|
return prev
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = fuzzysort.go(removeLineRange(currentFilter), mixed, {
|
const result = fuzzysort.go(removeLineRange(searchValue), mixed, {
|
||||||
keys: [
|
keys: [
|
||||||
(obj) => removeLineRange((obj.value ?? obj.display).trimEnd()),
|
(obj) => removeLineRange((obj.value ?? obj.display).trimEnd()),
|
||||||
"description",
|
"description",
|
||||||
@@ -398,7 +408,7 @@ export function Autocomplete(props: {
|
|||||||
scoreFn: (objResults) => {
|
scoreFn: (objResults) => {
|
||||||
const displayResult = objResults[0]
|
const displayResult = objResults[0]
|
||||||
let score = objResults.score
|
let score = objResults.score
|
||||||
if (displayResult && displayResult.target.startsWith(store.visible + currentFilter)) {
|
if (displayResult && displayResult.target.startsWith(store.visible + searchValue)) {
|
||||||
score *= 2
|
score *= 2
|
||||||
}
|
}
|
||||||
const frecencyScore = objResults.obj.path ? frecency.getFrecency(objResults.obj.path) : 0
|
const frecencyScore = objResults.obj.path ? frecency.getFrecency(objResults.obj.path) : 0
|
||||||
|
|||||||
Reference in New Issue
Block a user