Search command internals

vcspull.cli.search is the implementation behind vcspull search — it matches repositories with field-aware queries.

Search repositories functionality for vcspull.

class vcspull.cli.search.SearchToken
class vcspull.cli.search.SearchToken

Bases: NamedTuple

Parsed query token with optional field restrictions.

class vcspull.cli.search.SearchPattern
class vcspull.cli.search.SearchPattern

Bases: object

Compiled search pattern tied to repository fields.

vcspull.cli.search.normalize_fields(fields)
function[source]
function[source]
vcspull.cli.search.normalize_fields(fields)

Normalize and validate search fields.

Parameters:

fields (list[str] | None) – Raw field list, optionally comma-delimited

Returns:

Normalized field names

Return type:

tuple[str, ...]

Examples

>>> normalize_fields(["name", "url"])
('name', 'url')
>>> normalize_fields(["name,url", "workspace"])
('name', 'url', 'workspace')
>>> normalize_fields(None)
('name', 'path', 'url', 'workspace')
vcspull.cli.search.parse_query_terms(terms, *, default_fields)
function[source]
function[source]
vcspull.cli.search.parse_query_terms(terms, *, default_fields)

Parse raw search terms into field-scoped tokens.

Parameters:
  • terms (list[str]) – Raw query terms

  • default_fields (tuple[str, ...]) – Fields to apply when no field prefix is provided

Returns:

Parsed search tokens

Return type:

list[SearchToken]

Examples

>>> tokens = parse_query_terms(
...     ["name:django", "github"],
...     default_fields=("name", "url"),
... )
>>> tokens[0]
SearchToken(fields=('name',), pattern='django')
>>> tokens[1]
SearchToken(fields=('name', 'url'), pattern='github')
vcspull.cli.search.compile_search_patterns(tokens, *, ignore_case, smart_case, fixed_strings, word_regexp)
function[source]
function[source]
vcspull.cli.search.compile_search_patterns(tokens, *, ignore_case, smart_case, fixed_strings, word_regexp)

Compile search tokens into regex patterns.

Parameters:
  • tokens (list[SearchToken]) – Parsed tokens

  • ignore_case (bool) – Force case-insensitive matching

  • smart_case (bool) – Enable smart-case matching

  • fixed_strings (bool) – Treat patterns as literal strings

  • word_regexp (bool) – Match whole words only

Returns:

Compiled search patterns

Return type:

list[SearchPattern]

Examples

>>> tokens = [SearchToken(fields=("name",), pattern="django")]
>>> patterns = compile_search_patterns(
...     tokens,
...     ignore_case=True,
...     smart_case=False,
...     fixed_strings=False,
...     word_regexp=False,
... )
>>> bool(patterns[0].regex.search("Django"))
True
vcspull.cli.search.evaluate_match(fields, patterns, *, match_any)
function[source]
function[source]
vcspull.cli.search.evaluate_match(fields, patterns, *, match_any)

Return match status and matched substrings by field.

Parameters:
  • fields (dict[str, str]) – Field values to search

  • patterns (list[SearchPattern]) – Compiled search patterns

  • match_any (bool) – Whether to match any token instead of all tokens

Returns:

Match status and mapping of matched fields to match strings

Return type:

tuple[bool, dict[str, list[str]]]

Examples

>>> fields = {
...     "name": "django",
...     "path": "~/code/django",
...     "url": "git+https://github.com/django/django.git",
...     "workspace": "~/code/",
... }
>>> tokens = parse_query_terms(["name:django"], default_fields=("name", "url"))
>>> patterns = compile_search_patterns(
...     tokens,
...     ignore_case=False,
...     smart_case=False,
...     fixed_strings=False,
...     word_regexp=False,
... )
>>> matched, matches = evaluate_match(fields, patterns, match_any=False)
>>> matched
True
>>> matches["name"]
['django']
vcspull.cli.search.highlight_text(text, patterns, *, colors, base_color=None)
function[source]
function[source]
vcspull.cli.search.highlight_text(text, patterns, *, colors, base_color=None)

Return text with regex matches highlighted.

