from __future__ import annotations from typing import Any, Dict, List, Sequence import sys from SYS.logger import log from SYS.detail_view_helpers import create_detail_view, prepare_detail_metadata from SYS.payload_builders import build_table_result_payload from SYS.result_publication import publish_result_table from SYS.result_table_helpers import add_row_columns from SYS import pipeline as ctx from . import _shared as sh Cmdlet = sh.Cmdlet CmdletArg = sh.CmdletArg SharedArgs = sh.SharedArgs normalize_hash = sh.normalize_hash parse_cmdlet_args = sh.parse_cmdlet_args normalize_result_input = sh.normalize_result_input should_show_help = sh.should_show_help class Get_Note(Cmdlet): def __init__(self) -> None: super().__init__( name="get-note", summary="List notes on a file in a store.", usage='get-note -store [-query "hash:"]', alias=["get-notes", "get_note"], arg=[ SharedArgs.STORE, SharedArgs.QUERY, ], detail=[ "- Notes are retrieved via the selected store backend.", "- Lyrics are stored in a note named 'lyric'.", ], exec=self.run, ) try: SharedArgs.STORE.choices = SharedArgs.get_store_choices(None) except Exception: pass self.register() def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int: if should_show_help(args): log(f"Cmdlet: {self.name}\nSummary: {self.summary}\nUsage: {self.usage}") return 0 parsed = parse_cmdlet_args(args, self) store_override = parsed.get("store") query_hash, query_valid = sh.require_single_hash_query( parsed.get("query"), "[get_note] Error: -query must be of the form hash:", log_file=sys.stderr, ) if not query_valid: return 1 results = normalize_result_input(result) if not results: if store_override and query_hash: results = [{ "store": str(store_override), "hash": query_hash }] else: log( '[get_note] Error: Requires piped item(s) or -store and -query "hash:"', file=sys.stderr, ) return 1 store_registry = None any_notes = False display_items: List[Dict[str, Any]] = [] # We assume single subject for get-note detail view main_res = results[0] metadata = prepare_detail_metadata(main_res) note_table = create_detail_view( "Notes", metadata, table_name="note", source_command=("get-note", []), ) for res in results: if not isinstance(res, dict): continue store_name, resolved_hash = sh.resolve_item_store_hash( res, override_store=str(store_override) if store_override else None, override_hash=str(query_hash) if query_hash else None, path_fields=("path",), ) if not store_name: log( "[get_note] Error: Missing -store and item has no store field", file=sys.stderr ) return 1 if not resolved_hash: continue # Update metadata if we resolved a hash that wasn't in source if resolved_hash and not metadata.get("Hash"): metadata["Hash"] = resolved_hash if store_name and not metadata.get("Store"): metadata["Store"] = store_name backend, store_registry, exc = sh.get_store_backend( config, store_name, store_registry=store_registry, ) if backend is None: log( f"[get_note] Error: Unknown store '{store_name}': {exc}", file=sys.stderr ) return 1 notes = {} try: notes = backend.get_note( resolved_hash, config=config ) or {} except Exception: notes = {} if not notes: continue any_notes = True # Emit each note as its own row so CLI renders a proper note table for k in sorted(notes.keys(), key=lambda x: str(x).lower()): v = notes.get(k) raw_text = str(v or "") # Keep payload small for IPC/pipes. raw_text = raw_text[:999] preview = " ".join(raw_text.replace("\r", "").split("\n")) payload = build_table_result_payload( columns=[ ("Name", str(k)), ("Text", preview.strip()), ], store=store_name, hash=resolved_hash, note_name=str(k), note_text=raw_text, ) display_items.append(payload) if note_table is not None: add_row_columns( note_table, [("Name", str(k)), ("Text", preview.strip())], ) ctx.emit(payload) # Always set the table overlay even if empty to show item details publish_result_table(ctx, note_table, display_items, subject=result, overlay=True) if not any_notes: log("No notes found.") return 0 CMDLET = Get_Note()