Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cocoindex_code/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ def _search_with_wait_spinner(
query: str,
languages: list[str] | None = None,
paths: list[str] | None = None,
exclude_paths: list[str] | None = None,
limit: int = 10,
offset: int = 0,
) -> SearchResponse:
Expand All @@ -248,6 +249,7 @@ def _on_waiting() -> None:
query=query,
languages=languages,
paths=paths,
exclude_paths=exclude_paths,
limit=limit,
offset=offset,
on_waiting=_on_waiting,
Expand Down Expand Up @@ -540,6 +542,7 @@ def search(
query: list[str] = _typer.Argument(..., help="Search query"),
lang: list[str] = _typer.Option([], "--lang", help="Filter by language"),
path: str | None = _typer.Option(None, "--path", help="Filter by file path glob"),
exclude: list[str] = _typer.Option([], "--exclude", help="Exclude file path glob(s)"),
offset: int = _typer.Option(0, "--offset", help="Number of results to skip"),
limit: int = _typer.Option(10, "--limit", help="Maximum results to return"),
refresh: bool = _typer.Option(False, "--refresh", help="Refresh index before searching"),
Expand All @@ -565,6 +568,7 @@ def search(
query=query_str,
languages=lang or None,
paths=paths,
exclude_paths=exclude or None,
limit=limit,
offset=offset,
)
Expand Down
2 changes: 2 additions & 0 deletions src/cocoindex_code/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ def search(
query: str,
languages: list[str] | None = None,
paths: list[str] | None = None,
exclude_paths: list[str] | None = None,
limit: int = 5,
offset: int = 0,
on_waiting: Callable[[], None] | None = None,
Expand All @@ -298,6 +299,7 @@ def search(
query=query,
languages=languages,
paths=paths,
exclude_paths=exclude_paths,
limit=limit,
offset=offset,
)
Expand Down
1 change: 1 addition & 0 deletions src/cocoindex_code/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ async def _search_with_wait(
query=req.query,
languages=req.languages,
paths=req.paths,
exclude_paths=req.exclude_paths,
limit=req.limit,
offset=req.offset,
)
Expand Down
2 changes: 2 additions & 0 deletions src/cocoindex_code/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ async def search(
query: str,
languages: list[str] | None = None,
paths: list[str] | None = None,
exclude_paths: list[str] | None = None,
limit: int = 5,
offset: int = 0,
) -> list[SearchResult]:
Expand All @@ -192,6 +193,7 @@ async def search(
offset=offset,
languages=languages,
paths=paths,
exclude_paths=exclude_paths,
)
return [
SearchResult(
Expand Down
1 change: 1 addition & 0 deletions src/cocoindex_code/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SearchRequest(_msgspec.Struct, tag="search"):
query: str
languages: list[str] | None = None
paths: list[str] | None = None
exclude_paths: list[str] | None = None
limit: int = 5
offset: int = 0

Expand Down
13 changes: 10 additions & 3 deletions src/cocoindex_code/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def _full_scan_query(
offset: int,
languages: list[str] | None = None,
paths: list[str] | None = None,
exclude_paths: list[str] | None = None,
) -> list[tuple[Any, ...]]:
"""Full scan with SQL-level distance computation and filtering."""
conditions: list[str] = []
Expand All @@ -66,6 +67,11 @@ def _full_scan_query(
conditions.append(f"({path_clauses})")
params.extend(paths)

if exclude_paths:
exclude_clauses = " AND ".join("file_path NOT GLOB ?" for _ in exclude_paths)
conditions.append(f"({exclude_clauses})")
params.extend(exclude_paths)

where = f"WHERE {' AND '.join(conditions)}" if conditions else ""
params.extend([limit, offset])

Expand All @@ -90,6 +96,7 @@ async def query_codebase(
offset: int = 0,
languages: list[str] | None = None,
paths: list[str] | None = None,
exclude_paths: list[str] | None = None,
) -> list[QueryResult]:
"""
Perform vector similarity search using vec0 KNN index.
Expand All @@ -114,8 +121,8 @@ async def query_codebase(
embedding_bytes = query_embedding.astype("float32").tobytes()

with db.readonly() as conn:
if paths:
rows = _full_scan_query(conn, embedding_bytes, limit, offset, languages, paths)
if paths or exclude_paths:
rows = _full_scan_query(conn, embedding_bytes, limit, offset, languages, paths, exclude_paths)
elif not languages or len(languages) == 1:
lang = languages[0] if languages else None
rows = _knn_query(conn, embedding_bytes, limit + offset, lang)
Expand All @@ -131,7 +138,7 @@ async def query_codebase(
key=lambda r: r[5],
)

if not paths:
if not paths and not exclude_paths:
rows = rows[offset:]

return [
Expand Down
8 changes: 8 additions & 0 deletions src/cocoindex_code/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ async def search(
" Example: ['src/utils/*', '*.py']"
),
),
exclude_paths: list[str] | None = Field(
default=None,
description=(
"Exclude file path pattern(s) using GLOB wildcards (* and ?)."
" Example: ['i18n/locales/*', '*.min.js']"
),
),
) -> SearchResultModel:
"""Query the codebase index via the daemon."""
from . import client as _client
Expand All @@ -132,6 +139,7 @@ async def search(
query=query,
languages=languages,
paths=paths,
exclude_paths=exclude_paths,
limit=limit,
offset=offset,
),
Expand Down