diff --git a/README.md b/README.md index a23de80..ec5c7ce 100644 --- a/README.md +++ b/README.md @@ -119,4 +119,7 @@ Thank you for considering contributing! Please follow these steps: `LinkedIn` - [Visit](https://linkedin.com/in/anshsoni)
`Follow Us` - [Visit](https://linkedin.com/company/py-shell) +### Recent updates check: +updates_to_read.md + ## Thankyou ๐Ÿ˜€
diff --git a/ai_config.json b/ai_config.json new file mode 100644 index 0000000..3ccf8ab --- /dev/null +++ b/ai_config.json @@ -0,0 +1,4 @@ +{ + "api_key": "123", + "smart_suggestions": true +} \ No newline at end of file diff --git a/ai_panel.py b/ai_panel.py new file mode 100644 index 0000000..88e6d0f --- /dev/null +++ b/ai_panel.py @@ -0,0 +1,99 @@ +import json +import os +from prompt_toolkit.shortcuts import checkboxlist_dialog, radiolist_dialog +from rich.console import Console + +console = Console() +AI_CONFIG_FILE = "ai_config.json" + +def load_ai_config(): + """Loads the AI feature configuration from a JSON file.""" + if os.path.exists(AI_CONFIG_FILE): + try: + with open(AI_CONFIG_FILE, 'r') as f: + return json.load(f) + except (json.JSONDecodeError, IOError): + pass + return {"smart_suggestions": False} + +def save_ai_config(config): + """Saves the AI feature configuration to a JSON file.""" + with open(AI_CONFIG_FILE, 'w') as f: + json.dump(config, f, indent=4) + +def show_config_panel(): + """Shows a checklist to toggle AI features ON or OFF.""" + config = load_ai_config() + default_values = [key for key, value in config.items() if value] + + results = checkboxlist_dialog( + title="โš™๏ธ AI Configuration", + text="Use SPACE to toggle features ON/OFF. Press ENTER to save.", + values=[ + ("smart_suggestions", "๐Ÿ’ก Live Smart Suggestions"), + ], + default_values=default_values + ).run() + + if results is not None: + config["smart_suggestions"] = "smart_suggestions" in results + save_ai_config(config) + status = "ON" if config["smart_suggestions"] else "OFF" + console.print(f"\n[bold green]Live Smart Suggestions are now {status}[/bold green]") + +def show_ai_features(): + """Shows the AI features menu.""" + from features import nl_to_code, error_explainer, snippet_search, code_refactor + + AI_FEATURES = [ + ("nl", "๐Ÿง  NL to Code", nl_to_code.run), + ("explain", "โŒ Error Explainer", error_explainer.run), + ("snippet", "๐Ÿ“š Snippet Search", snippet_search.run), + ("refactor", "๐Ÿงน Code Refactor", code_refactor.run), + ("back", "โ†ฉ๏ธ Back to Main Menu", None) + ] + + while True: + choice = radiolist_dialog( + title="๐Ÿค– AI Features", + text="Select an AI feature to run:", + values=[(key, label) for key, label, _ in AI_FEATURES], + ).run() + + if choice is None or choice == "back": + break + + # Find and run the selected feature + for key, label, func in AI_FEATURES: + if key == choice and func: + try: + func() + except Exception as e: + print(f"[Error in {label}]: {e}") + input("\nPress Enter to return to the AI features menu...") + break + +def show_ai_panel(): + """Main AI panel with options to configure or run features.""" + while True: + choice = radiolist_dialog( + title="๐Ÿค– PyShell AI Panel", + text="Choose an option:", + values=[ + ("features", "๐Ÿš€ Run AI Features"), + ("config", "โš™๏ธ Configure AI Settings"), + ("exit", "โ†ฉ๏ธ Return to Shell") + ], + ).run() + + if choice == "features": + show_ai_features() + elif choice == "config": + show_config_panel() + elif choice == "exit" or choice is None: + break + +def is_feature_enabled(feature_name): + """Checks if a specific AI feature is enabled in the config.""" + config = load_ai_config() + return config.get(feature_name, False) \ No newline at end of file diff --git a/config.py b/config.py index bc7080c..c8b2761 100644 --- a/config.py +++ b/config.py @@ -1 +1 @@ -current_terminal_layout = 8 +current_terminal_layout = 2 diff --git a/equations.py b/equations.py index a1d5c99..cc8c463 100644 --- a/equations.py +++ b/equations.py @@ -6,6 +6,11 @@ from sympy.parsing.sympy_parser import parse_expr import re from sympy.abc import x +import time +import msvcrt +from rich.table import Table +from menu_base import MojiSwitchMenu +from statistics_menu import show_statistics_menu console = Console() @@ -119,4 +124,151 @@ def solve_differential(self, args): f"[red]โŒ Error:[/red] {str(e)}\n" "Please ensure your equation is in the correct format.", title="โš ๏ธ Invalid Input", border_style="red" - )) \ No newline at end of file + )) + +def show_equations_menu(): + # Define options for equation operations + options = [ + ("โž• Basic Math", "basic"), + ("๐Ÿ“ Algebra", "algebra"), + ("๐Ÿ“Š Calculus", "calculus"), + ("๐Ÿ“ˆ Statistics", "stats"), + ("๐Ÿ”ข Matrix", "matrix") + ] + + def on_execute(state): + # Get list of enabled operations + enabled_ops = [name for name, value in options if state[value]] + if not enabled_ops: + console.print("[bold red]No operations selected![/bold red]") + return + + # Animate calculation + animate_calculation() + + # Process each enabled operation + results = {} + for op in enabled_ops: + # Simulate calculation + time.sleep(0.5) + results[op] = f"Result for {op}" + + # Display results + animate_results_display(results) + + # Create and run menu + menu = MojiSwitchMenu( + title="๐Ÿงฎ Equation Operations", + options=options, + on_execute=on_execute + ) + menu.run() + +def display_equation_table(equations): + """Display equations in a modern table format""" + table = Table( + show_header=True, + header_style="bold cyan", + box=None, + padding=(0, 1) + ) + + # Add columns + table.add_column("No.", style="dim", width=4) + table.add_column("Type", style="bold") + table.add_column("Description", style="italic") + table.add_column("Status", justify="center", width=4) + + # Add rows with equation types + features = [ + ("1", "Basic Math", "Arithmetic and algebraic operations", "basic"), + ("2", "Algebra", "Solve linear and quadratic equations", "algebra"), + ("3", "Calculus", "Derivatives and integrals", "calculus"), + ("4", "Statistics", "Statistical formulas and calculations", "stats"), + ("5", "Matrix", "Matrix operations and determinants", "matrix") + ] + + for no, name, desc, key in features: + status = "โœ…" if equations.get(key, False) else "โŒ" + table.add_row(no, name, desc, status) + + # Create panel with table + panel = Panel( + table, + title="๐Ÿงฎ Equation Types", + border_style="cyan", + padding=(1, 2) + ) + + console.print(panel) + +def animate_calculation(): + """Animate calculation with a spinning effect""" + spinner = ["โ ‹", "โ ™", "โ น", "โ ธ", "โ ผ", "โ ด", "โ ฆ", "โ ง", "โ ‡", "โ "] + console.print("\n") + for _ in range(20): # 2 seconds of animation + for char in spinner: + console.print(f"\033[A\033[K[bold blue]{char} Calculating...[/bold blue]") + time.sleep(0.1) + console.print("\n") + +def animate_results_display(results): + """Animate results display with a fade-in effect""" + console.print("\n") + for i in range(3): + console.print("\033[A\033[K", end="") + if i == 0: + for key, value in results.items(): + console.print(f"[grey50]{key}: {value}[/grey50]") + elif i == 1: + for key, value in results.items(): + console.print(f"[bold blue]{key}: {value}[/bold blue]") + else: + for key, value in results.items(): + console.print(f"[bold green]{key}: {value}[/bold green]") + time.sleep(0.2) + console.print("\n") + +def animate_equation_solving(equation): + """Animate equation solving with a step-by-step effect""" + console.print("\n") + steps = [ + f"Original equation: {equation}", + "Simplifying...", + "Solving for x...", + "Checking solution..." + ] + + for step in steps: + console.print(f"\033[A\033[K[bold blue]{step}[/bold blue]") + time.sleep(0.5) + console.print("\n") + +def animate_matrix_operation(): + """Animate matrix operation with a progress bar effect""" + console.print("\n") + for i in range(10): + progress = "โ–ˆ" * i + "โ–‘" * (10 - i) + console.print(f"\033[A\033[K[bold blue]Performing matrix operation: [{progress}] {i*10}%[/bold blue]") + time.sleep(0.2) + console.print("\n") + +def solve_equation(equation_str): + try: + # Split equation into left and right sides + left, right = equation_str.split('=') + + # Convert strings to sympy expressions + left_expr = parse_expr(left.strip()) + right_expr = parse_expr(right.strip()) + + # Create equation + equation = Eq(left_expr, right_expr) + + # Solve equation + solution = solve(equation, x) + + return solution + except Exception as e: + console.print(f"Error solving equation: {e}", style="bold red") + return None \ No newline at end of file diff --git a/features/code_refactor.py b/features/code_refactor.py new file mode 100644 index 0000000..86cb82d --- /dev/null +++ b/features/code_refactor.py @@ -0,0 +1,10 @@ +from local_llm_client import run_llama_prompt +import sys + +def run(): + print("\n๐Ÿงน Paste your code below (CTRL+D to end):") + code = sys.stdin.read() + prompt = f"Refactor this code for better readability and performance:\n{code}" + result = run_llama_prompt(prompt) + print("\n๐Ÿ”ง Refactored Code:\n") + print(result) \ No newline at end of file diff --git a/features/error_explainer.py b/features/error_explainer.py new file mode 100644 index 0000000..af2b5f0 --- /dev/null +++ b/features/error_explainer.py @@ -0,0 +1,7 @@ +from local_llm_client import run_llama_prompt + +def run(): + error = input("\nโŒ Paste the error message: ") + prompt = f"Explain and fix this error:\n{error}" + explanation = run_llama_prompt(prompt) + print(f"\n๐Ÿ› ๏ธ Explanation:\n{explanation}") \ No newline at end of file diff --git a/features/nl_to_code.py b/features/nl_to_code.py new file mode 100644 index 0000000..868cb15 --- /dev/null +++ b/features/nl_to_code.py @@ -0,0 +1,13 @@ +from local_llm_client import run_llama_prompt +import os + +def run(): + instruction = input("\n๐Ÿ’ฌ Describe your task: ") + prompt = f"Convert this to a shell command:\nInstruction: {instruction}\nCommand:" + command = run_llama_prompt(prompt) + if command: + print(f"\n๐Ÿง  Suggested Command: {command}") + if input("Run it? (y/n): ").lower().startswith("y"): + os.system(command) + else: + print("\nCould not generate a command.") \ No newline at end of file diff --git a/features/smart_suggestions.py b/features/smart_suggestions.py new file mode 100644 index 0000000..34e1624 --- /dev/null +++ b/features/smart_suggestions.py @@ -0,0 +1,94 @@ +import os +import json +import html + +COMMAND_HINTS = { + "git": "Try: 'git status', 'git add ', 'git commit -m \"message\"'", + "ls": "Try: 'ls -l' for details, 'ls -a' to show hidden files", + "cd": "Try: 'cd ..' to go up, 'cd /path/to/dir' for absolute path", + "python": "Try: 'python my_script.py'", + "pip": "Try: 'pip install ', 'pip freeze > requirements.txt'", + "docker": "Try: 'docker ps', 'docker build .', 'docker run '", + "conda": "Try: 'conda activate ', 'conda list'", + "help": "Shows a list of available commands.", + "~ai": "Opens the AI feature configuration panel.", + "exit": "Exits PyShell." +} + +# Subcommand and syntax hints for commands with sub-features +SUBCOMMAND_HINTS = { + "git": [ + ("status", "git status"), + ("add", "git add "), + ("commit", 'git commit -m ""'), + ("push", "git push"), + ("pull", "git pull"), + ("branch", "git branch"), + ("checkout", "git checkout "), + ("merge", "git merge ") + ], + "pip": [ + ("install", "pip install "), + ("uninstall", "pip uninstall "), + ("freeze", "pip freeze > requirements.txt") + ], + # Add more subcommand hints as needed +} + +def get_live_suggestion(text: str, commands_dict: dict, command_args: dict) -> str: + """Generates a live suggestion with syntax based on all available CLI commands.""" + if not text.strip(): + return "๐Ÿ’ก Tip: Type a command or '~ai' for options." + + words = text.split() + if not words: + return "" + + command = words[0].lower() + rest = words[1:] if len(words) > 1 else [] + + # If the command is a known subcommand group (like git) + if command in SUBCOMMAND_HINTS: + if not rest: + # Show all subcommands + subcmds = [f"{name} ({syntax})" for name, syntax in SUBCOMMAND_HINTS[command]] + return f"๐Ÿ’ก Subcommands: {html.escape(', '.join(subcmds))}" + else: + # Suggest subcommands that match the next word + sub = rest[0].lower() + matches = [syntax for name, syntax in SUBCOMMAND_HINTS[command] if name.startswith(sub)] + if matches: + return f"๐Ÿ’ก Did you mean: {html.escape(', '.join(matches))}?" + + if command in commands_dict: + if command in command_args: + syntax = " ".join(command_args[command]) + return f"โœ… Usage: {command} {html.escape(syntax)}" + else: + return f"โœ… Command '{command}' is valid. Press Enter to execute." + + # Check for partial command matches from the full command list + possible_matches = [cmd for cmd in commands_dict if cmd.startswith(command)] + if possible_matches: + # Suggest the first few matches + suggestions = ", ".join(possible_matches[:3]) + return f"๐Ÿ’ก Did you mean: {suggestions}?" + + return "" # Return empty string if no specific hint + +def run(): + history_path = os.path.join(os.path.dirname(__file__), '..', 'history.json') + try: + with open(history_path, 'r') as f: + history = json.load(f) + except Exception: + history = {} + recent = history.get('commands', [])[-1] if history.get('commands') else '' + # Simple rule-based suggestion + if 'git status' in recent: + suggestion = 'git add .' + elif 'ls' in recent: + suggestion = 'cd ' + else: + suggestion = 'echo Hello World' + print(f"\n๐Ÿ’ก Based on '{recent}', try: {suggestion}") \ No newline at end of file diff --git a/features/snippet_search.py b/features/snippet_search.py new file mode 100644 index 0000000..91e83b8 --- /dev/null +++ b/features/snippet_search.py @@ -0,0 +1,7 @@ +from local_llm_client import run_llama_prompt + +def run(): + topic = input("\n๐Ÿ” What code snippet are you looking for? ") + prompt = f"Give a Python snippet to: {topic}" + snippet = run_llama_prompt(prompt) + print(f"\n๐Ÿ“š Snippet:\n{snippet}") \ No newline at end of file diff --git a/graphs.py b/graphs.py index c154e65..846b8f2 100644 --- a/graphs.py +++ b/graphs.py @@ -4,6 +4,10 @@ from rich.prompt import Prompt, FloatPrompt from rich.panel import Panel from rich import box +import time +from rich.text import Text +from rich.table import Table +from menu_base import MojiSwitchMenu # Safe functions for eval SAFE_FUNCTIONS = { @@ -87,4 +91,127 @@ def run(self): self.console.print("[bold red]Invalid choice. Please enter 1 or 2.[/bold red]") except KeyboardInterrupt: - print("\n") \ No newline at end of file + print("\n") + +def show_graphs_menu(): + # Define options for graph operations + options = [ + ("๐Ÿ“ˆ Line Plot", "line"), + ("๐Ÿ“Š Bar Chart", "bar"), + ("๐Ÿ“‰ Scatter Plot", "scatter"), + ("๐Ÿ“Š Histogram", "histogram"), + ("๐Ÿ“ˆ Pie Chart", "pie"), + ("๐Ÿ“Š 3D Plot", "3d") + ] + + def on_execute(state): + # Get list of enabled operations + enabled_ops = [name for name, value in options if state[value]] + if not enabled_ops: + console.print("[bold red]No operations selected![/bold red]") + return + + # Animate plot creation + animate_plot_creation() + + # Process each enabled operation + results = {} + for op in enabled_ops: + # Simulate plot creation + time.sleep(0.5) + results[op] = f"Plot created for {op}" + + # Display results + animate_plot_display(results) + + # Create and run menu + menu = MojiSwitchMenu( + title="๐Ÿ“Š Graph Operations", + options=options, + on_execute=on_execute + ) + menu.run() + +def display_graph_table(graphs): + """Display graphs in a modern table format""" + table = Table( + show_header=True, + header_style="bold cyan", + box=None, + padding=(0, 1) + ) + + # Add columns + table.add_column("No.", style="dim", width=4) + table.add_column("Type", style="bold") + table.add_column("Description", style="italic") + table.add_column("Status", justify="center", width=4) + + # Add rows with graph types + features = [ + ("1", "Line Plot", "Plot continuous data points", "line"), + ("2", "Bar Chart", "Compare categorical data", "bar"), + ("3", "Scatter Plot", "Show relationships between variables", "scatter"), + ("4", "Histogram", "Display data distribution", "histogram"), + ("5", "Pie Chart", "Show proportional data", "pie"), + ("6", "3D Plot", "Visualize three-dimensional data", "3d") + ] + + for no, name, desc, key in features: + status = "โœ…" if graphs.get(key, False) else "โŒ" + table.add_row(no, name, desc, status) + + # Create panel with table + panel = Panel( + table, + title="๐Ÿ“Š Graph Types", + border_style="cyan", + padding=(1, 2) + ) + + console.print(panel) + +def animate_plot_creation(): + """Animate plot creation with a progress bar effect""" + console.print("\n") + for i in range(10): + progress = "โ–ˆ" * i + "โ–‘" * (10 - i) + console.print(f"\033[A\033[K[bold blue]Creating plot: [{progress}] {i*10}%[/bold blue]") + time.sleep(0.2) + console.print("\n") + +def animate_plot_display(plots): + """Animate plot display with a fade-in effect""" + console.print("\n") + for i in range(3): + console.print("\033[A\033[K", end="") + if i == 0: + for key, value in plots.items(): + console.print(f"[grey50]{key}: {value}[/grey50]") + elif i == 1: + for key, value in plots.items(): + console.print(f"[bold blue]{key}: {value}[/bold blue]") + else: + for key, value in plots.items(): + console.print(f"[bold green]{key}: {value}[/bold green]") + time.sleep(0.2) + console.print("\n") + +def animate_data_loading(): + """Animate data loading with a spinning effect""" + spinner = ["โ ‹", "โ ™", "โ น", "โ ธ", "โ ผ", "โ ด", "โ ฆ", "โ ง", "โ ‡", "โ "] + console.print("\n") + for _ in range(10): # 1 second of animation + for char in spinner: + console.print(f"\033[A\033[K[bold blue]{char} Loading data...[/bold blue]") + time.sleep(0.1) + console.print("\n") + +def animate_export_progress(): + """Animate export progress with a progress bar effect""" + console.print("\n") + for i in range(10): + progress = "โ–ˆ" * i + "โ–‘" * (10 - i) + console.print(f"\033[A\033[K[bold blue]Exporting plot: [{progress}] {i*10}%[/bold blue]") + time.sleep(0.2) + console.print("\n") \ No newline at end of file diff --git a/local_llm_client.py b/local_llm_client.py new file mode 100644 index 0000000..a1f7dab --- /dev/null +++ b/local_llm_client.py @@ -0,0 +1,40 @@ +from llama_cpp import Llama, CreateCompletionResponse +from rich.console import Console +import typing + +console = Console() + +# The model path provided by the user +MODEL_PATH = "C:/Users/Prince Patel/models/mistral/mistral-7b-instruct-v0.1.Q4_K_M.gguf" + +_llm_cache = None + +def get_llama_client(): + """Initializes and returns the Llama client, caching it for the session.""" + global _llm_cache + if _llm_cache is None: + try: + console.print(f"[bold yellow]Loading model from: {MODEL_PATH}...[/bold yellow]") + _llm_cache = Llama(model_path=MODEL_PATH, n_ctx=2048, verbose=False) + console.print("[bold green]Model loaded successfully![/bold green]") + except Exception as e: + console.print(f"[bold red]Error loading model: {e}[/bold red]") + _llm_cache = None + return _llm_cache + +def run_llama_prompt(prompt: str, max_tokens=512, temperature=0.7) -> str: + """Runs a prompt against the local LLM and returns the text response.""" + llm = get_llama_client() + if not llm: + return "Local model is not available." + + try: + response = llm(prompt, max_tokens=max_tokens, temperature=temperature, stream=False) + # We expect a dictionary, so we assert the type to satisfy the linter + response_dict = typing.cast(CreateCompletionResponse, response) + if response_dict and 'choices' in response_dict and response_dict['choices']: + return response_dict['choices'][0]['text'].strip() + return "Failed to get a valid response from the model." + except Exception as e: + console.print(f"[bold red]Error during model inference: {e}[/bold red]") + return "An error occurred while generating a response." \ No newline at end of file diff --git a/main.py b/main.py index 6339349..5590b1b 100644 --- a/main.py +++ b/main.py @@ -1,17 +1,29 @@ import os, time, psutil, json, pyperclip, random, string, threading, time, pyfiglet, config from rich.console import Console from rich.prompt import Prompt +from rich.text import Text +from rich.panel import Panel +from rich.markdown import Markdown +from prompt_toolkit import PromptSession +from prompt_toolkit.completion import WordCompleter, Completer, Completion +from ai_panel import show_ai_panel, is_feature_enabled +from prompt_toolkit.key_binding import KeyBindings +from rich.live import Live +from rich.table import Table +import msvcrt +from prompt_toolkit.formatted_text import HTML +from features.smart_suggestions import get_live_suggestion # dependencies from weather import Weather -from task import Task +from tasks import Task from linux_commands import Commands from git_commands import Git from terminals import Terminal from song import Song from equations import Equations from game import Game -from statistical import StatisticsCalculator +from statistics_menu import show_statistics_menu from graphs import GraphPlotter console = Console() @@ -22,6 +34,93 @@ stop_scheduler = False prompt_flag = True +# Animated ASCII Art for PyShell +ASCII_ART = [ + " ____ ____ _ _ _ ", + "| _ \\ _ _/ ___|| |__ ___| | |", + "| |_) | | | \\___ \\| '_ \\ / _ \\ | |", + "| __/| |_| |___) | | | | __/ | |", + "|_| \\__, |____/|_| |_|\\___|_|_|", + " |___/" +] + +COLOR_WAVE = [ + "deep_pink3", "hot_pink", "magenta", "purple", + "blue_violet", "royal_blue1", "cyan", "turquoise2", + "spring_green3", "lime", "yellow", "orange1", + "red", "dark_red", "deep_pink2", "medium_purple" +] + +WELCOME_ASCII = [ + " __ __ _ ", + " \\ \\ / /__| | ___ ___ _ __ ___ ___ ", + " \\ \\ /\\ / / _ \\ |/ __/ _ \\| '_ ` _ \\ / _ \\ ", + " \\ V V / __/ | (_| (_) | | | | | | __/ ", + " \\_/\\_/ \\___|_|\\___\\___/|_| |_| |_|\\___| " +] + +def animate_welcome_zoom_out(): + max_padding = 12 + welcome_colors = ["deep_pink3", "hot_pink", "magenta", "purple", "blue_violet"] + for pad in range(max_padding, -1, -2): # 7 frames + console.clear() + for i, line in enumerate(WELCOME_ASCII): + color = welcome_colors[i % len(welcome_colors)] + console.print(" " * pad + f"[bold {color}]{line}[/bold {color}]", justify="left") + time.sleep(0.05) + console.clear() + +def animate_welcome_ascii_reveal(): + welcome_colors = ["deep_pink3", "hot_pink", "magenta", "purple", "blue_violet"] + for col in range(1, len(WELCOME_ASCII[0]) + 1): + console.clear() + for i, line in enumerate(WELCOME_ASCII): + # Reveal up to the current column, mask the rest + revealed = line[:col] + masked = line[col:] + color = welcome_colors[i % len(welcome_colors)] + console.print(f"[bold {color}]{revealed}[/bold {color}][grey23]{masked}[/grey23]", justify='left') + time.sleep(0.07) + time.sleep(0.5) + console.clear() + +def animate_ascii_art_wave(): + animate_welcome_zoom_out() + for frame in range(7): # 7 frames + console.clear() + for idx, line in enumerate(ASCII_ART): + wave_offset = (frame + idx) % len(COLOR_WAVE) + styled_line = Text() + for i, char in enumerate(line): + color = COLOR_WAVE[(wave_offset + i) % len(COLOR_WAVE)] + styled_line.append(char, style=color) + console.print(styled_line) + time.sleep(0.07) + console.clear() + # Final static display with gradient effect + final_colors = ["deep_pink3", "hot_pink", "magenta", "purple", "blue_violet", "royal_blue1"] + for i, line in enumerate(ASCII_ART): + color = final_colors[i % len(final_colors)] + console.print(Text(line, style=f"bold {color}")) + +def show_command_feedback(cmd): + table = Table.grid(padding=(0, 1)) + table.add_column("Status", style="cyan") + table.add_column("Command", style="green") + table.add_row("", cmd) + with Live(table, refresh_per_second=10): + time.sleep(0.1) # Brief pause for visual feedback + +def show_smart_suggestion(): + suggestions = [ + "Try 'git status' to check repository state", + "Use 'weather' to get local forecast", + "Run 'stats' for statistical calculations", + "Type '~ai' to configure AI features" + ] + suggestion = random.choice(suggestions) + console.print(f"\n[bold green]๐Ÿ’ก {suggestion}[/bold green]") + # Load users def load_users(): with lock: @@ -91,7 +190,6 @@ def generate_password(*args): except ValueError: console.print("Invalid input. Using default length (12)", style="bold red") length = 12 - display_prompt(username) return characters = string.ascii_letters + string.digits + string.punctuation @@ -121,18 +219,140 @@ def display_prompt(username): elif config.current_terminal_layout == 8: Terminal().terminal_8() - console.print(terminal.get_prompt()) + prompt = terminal.get_prompt() + console.print(f"{prompt}", justify="left") # clear console def clear(*args): os.system('cls' if os.name == 'nt' else 'clear') +def show_suggestions(): + suggestions = """ +# Welcome to PyShell! + +Here are some things you can try: + +โ€ข File: rename, move, copy, delete, create, list, edit, cd +โ€ข Processes: list, kill +โ€ข Network: info +โ€ข Clipboard: copy, paste +โ€ข Password: generate +โ€ข Math: calculator, math-help, equation, differential, stats +โ€ข Weather: get weather +โ€ข Tasks: schedule, list, unschedule, stop +โ€ข Terminal: change style +โ€ข Games: play games +โ€ข Graphs: plot +โ€ข Git: status, branches, create, switch, delete, merge, clone, add, commit, push, pull, stash, undo, recover, dashboard, auto_merge, voice, reminder, offline_sync, history, help +โ€ข Music: play a song +โ€ข Other: clear, exit +""" + panel = Panel.fit(Markdown(suggestions), title="๐Ÿ’ก Suggestions", border_style="yellow", padding=(1, 2)) + console.print(panel) + +def show_menu(): + menu_items = [ + ("1", "๐Ÿ“Š Statistics", "Calculate statistics and generate plots"), + ("2", "๐ŸŒค๏ธ Weather", "Get weather information"), + ("3", "๐Ÿ“ Tasks", "Manage your tasks"), + ("4", "๐Ÿ”ง Terminal", "Customize terminal appearance"), + ("5", "๐Ÿค– AI Panel", "Configure AI features"), + ("6", "๐Ÿ“ˆ Graph", "Create and visualize graphs"), + ("7", "๐Ÿงฎ Equations", "Solve mathematical equations"), + ("8", "๐Ÿ“‚ Git", "Git repository management"), + ("9", "โš™๏ธ Settings", "Configure PyShell settings"), + ("0", "โŒ Exit", "Exit PyShell") + ] + + selected_index = 0 + + # Animate header + console.print("\n") + for i in range(3): + console.print("\033[A\033[K", end="") + if i == 0: + console.print("[bold cyan]โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—[/bold cyan]") + elif i == 1: + console.print("[bold cyan]โ•‘ PyShell Menu โ•‘[/bold cyan]") + else: + console.print("[bold cyan]โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•[/bold cyan]") + time.sleep(0.05) + + # Print initial menu with fade-in effect + for i, (no, name, desc) in enumerate(menu_items): + if i == selected_index: + console.print(f"[bold green]โ–ถ {name}[/bold green]") + else: + console.print(f" {name}") + time.sleep(0.02) # Fade-in effect + + while True: + if msvcrt.kbhit(): + key = msvcrt.getch() + + # Arrow key handling + if key == b'\xe0': # Arrow key prefix + key = msvcrt.getch() + if key == b'H': # Up arrow + # Move up one line + console.print("\033[A", end="") + # Clear current line + console.print("\033[K", end="") + # Print previous item without arrow + console.print(f" {menu_items[selected_index][1]}") + # Move up one more line + console.print("\033[A", end="") + # Clear current line + console.print("\033[K", end="") + # Update selection + selected_index = (selected_index - 1) % len(menu_items) + # Print new selection with arrow and glow effect + console.print(f"[bold green]โ–ถ {menu_items[selected_index][1]}[/bold green]") + elif key == b'P': # Down arrow + # Move down one line + console.print("\033[B", end="") + # Clear current line + console.print("\033[K", end="") + # Print next item without arrow + console.print(f" {menu_items[selected_index][1]}") + # Move up one line + console.print("\033[A", end="") + # Clear current line + console.print("\033[K", end="") + # Update selection + selected_index = (selected_index + 1) % len(menu_items) + # Print new selection with arrow and glow effect + console.print(f"[bold green]โ–ถ {menu_items[selected_index][1]}[/bold green]") + + # Enter key to select + elif key == b'\r': + # Animate selection + for _ in range(3): + console.print(f"\033[A\033[K[bold green]โ–ถ {menu_items[selected_index][1]}[/bold green]") + time.sleep(0.1) + console.print(f"\033[A\033[K {menu_items[selected_index][1]}") + time.sleep(0.1) + # Call the correct function for each menu item + if menu_items[selected_index][0] == "4": + terminal.show_terminal_themes() + continue + return menu_items[selected_index][0] + + # Escape key to exit + elif key == b'\x1b': + return "0" # Exit option + +def show_help(commands_dict): + """Displays a list of all available commands.""" + console.print("\n[bold cyan]Available Commands:[/bold cyan]") + for command in sorted(commands_dict.keys()): + console.print(f"- {command}") + console.print("\nType `~ai` to access AI features.") + def main(): console.clear() - ascii_banner = pyfiglet.figlet_format("PyShell") - print(ascii_banner) - + animate_ascii_art_wave() global username username, role = register_user() if Prompt.ask("New user?", choices=["y", "n"]) == "y" else login_user() @@ -143,9 +363,11 @@ def main(): terminl = Terminal() git = Git() eq = Equations() - stats = StatisticsCalculator() graph = GraphPlotter() + # AI Feature command stubs are removed from the 'commands' dictionary. + # The '~ai' command is the single entry point. + commands = { "rename": cmds.rename_item, "move": cmds.move_file, @@ -157,7 +379,7 @@ def main(): "paste": clipboard_paste, "password": generate_password, "calc": cmds.calculator, - "stats": lambda args: stats.calculate_statistics(), + "stats": lambda args: show_statistics_menu(), "equation": eq.solve_equation, "differential": lambda args: eq.solve_differential(args), "math-help": cmds.math_help, @@ -167,87 +389,117 @@ def main(): "unschedule": task.remove_scheduled_task, "stop": task.stop_running_tasks, "cls": clear, - "terminal": terminl.change_terminal, - "game": lambda args: Game.play_game(" ".join(args)), + "terminal": lambda args: terminl.show_terminal_themes(), + "games": lambda *args: console.print('Game feature not implemented.'), "plot": lambda args: graph.run(), + "help": lambda *args: show_help(commands), "exit": lambda _: exit(), - - # Git Commands (Using Git Class) - "git-status": git.git_status, - "git-branches": git.git_branches, - "git-create": git.git_create_branch, - "git-switch": git.git_switch_branch, - "git-push": git.git_push, - "git-pull": git.git_pull, - "git-merge": git.git_merge, - "git-delete": git.git_delete_branch, - "git-clone": git.git_clone, - "git-add": git.git_add, - "git-commit": git.git_commit, - - # Unique Git Features - "play": lambda args: Song.play_song(" ".join(args)), - "git-smart": git.git_smart_commit, - "git-help": git.git_help, - "git-history": git.git_history, - "git-undo": git.git_undo, - "git-stash": git.git_stash, - "git-recover": git.git_recover, - "git-dashboard": git.git_dashboard, - "git-auto_merge": git.git_auto_merge, - "git-voice": git.git_voice_command, - "git-reminder": git.git_reminder, - "git-offline_sync": git.git_offline_sync, } scheduler_thread = threading.Thread(target=Task().run_scheduler, daemon=True) scheduler_thread.start() + show_suggestions() + + # Define required arguments for each command + command_args = { + "rename": ["", ""], + "move": ["", ""], + "copy": ["", ""], + "kill": [""], + "copytext": [""], + "equation": [""], + "differential": [""], + "weather": [""], + "schedule": ["", "