| """ |
| Interactive shell for the Folio CLI. |
| |
| This module provides the main entry point for the Folio CLI interactive shell. |
| """ |
|
|
| import argparse |
| import os |
| import traceback |
|
|
| from prompt_toolkit import PromptSession |
| from prompt_toolkit.completion import NestedCompleter |
| from prompt_toolkit.history import FileHistory |
| from prompt_toolkit.shortcuts import confirm |
| from rich.console import Console |
|
|
| from src.focli.commands import execute_command, get_command_registry |
| from src.focli.commands.simulate import simulate_command |
| from src.focli.utils import load_portfolio |
|
|
|
|
| def create_completer(): |
| """Create a nested completer for command auto-completion. |
| |
| Returns: |
| NestedCompleter for command auto-completion |
| """ |
| |
| commands = get_command_registry() |
|
|
| |
| completion_dict = {} |
| for cmd_name, cmd_info in commands.items(): |
| if cmd_info.get("subcommands"): |
| completion_dict[cmd_name] = { |
| subcmd: None for subcmd in cmd_info["subcommands"] |
| } |
| else: |
| completion_dict[cmd_name] = None |
|
|
| return NestedCompleter.from_nested_dict(completion_dict) |
|
|
|
|
| def initialize_state(): |
| """Initialize the application state. |
| |
| Returns: |
| Dictionary containing the initial application state |
| """ |
| return { |
| "portfolio_groups": None, |
| "portfolio_summary": None, |
| "loaded_portfolio": None, |
| "last_simulation": None, |
| "simulation_history": [], |
| "last_position": None, |
| "position_simulations": {}, |
| "filtered_groups": None, |
| "simulation_presets": { |
| "default": {"range": 20.0, "steps": 13}, |
| "detailed": {"range": 20.0, "steps": 21, "detailed": True}, |
| "quick": {"range": 10.0, "steps": 5}, |
| }, |
| "command_history": [], |
| } |
|
|
|
|
| def load_default_portfolio(state, console): |
| """Try to load the default portfolio. |
| |
| Args: |
| state: Application state |
| console: Rich console for output |
| |
| Returns: |
| True if portfolio was loaded successfully, False otherwise |
| """ |
| default_portfolio = "private-data/portfolio-private.csv" |
| try: |
| load_portfolio(default_portfolio, state, console) |
| return True |
| except Exception as e: |
| console.print(f"[yellow]Could not load default portfolio: {e}[/yellow]") |
| console.print( |
| "[yellow]Use 'portfolio load <path>' to load a portfolio.[/yellow]" |
| ) |
| return False |
|
|
|
|
| def main(): |
| """Main entry point for the Folio CLI.""" |
| |
| parser = argparse.ArgumentParser(description="Folio CLI") |
| parser.add_argument( |
| "--simulate", action="store_true", help="Run simulation directly" |
| ) |
| parser.add_argument( |
| "--preset", type=str, help="Simulation preset to use (default, quick, detailed)" |
| ) |
| args = parser.parse_args() |
|
|
| console = Console() |
|
|
| |
| state = initialize_state() |
|
|
| |
| if args.simulate: |
| console.print("[bold cyan]Folio CLI - Direct Simulation[/bold cyan]") |
|
|
| |
| if load_default_portfolio(state, console): |
| |
| sim_args = [] |
| if args.preset: |
| sim_args = ["-p", args.preset] |
|
|
| |
| simulate_command(sim_args, state, console) |
| return |
| else: |
| console.print( |
| "[bold red]Error:[/bold red] Cannot run simulation without a portfolio." |
| ) |
| console.print( |
| "Please run the CLI without --simulate to load a portfolio first." |
| ) |
| return |
|
|
| |
| console.print("[bold cyan]Folio Interactive Shell[/bold cyan]") |
| console.print("Type 'help' for available commands.") |
|
|
| |
| history_file = os.path.expanduser("~/.folio_history") |
|
|
| |
| session = PromptSession( |
| completer=create_completer(), history=FileHistory(history_file) |
| ) |
|
|
| |
| load_default_portfolio(state, console) |
|
|
| |
| while True: |
| try: |
| |
| text = session.prompt("folio> ") |
|
|
| if not text.strip(): |
| continue |
|
|
| |
| if text.strip().lower() == "exit": |
| if confirm_exit(): |
| break |
| continue |
|
|
| |
| execute_command(text, state, console) |
|
|
| |
| state["command_history"].append(text) |
|
|
| except KeyboardInterrupt: |
| |
| console.print("[yellow]Use 'exit' to exit the application.[/yellow]") |
| except EOFError: |
| |
| break |
| except Exception as e: |
| |
| console.print(f"[bold red]Error:[/bold red] {e}") |
| console.print(traceback.format_exc()) |
|
|
|
|
| def confirm_exit(): |
| """Confirm exit with the user. |
| |
| Returns: |
| True if the user confirms, False otherwise |
| """ |
| return confirm("Are you sure you want to exit?") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|