49 lines
1.4 KiB
JavaScript
49 lines
1.4 KiB
JavaScript
// Pure logic for autocomplete trigger detection and skill filtering.
|
|
// Extracted from SimpleInput.js for testability.
|
|
|
|
/**
|
|
* Detect if cursor is at a trigger position for autocomplete.
|
|
* Returns trigger info object or null.
|
|
*/
|
|
export function getTriggerInfo(value, cursorPos, autocompleteConfig) {
|
|
if (!autocompleteConfig) return null;
|
|
|
|
const { trigger } = autocompleteConfig;
|
|
|
|
// Find the start of the current "word" (after last whitespace before cursor)
|
|
let wordStart = cursorPos;
|
|
while (wordStart > 0 && !/\s/.test(value[wordStart - 1])) {
|
|
wordStart--;
|
|
}
|
|
|
|
// Check if word starts with this agent's trigger character
|
|
if (value[wordStart] === trigger) {
|
|
return {
|
|
trigger,
|
|
filterText: value.slice(wordStart + 1, cursorPos).toLowerCase(),
|
|
replaceStart: wordStart,
|
|
replaceEnd: cursorPos,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Filter and sort skills based on trigger info.
|
|
* Returns sorted array of matching skills.
|
|
*/
|
|
export function filteredSkills(autocompleteConfig, triggerInfo) {
|
|
if (!autocompleteConfig || !triggerInfo) return [];
|
|
|
|
const { skills } = autocompleteConfig;
|
|
const { filterText } = triggerInfo;
|
|
|
|
let filtered = filterText
|
|
? skills.filter(s => s.name.toLowerCase().includes(filterText))
|
|
: skills.slice();
|
|
|
|
// Server pre-sorts, but re-sort after filtering for stability
|
|
return filtered.sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|