v2.5.0 (#495)
Co-authored-by: Quentin Torroba <quentin.torroba@mistral.ai> Co-authored-by: Clement Sirieix <clem.sirieix@gmail.com> Co-authored-by: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai> Co-authored-by: Simon Van de Kerckhove <simon.vandekerckhove@mistral.ai> Co-authored-by: Vincent Guilloux <vincent.guilloux@mistral.ai> Co-authored-by: Michel Thomazo <michel.thomazo@mistral.ai> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
parent
9421fbc08e
commit
5103019b01
104 changed files with 7277 additions and 691 deletions
|
|
@ -4,7 +4,9 @@ from pathlib import Path
|
|||
|
||||
import pytest
|
||||
|
||||
import vibe.core.autocompletion.completers as completers_module
|
||||
from vibe.core.autocompletion.completers import PathCompleter
|
||||
from vibe.core.autocompletion.fuzzy import fuzzy_match as real_fuzzy_match
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
|
@ -120,3 +122,229 @@ def test_fuzzy_matches_directory_traversal(file_tree: Path) -> None:
|
|||
assert "@src/main.py" in results
|
||||
assert "@src/core/" in results
|
||||
assert "@src/utils/" in results
|
||||
|
||||
|
||||
def test_directory_prefix_can_match_from_a_nested_path_segment(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(tmp_path / "vibe" / "acp").mkdir(parents=True)
|
||||
(tmp_path / "vibe" / "acp" / "entrypoint.py").write_text("", encoding="utf-8")
|
||||
(tmp_path / "vibe" / "myacp").mkdir(parents=True)
|
||||
(tmp_path / "vibe" / "myacp" / "entrypoint.py").write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter().get_completions("@acp/", cursor_pos=5)
|
||||
|
||||
assert "@vibe/acp/entrypoint.py" in results
|
||||
assert "@vibe/myacp/entrypoint.py" not in results
|
||||
|
||||
|
||||
def test_prefers_exact_filename_match_over_other_path_matches(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(tmp_path / "src").mkdir(parents=True)
|
||||
(tmp_path / "src" / "chat-input.tsx").write_text("", encoding="utf-8")
|
||||
(tmp_path / "src" / "features").mkdir(parents=True)
|
||||
(tmp_path / "src" / "features" / "chat-input-state.ts").write_text(
|
||||
"", encoding="utf-8"
|
||||
)
|
||||
(tmp_path / "docs").mkdir()
|
||||
(tmp_path / "docs" / "chat-input.md").write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter().get_completions("@chat-input", cursor_pos=11)
|
||||
|
||||
assert results[0] == "@src/chat-input.tsx"
|
||||
|
||||
|
||||
def test_keeps_late_strong_match_when_target_matches_is_small(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
for i in range(10):
|
||||
(tmp_path / f"prefix_{i}_chatnoise.txt").write_text("", encoding="utf-8")
|
||||
(tmp_path / "src").mkdir()
|
||||
(tmp_path / "src" / "chat-input.tsx").write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter(target_matches=5).get_completions("@chati", cursor_pos=6)
|
||||
|
||||
assert results[0] == "@src/chat-input.tsx"
|
||||
|
||||
|
||||
def test_prefers_source_file_over_lock_file_for_stem_query(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(tmp_path / "pkg").mkdir()
|
||||
(tmp_path / "pkg" / "foo.lock").write_text("", encoding="utf-8")
|
||||
(tmp_path / "src").mkdir()
|
||||
(tmp_path / "src" / "foo.py").write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter().get_completions("@foo", cursor_pos=4)
|
||||
|
||||
assert results[0] == "@src/foo.py"
|
||||
|
||||
|
||||
def test_prefers_exact_filename_matches_for_filename_query(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(
|
||||
tmp_path
|
||||
/ "ts"
|
||||
/ "apps"
|
||||
/ "le-chat-web"
|
||||
/ "src"
|
||||
/ "app"
|
||||
/ "chat"
|
||||
/ "_components"
|
||||
).mkdir(parents=True)
|
||||
(
|
||||
tmp_path
|
||||
/ "ts"
|
||||
/ "apps"
|
||||
/ "le-chat-web"
|
||||
/ "src"
|
||||
/ "app"
|
||||
/ "chat"
|
||||
/ "_components"
|
||||
/ "chat-input.tsx"
|
||||
).write_text("", encoding="utf-8")
|
||||
(tmp_path / "ts" / "apps" / "le-chat-web" / "src" / "components").mkdir(
|
||||
parents=True
|
||||
)
|
||||
(
|
||||
tmp_path
|
||||
/ "ts"
|
||||
/ "apps"
|
||||
/ "le-chat-web"
|
||||
/ "src"
|
||||
/ "components"
|
||||
/ "chat-input.tsx"
|
||||
).write_text("", encoding="utf-8")
|
||||
(
|
||||
tmp_path / "ts" / "apps" / "le-chat-mobile" / "components" / "SearchInput.tsx"
|
||||
).parent.mkdir(parents=True)
|
||||
(
|
||||
tmp_path / "ts" / "apps" / "le-chat-mobile" / "components" / "SearchInput.tsx"
|
||||
).write_text("", encoding="utf-8")
|
||||
(
|
||||
tmp_path
|
||||
/ "ts"
|
||||
/ "apps"
|
||||
/ "le-chat-web"
|
||||
/ "src"
|
||||
/ "app"
|
||||
/ "chat"
|
||||
/ "_components"
|
||||
/ "message-input.tsx"
|
||||
).write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter().get_completions("@chat-input.tsx", cursor_pos=16)
|
||||
|
||||
assert set(results[:2]) == {
|
||||
"@ts/apps/le-chat-web/src/app/chat/_components/chat-input.tsx",
|
||||
"@ts/apps/le-chat-web/src/components/chat-input.tsx",
|
||||
}
|
||||
assert results.index("@ts/apps/le-chat-mobile/components/SearchInput.tsx") > 1
|
||||
assert (
|
||||
results.index("@ts/apps/le-chat-web/src/app/chat/_components/message-input.tsx")
|
||||
> 1
|
||||
)
|
||||
|
||||
|
||||
def test_exact_path_query_ranks_children_ahead_of_unrelated_fuzzy_matches(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(tmp_path / "scripts" / "zephyr" / "generators").mkdir(parents=True)
|
||||
(tmp_path / "zephyr" / "generators" / "tests").mkdir(parents=True)
|
||||
(tmp_path / "zephyr" / "generators" / "prompts").mkdir(parents=True)
|
||||
(tmp_path / "zephyr" / "generators" / "common.py").write_text("", encoding="utf-8")
|
||||
(tmp_path / "zephyr" / "generators" / "README.md").write_text("", encoding="utf-8")
|
||||
(
|
||||
tmp_path
|
||||
/ "zephyr"
|
||||
/ "datasets"
|
||||
/ "synthetic_sp_up_conflict"
|
||||
/ "grounded_policies"
|
||||
/ "hotel"
|
||||
).mkdir(parents=True)
|
||||
(
|
||||
tmp_path
|
||||
/ "zephyr"
|
||||
/ "datasets"
|
||||
/ "synthetic_sp_up_conflict"
|
||||
/ "grounded_policies"
|
||||
/ "hotel"
|
||||
/ "generators.py"
|
||||
).write_text("", encoding="utf-8")
|
||||
(
|
||||
tmp_path
|
||||
/ "zephyr"
|
||||
/ "datasets"
|
||||
/ "synthetic_sp_up_conflict"
|
||||
/ "grounded_policies"
|
||||
/ "retail"
|
||||
).mkdir(parents=True)
|
||||
(
|
||||
tmp_path
|
||||
/ "zephyr"
|
||||
/ "datasets"
|
||||
/ "synthetic_sp_up_conflict"
|
||||
/ "grounded_policies"
|
||||
/ "retail"
|
||||
/ "generators.py"
|
||||
).write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter().get_completions("@zephyr/generators", cursor_pos=18)
|
||||
|
||||
assert results[0] == "@zephyr/generators/"
|
||||
assert results.index("@zephyr/generators/common.py") < results.index(
|
||||
"@zephyr/datasets/synthetic_sp_up_conflict/grounded_policies/hotel/generators.py"
|
||||
)
|
||||
assert results.index("@zephyr/generators/prompts/") < results.index(
|
||||
"@zephyr/datasets/synthetic_sp_up_conflict/grounded_policies/retail/generators.py"
|
||||
)
|
||||
assert results.index("@zephyr/generators/tests/") < results.index(
|
||||
"@zephyr/datasets/synthetic_sp_up_conflict/grounded_policies/hotel/generators.py"
|
||||
)
|
||||
|
||||
|
||||
def test_skips_fuzzy_scoring_for_entries_missing_required_query_characters(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(tmp_path / "src").mkdir()
|
||||
(tmp_path / "src" / "chat-input.tsx").write_text("", encoding="utf-8")
|
||||
for name in ("alpha.txt", "theta.txt", "notes.md"):
|
||||
(tmp_path / name).write_text("", encoding="utf-8")
|
||||
for i in range(20):
|
||||
(tmp_path / f"zzzz_{i}.txt").write_text("", encoding="utf-8")
|
||||
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
fuzzy_calls: list[str] = []
|
||||
|
||||
def counting_fuzzy_match(
|
||||
pattern: str, text: str, text_lower: str | None = None
|
||||
) -> object:
|
||||
fuzzy_calls.append(text)
|
||||
return real_fuzzy_match(pattern, text, text_lower)
|
||||
|
||||
monkeypatch.setattr(completers_module, "fuzzy_match", counting_fuzzy_match)
|
||||
|
||||
results = PathCompleter().get_completions("@chati", cursor_pos=6)
|
||||
|
||||
assert results[0] == "@src/chat-input.tsx"
|
||||
assert fuzzy_calls == ["src/chat-input.tsx"]
|
||||
|
||||
|
||||
def test_non_ascii_queries_still_match_when_ascii_prefilter_is_disabled(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
(tmp_path / "café.txt").write_text("", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
results = PathCompleter().get_completions("@café", cursor_pos=5)
|
||||
|
||||
assert results == ["@café.txt"]
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ async def test_path_completion_popup_lists_files_and_directories(
|
|||
await pilot.press(*"@s")
|
||||
|
||||
popup_content = str(popup.render())
|
||||
assert "@src/" in popup_content
|
||||
assert "src/" in popup_content
|
||||
assert popup.styles.display == "block"
|
||||
|
||||
|
||||
|
|
@ -177,16 +177,16 @@ async def test_path_completion_popup_shows_up_to_ten_results(
|
|||
await pilot.press(*"@src/core/extra/")
|
||||
|
||||
popup_content = str(popup.render())
|
||||
assert "@src/core/extra/extra_file_1.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_10.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_11.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_12.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_2.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_3.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_4.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_5.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_6.py" in popup_content
|
||||
assert "@src/core/extra/extra_file_7.py" in popup_content
|
||||
assert "src/core/extra/extra_file_1.py" in popup_content
|
||||
assert "src/core/extra/extra_file_10.py" in popup_content
|
||||
assert "src/core/extra/extra_file_11.py" in popup_content
|
||||
assert "src/core/extra/extra_file_12.py" in popup_content
|
||||
assert "src/core/extra/extra_file_2.py" in popup_content
|
||||
assert "src/core/extra/extra_file_3.py" in popup_content
|
||||
assert "src/core/extra/extra_file_4.py" in popup_content
|
||||
assert "src/core/extra/extra_file_5.py" in popup_content
|
||||
assert "src/core/extra/extra_file_6.py" in popup_content
|
||||
assert "src/core/extra/extra_file_7.py" in popup_content
|
||||
assert popup.styles.display == "block"
|
||||
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ async def test_fuzzy_matches_subsequence_characters(
|
|||
await pilot.press(*"@src/utils/handling")
|
||||
|
||||
popup_content = str(popup.render())
|
||||
assert "@src/utils/error_handling.py" in popup_content
|
||||
assert "src/utils/error_handling.py" in popup_content
|
||||
assert popup.styles.display == "block"
|
||||
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ async def test_fuzzy_matches_word_boundaries(
|
|||
await pilot.press(*"@src/utils/eh")
|
||||
|
||||
popup_content = str(popup.render())
|
||||
assert "@src/utils/error_handling.py" in popup_content
|
||||
assert "src/utils/error_handling.py" in popup_content
|
||||
assert popup.styles.display == "block"
|
||||
|
||||
|
||||
|
|
@ -258,7 +258,7 @@ async def test_finds_files_recursively_by_filename(
|
|||
await pilot.press(*"@entryp")
|
||||
|
||||
popup_content = str(popup.render())
|
||||
assert "@vibe/acp/entrypoint.py" in popup_content
|
||||
assert "vibe/acp/entrypoint.py" in popup_content
|
||||
assert popup.styles.display == "block"
|
||||
|
||||
|
||||
|
|
@ -272,7 +272,7 @@ async def test_finds_files_recursively_with_partial_path(
|
|||
await pilot.press(*"@acp/entry")
|
||||
|
||||
popup_content = str(popup.render())
|
||||
assert "@vibe/acp/entrypoint.py" in popup_content
|
||||
assert "vibe/acp/entrypoint.py" in popup_content
|
||||
assert popup.styles.display == "block"
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue