fix(autocomplete): support slash commands after non-ASCII prefix and multiple slashes (#3924)

This commit is contained in:
Rod Boev authored and nesquena-hermes committed 2026-06-14 19:57:17 +00:00
1 parent db9803946f
commit fcaab02e93
3 files changed
+170 -8

No files matched your search

@@ -0,0 +1,134 @@
"""Tests for #3924 — CJK text before / should not block slash autocomplete.
The autocomplete trigger previously gated on text.startsWith('/') which
fails when CJK (or any non-/ text) precedes the slash. The fix introduces
_activeSlashCommandOffset() which finds the / at a token-initial position
(start of line or after whitespace), excluding ~/ path tokens and mid-word
slashes (URLs, provider/model IDs).
"""
import os
import re
_SRC = os.path.join(os.path.dirname(__file__), "..")
def _read(name):
return open(os.path.join(_SRC, name), encoding="utf-8").read()
class TestActiveSlashCommandOffset:
"""_activeSlashCommandOffset must exist and use token-initial logic."""
def test_helper_exists(self):
js = _read("static/commands.js")
assert "function _activeSlashCommandOffset(text)" in js
def test_helper_checks_token_initial_position(self):
js = _read("static/commands.js")
m = re.search(
r'function _activeSlashCommandOffset\(text\)\{(.*?)\n\}',
js, re.DOTALL,
)
assert m, "_activeSlashCommandOffset not found"
fn = m.group(0)
# Must check for start-of-line (i===0) or after whitespace
assert "i===0" in fn or "i === 0" in fn, (
"_activeSlashCommandOffset must check start-of-line position"
)
assert "text[i-1]" in fn, (
"_activeSlashCommandOffset must check character before /"
)
def test_helper_excludes_path_tokens(self):
js = _read("static/commands.js")
m = re.search(
r'function _activeSlashCommandOffset\(text\)\{(.*?)\n\}',
js, re.DOTALL,
)
assert m
fn = m.group(0)
# Must exclude ~/ path tokens
assert "~" in fn, (
"_activeSlashCommandOffset must exclude ~/ path tokens"
)
class TestParseSlashAutocompleteUsesHelper:
"""_parseSlashAutocomplete must delegate to _activeSlashCommandOffset."""
def test_delegates_to_helper(self):
js = _read("static/commands.js")
m = re.search(
r'function _parseSlashAutocomplete\(text\)\{(.*?)\n\}',
js, re.DOTALL,
)
assert m, "_parseSlashAutocomplete not found"
fn = m.group(0)
assert "_activeSlashCommandOffset" in fn, (
"_parseSlashAutocomplete must use _activeSlashCommandOffset"
)
def test_does_not_use_startswith(self):
js = _read("static/commands.js")
m = re.search(
r'function _parseSlashAutocomplete\(text\)\{(.*?)\n\}',
js, re.DOTALL,
)
assert m
fn = m.group(0)
assert "startsWith('/')" not in fn, (
"_parseSlashAutocomplete must not gate on startsWith('/')"
)
class TestRefreshSlashCommandDropdownUsesHelper:
"""refreshSlashCommandDropdown must delegate to _activeSlashCommandOffset."""
def test_delegates_to_helper(self):
js = _read("static/commands.js")
m = re.search(
r'function refreshSlashCommandDropdown\(\)\{(.*?)\n\}',
js, re.DOTALL,
)
assert m, "refreshSlashCommandDropdown not found"
fn = m.group(0)
assert "_activeSlashCommandOffset" in fn, (
"refreshSlashCommandDropdown must use _activeSlashCommandOffset"
)
class TestBootJsSlashTrigger:
"""boot.js input handler must use _activeSlashCommandOffset."""
def test_boot_uses_helper(self):
js = _read("static/boot.js")
assert "_activeSlashCommandOffset" in js, (
"boot.js must use _activeSlashCommandOffset for the slash "
"autocomplete trigger (#3924)"
)
def test_boot_falls_back_to_path_autocomplete(self):
js = _read("static/boot.js")
# The path autocomplete else-if must still be present
assert "getComposerPathAutocompleteMatches" in js, (
"boot.js must preserve path autocomplete fallback"
)
class TestSelectionHandlerPreservesPrefix:
"""When an autocomplete item is selected, prefix text before the active
slash must be preserved rather than discarded."""
def test_selection_uses_helper(self):
js = _read("static/commands.js")
m = re.search(
r'function showCmdDropdown\(matches\)\{(.*?)\nfunction hideCmdDropdown',
js, re.DOTALL,
)
assert m, "showCmdDropdown not found"
fn = m.group(0)
assert "_activeSlashCommandOffset" in fn, (
"showCmdDropdown selection handler must use _activeSlashCommandOffset "
"to preserve prefix text before the slash (#3924)"
)