✨ Add Epic Progress Bars & Smart Auto-completion! - 6 progress bar styles with animations - Smart fuzzy command completion - Interactive demos and feature showcase - Enhanced shell with suggestion system - Progress tracking for code execution - Multiple spinner animations - Package installation simulation
This commit is contained in:
277
commands/cmd_demo.py
Normal file
277
commands/cmd_demo.py
Normal file
@@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Demo Command - Showcase OverCode features
|
||||
"""
|
||||
|
||||
import time
|
||||
import os
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
# Import progress utilities
|
||||
try:
|
||||
from utils.progress import ProgressBar, SpinnerProgress, simulate_progress, demo_progress_bars, demo_spinner
|
||||
from utils.autocomplete import demo_autocomplete
|
||||
UTILS_AVAILABLE = True
|
||||
except ImportError:
|
||||
UTILS_AVAILABLE = False
|
||||
|
||||
init(autoreset=True)
|
||||
|
||||
class DemoCommand:
|
||||
"""Demonstrate OverCode features"""
|
||||
|
||||
def __init__(self, feature=""):
|
||||
self.feature = feature.strip().lower()
|
||||
self.features = {
|
||||
'progress': self._demo_progress_bars,
|
||||
'spinner': self._demo_spinners,
|
||||
'autocomplete': self._demo_autocomplete,
|
||||
'all': self._demo_all,
|
||||
'install': self._demo_install,
|
||||
'compile': self._demo_compile,
|
||||
'download': self._demo_download
|
||||
}
|
||||
|
||||
def run(self):
|
||||
"""Execute the demo command"""
|
||||
if not self.feature:
|
||||
self._show_demo_menu()
|
||||
return
|
||||
|
||||
if self.feature in self.features:
|
||||
print(Fore.CYAN + f"🚀 Demo: {self.feature.title()}")
|
||||
print(Fore.YELLOW + "=" * 40)
|
||||
self.features[self.feature]()
|
||||
else:
|
||||
print(Fore.RED + f"❌ Demo '{self.feature}' not found!")
|
||||
self._show_demo_menu()
|
||||
|
||||
def _show_demo_menu(self):
|
||||
"""Show available demos"""
|
||||
print(Fore.CYAN + "🎭 OverCode Feature Demos")
|
||||
print(Fore.YELLOW + "─" * 30)
|
||||
print()
|
||||
|
||||
demos = {
|
||||
'progress': '📊 Progress bar styles and animations',
|
||||
'spinner': '🔄 Loading spinners and animations',
|
||||
'autocomplete': '🔍 Smart command completion',
|
||||
'install': '📦 Simulated package installation',
|
||||
'compile': '⚙️ Code compilation simulation',
|
||||
'download': '⬇️ File download simulation',
|
||||
'all': '🌟 Run all demos'
|
||||
}
|
||||
|
||||
for demo, desc in demos.items():
|
||||
print(f"{Fore.GREEN}{demo:<15} {Fore.WHITE}→ {desc}")
|
||||
|
||||
print()
|
||||
print(Fore.MAGENTA + "Usage:")
|
||||
print(f"{Fore.WHITE} demo <feature_name>")
|
||||
print(f"{Fore.LIGHTBLACK_EX} Example: demo progress")
|
||||
|
||||
def _demo_progress_bars(self):
|
||||
"""Demonstrate progress bar styles"""
|
||||
if not UTILS_AVAILABLE:
|
||||
print(Fore.RED + "Progress bars not available - utils module missing")
|
||||
return
|
||||
|
||||
print(Fore.GREEN + "📊 Progress Bar Demo")
|
||||
print("Testing different styles and colors...\n")
|
||||
|
||||
# Modern style
|
||||
print(Fore.CYAN + "Modern Style (Cyan):")
|
||||
bar1 = ProgressBar(50, style='modern', color='cyan')
|
||||
for i in range(51):
|
||||
bar1.update(i, "Processing modern style...")
|
||||
time.sleep(0.03)
|
||||
|
||||
# Fire style
|
||||
print(f"\n{Fore.RED}Fire Style (Epic!):")
|
||||
bar2 = ProgressBar(30, style='fire', color='red')
|
||||
for i in range(31):
|
||||
bar2.update(i, "🔥 Blazing through tasks...")
|
||||
time.sleep(0.05)
|
||||
|
||||
# Dots style
|
||||
print(f"\n{Fore.YELLOW}Dots Style (Yellow):")
|
||||
bar3 = ProgressBar(40, style='dots', color='yellow')
|
||||
for i in range(41):
|
||||
bar3.update(i, "● Processing dots...")
|
||||
time.sleep(0.02)
|
||||
|
||||
print(f"\n{Fore.GREEN}✨ Progress bar demo complete!")
|
||||
|
||||
def _demo_spinners(self):
|
||||
"""Demonstrate spinner animations"""
|
||||
if not UTILS_AVAILABLE:
|
||||
print(Fore.RED + "Spinners not available - utils module missing")
|
||||
return
|
||||
|
||||
print(Fore.GREEN + "🔄 Spinner Animation Demo")
|
||||
|
||||
spinner_styles = [
|
||||
('dots', 'Braille dots animation'),
|
||||
('arrows', 'Rotating arrows'),
|
||||
('bars', 'Classic spinning bars'),
|
||||
('fire', 'Epic fire animation'),
|
||||
('blocks', 'Building blocks')
|
||||
]
|
||||
|
||||
for style, description in spinner_styles:
|
||||
print(f"\n{Fore.CYAN}{description}:")
|
||||
spinner = SpinnerProgress(f"Loading with {style} style", style)
|
||||
spinner.start()
|
||||
time.sleep(2)
|
||||
spinner.stop(f"{style.title()} complete!")
|
||||
|
||||
print(f"\n{Fore.GREEN}✨ Spinner demo complete!")
|
||||
|
||||
def _demo_autocomplete(self):
|
||||
"""Demonstrate auto-completion"""
|
||||
if not UTILS_AVAILABLE:
|
||||
print(Fore.RED + "Auto-completion not available - utils module missing")
|
||||
return
|
||||
|
||||
print(Fore.GREEN + "🔍 Auto-completion Demo")
|
||||
demo_autocomplete()
|
||||
|
||||
def _demo_install(self):
|
||||
"""Simulate package installation with progress"""
|
||||
if not UTILS_AVAILABLE:
|
||||
print(Fore.RED + "Progress bars not available - utils module missing")
|
||||
return
|
||||
|
||||
print(Fore.GREEN + "📦 Package Installation Simulation")
|
||||
|
||||
packages = [
|
||||
("awesome-games", 45),
|
||||
("ai-tools", 30),
|
||||
("theme-pack", 25),
|
||||
("dev-utils", 35)
|
||||
]
|
||||
|
||||
for package, size in packages:
|
||||
print(f"\n{Fore.CYAN}Installing {package}...")
|
||||
|
||||
# Download phase
|
||||
print(f"{Fore.YELLOW}⬇️ Downloading...")
|
||||
bar = ProgressBar(size, style='arrows', color='blue')
|
||||
for i in range(size + 1):
|
||||
bar.update(i, f"Downloading {package} ({i}/{size})")
|
||||
time.sleep(0.05)
|
||||
|
||||
# Installation phase
|
||||
print(f"\n{Fore.GREEN}📦 Installing...")
|
||||
spinner = SpinnerProgress(f"Installing {package}", 'dots')
|
||||
spinner.start()
|
||||
time.sleep(1.5)
|
||||
spinner.stop(f"✓ {package} installed successfully!")
|
||||
|
||||
print(f"\n{Fore.GREEN}🎉 All packages installed!")
|
||||
|
||||
def _demo_compile(self):
|
||||
"""Simulate code compilation"""
|
||||
if not UTILS_AVAILABLE:
|
||||
print(Fore.RED + "Progress bars not available - utils module missing")
|
||||
return
|
||||
|
||||
print(Fore.GREEN + "⚙️ Code Compilation Simulation")
|
||||
|
||||
stages = [
|
||||
("Parsing", 15, "Analyzing source code..."),
|
||||
("Lexing", 20, "Tokenizing input..."),
|
||||
("Compiling", 40, "Generating bytecode..."),
|
||||
("Optimizing", 25, "Applying optimizations..."),
|
||||
("Linking", 10, "Linking dependencies...")
|
||||
]
|
||||
|
||||
for stage, duration, description in stages:
|
||||
print(f"\n{Fore.CYAN}{stage}:")
|
||||
bar = ProgressBar(duration, style='blocks', color='green')
|
||||
|
||||
for i in range(duration + 1):
|
||||
bar.update(i, description)
|
||||
time.sleep(0.08)
|
||||
|
||||
print(f"\n{Fore.GREEN}✅ Compilation successful!")
|
||||
print(f"{Fore.YELLOW}Output: awesome_program.exe")
|
||||
|
||||
def _demo_download(self):
|
||||
"""Simulate file download with realistic progress"""
|
||||
if not UTILS_AVAILABLE:
|
||||
print(Fore.RED + "Progress bars not available - utils module missing")
|
||||
return
|
||||
|
||||
print(Fore.GREEN + "⬇️ Download Simulation")
|
||||
|
||||
files = [
|
||||
("overcode-themes.zip", 100, 'modern'),
|
||||
("game-pack-ultra.zip", 150, 'fire'),
|
||||
("dev-tools.tar.gz", 80, 'dots')
|
||||
]
|
||||
|
||||
for filename, size, style in files:
|
||||
print(f"\n{Fore.CYAN}Downloading {filename}...")
|
||||
|
||||
bar = ProgressBar(size, style=style, color='cyan')
|
||||
|
||||
# Simulate variable download speed
|
||||
downloaded = 0
|
||||
while downloaded < size:
|
||||
import random
|
||||
chunk = random.randint(1, 5)
|
||||
downloaded = min(downloaded + chunk, size)
|
||||
|
||||
speed = random.uniform(1.5, 3.0) # MB/s
|
||||
eta = (size - downloaded) / speed if speed > 0 else 0
|
||||
|
||||
bar.update(downloaded, f"Download speed: {speed:.1f} MB/s")
|
||||
time.sleep(0.03)
|
||||
|
||||
print(f"{Fore.GREEN}✓ {filename} downloaded successfully!")
|
||||
|
||||
print(f"\n{Fore.GREEN}🎉 All downloads complete!")
|
||||
|
||||
def _demo_all(self):
|
||||
"""Run all demos"""
|
||||
print(Fore.MAGENTA + "🌟 Running All OverCode Demos!")
|
||||
print(Fore.YELLOW + "=" * 50)
|
||||
|
||||
demos = ['progress', 'spinner', 'install', 'compile']
|
||||
|
||||
for i, demo in enumerate(demos, 1):
|
||||
print(f"\n{Fore.CYAN}[{i}/{len(demos)}] {demo.title()} Demo")
|
||||
print(Fore.YELLOW + "─" * 30)
|
||||
self.features[demo]()
|
||||
|
||||
if i < len(demos):
|
||||
print(f"\n{Fore.LIGHTBLACK_EX}(Next demo in 2 seconds...)")
|
||||
time.sleep(2)
|
||||
|
||||
print(f"\n{Fore.GREEN}🎊 All demos complete! OverCode is AMAZING!")
|
||||
|
||||
class SuggestCommand:
|
||||
"""Provide command suggestions"""
|
||||
|
||||
def __init__(self, shell_instance):
|
||||
self.shell = shell_instance
|
||||
|
||||
def run(self):
|
||||
"""Show command suggestions"""
|
||||
if hasattr(self.shell, 'autocomplete') and self.shell.autocomplete:
|
||||
print(Fore.CYAN + "💡 Smart Command Suggestions")
|
||||
print(Fore.YELLOW + "─" * 30)
|
||||
|
||||
# Show popular commands
|
||||
suggestions = self.shell.autocomplete.get_command_suggestions("")
|
||||
for cmd, desc in suggestions[:10]:
|
||||
print(f"{Fore.GREEN}{cmd:<12} {Fore.WHITE}→ {desc}")
|
||||
|
||||
print(f"\n{Fore.MAGENTA}💡 Pro Tips:")
|
||||
print(f"{Fore.WHITE}• Tab completion coming soon!")
|
||||
print(f"{Fore.WHITE}• Type partial commands for smart suggestions")
|
||||
print(f"{Fore.WHITE}• Mistype commands to see corrections")
|
||||
else:
|
||||
print(Fore.YELLOW + "Auto-completion not available")
|
||||
print(Fore.WHITE + "Available commands: help, new, run, game, theme, clear, ls, cd, exit")
|
||||
@@ -14,6 +14,20 @@ import time
|
||||
from pathlib import Path
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
# Import progress bars
|
||||
try:
|
||||
from utils.progress import ProgressBar, SpinnerProgress
|
||||
except ImportError:
|
||||
# Fallback if utils not available
|
||||
class ProgressBar:
|
||||
def __init__(self, *args, **kwargs): pass
|
||||
def update(self, *args, **kwargs): pass
|
||||
|
||||
class SpinnerProgress:
|
||||
def __init__(self, *args, **kwargs): pass
|
||||
def start(self): pass
|
||||
def stop(self, *args): pass
|
||||
|
||||
init(autoreset=True)
|
||||
|
||||
class OverCodeInterpreter:
|
||||
@@ -48,15 +62,31 @@ class OverCodeInterpreter:
|
||||
self.errors = []
|
||||
|
||||
def interpret(self, source_code, verbose=False):
|
||||
"""Main interpretation method"""
|
||||
"""Main interpretation method with progress bars"""
|
||||
print(Fore.CYAN + "🚀 OverCode Interpreter v2.0" + Style.RESET_ALL)
|
||||
print(Fore.YELLOW + "─" * 50)
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# Process each language block
|
||||
for lang_key, lang_name in self.supported_languages.items():
|
||||
self._process_language(source_code, lang_key, lang_name, verbose)
|
||||
# Count total language blocks to process
|
||||
total_blocks = 0
|
||||
for lang_key in self.supported_languages.keys():
|
||||
pattern = f'<\\?{lang_key}(.*?)\\?>'
|
||||
segments = re.findall(pattern, source_code, re.DOTALL)
|
||||
total_blocks += len([s for s in segments if s.strip()])
|
||||
|
||||
if total_blocks > 0:
|
||||
# Create progress bar for execution
|
||||
progress = ProgressBar(total_blocks, style='fire', color='green')
|
||||
current_block = 0
|
||||
|
||||
# Process each language block
|
||||
for lang_key, lang_name in self.supported_languages.items():
|
||||
current_block = self._process_language_with_progress(
|
||||
source_code, lang_key, lang_name, verbose, progress, current_block
|
||||
)
|
||||
else:
|
||||
print(Fore.YELLOW + "No executable code blocks found.")
|
||||
|
||||
# Display results
|
||||
self._display_results()
|
||||
@@ -66,6 +96,35 @@ class OverCodeInterpreter:
|
||||
|
||||
return '\n'.join(self.outputs)
|
||||
|
||||
def _process_language_with_progress(self, source, lang_key, lang_name, verbose, progress, current_block):
|
||||
"""Process language blocks with progress tracking"""
|
||||
pattern = f'<\\?{lang_key}(.*?)\\?>'
|
||||
segments = re.findall(pattern, source, re.DOTALL)
|
||||
|
||||
if not segments:
|
||||
return current_block
|
||||
|
||||
for i, segment in enumerate(segments):
|
||||
code = segment.strip()
|
||||
if not code:
|
||||
continue
|
||||
|
||||
# Update progress
|
||||
progress.update(current_block + 1, f"Executing {lang_name} block {i+1}")
|
||||
|
||||
start = time.time()
|
||||
output = self._execute_code(lang_key, code, verbose)
|
||||
exec_time = time.time() - start
|
||||
|
||||
if output:
|
||||
self.outputs.append(f"[{lang_name} Block {i+1}]\n{output}")
|
||||
self.execution_times[f"{lang_name}_{i+1}"] = exec_time
|
||||
|
||||
current_block += 1
|
||||
time.sleep(0.1) # Small delay to show progress
|
||||
|
||||
return current_block
|
||||
|
||||
def _process_language(self, source, lang_key, lang_name, verbose):
|
||||
"""Process code blocks for a specific language"""
|
||||
pattern = f'<\\?{lang_key}(.*?)\\?>'
|
||||
|
||||
45
overshell.py
45
overshell.py
@@ -30,6 +30,7 @@ from commands.cmd_stubs import (
|
||||
ExitCommand, WdirCommand, FormatCommand, DebugCommand,
|
||||
PackageCommand, AsciiCommand, StatsCommand, BenchmarkCommand, EncryptCommand
|
||||
)
|
||||
from commands.cmd_demo import DemoCommand, SuggestCommand
|
||||
|
||||
# Try Discord RPC (optional)
|
||||
try:
|
||||
@@ -38,6 +39,15 @@ try:
|
||||
except ImportError:
|
||||
RPC_AVAILABLE = False
|
||||
|
||||
# Import auto-completion and progress bars
|
||||
try:
|
||||
from utils.autocomplete import AutoComplete, setup_autocomplete
|
||||
from utils.progress import SpinnerProgress, simulate_progress
|
||||
UTILS_AVAILABLE = True
|
||||
except ImportError:
|
||||
UTILS_AVAILABLE = False
|
||||
print("Utils not available - some features disabled")
|
||||
|
||||
CLIENT_ID = '1414669512158220409'
|
||||
|
||||
class Theme:
|
||||
@@ -138,6 +148,12 @@ class OverCodeShell(cmd.Cmd):
|
||||
if RPC_AVAILABLE:
|
||||
self._connect_rpc()
|
||||
|
||||
# Set up auto-completion
|
||||
if UTILS_AVAILABLE:
|
||||
self.autocomplete = setup_autocomplete(self)
|
||||
else:
|
||||
self.autocomplete = None
|
||||
|
||||
self.update_prompt()
|
||||
|
||||
def _connect_rpc(self):
|
||||
@@ -242,7 +258,7 @@ class OverCodeShell(cmd.Cmd):
|
||||
return stop
|
||||
|
||||
def default(self, line):
|
||||
"""Handle unknown commands"""
|
||||
"""Handle unknown commands with smart suggestions"""
|
||||
# Check for aliases
|
||||
parts = line.split()
|
||||
if parts and parts[0] in self.aliases:
|
||||
@@ -258,8 +274,17 @@ class OverCodeShell(cmd.Cmd):
|
||||
|
||||
c = self.theme.colors
|
||||
print(c['error'] + f"✗ Unknown command: '{line}'")
|
||||
print(c['warning'] + "→ Type 'help' for available commands")
|
||||
print(c['info'] + "→ Type 'suggest' for command suggestions")
|
||||
|
||||
# Show smart suggestions if auto-completion is available
|
||||
if self.autocomplete:
|
||||
suggestion = self.autocomplete.smart_suggest(line)
|
||||
if suggestion:
|
||||
print(suggestion)
|
||||
else:
|
||||
print(c['warning'] + "→ Type 'help' for available commands")
|
||||
else:
|
||||
print(c['warning'] + "→ Type 'help' for available commands")
|
||||
print(c['info'] + "→ Type 'suggest' for command suggestions")
|
||||
|
||||
def emptyline(self):
|
||||
"""Do nothing on empty line"""
|
||||
@@ -326,6 +351,10 @@ class OverCodeShell(cmd.Cmd):
|
||||
("server", "Start local server"),
|
||||
("share", "Share files online"),
|
||||
],
|
||||
"🎭 Demos & Features": [
|
||||
("demo", "Feature demonstrations"),
|
||||
("suggest", "Smart command suggestions"),
|
||||
],
|
||||
"ℹ️ Information": [
|
||||
("fastfetch", "System information"),
|
||||
("credits", "Show credits"),
|
||||
@@ -389,6 +418,16 @@ class OverCodeShell(cmd.Cmd):
|
||||
"""Show session statistics"""
|
||||
StatsCommand(self.stats).run()
|
||||
|
||||
def do_demo(self, arg):
|
||||
"""Run feature demonstrations"""
|
||||
if self.rpc_active:
|
||||
self._set_presence("Demo Mode", f"Testing: {arg or 'Features'}")
|
||||
DemoCommand(arg.strip()).run()
|
||||
|
||||
def do_suggest(self, arg):
|
||||
"""Show command suggestions"""
|
||||
SuggestCommand(self).run()
|
||||
|
||||
def do_clear(self, arg):
|
||||
"""Clear the screen"""
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
|
||||
1
utils/__init__.py
Normal file
1
utils/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# OverCode Utils Package
|
||||
351
utils/autocomplete.py
Normal file
351
utils/autocomplete.py
Normal file
@@ -0,0 +1,351 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
OverCode Auto-completion System - Smart command suggestions and tab completion
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import difflib
|
||||
from typing import List, Dict, Tuple
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
init(autoreset=True)
|
||||
|
||||
class AutoComplete:
|
||||
"""Advanced auto-completion system for OverCode"""
|
||||
|
||||
def __init__(self):
|
||||
# Core commands
|
||||
self.commands = {
|
||||
'help': 'Show available commands and help',
|
||||
'new': 'Create a new file with templates',
|
||||
'run': 'Execute an OverCode file',
|
||||
'game': 'Launch the gaming center',
|
||||
'theme': 'Change shell theme',
|
||||
'clear': 'Clear the screen',
|
||||
'ls': 'List directory contents',
|
||||
'cd': 'Change directory',
|
||||
'exit': 'Exit OverCode shell',
|
||||
'stats': 'Show session statistics',
|
||||
'fastfetch': 'Show system information',
|
||||
'credits': 'Show project credits'
|
||||
}
|
||||
|
||||
# Command arguments and subcommands
|
||||
self.command_args = {
|
||||
'new': {
|
||||
'templates': ['hello', 'demo', 'games', 'web', 'ai', 'crypto'],
|
||||
'extensions': ['.ovc'],
|
||||
'syntax': 'new <filename>:<template>'
|
||||
},
|
||||
'game': {
|
||||
'games': ['snake', 'tetris', '2048', 'life', 'adventure', 'mines',
|
||||
'pong', 'breakout', 'memory', 'hangman', 'rps', 'quiz'],
|
||||
'syntax': 'game [game_name]'
|
||||
},
|
||||
'theme': {
|
||||
'themes': ['cyberpunk', 'matrix', 'ocean', 'sunset', 'hacker'],
|
||||
'syntax': 'theme [theme_name]'
|
||||
},
|
||||
'run': {
|
||||
'extensions': ['.ovc'],
|
||||
'syntax': 'run <filename>'
|
||||
}
|
||||
}
|
||||
|
||||
# File patterns
|
||||
self.file_patterns = {
|
||||
'.ovc': 'OverCode polyglot files',
|
||||
'.py': 'Python files',
|
||||
'.js': 'JavaScript files',
|
||||
'.php': 'PHP files',
|
||||
'.go': 'Go files',
|
||||
'.rs': 'Rust files',
|
||||
'.java': 'Java files',
|
||||
'.cpp': 'C++ files',
|
||||
'.c': 'C files'
|
||||
}
|
||||
|
||||
# Fuzzy matching threshold
|
||||
self.fuzzy_threshold = 0.6
|
||||
|
||||
def complete(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
|
||||
"""Main completion method"""
|
||||
words = line.split()
|
||||
|
||||
if not words:
|
||||
return list(self.commands.keys())
|
||||
|
||||
# First word - complete command names
|
||||
if len(words) == 1 and not line.endswith(' '):
|
||||
return self._complete_command(text)
|
||||
|
||||
# Command arguments
|
||||
command = words[0]
|
||||
if command in self.command_args:
|
||||
return self._complete_args(command, text, words[1:])
|
||||
|
||||
# File completion
|
||||
return self._complete_files(text)
|
||||
|
||||
def _complete_command(self, text: str) -> List[str]:
|
||||
"""Complete command names"""
|
||||
matches = []
|
||||
for cmd in self.commands:
|
||||
if cmd.startswith(text.lower()):
|
||||
matches.append(cmd)
|
||||
|
||||
# Add fuzzy matches if no exact matches
|
||||
if not matches:
|
||||
matches = self._fuzzy_match(text, list(self.commands.keys()))
|
||||
|
||||
return sorted(matches)
|
||||
|
||||
def _complete_args(self, command: str, text: str, args: List[str]) -> List[str]:
|
||||
"""Complete command arguments"""
|
||||
cmd_info = self.command_args[command]
|
||||
|
||||
# Game completion
|
||||
if command == 'game':
|
||||
return self._fuzzy_match(text, cmd_info['games'])
|
||||
|
||||
# Theme completion
|
||||
elif command == 'theme':
|
||||
return self._fuzzy_match(text, cmd_info['themes'])
|
||||
|
||||
# New file template completion
|
||||
elif command == 'new':
|
||||
if ':' in text:
|
||||
# Template completion after colon
|
||||
filename, template_part = text.split(':', 1)
|
||||
matches = self._fuzzy_match(template_part, cmd_info['templates'])
|
||||
return [f"{filename}:{match}" for match in matches]
|
||||
else:
|
||||
# File completion or template suggestion
|
||||
file_matches = self._complete_files(text, ['.ovc'])
|
||||
if not file_matches:
|
||||
return [f"{text}:{template}" for template in cmd_info['templates']]
|
||||
return file_matches
|
||||
|
||||
# File completion for run command
|
||||
elif command == 'run':
|
||||
return self._complete_files(text, ['.ovc'])
|
||||
|
||||
return []
|
||||
|
||||
def _complete_files(self, text: str, extensions: List[str] = None) -> List[str]:
|
||||
"""Complete file names"""
|
||||
try:
|
||||
# Get current directory files
|
||||
current_dir = os.getcwd()
|
||||
files = os.listdir(current_dir)
|
||||
|
||||
matches = []
|
||||
for file in files:
|
||||
# Filter by extensions if specified
|
||||
if extensions:
|
||||
if not any(file.endswith(ext) for ext in extensions):
|
||||
continue
|
||||
|
||||
if file.startswith(text):
|
||||
matches.append(file)
|
||||
|
||||
# Add directories
|
||||
for item in files:
|
||||
if os.path.isdir(os.path.join(current_dir, item)):
|
||||
if item.startswith(text):
|
||||
matches.append(item + '/')
|
||||
|
||||
return sorted(matches)
|
||||
|
||||
except (OSError, PermissionError):
|
||||
return []
|
||||
|
||||
def _fuzzy_match(self, text: str, candidates: List[str]) -> List[str]:
|
||||
"""Fuzzy string matching for suggestions"""
|
||||
if not text:
|
||||
return candidates
|
||||
|
||||
matches = difflib.get_close_matches(
|
||||
text.lower(),
|
||||
[c.lower() for c in candidates],
|
||||
n=10,
|
||||
cutoff=self.fuzzy_threshold
|
||||
)
|
||||
|
||||
# Return original case versions
|
||||
result = []
|
||||
for match in matches:
|
||||
for candidate in candidates:
|
||||
if candidate.lower() == match:
|
||||
result.append(candidate)
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
def suggest_correction(self, command: str) -> str:
|
||||
"""Suggest correction for mistyped commands"""
|
||||
# Try fuzzy matching on commands
|
||||
matches = self._fuzzy_match(command, list(self.commands.keys()))
|
||||
|
||||
if matches:
|
||||
suggestion = matches[0]
|
||||
return f"{Fore.YELLOW}Did you mean: {Fore.CYAN}{suggestion}{Fore.YELLOW}?"
|
||||
|
||||
return ""
|
||||
|
||||
def show_command_help(self, command: str) -> str:
|
||||
"""Show help for specific command"""
|
||||
if command in self.commands:
|
||||
help_text = f"{Fore.CYAN}{command}{Fore.WHITE} - {self.commands[command]}"
|
||||
|
||||
if command in self.command_args:
|
||||
cmd_info = self.command_args[command]
|
||||
help_text += f"\n{Fore.YELLOW}Syntax: {cmd_info['syntax']}"
|
||||
|
||||
if 'games' in cmd_info:
|
||||
help_text += f"\n{Fore.GREEN}Games: {', '.join(cmd_info['games'])}"
|
||||
elif 'themes' in cmd_info:
|
||||
help_text += f"\n{Fore.GREEN}Themes: {', '.join(cmd_info['themes'])}"
|
||||
elif 'templates' in cmd_info:
|
||||
help_text += f"\n{Fore.GREEN}Templates: {', '.join(cmd_info['templates'])}"
|
||||
|
||||
return help_text
|
||||
|
||||
return f"{Fore.RED}Command '{command}' not found"
|
||||
|
||||
def get_command_suggestions(self, partial_command: str) -> List[Tuple[str, str]]:
|
||||
"""Get command suggestions with descriptions"""
|
||||
matches = self._complete_command(partial_command)
|
||||
return [(cmd, self.commands[cmd]) for cmd in matches[:5]]
|
||||
|
||||
def smart_suggest(self, line: str) -> str:
|
||||
"""Provide smart suggestions based on context"""
|
||||
words = line.strip().split()
|
||||
|
||||
if not words:
|
||||
return f"{Fore.CYAN}💡 Try: help, new, game, theme, run"
|
||||
|
||||
command = words[0]
|
||||
|
||||
# Unknown command
|
||||
if command not in self.commands:
|
||||
correction = self.suggest_correction(command)
|
||||
if correction:
|
||||
return correction
|
||||
return f"{Fore.RED}Unknown command. {Fore.CYAN}Type 'help' for available commands."
|
||||
|
||||
# Incomplete command
|
||||
if len(words) == 1:
|
||||
if command in self.command_args:
|
||||
cmd_info = self.command_args[command]
|
||||
return f"{Fore.YELLOW}💡 Syntax: {cmd_info['syntax']}"
|
||||
|
||||
# Command-specific suggestions
|
||||
if command == 'new' and len(words) == 2:
|
||||
arg = words[1]
|
||||
if ':' not in arg:
|
||||
templates = self.command_args['new']['templates']
|
||||
return f"{Fore.YELLOW}💡 Add template: {Fore.CYAN}{arg}:<template> {Fore.WHITE}({', '.join(templates)})"
|
||||
|
||||
elif command == 'game' and len(words) == 1:
|
||||
games = self.command_args['game']['games'][:5]
|
||||
return f"{Fore.YELLOW}💡 Available games: {Fore.CYAN}{', '.join(games)}..."
|
||||
|
||||
elif command == 'theme' and len(words) == 1:
|
||||
themes = self.command_args['theme']['themes']
|
||||
return f"{Fore.YELLOW}💡 Available themes: {Fore.CYAN}{', '.join(themes)}"
|
||||
|
||||
return ""
|
||||
|
||||
class SmartPrompt:
|
||||
"""Enhanced prompt with auto-completion hints"""
|
||||
|
||||
def __init__(self, autocomplete: AutoComplete):
|
||||
self.autocomplete = autocomplete
|
||||
self.history = []
|
||||
self.history_index = -1
|
||||
|
||||
def get_input(self, prompt: str) -> str:
|
||||
"""Get input with smart suggestions"""
|
||||
try:
|
||||
# Simple input for now - in real implementation would use readline
|
||||
user_input = input(prompt).strip()
|
||||
|
||||
if user_input:
|
||||
self.history.append(user_input)
|
||||
self.history_index = len(self.history)
|
||||
|
||||
return user_input
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n^C")
|
||||
return ""
|
||||
except EOFError:
|
||||
return "exit"
|
||||
|
||||
def show_suggestions(self, partial_line: str):
|
||||
"""Show contextual suggestions"""
|
||||
suggestions = self.autocomplete.smart_suggest(partial_line)
|
||||
if suggestions:
|
||||
print(suggestions)
|
||||
|
||||
def show_completions(self, text: str, line: str):
|
||||
"""Show available completions"""
|
||||
completions = self.autocomplete.complete(text, line, 0, len(text))
|
||||
|
||||
if completions:
|
||||
print(f"\n{Fore.CYAN}Suggestions:")
|
||||
for i, comp in enumerate(completions[:8]): # Show max 8
|
||||
print(f" {Fore.YELLOW}{i+1}.{Fore.WHITE} {comp}")
|
||||
|
||||
if len(completions) > 8:
|
||||
print(f" {Fore.LIGHTBLACK_EX}... and {len(completions) - 8} more")
|
||||
|
||||
# Integration with the main shell
|
||||
def setup_autocomplete(shell_instance):
|
||||
"""Set up auto-completion for the shell"""
|
||||
autocomplete = AutoComplete()
|
||||
smart_prompt = SmartPrompt(autocomplete)
|
||||
|
||||
# Add completion method to shell
|
||||
def complete_command(self, text, line, begidx, endidx):
|
||||
return autocomplete.complete(text, line, begidx, endidx)
|
||||
|
||||
shell_instance.complete_command = complete_command
|
||||
shell_instance.autocomplete = autocomplete
|
||||
shell_instance.smart_prompt = smart_prompt
|
||||
|
||||
return autocomplete
|
||||
|
||||
# Demo and testing functions
|
||||
def demo_autocomplete():
|
||||
"""Demonstrate auto-completion features"""
|
||||
print(Fore.CYAN + "🔍 OverCode Auto-completion Demo")
|
||||
print("=" * 50)
|
||||
|
||||
ac = AutoComplete()
|
||||
|
||||
# Test command completion
|
||||
print(f"\n{Fore.WHITE}Command completion for 'g':")
|
||||
matches = ac._complete_command('g')
|
||||
for match in matches:
|
||||
print(f" {Fore.GREEN}→ {match}")
|
||||
|
||||
# Test fuzzy matching
|
||||
print(f"\n{Fore.WHITE}Fuzzy matching for 'tem':")
|
||||
matches = ac._fuzzy_match('tem', ac.command_args['theme']['themes'])
|
||||
for match in matches:
|
||||
print(f" {Fore.YELLOW}→ {match}")
|
||||
|
||||
# Test suggestions
|
||||
print(f"\n{Fore.WHITE}Smart suggestions:")
|
||||
test_commands = ['gam', 'new hello.ovc', 'theme', 'unknown_command']
|
||||
for cmd in test_commands:
|
||||
suggestion = ac.smart_suggest(cmd)
|
||||
print(f" '{cmd}' → {suggestion}")
|
||||
|
||||
print(f"\n{Fore.GREEN}✨ Auto-completion demo complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_autocomplete()
|
||||
315
utils/progress.py
Normal file
315
utils/progress.py
Normal file
@@ -0,0 +1,315 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
OverCode Progress Bars - Epic animated progress indicators
|
||||
"""
|
||||
|
||||
import time
|
||||
import sys
|
||||
import threading
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
init(autoreset=True)
|
||||
|
||||
class ProgressBar:
|
||||
"""Animated progress bar with multiple styles"""
|
||||
|
||||
def __init__(self, total=100, width=40, style='modern', color='cyan'):
|
||||
self.total = total
|
||||
self.current = 0
|
||||
self.width = width
|
||||
self.style = style
|
||||
self.color = color
|
||||
self.start_time = time.time()
|
||||
self.is_running = False
|
||||
self.animation_thread = None
|
||||
|
||||
# Color mapping
|
||||
self.colors = {
|
||||
'cyan': Fore.CYAN,
|
||||
'green': Fore.GREEN,
|
||||
'yellow': Fore.YELLOW,
|
||||
'red': Fore.RED,
|
||||
'magenta': Fore.MAGENTA,
|
||||
'blue': Fore.BLUE
|
||||
}
|
||||
|
||||
# Style configurations
|
||||
self.styles = {
|
||||
'modern': {
|
||||
'filled': '█',
|
||||
'empty': '░',
|
||||
'prefix': '[',
|
||||
'suffix': ']'
|
||||
},
|
||||
'classic': {
|
||||
'filled': '=',
|
||||
'empty': '-',
|
||||
'prefix': '[',
|
||||
'suffix': ']'
|
||||
},
|
||||
'dots': {
|
||||
'filled': '●',
|
||||
'empty': '○',
|
||||
'prefix': '(',
|
||||
'suffix': ')'
|
||||
},
|
||||
'arrows': {
|
||||
'filled': '▶',
|
||||
'empty': '▷',
|
||||
'prefix': '⟨',
|
||||
'suffix': '⟩'
|
||||
},
|
||||
'blocks': {
|
||||
'filled': '■',
|
||||
'empty': '□',
|
||||
'prefix': '⌊',
|
||||
'suffix': '⌋'
|
||||
},
|
||||
'fire': {
|
||||
'filled': '🔥',
|
||||
'empty': '💨',
|
||||
'prefix': '🚀',
|
||||
'suffix': '✨'
|
||||
}
|
||||
}
|
||||
|
||||
def update(self, value, message=""):
|
||||
"""Update progress bar value"""
|
||||
self.current = min(value, self.total)
|
||||
self._render(message)
|
||||
|
||||
def increment(self, amount=1, message=""):
|
||||
"""Increment progress by amount"""
|
||||
self.current = min(self.current + amount, self.total)
|
||||
self._render(message)
|
||||
|
||||
def _render(self, message=""):
|
||||
"""Render the progress bar"""
|
||||
if self.total == 0:
|
||||
percentage = 100
|
||||
else:
|
||||
percentage = (self.current / self.total) * 100
|
||||
|
||||
filled_width = int((self.current / self.total) * self.width) if self.total > 0 else 0
|
||||
empty_width = self.width - filled_width
|
||||
|
||||
style_config = self.styles.get(self.style, self.styles['modern'])
|
||||
color = self.colors.get(self.color, Fore.CYAN)
|
||||
|
||||
# Build progress bar
|
||||
filled = style_config['filled'] * filled_width
|
||||
empty = style_config['empty'] * empty_width
|
||||
prefix = style_config['prefix']
|
||||
suffix = style_config['suffix']
|
||||
|
||||
# Calculate ETA
|
||||
elapsed = time.time() - self.start_time
|
||||
if self.current > 0:
|
||||
eta = (elapsed / self.current) * (self.total - self.current)
|
||||
eta_str = f" ETA: {eta:.1f}s"
|
||||
else:
|
||||
eta_str = ""
|
||||
|
||||
# Format the bar
|
||||
bar = f"{color}{prefix}{filled}{Fore.LIGHTBLACK_EX}{empty}{color}{suffix}"
|
||||
percentage_str = f" {percentage:6.1f}%"
|
||||
|
||||
if message:
|
||||
message = f" {Fore.WHITE}{message}"
|
||||
|
||||
# Print with carriage return to overwrite
|
||||
sys.stdout.write(f"\r{bar}{percentage_str}{eta_str}{message}")
|
||||
sys.stdout.flush()
|
||||
|
||||
if self.current >= self.total:
|
||||
print() # New line when complete
|
||||
|
||||
class SpinnerProgress:
|
||||
"""Animated spinner for indefinite operations"""
|
||||
|
||||
def __init__(self, message="Loading", style='dots'):
|
||||
self.message = message
|
||||
self.style = style
|
||||
self.is_running = False
|
||||
self.thread = None
|
||||
|
||||
self.spinners = {
|
||||
'dots': ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
|
||||
'arrows': ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'],
|
||||
'bars': ['|', '/', '-', '\\'],
|
||||
'blocks': ['▁', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃'],
|
||||
'braille': ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'],
|
||||
'fire': ['🔥', '🚀', '⚡', '✨', '💫', '🌟']
|
||||
}
|
||||
|
||||
def start(self):
|
||||
"""Start the spinner animation"""
|
||||
if self.is_running:
|
||||
return
|
||||
|
||||
self.is_running = True
|
||||
self.thread = threading.Thread(target=self._animate)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
|
||||
def stop(self, final_message="Done"):
|
||||
"""Stop the spinner"""
|
||||
self.is_running = False
|
||||
if self.thread:
|
||||
self.thread.join()
|
||||
|
||||
# Clear the line and show final message
|
||||
sys.stdout.write(f"\r{Fore.GREEN}✓ {final_message}{' ' * 20}\n")
|
||||
sys.stdout.flush()
|
||||
|
||||
def _animate(self):
|
||||
"""Animation loop"""
|
||||
frames = self.spinners.get(self.style, self.spinners['dots'])
|
||||
i = 0
|
||||
|
||||
while self.is_running:
|
||||
frame = frames[i % len(frames)]
|
||||
sys.stdout.write(f"\r{Fore.CYAN}{frame} {Fore.WHITE}{self.message}")
|
||||
sys.stdout.flush()
|
||||
time.sleep(0.1)
|
||||
i += 1
|
||||
|
||||
class MultiProgress:
|
||||
"""Multiple progress bars for complex operations"""
|
||||
|
||||
def __init__(self):
|
||||
self.bars = {}
|
||||
self.order = []
|
||||
|
||||
def add_bar(self, name, total, style='modern', color='cyan'):
|
||||
"""Add a new progress bar"""
|
||||
self.bars[name] = {
|
||||
'bar': ProgressBar(total, style=style, color=color),
|
||||
'total': total,
|
||||
'current': 0,
|
||||
'message': ''
|
||||
}
|
||||
self.order.append(name)
|
||||
|
||||
def update(self, name, value, message=""):
|
||||
"""Update a specific progress bar"""
|
||||
if name in self.bars:
|
||||
self.bars[name]['current'] = value
|
||||
self.bars[name]['message'] = message
|
||||
self._render_all()
|
||||
|
||||
def increment(self, name, amount=1, message=""):
|
||||
"""Increment a specific progress bar"""
|
||||
if name in self.bars:
|
||||
self.bars[name]['current'] = min(
|
||||
self.bars[name]['current'] + amount,
|
||||
self.bars[name]['total']
|
||||
)
|
||||
self.bars[name]['message'] = message
|
||||
self._render_all()
|
||||
|
||||
def _render_all(self):
|
||||
"""Render all progress bars"""
|
||||
# Move cursor up to overwrite previous output
|
||||
if len(self.bars) > 1:
|
||||
sys.stdout.write(f"\033[{len(self.bars)}A")
|
||||
|
||||
for name in self.order:
|
||||
bar_data = self.bars[name]
|
||||
bar_data['bar'].current = bar_data['current']
|
||||
print(f"{Fore.YELLOW}{name:<15}", end=" ")
|
||||
bar_data['bar']._render(bar_data['message'])
|
||||
|
||||
# Utility functions for easy use
|
||||
def progress_bar(iterable, desc="Processing", style='modern', color='cyan'):
|
||||
"""Wrapper for iterables with progress bar"""
|
||||
total = len(iterable) if hasattr(iterable, '__len__') else 100
|
||||
bar = ProgressBar(total, style=style, color=color)
|
||||
|
||||
for i, item in enumerate(iterable):
|
||||
bar.update(i + 1, desc)
|
||||
yield item
|
||||
|
||||
bar.update(total, f"{desc} - Complete!")
|
||||
|
||||
def simulate_progress(message="Processing", duration=3, style='modern', color='cyan'):
|
||||
"""Simulate progress for demo purposes"""
|
||||
bar = ProgressBar(100, style=style, color=color)
|
||||
|
||||
for i in range(101):
|
||||
time.sleep(duration / 100)
|
||||
bar.update(i, message)
|
||||
|
||||
def with_spinner(func, message="Loading", style='dots'):
|
||||
"""Decorator to show spinner during function execution"""
|
||||
def wrapper(*args, **kwargs):
|
||||
spinner = SpinnerProgress(message, style)
|
||||
spinner.start()
|
||||
try:
|
||||
result = func(*args, **kwargs)
|
||||
spinner.stop("Complete!")
|
||||
return result
|
||||
except Exception as e:
|
||||
spinner.stop(f"Error: {str(e)}")
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
# Demo functions
|
||||
def demo_progress_bars():
|
||||
"""Demonstrate different progress bar styles"""
|
||||
print(Fore.CYAN + "🚀 OverCode Progress Bar Demo")
|
||||
print("=" * 50)
|
||||
|
||||
styles = ['modern', 'classic', 'dots', 'arrows', 'blocks', 'fire']
|
||||
colors = ['cyan', 'green', 'yellow', 'magenta', 'blue']
|
||||
|
||||
for style in styles:
|
||||
color = colors[styles.index(style) % len(colors)]
|
||||
print(f"\n{Fore.WHITE}Style: {style.title()} ({color})")
|
||||
|
||||
bar = ProgressBar(50, style=style, color=color)
|
||||
for i in range(51):
|
||||
bar.update(i, f"Processing {style} style...")
|
||||
time.sleep(0.02)
|
||||
|
||||
print(f"\n{Fore.GREEN}✨ All styles demonstrated!")
|
||||
|
||||
def demo_spinner():
|
||||
"""Demonstrate spinner animations"""
|
||||
print(Fore.CYAN + "\n🔄 Spinner Demo")
|
||||
|
||||
styles = ['dots', 'arrows', 'bars', 'blocks', 'braille', 'fire']
|
||||
|
||||
for style in styles:
|
||||
spinner = SpinnerProgress(f"Loading with {style} style", style)
|
||||
spinner.start()
|
||||
time.sleep(2)
|
||||
spinner.stop(f"{style.title()} complete!")
|
||||
|
||||
def demo_multi_progress():
|
||||
"""Demonstrate multiple progress bars"""
|
||||
print(Fore.CYAN + "\n📊 Multi-Progress Demo")
|
||||
|
||||
multi = MultiProgress()
|
||||
multi.add_bar("Download", 100, 'modern', 'green')
|
||||
multi.add_bar("Extract", 80, 'arrows', 'yellow')
|
||||
multi.add_bar("Install", 60, 'dots', 'blue')
|
||||
|
||||
import random
|
||||
|
||||
for i in range(100):
|
||||
if i < 80:
|
||||
multi.increment("Download", 1, f"Downloading file {i+1}")
|
||||
if i > 20 and i < 60:
|
||||
multi.increment("Extract", random.randint(1, 2), "Extracting files...")
|
||||
if i > 40:
|
||||
multi.increment("Install", 1, "Installing packages...")
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
print(f"\n{Fore.GREEN}🎉 All operations complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_progress_bars()
|
||||
demo_spinner()
|
||||
demo_multi_progress()
|
||||
Reference in New Issue
Block a user