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": ["", "