From dca47ab1ebc699920cfbc8ce16f5e7d7194fe562 Mon Sep 17 00:00:00 2001 From: Zane V Date: Sat, 15 Nov 2025 13:52:40 -0500 Subject: [PATCH] Update version to v0.1.2.a.3 and enhance UI/UX features - Updated version number in version.txt. - Improved smooth scrolling for anchor links in script.js. - Added Intersection Observer for fade-in animations in script.js. - Enhanced CSS styles for various elements, including buttons, metrics, and backgrounds for better visual appeal and interactivity. --- index.html | 2 +- script.js | 42 +++++ styles.css | 340 +++++++++++++++++++++++++++++++++++--- terminal.py | 462 +++++++++++++++++++++++++++++++++++++--------------- version.txt | 2 +- 5 files changed, 695 insertions(+), 153 deletions(-) diff --git a/index.html b/index.html index 872a272..a4eeb43 100644 --- a/index.html +++ b/index.html @@ -45,7 +45,7 @@

Current release

-

v0.1.2.a.2

+

v0.1.2.a.3

Supported families

diff --git a/script.js b/script.js index e293473..be11465 100644 --- a/script.js +++ b/script.js @@ -72,4 +72,46 @@ document.addEventListener('DOMContentLoaded', () => { } }); }); + + // Smooth scroll for anchor links + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function (e) { + const href = this.getAttribute('href'); + if (href === '#' || href === '#top') return; + + e.preventDefault(); + const target = document.querySelector(href); + if (target) { + target.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + }); + }); + + // Intersection Observer for fade-in animations + const observerOptions = { + threshold: 0.1, + rootMargin: '0px 0px -50px 0px' + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.style.opacity = '1'; + entry.target.style.transform = 'translateY(0)'; + } + }); + }, observerOptions); + + // Observe sections and cards for fade-in effect (exclude hero section) + const animatedElements = document.querySelectorAll('.section:not(.hero), .card, .metric, figure, .install-steps li'); + animatedElements.forEach(el => { + el.style.opacity = '0'; + el.style.transform = 'translateY(20px)'; + el.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; + observer.observe(el); + }); + }); diff --git a/styles.css b/styles.css index f13b16d..5525211 100644 --- a/styles.css +++ b/styles.css @@ -4,12 +4,14 @@ --bg: #05060a; --bg-alt: #0e1018; --card: #121422; - --card-border: rgba(255, 255, 255, 0.08); + --card-border: rgba(255, 255, 255, 0.12); --text: #f5f6fd; --muted: #9aa2c4; --accent: #4dd5ff; --accent-strong: #6d84ff; + --accent-glow: rgba(77, 213, 255, 0.4); --shadow: 0 18px 45px rgba(4, 6, 11, 0.6); + --shadow-glow: 0 0 30px rgba(77, 213, 255, 0.2); } *, @@ -18,15 +20,43 @@ box-sizing: border-box; } +html { + scroll-behavior: smooth; +} + body { margin: 0; min-height: 100vh; - background: radial-gradient(circle at top, rgba(77, 213, 255, 0.12), transparent 55%), - radial-gradient(circle at 20% 20%, rgba(109, 132, 255, 0.25), transparent 35%), - var(--bg); + background: + radial-gradient(circle at 0% 0%, rgba(77, 213, 255, 0.15), transparent 50%), + radial-gradient(circle at 100% 0%, rgba(109, 132, 255, 0.2), transparent 50%), + radial-gradient(circle at 50% 100%, rgba(77, 213, 255, 0.08), transparent 60%), + var(--bg); + background-attachment: fixed; color: var(--text); font-size: 1rem; line-height: 1.6; + position: relative; + overflow-x: hidden; +} + +body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: + radial-gradient(circle at 20% 30%, rgba(77, 213, 255, 0.03), transparent 50%), + radial-gradient(circle at 80% 70%, rgba(109, 132, 255, 0.03), transparent 50%); + pointer-events: none; + z-index: 0; +} + +body > * { + position: relative; + z-index: 1; } img { @@ -56,6 +86,27 @@ button:focus-visible { display: flex; flex-direction: column; gap: 2rem; + position: relative; + overflow: hidden; +} + +.hero::after { + content: ''; + position: absolute; + top: -50%; + right: -20%; + width: 600px; + height: 600px; + background: radial-gradient(circle, rgba(77, 213, 255, 0.1), transparent 70%); + border-radius: 50%; + filter: blur(60px); + pointer-events: none; + animation: pulse 8s ease-in-out infinite; +} + +@keyframes pulse { + 0%, 100% { transform: scale(1) translate(0, 0); opacity: 0.6; } + 50% { transform: scale(1.2) translate(-10%, 10%); opacity: 0.8; } } .nav { @@ -68,6 +119,12 @@ button:focus-visible { .brand { font-weight: 700; letter-spacing: 0.08em; + font-size: 1.25rem; + background: linear-gradient(135deg, var(--accent), var(--accent-strong)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 0 0 20px var(--accent-glow); } .nav__links { @@ -79,14 +136,32 @@ button:focus-visible { .nav__links a { color: var(--muted); font-weight: 500; - transition: color 0.2s ease; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); text-decoration: none; + position: relative; + padding: 0.5rem 0; +} + +.nav__links a::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 0; + height: 2px; + background: linear-gradient(90deg, var(--accent), var(--accent-strong)); + transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 0 10px var(--accent-glow); } .nav__links a:hover { color: var(--text); } +.nav__links a:hover::after { + width: 100%; +} + .nav__toggle { display: none; background: none; @@ -119,6 +194,11 @@ h1 { font-size: clamp(2.7rem, 5vw, 4.8rem); margin: 0 0 1rem; line-height: 1.05; + background: linear-gradient(135deg, var(--text) 0%, var(--accent) 50%, var(--accent-strong) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + filter: drop-shadow(0 0 20px rgba(77, 213, 255, 0.3)); } h2 { @@ -149,8 +229,28 @@ h3 { border-radius: 999px; font-weight: 600; cursor: pointer; - transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); text-decoration: none; + position: relative; + overflow: hidden; +} + +.btn::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 255, 255, 0.2); + transform: translate(-50%, -50%); + transition: width 0.6s, height 0.6s; +} + +.btn:hover::before { + width: 300px; + height: 300px; } .btn:focus-visible { @@ -163,32 +263,51 @@ h3 { } .btn.primary { - background: linear-gradient(90deg, var(--accent-strong), var(--accent)); + background: linear-gradient(135deg, var(--accent-strong), var(--accent)); color: #05060a; border: none; - box-shadow: 0 15px 40px rgba(77, 213, 255, 0.3); + box-shadow: 0 15px 40px rgba(77, 213, 255, 0.3), 0 0 20px rgba(77, 213, 255, 0.2); + z-index: 1; +} + +.btn.primary:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: 0 20px 50px rgba(77, 213, 255, 0.4), 0 0 30px rgba(77, 213, 255, 0.3); } .btn.ghost { - border-color: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.25); color: var(--text); - background: transparent; + background: rgba(255, 255, 255, 0.03); + backdrop-filter: blur(10px); + z-index: 1; } -.btn:hover { - transform: translateY(-1px); - box-shadow: 0 12px 30px rgba(109, 132, 255, 0.25); +.btn.ghost:hover { + transform: translateY(-2px); + border-color: rgba(77, 213, 255, 0.5); + background: rgba(77, 213, 255, 0.1); + box-shadow: 0 10px 30px rgba(77, 213, 255, 0.15); } .install-command { display: block; padding: 1rem 1.25rem; border-radius: 0.75rem; - background: rgba(18, 20, 34, 0.7); + background: rgba(18, 20, 34, 0.8); border: 1px solid var(--card-border); font-family: 'JetBrains Mono', 'Space Grotesk', monospace; font-size: 0.95rem; overflow-x: auto; + backdrop-filter: blur(10px); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); + transition: all 0.3s ease; + position: relative; +} + +.install-command:hover { + border-color: rgba(77, 213, 255, 0.3); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 0 20px rgba(77, 213, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.1); } .hero__metrics { @@ -201,7 +320,32 @@ h3 { padding: 1.25rem; border-radius: 1rem; border: 1px solid var(--card-border); - background: rgba(5, 6, 10, 0.55); + background: rgba(5, 6, 10, 0.6); + backdrop-filter: blur(10px); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; +} + +.metric::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(77, 213, 255, 0.1), transparent); + transition: left 0.5s ease; +} + +.metric:hover { + transform: translateY(-4px); + border-color: rgba(77, 213, 255, 0.3); + box-shadow: 0 10px 30px rgba(77, 213, 255, 0.15); +} + +.metric:hover::before { + left: 100%; } .metric__label { @@ -239,6 +383,40 @@ h3 { background: var(--card); box-shadow: var(--shadow); min-height: 10rem; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; + backdrop-filter: blur(10px); +} + +.card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + transform: translateX(-100%); + transition: transform 0.6s ease; +} + +.card:hover { + transform: translateY(-6px); + border-color: rgba(77, 213, 255, 0.4); + box-shadow: 0 20px 50px rgba(77, 213, 255, 0.2), var(--shadow); +} + +.card:hover::before { + transform: translateX(100%); +} + +.card h3 { + transition: color 0.3s ease; +} + +.card:hover h3 { + color: var(--accent); } .card p { @@ -262,10 +440,19 @@ h3 { padding: 1.5rem; border-radius: 1rem; border: 1px solid var(--card-border); - background: rgba(5, 6, 10, 0.5); + background: rgba(5, 6, 10, 0.6); + backdrop-filter: blur(10px); counter-increment: install-step; position: relative; padding-left: 4.5rem; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.install-steps li:hover { + transform: translateX(8px); + border-color: rgba(77, 213, 255, 0.3); + background: rgba(5, 6, 10, 0.7); + box-shadow: 0 10px 30px rgba(77, 213, 255, 0.1); } .install-steps li::before { @@ -281,6 +468,14 @@ h3 { display: grid; place-items: center; font-weight: 600; + transition: all 0.3s ease; + box-shadow: 0 0 15px rgba(77, 213, 255, 0.3); +} + +.install-steps li:hover::before { + background: rgba(77, 213, 255, 0.3); + box-shadow: 0 0 25px rgba(77, 213, 255, 0.5); + transform: scale(1.1); } .callout { @@ -289,6 +484,14 @@ h3 { border-radius: 1rem; background: rgba(255, 196, 87, 0.12); border: 1px solid rgba(255, 196, 87, 0.35); + backdrop-filter: blur(10px); + box-shadow: 0 8px 32px rgba(255, 196, 87, 0.1); + transition: all 0.3s ease; +} + +.callout:hover { + border-color: rgba(255, 196, 87, 0.5); + box-shadow: 0 8px 32px rgba(255, 196, 87, 0.2); } .showcase__grid { @@ -303,7 +506,33 @@ figure { border-radius: 1rem; padding: 1rem; background: rgba(9, 10, 18, 0.8); + backdrop-filter: blur(10px); min-height: 15rem; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; +} + +figure::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(77, 213, 255, 0.1), transparent 70%); + opacity: 0; + transition: opacity 0.4s ease; +} + +figure:hover { + transform: translateY(-8px) scale(1.02); + border-color: rgba(77, 213, 255, 0.4); + box-shadow: 0 20px 50px rgba(77, 213, 255, 0.2); +} + +figure:hover::before { + opacity: 1; } figcaption { @@ -313,22 +542,55 @@ figcaption { } pre { - background: rgba(5, 6, 10, 0.65); + background: rgba(5, 6, 10, 0.8); padding: 1rem; border-radius: 0.75rem; overflow: auto; font-size: 0.85rem; line-height: 1.3; + border: 1px solid rgba(77, 213, 255, 0.1); + box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.3); + position: relative; + backdrop-filter: blur(5px); +} + +pre::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(77, 213, 255, 0.3), transparent); } .statusbar-demo { display: flex; justify-content: space-between; - background: linear-gradient(90deg, var(--accent-strong), var(--accent)); + background: linear-gradient(135deg, var(--accent-strong), var(--accent)); color: #05060a; padding: 0.65rem 1rem; border-radius: 0.5rem; font-weight: 600; + box-shadow: 0 4px 20px rgba(77, 213, 255, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2); + position: relative; + overflow: hidden; +} + +.statusbar-demo::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + animation: shimmer 3s infinite; +} + +@keyframes shimmer { + 0% { left: -100%; } + 100% { left: 100%; } } .community__actions { @@ -340,7 +602,7 @@ pre { .footer { padding: 2rem clamp(1.5rem, 5vw, 5rem); - border-top: 1px solid rgba(255, 255, 255, 0.08); + border-top: 1px solid rgba(255, 255, 255, 0.1); display: flex; justify-content: space-between; align-items: center; @@ -348,6 +610,28 @@ pre { gap: 1rem; font-size: 0.9rem; color: var(--muted); + background: rgba(5, 6, 10, 0.5); + backdrop-filter: blur(10px); + position: relative; +} + +.footer::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(77, 213, 255, 0.3), transparent); +} + +.footer a { + transition: all 0.3s ease; +} + +.footer a:hover { + color: var(--accent); + text-shadow: 0 0 10px var(--accent-glow); } @media (max-width: 720px) { @@ -365,9 +649,27 @@ pre { flex-direction: column; padding: 1rem 0 0; gap: 0.75rem; + background: rgba(5, 6, 10, 0.95); + backdrop-filter: blur(20px); + border-radius: 0.5rem; + padding: 1rem; + margin-top: 1rem; + border: 1px solid var(--card-border); } .nav__links.is-open { display: flex; + animation: slideDown 0.3s ease; + } + + @keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } } } diff --git a/terminal.py b/terminal.py index 5676110..4368053 100644 --- a/terminal.py +++ b/terminal.py @@ -16,6 +16,7 @@ import logging import threading import json import shlex +import signal from datetime import datetime import urllib.request import urllib.error @@ -218,6 +219,7 @@ class ZDTTTerminal: self.scroll_region_set = False self.plugin_command_names = set() self.update_check_thread = None + self.resize_lock = threading.Lock() # Lock for resize operations # Setup logging for plugins self.setup_logging() @@ -232,12 +234,50 @@ class ZDTTTerminal: # Load user preferences (status bar color, etc.) self.load_preferences() - # ANSI color codes + # ANSI color codes - Enhanced palette self.COLOR_RESET = '\033[0m' - self.COLOR_GREEN = '\033[92m' - self.COLOR_BLUE = '\033[94m' - self.COLOR_CYAN = '\033[96m' self.COLOR_BOLD = '\033[1m' + self.COLOR_DIM = '\033[2m' + self.COLOR_ITALIC = '\033[3m' + + # Standard colors + self.COLOR_BLACK = '\033[30m' + self.COLOR_RED = '\033[31m' + self.COLOR_GREEN = '\033[32m' + self.COLOR_YELLOW = '\033[33m' + self.COLOR_BLUE = '\033[34m' + self.COLOR_MAGENTA = '\033[35m' + self.COLOR_CYAN = '\033[36m' + self.COLOR_WHITE = '\033[37m' + + # Bright colors + self.COLOR_BRIGHT_BLACK = '\033[90m' + self.COLOR_BRIGHT_RED = '\033[91m' + self.COLOR_BRIGHT_GREEN = '\033[92m' + self.COLOR_BRIGHT_YELLOW = '\033[93m' + self.COLOR_BRIGHT_BLUE = '\033[94m' + self.COLOR_BRIGHT_MAGENTA = '\033[95m' + self.COLOR_BRIGHT_CYAN = '\033[96m' + self.COLOR_BRIGHT_WHITE = '\033[97m' + + # Accent colors (using bright variants for better visibility) + self.COLOR_ACCENT = '\033[96m' # Bright cyan + self.COLOR_ACCENT2 = '\033[94m' # Bright blue + self.COLOR_SUCCESS = '\033[92m' # Bright green + self.COLOR_WARNING = '\033[93m' # Bright yellow + self.COLOR_ERROR = '\033[91m' # Bright red + self.COLOR_INFO = '\033[96m' # Bright cyan + + # Background colors + self.BG_BLACK = '\033[40m' + self.BG_RED = '\033[41m' + self.BG_GREEN = '\033[42m' + self.BG_YELLOW = '\033[43m' + self.BG_BLUE = '\033[44m' + self.BG_MAGENTA = '\033[45m' + self.BG_CYAN = '\033[46m' + self.BG_WHITE = '\033[47m' + self.BG_BRIGHT_CYAN = '\033[106m' self.commands = { 'help': self.cmd_help, @@ -473,35 +513,106 @@ ZDTT Terminal v{self.version} def _render_status_bar(self): """Render a single-line status bar with branding and time.""" - bar_text = self._build_status_bar_text() try: + # Get terminal size first to ensure we don't write beyond bounds + try: + term_size = shutil.get_terminal_size() + max_width = term_size.columns + except Exception: + max_width = 80 # Fallback + + bar_text = self._build_status_bar_text() + + # Ensure bar_text doesn't exceed terminal width (safety check) + # Count visible characters (approximate - ANSI codes don't count) + # This is a rough check, but better than nothing + if len(bar_text) > max_width * 3: # Allow for ANSI codes (rough estimate) + # Rebuild with safer width + bar_text = self._build_status_bar_text() + sys.stdout.write("\033[s") # Save cursor position - sys.stdout.write("\033[1;1H") # Move to first row - sys.stdout.write("\033[2K") # Clear the line + sys.stdout.write("\033[1;1H") # Move to first row, first column + sys.stdout.write("\033[2K") # Clear the entire line + sys.stdout.write("\033[0m") # Reset all attributes sys.stdout.write(bar_text) - sys.stdout.write(self.COLOR_RESET) + sys.stdout.write("\033[0m") # Ensure reset at end + # Move cursor to end of line to prevent wrapping issues + sys.stdout.write(f"\033[{max_width}G") # Move to column max_width sys.stdout.write("\033[u") # Restore cursor sys.stdout.flush() except Exception: - print(bar_text) + # Fallback: just skip rendering if there's an error + pass def _build_status_bar_text(self): - left_text = "ZDTT by ZaneDev" - time_str = datetime.now().strftime("%I:%M:%p").lower() - try: - term_size = shutil.get_terminal_size() - width = max(term_size.columns, len(left_text) + len(time_str) + 4) - except Exception: - width = len(left_text) + len(time_str) + 4 + """Render a single-line status bar with enhanced branding and time.""" + left_text = f"{self.COLOR_BOLD}ZDTT{self.COLOR_RESET} by {self.COLOR_BOLD}ZaneDev{self.COLOR_RESET}" + time_str = datetime.now().strftime("%I:%M %p") + plain_left = "ZDTT by ZaneDev" + plain_time = time_str - padding = max(width - len(left_text) - len(time_str) - 2, 1) - bar_plain = f" {left_text}{' ' * padding}{time_str} " - if len(bar_plain) < width: - bar_plain = bar_plain.ljust(width) + try: + # Always get fresh terminal size to handle resizes + term_size = shutil.get_terminal_size() + width = term_size.columns + # Safety: ensure width is at least 1 + width = max(1, width) + except Exception: + # Fallback to minimum width if we can't get terminal size + width = max(1, len(plain_left) + len(plain_time) + 6) + + # Calculate the minimum content width (plain text only, no ANSI codes) + # Format: " ZDTT by ZaneDev | TIME " + min_content_width = len(plain_left) + len(plain_time) + 5 # 5 = spaces + separator + + # Calculate padding to fill the line + if width < min_content_width: + # Terminal too narrow, use minimum padding + padding = 0 else: - bar_plain = bar_plain[:width] + padding = width - min_content_width + + # Build the content (plain text calculation) + separator = f"{self.COLOR_DIM}│{self.COLOR_RESET}" + bar_content = f" {left_text} {' ' * padding}{separator} {self.COLOR_BRIGHT_WHITE}{time_str}{self.COLOR_RESET} " + + # Calculate actual display length (plain text only) + actual_display_len = len(plain_left) + len(plain_time) + padding + 5 + + # Ensure we fill exactly to terminal width (but never exceed it) + if actual_display_len < width: + # Add trailing spaces to fill exactly to width + trailing_spaces = width - actual_display_len + bar_content = bar_content.rstrip() + ' ' * trailing_spaces + elif actual_display_len > width: + # We exceeded width, recalculate with less padding + padding = max(0, width - min_content_width) + bar_content = f" {left_text} {' ' * padding}{separator} {self.COLOR_BRIGHT_WHITE}{time_str}{self.COLOR_RESET} " + actual_display_len = len(plain_left) + len(plain_time) + padding + 5 + if actual_display_len < width: + trailing_spaces = width - actual_display_len + bar_content = bar_content.rstrip() + ' ' * trailing_spaces + else: + # Still too wide, trim the time if necessary + if width < len(plain_left) + 10: + # Very narrow terminal, just show minimal content + bar_content = f" {left_text} {separator} {self.COLOR_BRIGHT_WHITE}{time_str[:8]}{self.COLOR_RESET} " + bar_content = bar_content[:width] if len(bar_content) > width else bar_content + + # Final safety check: ensure we never exceed terminal width + # This is approximate since ANSI codes don't count, but better than nothing bg_code, fg_code = STATUS_BAR_COLORS.get(self.status_bar_color, ('44', '97')) - return f"\033[{bg_code}m\033[{fg_code}m{bar_plain}" + result = f"\033[{bg_code}m\033[{fg_code}m{bar_content}\033[0m" + + # If the result is suspiciously long, truncate it + # (rough heuristic: ANSI codes add ~30-50 chars, so if result > width*2, it's probably wrong) + if len(result) > width * 2: + # Emergency fallback: simple status bar + simple_bar = f" ZDTT by ZaneDev | {time_str} " + simple_bar = simple_bar[:width] if len(simple_bar) > width else simple_bar.ljust(width) + result = f"\033[{bg_code}m\033[{fg_code}m{simple_bar}\033[0m" + + return result def _set_scroll_region(self): """Reserve the top row for the status bar.""" @@ -525,6 +636,50 @@ ZDTT Terminal v{self.version} sys.stdout.flush() self.scroll_region_set = False + def _handle_resize(self, signum=None, frame=None): + """Handle terminal resize event (SIGWINCH).""" + # Use a lock to prevent race conditions + if not self.resize_lock.acquire(blocking=False): + # If we can't acquire the lock immediately, skip this resize + # (another resize is already being handled) + return + + try: + # Small delay to let terminal settle after resize + time_module.sleep(0.05) + + # Reset scroll region first to clear any corrupted state + self._reset_scroll_region() + + # Update scroll region with new terminal size + self._set_scroll_region() + + # Clear the status bar line completely before redrawing + try: + sys.stdout.write("\033[1;1H") # Move to first row + sys.stdout.write("\033[2K") # Clear the entire line + sys.stdout.write("\033[0m") # Reset attributes + sys.stdout.flush() + except Exception: + pass + + # Force immediate status bar refresh + self._render_status_bar() + + # Ensure cursor is in a safe position + try: + term_size = shutil.get_terminal_size() + sys.stdout.write(f"\033[{term_size.lines};1H") # Move to last line, first column + sys.stdout.flush() + except Exception: + pass + + except Exception: + # Silently fail if resize handling fails + pass + finally: + self.resize_lock.release() + def setup_readline(self): """Setup readline for history and tab completion""" # Setup history @@ -626,7 +781,7 @@ ZDTT Terminal v{self.version} # Show brief status if there were failures if failed_count > 0: - print(f"⚠ {failed_count} plugin(s) failed to load. Check ~/.zdtt/plugin_errors.log") + print(f"{self.COLOR_WARNING}⚠ {failed_count} plugin(s) failed to load. Check ~/.zdtt/plugin_errors.log{self.COLOR_RESET}") def unload_plugin_commands(self): """Remove commands that originated from plugins.""" @@ -668,7 +823,7 @@ ZDTT Terminal v{self.version} f.write(f"{name}={command}\n") except Exception as e: logging.error(f"Failed to save aliases: {e}") - print(f"Error: Failed to save aliases: {e}") + print(f"{self.COLOR_ERROR}Error: Failed to save aliases: {e}{self.COLOR_RESET}") def expand_aliases(self, command_line): """Expand aliases in command line""" @@ -689,7 +844,7 @@ ZDTT Terminal v{self.version} return command_line def get_prompt(self): - """Return the custom prompt string with colors""" + """Return the custom prompt string with enhanced colors""" # Show current directory in prompt cwd = os.getcwd() # Show ~ for home directory @@ -704,63 +859,72 @@ ZDTT Terminal v{self.version} RL_PROMPT_START = '\001' RL_PROMPT_END = '\002' - # Create colorized prompt with readline-safe escape codes - # [username in green @ ZDTT path in blue]=> - prompt = (f"[{RL_PROMPT_START}{self.COLOR_GREEN}{RL_PROMPT_END}{self.username}" + # Create enhanced colorized prompt with gradient-like effect + # [username in bright green @ ZDTT in bright cyan path in bright blue]=> + prompt = (f"{RL_PROMPT_START}{self.COLOR_BRIGHT_CYAN}{RL_PROMPT_END}┌─{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END}" + f"[{RL_PROMPT_START}{self.COLOR_BRIGHT_GREEN}{RL_PROMPT_END}{self.username}" f"{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END}" - f"@{RL_PROMPT_START}{self.COLOR_CYAN}{RL_PROMPT_END}ZDTT{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END} " - f"{RL_PROMPT_START}{self.COLOR_BLUE}{RL_PROMPT_END}{display_path}" - f"{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END}]=> ") + f"{RL_PROMPT_START}{self.COLOR_BRIGHT_WHITE}{RL_PROMPT_END}@{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END}" + f"{RL_PROMPT_START}{self.COLOR_BRIGHT_CYAN}{RL_PROMPT_END}ZDTT{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END} " + f"{RL_PROMPT_START}{self.COLOR_BRIGHT_BLUE}{RL_PROMPT_END}{display_path}" + f"{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END}]" + f"{RL_PROMPT_START}{self.COLOR_BRIGHT_CYAN}{RL_PROMPT_END}─{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END}\n" + f"{RL_PROMPT_START}{self.COLOR_BRIGHT_CYAN}{RL_PROMPT_END}└─{RL_PROMPT_START}{self.COLOR_BRIGHT_MAGENTA}{RL_PROMPT_END}➜{RL_PROMPT_START}{self.COLOR_RESET}{RL_PROMPT_END} ") return prompt def cmd_help(self, args): - """Display available commands""" - print("\nZDTT Terminal Commands:") - print(" help - Display this help message") - print(" clear - Clear the screen") - print(" echo - Echo a message") - print(" about - About ZDTT Terminal") - print(" history - Show command history") - print(" plugins [reload] - List or reload plugins") - print(" alias [name=cmd] - Create or display command aliases") - print(" unalias - Remove an alias") - print(" zps install - Install plugin from URL") - print(" time [options] - Display date/time (MM/DD/YY 12h default)") - print(" statusbar color - Change status bar highlight color") - print(" update - Run the ZDTT updater helper") - print(" exit - Exit ZDTT (return to shell)") - print(" quit - Quit and close terminal window") + """Display available commands with enhanced formatting""" print() - print("File System Commands:") - print(" ls [options] - List directory contents") - print(" pwd - Print working directory") - print(" cd - Change directory") - print(" cat - Display file contents") - print(" mkdir - Create directory") - print(" touch - Create empty file") - print(" rm [-rf] - Remove file/directory (prompts without -f)") - print(" mv - Move/rename file") - print(" cp [-r] - Copy file") - print(" grep - Search for pattern in file") + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}╔═══════════════════════════════════════════════════════════╗{self.COLOR_RESET}") + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}║{self.COLOR_RESET} {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}ZDTT Terminal Commands{self.COLOR_RESET} {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}║{self.COLOR_RESET}") + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}╚═══════════════════════════════════════════════════════════╝{self.COLOR_RESET}") print() - print("System Commands:") - print(" whoami - Display current user") - print(" date - Display current date/time") - print(" uname [options] - Display system information") - print(" nano - Edit file with nano") - print(" sysfetch - Display system info (prefers distro tools)") + print(f"{self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}Core Commands:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_GREEN}help{self.COLOR_RESET} - Display this help message") + print(f" {self.COLOR_BRIGHT_GREEN}clear{self.COLOR_RESET} - Clear the screen") + print(f" {self.COLOR_BRIGHT_GREEN}echo{self.COLOR_RESET} - Echo a message") + print(f" {self.COLOR_BRIGHT_GREEN}about{self.COLOR_RESET} - About ZDTT Terminal") + print(f" {self.COLOR_BRIGHT_GREEN}history{self.COLOR_RESET} - Show command history") + print(f" {self.COLOR_BRIGHT_GREEN}plugins{self.COLOR_RESET} [reload] - List or reload plugins") + print(f" {self.COLOR_BRIGHT_GREEN}alias{self.COLOR_RESET} [name=cmd] - Create or display command aliases") + print(f" {self.COLOR_BRIGHT_GREEN}unalias{self.COLOR_RESET} - Remove an alias") + print(f" {self.COLOR_BRIGHT_GREEN}zps{self.COLOR_RESET} install - Install plugin from URL") + print(f" {self.COLOR_BRIGHT_GREEN}time{self.COLOR_RESET} [options] - Display date/time (MM/DD/YY 12h default)") + print(f" {self.COLOR_BRIGHT_GREEN}statusbar{self.COLOR_RESET} color - Change status bar highlight color") + print(f" {self.COLOR_BRIGHT_GREEN}update{self.COLOR_RESET} - Run the ZDTT updater helper") + print(f" {self.COLOR_BRIGHT_GREEN}exit{self.COLOR_RESET} - Exit ZDTT (return to shell)") + print(f" {self.COLOR_BRIGHT_GREEN}quit{self.COLOR_RESET} - Quit and close terminal window") print() - print("Python Commands:") - print(" python [args] - Run Python interpreter") - print(" python3 [args] - Run Python 3 interpreter") - print(" pip [args] - Run pip package manager") - print(" pip3 [args] - Run pip3 package manager") + print(f"{self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}File System Commands:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_GREEN}ls{self.COLOR_RESET} [options] - List directory contents") + print(f" {self.COLOR_BRIGHT_GREEN}pwd{self.COLOR_RESET} - Print working directory") + print(f" {self.COLOR_BRIGHT_GREEN}cd{self.COLOR_RESET} - Change directory") + print(f" {self.COLOR_BRIGHT_GREEN}cat{self.COLOR_RESET} - Display file contents") + print(f" {self.COLOR_BRIGHT_GREEN}mkdir{self.COLOR_RESET} - Create directory") + print(f" {self.COLOR_BRIGHT_GREEN}touch{self.COLOR_RESET} - Create empty file") + print(f" {self.COLOR_BRIGHT_GREEN}rm{self.COLOR_RESET} [-rf] - Remove file/directory (prompts without -f)") + print(f" {self.COLOR_BRIGHT_GREEN}mv{self.COLOR_RESET} - Move/rename file") + print(f" {self.COLOR_BRIGHT_GREEN}cp{self.COLOR_RESET} [-r] - Copy file") + print(f" {self.COLOR_BRIGHT_GREEN}grep{self.COLOR_RESET} - Search for pattern in file") print() - print("Features:") - print(" ↑/↓ arrows - Navigate command history") - print(" Tab - Auto-complete commands/files") - print(" -oszdtt flag - Run any command in system shell") - print(" Example: htop -oszdtt") + print(f"{self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}System Commands:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_GREEN}whoami{self.COLOR_RESET} - Display current user") + print(f" {self.COLOR_BRIGHT_GREEN}date{self.COLOR_RESET} - Display current date/time") + print(f" {self.COLOR_BRIGHT_GREEN}uname{self.COLOR_RESET} [options] - Display system information") + print(f" {self.COLOR_BRIGHT_GREEN}nano{self.COLOR_RESET} - Edit file with nano") + print(f" {self.COLOR_BRIGHT_GREEN}sysfetch{self.COLOR_RESET} - Display system info (prefers distro tools)") + print() + print(f"{self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}Python Commands:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_GREEN}python{self.COLOR_RESET} [args] - Run Python interpreter") + print(f" {self.COLOR_BRIGHT_GREEN}python3{self.COLOR_RESET} [args] - Run Python 3 interpreter") + print(f" {self.COLOR_BRIGHT_GREEN}pip{self.COLOR_RESET} [args] - Run pip package manager") + print(f" {self.COLOR_BRIGHT_GREEN}pip3{self.COLOR_RESET} [args] - Run pip3 package manager") + print() + print(f"{self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}Features:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_YELLOW}↑/↓ arrows{self.COLOR_RESET} - Navigate command history") + print(f" {self.COLOR_BRIGHT_YELLOW}Tab{self.COLOR_RESET} - Auto-complete commands/files") + print(f" {self.COLOR_BRIGHT_YELLOW}-oszdtt flag{self.COLOR_RESET} - Run any command in system shell") + print(f" {self.COLOR_DIM}Example: htop -oszdtt{self.COLOR_RESET}") print() def cmd_clear(self, args): @@ -784,48 +948,55 @@ ZDTT Terminal v{self.version} sys.exit(0) def cmd_about(self, args): - """Display information about ZDTT Terminal""" - print(f"\nZDTT Terminal v{self.version}") - print("A custom terminal interface for Debian-based and Arch Linux systems") + """Display information about ZDTT Terminal with enhanced formatting""" + print() + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}╔═══════════════════════════════════════════════════════════╗{self.COLOR_RESET}") + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}║{self.COLOR_RESET} {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}About ZDTT Terminal{self.COLOR_RESET} {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}║{self.COLOR_RESET}") + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}╚═══════════════════════════════════════════════════════════╝{self.COLOR_RESET}") + print() + print(f" {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Version:{self.COLOR_RESET} {self.COLOR_BRIGHT_WHITE}v{self.version}{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Description:{self.COLOR_RESET} A custom terminal interface for Debian-based and Arch Linux systems") + print() - # Show distribution status + # Show distribution status with colors + print(f" {self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}System Status:{self.COLOR_RESET}") if self.is_debian: - print("Running on: Debian-based system (fully supported)") + print(f" {self.COLOR_BRIGHT_GREEN}✓{self.COLOR_RESET} Debian-based system {self.COLOR_BRIGHT_GREEN}(fully supported){self.COLOR_RESET}") elif self.is_arch: - print("Running on: Arch Linux (fully supported)") + print(f" {self.COLOR_BRIGHT_GREEN}✓{self.COLOR_RESET} Arch Linux {self.COLOR_BRIGHT_GREEN}(fully supported){self.COLOR_RESET}") else: - print("Running on: Unsupported system (limited support)") + print(f" {self.COLOR_WARNING}⚠{self.COLOR_RESET} Unsupported system {self.COLOR_WARNING}(limited support){self.COLOR_RESET}") print() - print("Features:") - print(" • Automatic update checking on startup") - print(" • Command history with ↑/↓ navigation (1000 commands)") - print(" • Tab completion for commands and files") - print(" • Command aliases (alias g=git)") - print(" • Flexible time/date display with multiple formats") - print(" • Colorized prompt") - print(" • Smart banner (auto-hides on small terminals)") - print(" • Plugin system with ZPS package manager") - print(" • Plugin hot-reload (plugins reload)") - print(" • Safe rm with confirmation prompts") - print(" • Custom banner support (~/.zdtt/banner.txt)") - print(" • Native command support") - print(" • System command execution via -oszdtt flag") - print(" • Clean, premium interface") + print(f" {self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}Features:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Automatic update checking on startup") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Command history with ↑/↓ navigation (1000 commands)") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Tab completion for commands and files") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Command aliases (alias g=git)") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Flexible time/date display with multiple formats") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Colorized prompt with enhanced styling") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Smart banner (auto-hides on small terminals)") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Plugin system with ZPS package manager") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Plugin hot-reload (plugins reload)") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Safe rm with confirmation prompts") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Custom banner support (~/.zdtt/banner.txt)") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Native command support") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} System command execution via -oszdtt flag") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} Clean, premium interface") print() - print("Configuration:") - print(f" • ZDTT directory: {self.zdtt_dir}") - print(f" • Aliases: {self.aliases_file}") - print(f" • Custom banner: {self.banner_file}") - print(f" • Plugin errors: {self.log_file}") + print(f" {self.COLOR_BRIGHT_MAGENTA}{self.COLOR_BOLD}Configuration:{self.COLOR_RESET}") + print(f" {self.COLOR_DIM}•{self.COLOR_RESET} ZDTT directory: {self.COLOR_BRIGHT_CYAN}{self.zdtt_dir}{self.COLOR_RESET}") + print(f" {self.COLOR_DIM}•{self.COLOR_RESET} Aliases: {self.COLOR_BRIGHT_CYAN}{self.aliases_file}{self.COLOR_RESET}") + print(f" {self.COLOR_DIM}•{self.COLOR_RESET} Custom banner: {self.COLOR_BRIGHT_CYAN}{self.banner_file}{self.COLOR_RESET}") + print(f" {self.COLOR_DIM}•{self.COLOR_RESET} Plugin errors: {self.COLOR_BRIGHT_CYAN}{self.log_file}{self.COLOR_RESET}") print() def cmd_history(self, args): - """Display command history""" + """Display command history with enhanced formatting""" history_length = readline.get_current_history_length() if history_length == 0: - print("No history available") + print(f"{self.COLOR_WARNING}No history available{self.COLOR_RESET}") return # Show last 50 commands by default @@ -836,17 +1007,20 @@ ZDTT Terminal v{self.version} start = max(1, history_length - limit + 1) print() + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Command History:{self.COLOR_RESET} (showing {limit} of {history_length} commands)") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") for i in range(start, history_length + 1): cmd = readline.get_history_item(i) if cmd: - print(f"{i:4d} {cmd}") + print(f"{self.COLOR_BRIGHT_BLACK}{i:4d}{self.COLOR_RESET} {self.COLOR_BRIGHT_CYAN}{cmd}{self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") print() def cmd_plugins(self, args): """List or reload plugins""" # Check for reload subcommand if args and args[0] == 'reload': - print("Reloading plugins...") + print(f"{self.COLOR_BRIGHT_CYAN}Reloading plugins...{self.COLOR_RESET}") # Remove plugin commands and reload aliases to avoid conflicts self.unload_plugin_commands() self.aliases.clear() @@ -854,7 +1028,7 @@ ZDTT Terminal v{self.version} # Reload plugins self.load_plugins() - print("✓ Plugins reloaded successfully!") + print(f"{self.COLOR_BRIGHT_GREEN}✓ Plugins reloaded successfully!{self.COLOR_RESET}") print() return @@ -862,24 +1036,33 @@ ZDTT Terminal v{self.version} plugin_files = glob.glob(os.path.join(self.plugin_dir, "*.py")) if not plugin_files: - print("\nNo plugins installed.") - print(f"Plugin directory: {self.plugin_dir}") - print("\nTo create a plugin, create a .py file with a register_commands() function") - print("that returns a dictionary of command names to functions.") - print("\nOr use: zps install to install from a URL") + print() + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Plugins:{self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") + print(f"{self.COLOR_WARNING}No plugins installed.{self.COLOR_RESET}") + print() + print(f"Plugin directory: {self.COLOR_BRIGHT_CYAN}{self.plugin_dir}{self.COLOR_RESET}") + print() + print(f"{self.COLOR_DIM}To create a plugin, create a .py file with a register_commands() function{self.COLOR_RESET}") + print(f"{self.COLOR_DIM}that returns a dictionary of command names to functions.{self.COLOR_RESET}") + print() + print(f"Or use: {self.COLOR_BRIGHT_GREEN}zps install {self.COLOR_RESET} to install from a URL") print() return - print(f"\nLoaded Plugins ({len(plugin_files)}):") + print() + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Loaded Plugins:{self.COLOR_RESET} {self.COLOR_BRIGHT_GREEN}({len(plugin_files)}){self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") for plugin_file in plugin_files: plugin_name = os.path.basename(plugin_file)[:-3] - print(f" • {plugin_name}") + print(f" {self.COLOR_BRIGHT_GREEN}•{self.COLOR_RESET} {self.COLOR_BRIGHT_CYAN}{plugin_name}{self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") print() - print(f"Plugin directory: {self.plugin_dir}") - print(f"Error log: {self.log_file}") + print(f"Plugin directory: {self.COLOR_BRIGHT_CYAN}{self.plugin_dir}{self.COLOR_RESET}") + print(f"Error log: {self.COLOR_BRIGHT_CYAN}{self.log_file}{self.COLOR_RESET}") print() - print("Commands:") - print(" plugins reload - Reload all plugins without restarting") + print(f"{self.COLOR_BRIGHT_MAGENTA}Commands:{self.COLOR_RESET}") + print(f" {self.COLOR_BRIGHT_GREEN}plugins reload{self.COLOR_RESET} - Reload all plugins without restarting") print() def cmd_alias(self, args): @@ -887,14 +1070,21 @@ ZDTT Terminal v{self.version} if not args: # Display all aliases if not self.aliases: - print("\nNo aliases defined.") - print("Usage: alias name=command") - print("Example: alias g=git") + print() + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Aliases:{self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") + print(f"{self.COLOR_WARNING}No aliases defined.{self.COLOR_RESET}") + print() + print(f"Usage: {self.COLOR_BRIGHT_GREEN}alias name=command{self.COLOR_RESET}") + print(f"Example: {self.COLOR_BRIGHT_GREEN}alias g=git{self.COLOR_RESET}") print() else: - print("\nDefined Aliases:") + print() + print(f"{self.COLOR_BRIGHT_CYAN}{self.COLOR_BOLD}Defined Aliases:{self.COLOR_RESET} {self.COLOR_BRIGHT_GREEN}({len(self.aliases)}){self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") for name, command in sorted(self.aliases.items()): - print(f" {name}={command}") + print(f" {self.COLOR_BRIGHT_GREEN}{name}{self.COLOR_RESET}={self.COLOR_BRIGHT_CYAN}{command}{self.COLOR_RESET}") + print(f"{self.COLOR_DIM}{'─' * 60}{self.COLOR_RESET}") print() return @@ -975,7 +1165,7 @@ ZDTT Terminal v{self.version} # Validate it's a .py file if not filename.endswith('.py'): - print(f"Error: '{filename}' is not a Python file") + print(f"{self.COLOR_ERROR}Error: '{filename}' is not a Python file{self.COLOR_RESET}") print("Plugin URLs must end with .py") return @@ -1002,7 +1192,7 @@ ZDTT Terminal v{self.version} with open(target_path, 'wb') as f: f.write(plugin_content) - print(f"✓ Plugin '{filename}' installed successfully!") + print(f"{self.COLOR_BRIGHT_GREEN}✓ Plugin '{filename}' installed successfully!{self.COLOR_RESET}") print(f" Location: {target_path}") print() print("To use the plugin:") @@ -1011,13 +1201,13 @@ ZDTT Terminal v{self.version} print() except urllib.error.HTTPError as e: - print(f"Error: Failed to download plugin (HTTP {e.code})") + print(f"{self.COLOR_ERROR}Error: Failed to download plugin (HTTP {e.code}){self.COLOR_RESET}") print(f"URL: {url}") except urllib.error.URLError as e: - print(f"Error: Failed to connect to server") + print(f"{self.COLOR_ERROR}Error: Failed to connect to server{self.COLOR_RESET}") print(f"Reason: {e.reason}") except Exception as e: - print(f"Error: {e}") + print(f"{self.COLOR_ERROR}Error: {e}{self.COLOR_RESET}") return @@ -1085,7 +1275,7 @@ ZDTT Terminal v{self.version} try: print(now.strftime(custom_format)) except Exception as e: - print(f"Error: Invalid format string - {e}") + print(f"{self.COLOR_ERROR}Error: Invalid format string - {e}{self.COLOR_RESET}") return # Default format: MM/DD/YY with time @@ -1125,7 +1315,7 @@ ZDTT Terminal v{self.version} self.status_bar_color = color self.save_preferences() self._render_status_bar() - print(f"Status bar color updated to {color}.") + print(f"{self.COLOR_BRIGHT_GREEN}✓{self.COLOR_RESET} Status bar color updated to {self.COLOR_BRIGHT_CYAN}{color}{self.COLOR_RESET}.") def cmd_echo(self, args): """Echo the provided arguments""" @@ -1502,12 +1692,20 @@ ZDTT Terminal v{self.version} if cmd in self.commands: self.commands[cmd](args) else: - print(f"Command not found: {cmd}") - print("Type 'help' for available commands.") - print("Tip: Use -oszdtt flag to run system commands") + print(f"{self.COLOR_ERROR}Command not found: {self.COLOR_BRIGHT_RED}{cmd}{self.COLOR_RESET}") + print(f"Type {self.COLOR_BRIGHT_GREEN}'help'{self.COLOR_RESET} for available commands.") + print(f"{self.COLOR_DIM}Tip: Use -oszdtt flag to run system commands{self.COLOR_RESET}") def run(self): """Main terminal loop""" + # Setup signal handler for terminal resize (SIGWINCH) + if sys.platform != 'win32': + try: + signal.signal(signal.SIGWINCH, self._handle_resize) + except (AttributeError, ValueError): + # SIGWINCH not available on this platform + pass + # Clear screen and display banner os.system('clear' if os.name != 'nt' else 'cls') self.initialize_status_bar() diff --git a/version.txt b/version.txt index dc2063d..fe3aea7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.1.2.a.2 \ No newline at end of file +0.1.2.a.3 \ No newline at end of file