Parameters:
  • text (str) – Input text

  • patterns (list[re.Pattern[str]]) – Patterns to highlight

  • colors (Colors) – Color manager

  • base_color (str | None) – Base color code to reapply outside highlights

Returns:

Highlighted text

Return type:

str

Examples

>>> from vcspull.cli._colors import ColorMode
>>> colors = Colors(ColorMode.NEVER)
>>> highlight_text("django", [re.compile("jan")], colors=colors)
'django'
vcspull.cli.search.find_search_matches(repos, patterns, *, match_any, invert_match)
function[source]
function[source]
vcspull.cli.search.find_search_matches(repos, patterns, *, match_any, invert_match)

Return search matches for repositories.

Parameters:
  • repos (list[ConfigDict]) – Repository configurations to search

  • patterns (list[SearchPattern]) – Compiled search patterns

  • match_any (bool) – Whether any token match is sufficient

  • invert_match (bool) – Whether to return non-matching repositories

Returns:

Search results containing matched fields

Return type:

list[dict[str, t.Any]]

Examples

>>> repos = [
...     {
...         "name": "django",
...         "path": "/tmp/django",
...         "url": "git+https://github.com/django/django.git",
...         "workspace_root": "~/code/",
...     },
... ]
>>> tokens = parse_query_terms(["django"], default_fields=DEFAULT_FIELDS)
>>> patterns = compile_search_patterns(
...     tokens,
...     ignore_case=False,
...     smart_case=False,
...     fixed_strings=False,
...     word_regexp=False,
... )
>>> results = find_search_matches(
...     repos,
...     patterns,
...     match_any=False,
...     invert_match=False,
... )
>>> [item["name"] for item in results]
['django']
vcspull.cli.search.create_search_subparser(parser)
function[source]
function[source]
vcspull.cli.search.create_search_subparser(parser)

Create vcspull search argument subparser.

Parameters:

parser (argparse.ArgumentParser) – The parser to configure

Return type:

None

Examples

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> create_search_subparser(parser)
>>> parsed = parser.parse_args(["django"])
>>> parsed.query_terms
['django']
vcspull.cli.search.search_repos(query_terms, config_path, workspace_root, output_json, output_ndjson, color, *, fields, ignore_case, smart_case, fixed_strings, word_regexp, invert_match, match_any, emit_output=True)
function[source]
function[source]
vcspull.cli.search.search_repos(query_terms, config_path, workspace_root, output_json, output_ndjson, color, *, fields, ignore_case, smart_case, fixed_strings, word_regexp, invert_match, match_any, emit_output=True)

Search configured repositories.

Parameters:
  • query_terms (list[str]) – Search query terms

  • config_path (pathlib.Path | None) – Path to config file, or None to auto-discover

  • workspace_root (str | None) – Filter by workspace root

  • output_json (bool) – Output as JSON

  • output_ndjson (bool) – Output as NDJSON

  • color (str) – Color mode (auto, always, never)

  • fields (list[str] | None) – Field list for unscoped queries

  • ignore_case (bool) – Force case-insensitive matching

  • smart_case (bool) – Enable smart-case matching

  • fixed_strings (bool) – Treat terms as literal strings

  • word_regexp (bool) – Match whole words only

  • invert_match (bool) – Return non-matching repositories

  • match_any (bool) – Match if any term matches

  • emit_output (bool) – Whether to emit human/JSON output

Returns:

Search results

Return type:

list[dict[str, t.Any]]

Examples

>>> from vcspull.config import save_config_yaml
>>> config_file = tmp_path / ".vcspull.yaml"
>>> save_config_yaml(
...     config_file,
...     {"~/code/": {"django": {"repo": "git+https://github.com/django/django.git"}}},
... )
>>> results = search_repos(
...     ["django"],
...     config_path=config_file,
...     workspace_root=None,
...     output_json=False,
...     output_ndjson=False,
...     color="never",
...     fields=None,
...     ignore_case=False,
...     smart_case=False,
...     fixed_strings=False,
...     word_regexp=False,
...     invert_match=False,
...     match_any=False,
...     emit_output=False,
... )
>>> [item["name"] for item in results]
['django']