Loading...
No commits yet
Not committed History
Blame
bib.py • 5.6 KB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Timestamp: 2026-01-27
# File: src/scitex_writer/_cli/bib.py

"""Bibliography CLI commands."""

import argparse
import sys
from pathlib import Path


def cmd_list_files(args: argparse.Namespace) -> int:
    """List bibliography files."""
    from .. import bib

    result = bib.list_files(args.project)
    if not result["success"]:
        print(f"Error: {result['error']}", file=sys.stderr)
        return 1

    print(f"# Bibliography Files ({result['count']})\n")
    print("| File | Entries | Merged |")
    print("|------|---------|--------|")
    for f in result["bibfiles"]:
        merged = "✓" if f["is_merged"] else ""
        print(f"| {f['name']} | {f['entry_count']} | {merged} |")
    return 0


def cmd_list_entries(args: argparse.Namespace) -> int:
    """List bibliography entries."""
    from .. import bib

    result = bib.list_entries(args.project, args.file)
    if not result["success"]:
        print(f"Error: {result['error']}", file=sys.stderr)
        return 1

    print(f"# Bibliography Entries ({result['count']})\n")
    print("| Key | Type | File |")
    print("|-----|------|------|")
    for e in result["entries"]:
        print(f"| {e['citation_key']} | {e['entry_type']} | {e['bibfile']} |")
    return 0


def cmd_get(args: argparse.Namespace) -> int:
    """Get a specific bibliography entry."""
    from .. import bib

    result = bib.get(args.project, args.key)
    if not result["success"]:
        print(f"Error: {result['error']}", file=sys.stderr)
        return 1

    print(result["entry"])
    return 0


def cmd_add(args: argparse.Namespace) -> int:
    """Add a bibliography entry."""
    from .. import bib

    if args.entry == "-":
        entry = sys.stdin.read()
    elif args.entry.startswith("@"):
        entry = args.entry
    else:
        entry_path = Path(args.entry)
        if entry_path.exists():
            entry = entry_path.read_text(encoding="utf-8")
        else:
            entry = args.entry

    result = bib.add(args.project, entry, args.file, not args.allow_duplicates)
    if not result["success"]:
        print(f"Error: {result['error']}", file=sys.stderr)
        return 1

    print(f"Added: {result['citation_key']} to {result['bibfile']}")
    return 0


def cmd_remove(args: argparse.Namespace) -> int:
    """Remove a bibliography entry."""
    from .. import bib

    result = bib.remove(args.project, args.key)
    if not result["success"]:
        print(f"Error: {result['error']}", file=sys.stderr)
        return 1

    print(f"Removed: {result['citation_key']} from {result['removed_from']}")
    return 0


def cmd_merge(args: argparse.Namespace) -> int:
    """Merge all bibliography files."""
    from .. import bib

    result = bib.merge(args.project, args.output, not args.keep_duplicates)
    if not result["success"]:
        print(f"Error: {result['error']}", file=sys.stderr)
        return 1

    print(f"Merged {result['entry_count']} entries to {result['output_file']}")
    if result["duplicates_skipped"] > 0:
        print(f"Skipped {result['duplicates_skipped']} duplicates")
    return 0


def register_parser(subparsers) -> argparse.ArgumentParser:
    """Register bib subcommand parser."""
    bib_help = """Bibliography management.

Quick start:
  scitex-writer bib list-files               # List .bib files
  scitex-writer bib list-entries             # List all entries
  scitex-writer bib get Smith2024            # Get specific entry
  scitex-writer bib add '@article{...}'      # Add entry
  scitex-writer bib remove Smith2024         # Remove entry
  scitex-writer bib merge                    # Merge and deduplicate
"""
    parser = subparsers.add_parser(
        "bib",
        help="Bibliography management",
        description=bib_help,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    sub = parser.add_subparsers(dest="bib_command", title="Commands")

    # list-files
    lf = sub.add_parser("list-files", help="List .bib files")
    lf.add_argument("-p", "--project", default=".", help="Project path")
    lf.set_defaults(func=cmd_list_files)

    # list-entries
    le = sub.add_parser("list-entries", help="List bibliography entries")
    le.add_argument("-p", "--project", default=".", help="Project path")
    le.add_argument("-f", "--file", help="Specific .bib file")
    le.set_defaults(func=cmd_list_entries)

    # get
    g = sub.add_parser("get", help="Get a specific entry")
    g.add_argument("key", help="Citation key")
    g.add_argument("-p", "--project", default=".", help="Project path")
    g.set_defaults(func=cmd_get)

    # add
    a = sub.add_parser("add", help="Add a bibliography entry")
    a.add_argument("entry", help="BibTeX entry, file path, or '-' for stdin")
    a.add_argument("-p", "--project", default=".", help="Project path")
    a.add_argument("-f", "--file", default="custom.bib", help="Target .bib file")
    a.add_argument(
        "--allow-duplicates", action="store_true", help="Allow duplicate keys"
    )
    a.set_defaults(func=cmd_add)

    # remove
    r = sub.add_parser("remove", help="Remove an entry")
    r.add_argument("key", help="Citation key to remove")
    r.add_argument("-p", "--project", default=".", help="Project path")
    r.set_defaults(func=cmd_remove)

    # merge
    m = sub.add_parser("merge", help="Merge all .bib files")
    m.add_argument("-p", "--project", default=".", help="Project path")
    m.add_argument("-o", "--output", default="bibliography.bib", help="Output file")
    m.add_argument(
        "--keep-duplicates", action="store_true", help="Keep duplicate entries"
    )
    m.set_defaults(func=cmd_merge)

    return parser


# EOF