This commit is contained in:
2026-01-12 20:50:39 -08:00
parent bb4ac1f36b
commit 3bd36baf5a
2 changed files with 102 additions and 1833 deletions

View File

@@ -34,6 +34,14 @@ except ImportError:
TEXTUAL_AVAILABLE = False TEXTUAL_AVAILABLE = False
# Import ResultModel from the API for unification
try:
from SYS.result_table_api import ResultModel
except ImportError:
# Fallback if not available yet in directory structure (unlikely)
ResultModel = None
def _sanitize_cell_text(value: Any) -> str: def _sanitize_cell_text(value: Any) -> str:
"""Coerce to a single-line, tab-free string suitable for terminal display.""" """Coerce to a single-line, tab-free string suitable for terminal display."""
if value is None: if value is None:
@@ -741,8 +749,11 @@ class ResultTable:
row = self.add_row() row = self.add_row()
row.payload = result row.payload = result
# Handle ResultModel from the new strict API (SYS/result_table_api.py)
if ResultModel and isinstance(result, ResultModel):
self._add_result_model(row, result)
# Handle TagItem from get_tag.py (tag display with index) # Handle TagItem from get_tag.py (tag display with index)
if hasattr(result, "__class__") and result.__class__.__name__ == "TagItem": elif hasattr(result, "__class__") and result.__class__.__name__ == "TagItem":
self._add_tag_item(row, result) self._add_tag_item(row, result)
# Handle ResultItem from search_file.py (compact display) # Handle ResultItem from search_file.py (compact display)
elif hasattr(result, "__class__") and result.__class__.__name__ == "ResultItem": elif hasattr(result, "__class__") and result.__class__.__name__ == "ResultItem":
@@ -781,6 +792,62 @@ class ResultTable:
payloads.append(payload) payloads.append(payload)
return payloads return payloads
@classmethod
def from_api_table(cls, api_table: Any) -> "ResultTable":
"""Convert a strict SYS.result_table_api.ResultTable into an interactive monolith ResultTable.
This allows providers using the new strict API to benefit from the monolith's
interactive selection (@N) and rich layout features.
"""
# Duck typing check instead of strict isinstance to keep dependencies light
if not hasattr(api_table, "rows") or not hasattr(api_table, "columns"):
return cls(str(api_table))
title = getattr(api_table, "provider", "")
# Try to get provider metadata title if available
meta = getattr(api_table, "meta", {})
if meta and isinstance(meta, dict):
title = meta.get("title") or title
instance = cls(title)
# Import adapters if we want to extract selection args automatically
# but let's keep it simple: we rely on add_result logic for most things.
# Iterate rows and build interactive ones
for r in api_table.rows:
row = instance.add_row()
row.payload = r
# Use columns defined in the API table
for col in api_table.columns:
try:
val = col.extractor(r)
if col.format_fn:
val = col.format_fn(val)
row.add_column(col.header, val)
except Exception:
pass
return instance
def _add_result_model(self, row: ResultRow, result: ResultModel) -> None:
"""Extract and add ResultModel fields from the new API to row."""
row.add_column("Title", result.title)
if result.ext:
row.add_column("Ext", result.ext)
if result.size_bytes is not None:
# Use the existing format_mb helper in this file
row.add_column("Size", format_mb(result.size_bytes))
if result.source:
row.add_column("Source", result.source)
# Add a placeholder for metadata-like display if needed in the main table
# but usually metadata is handled by the detail panel now
def _add_search_result(self, row: ResultRow, result: Any) -> None: def _add_search_result(self, row: ResultRow, result: Any) -> None:
"""Extract and add SearchResult fields to row.""" """Extract and add SearchResult fields to row."""
cols = getattr(result, "columns", None) cols = getattr(result, "columns", None)
@@ -1830,12 +1897,45 @@ def format_result(result: Any, title: str = "") -> str:
return str(table) return str(table)
def extract_item_metadata(item: Any) -> Dict[str, Any]: def extract_item_metadata(item: Any) -> Dict[str, Any]:
"""Extract a comprehensive set of metadata from an item for the ItemDetailView.""" """Extract a comprehensive set of metadata from an item for the ItemDetailView.
Now supports SYS.result_table_api.ResultModel as a first-class input.
"""
if item is None: if item is None:
return {} return {}
out = {} out = {}
# Handle ResultModel specifically for better detail display
if ResultModel and isinstance(item, ResultModel):
if item.title: out["Title"] = item.title
if item.path: out["Path"] = item.path
if item.ext: out["Ext"] = item.ext
if item.size_bytes: out["Size"] = format_mb(item.size_bytes)
if item.source: out["Store"] = item.source
# Merge internal metadata dict
if item.metadata:
for k, v in item.metadata.items():
# Convert keys to readable labels (snake_case -> Title Case)
label = str(k).replace("_", " ").title()
if label not in out and v is not None:
out[label] = v
# URLs/Tags/Relations from metadata if present
data = item.metadata or {}
url = _get_first_dict_value(data, ["url", "URL"])
if url: out["Url"] = url
rels = _get_first_dict_value(data, ["relationships", "rel"])
if rels: out["Relations"] = rels
tags = _get_first_dict_value(data, ["tags", "tag"])
if tags: out["Tags"] = tags
return out
# Fallback to existing extraction logic for legacy objects/dicts
# Use existing extractors from match-standard result table columns # Use existing extractors from match-standard result table columns
title = extract_title_value(item) title = extract_title_value(item)
if title: if title:

File diff suppressed because it is too large Load Diff