feat: Enhance navigation accessibility and update terminal commands
This commit is contained in:
Binary file not shown.
@@ -13,12 +13,12 @@
|
|||||||
<header class="hero" id="top">
|
<header class="hero" id="top">
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<div class="brand">ZDTT</div>
|
<div class="brand">ZDTT</div>
|
||||||
<button class="nav__toggle" aria-label="Toggle navigation">
|
<button class="nav__toggle" type="button" aria-label="Toggle navigation" aria-expanded="false" aria-controls="primary-nav">
|
||||||
<span></span>
|
<span></span>
|
||||||
<span></span>
|
<span></span>
|
||||||
<span></span>
|
<span></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="nav__links">
|
<div class="nav__links" id="primary-nav">
|
||||||
<a href="#features">Features</a>
|
<a href="#features">Features</a>
|
||||||
<a href="#install">Install</a>
|
<a href="#install">Install</a>
|
||||||
<a href="#showcase">Showcase</a>
|
<a href="#showcase">Showcase</a>
|
||||||
|
|||||||
62
script.js
62
script.js
@@ -8,28 +8,68 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (navToggle && navLinks) {
|
if (navToggle && navLinks) {
|
||||||
|
const setExpanded = (isOpen) => {
|
||||||
|
navLinks.classList.toggle('is-open', isOpen);
|
||||||
|
navToggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||||
|
};
|
||||||
|
|
||||||
navToggle.addEventListener('click', () => {
|
navToggle.addEventListener('click', () => {
|
||||||
navLinks.classList.toggle('is-open');
|
const nextState = !navLinks.classList.contains('is-open');
|
||||||
|
setExpanded(nextState);
|
||||||
|
});
|
||||||
|
|
||||||
|
navLinks.addEventListener('click', (event) => {
|
||||||
|
if (event.target.closest('a')) {
|
||||||
|
setExpanded(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (event) => {
|
||||||
|
if (event.key === 'Escape' && navLinks.classList.contains('is-open')) {
|
||||||
|
setExpanded(false);
|
||||||
|
navToggle.focus();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll('[data-copy]').forEach((button) => {
|
document.querySelectorAll('[data-copy]').forEach((button) => {
|
||||||
|
const defaultLabel = button.textContent;
|
||||||
|
const setStatus = (label) => {
|
||||||
|
button.textContent = label;
|
||||||
|
setTimeout(() => {
|
||||||
|
button.textContent = defaultLabel;
|
||||||
|
}, 1800);
|
||||||
|
};
|
||||||
|
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
const target = document.querySelector(button.dataset.copy);
|
const target = document.querySelector(button.dataset.copy);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigator.clipboard?.writeText(target.textContent.trim()).then(() => {
|
const textToCopy = target.textContent.trim();
|
||||||
button.textContent = 'Copied!';
|
const clipboard = navigator.clipboard;
|
||||||
setTimeout(() => {
|
|
||||||
button.textContent = 'Copy Install Command';
|
if (clipboard && typeof clipboard.writeText === 'function') {
|
||||||
}, 1800);
|
clipboard.writeText(textToCopy).then(() => {
|
||||||
|
setStatus('Copied!');
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
button.textContent = 'Unable to copy';
|
setStatus('Copy manually');
|
||||||
setTimeout(() => {
|
});
|
||||||
button.textContent = 'Copy Install Command';
|
return;
|
||||||
}, 1800);
|
}
|
||||||
});
|
|
||||||
|
try {
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(target);
|
||||||
|
const selection = window.getSelection();
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
const successful = document.execCommand('copy');
|
||||||
|
selection.removeAllRanges();
|
||||||
|
setStatus(successful ? 'Copied!' : 'Copy manually');
|
||||||
|
} catch (error) {
|
||||||
|
setStatus('Copy manually');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
27
styles.css
27
styles.css
@@ -35,8 +35,20 @@ img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit;
|
color: var(--accent);
|
||||||
text-decoration: none;
|
text-decoration: underline;
|
||||||
|
text-decoration-color: rgba(77, 213, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration-color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus-visible,
|
||||||
|
button:focus-visible {
|
||||||
|
outline: 2px solid rgba(77, 213, 255, 0.8);
|
||||||
|
outline-offset: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero {
|
.hero {
|
||||||
@@ -68,6 +80,7 @@ a {
|
|||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__links a:hover {
|
.nav__links a:hover {
|
||||||
@@ -137,6 +150,16 @@ h3 {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 3px rgba(77, 213, 255, 0.35), 0 12px 30px rgba(109, 132, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__toggle:focus-visible {
|
||||||
|
outline-offset: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.primary {
|
.btn.primary {
|
||||||
|
|||||||
180
terminal.py
180
terminal.py
@@ -15,6 +15,7 @@ import atexit
|
|||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
import json
|
import json
|
||||||
|
import shlex
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error
|
import urllib.error
|
||||||
@@ -215,6 +216,8 @@ class ZDTTTerminal:
|
|||||||
self.status_bar_thread = None
|
self.status_bar_thread = None
|
||||||
self.status_bar_stop_event = threading.Event()
|
self.status_bar_stop_event = threading.Event()
|
||||||
self.scroll_region_set = False
|
self.scroll_region_set = False
|
||||||
|
self.plugin_command_names = set()
|
||||||
|
self.update_check_thread = None
|
||||||
|
|
||||||
# Setup logging for plugins
|
# Setup logging for plugins
|
||||||
self.setup_logging()
|
self.setup_logging()
|
||||||
@@ -250,13 +253,14 @@ class ZDTTTerminal:
|
|||||||
'zps': self.cmd_zps,
|
'zps': self.cmd_zps,
|
||||||
'time': self.cmd_time,
|
'time': self.cmd_time,
|
||||||
'statusbar': self.cmd_statusbar,
|
'statusbar': self.cmd_statusbar,
|
||||||
|
'update': self.cmd_update,
|
||||||
# System commands
|
# System commands
|
||||||
'ls': self.cmd_ls,
|
'ls': self.cmd_ls,
|
||||||
'pwd': self.cmd_pwd,
|
'pwd': self.cmd_pwd,
|
||||||
'cd': self.cmd_cd,
|
'cd': self.cmd_cd,
|
||||||
'cat': self.cmd_cat,
|
'cat': self.cmd_cat,
|
||||||
'nano': self.cmd_nano,
|
'nano': self.cmd_nano,
|
||||||
'fastfetch': self.cmd_fastfetch,
|
'sysfetch': self.cmd_sysfetch,
|
||||||
'mkdir': self.cmd_mkdir,
|
'mkdir': self.cmd_mkdir,
|
||||||
'touch': self.cmd_touch,
|
'touch': self.cmd_touch,
|
||||||
'rm': self.cmd_rm,
|
'rm': self.cmd_rm,
|
||||||
@@ -279,8 +283,8 @@ class ZDTTTerminal:
|
|||||||
# Load plugins
|
# Load plugins
|
||||||
self.load_plugins()
|
self.load_plugins()
|
||||||
|
|
||||||
# Check for updates (non-blocking)
|
# Kick off async update check
|
||||||
self.check_for_updates()
|
self.start_update_check()
|
||||||
|
|
||||||
def setup_logging(self):
|
def setup_logging(self):
|
||||||
"""Setup logging for plugin errors"""
|
"""Setup logging for plugin errors"""
|
||||||
@@ -338,8 +342,19 @@ class ZDTTTerminal:
|
|||||||
with open(self.config_file, 'w') as f:
|
with open(self.config_file, 'w') as f:
|
||||||
json.dump(data, f, indent=2)
|
json.dump(data, f, indent=2)
|
||||||
|
|
||||||
def check_for_updates(self):
|
def start_update_check(self):
|
||||||
"""Check if a new version is available"""
|
"""Start the background thread that checks for updates."""
|
||||||
|
if self.update_check_thread and self.update_check_thread.is_alive():
|
||||||
|
return
|
||||||
|
self.update_check_thread = threading.Thread(
|
||||||
|
target=self._check_for_updates,
|
||||||
|
name="ZDTTUpdateCheck",
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
self.update_check_thread.start()
|
||||||
|
|
||||||
|
def _check_for_updates(self):
|
||||||
|
"""Background worker that checks if a new version is available."""
|
||||||
try:
|
try:
|
||||||
# Get remote version
|
# Get remote version
|
||||||
url = "https://zdtt-sources.zane.org/version.txt"
|
url = "https://zdtt-sources.zane.org/version.txt"
|
||||||
@@ -350,7 +365,7 @@ class ZDTTTerminal:
|
|||||||
if remote_version != self.version:
|
if remote_version != self.version:
|
||||||
print()
|
print()
|
||||||
print(f"🔔 Update available! Current: {self.version} → Latest: {remote_version}")
|
print(f"🔔 Update available! Current: {self.version} → Latest: {remote_version}")
|
||||||
print(" Run 'zdtt update' to update")
|
print(" Run 'zdtt update' from your shell to update")
|
||||||
print()
|
print()
|
||||||
except Exception:
|
except Exception:
|
||||||
# Silently fail if we can't check for updates
|
# Silently fail if we can't check for updates
|
||||||
@@ -596,6 +611,7 @@ ZDTT Terminal v{self.version}
|
|||||||
plugin_commands = plugin_namespace['register_commands']()
|
plugin_commands = plugin_namespace['register_commands']()
|
||||||
if isinstance(plugin_commands, dict):
|
if isinstance(plugin_commands, dict):
|
||||||
self.commands.update(plugin_commands)
|
self.commands.update(plugin_commands)
|
||||||
|
self.plugin_command_names.update(plugin_commands.keys())
|
||||||
loaded_count += 1
|
loaded_count += 1
|
||||||
else:
|
else:
|
||||||
raise ValueError("register_commands() must return a dictionary")
|
raise ValueError("register_commands() must return a dictionary")
|
||||||
@@ -612,6 +628,12 @@ ZDTT Terminal v{self.version}
|
|||||||
if failed_count > 0:
|
if failed_count > 0:
|
||||||
print(f"⚠ {failed_count} plugin(s) failed to load. Check ~/.zdtt/plugin_errors.log")
|
print(f"⚠ {failed_count} plugin(s) failed to load. Check ~/.zdtt/plugin_errors.log")
|
||||||
|
|
||||||
|
def unload_plugin_commands(self):
|
||||||
|
"""Remove commands that originated from plugins."""
|
||||||
|
for cmd_name in list(self.plugin_command_names):
|
||||||
|
self.commands.pop(cmd_name, None)
|
||||||
|
self.plugin_command_names.clear()
|
||||||
|
|
||||||
def load_aliases(self):
|
def load_aliases(self):
|
||||||
"""Load user-defined aliases from file"""
|
"""Load user-defined aliases from file"""
|
||||||
if not os.path.exists(self.aliases_file):
|
if not os.path.exists(self.aliases_file):
|
||||||
@@ -705,6 +727,7 @@ ZDTT Terminal v{self.version}
|
|||||||
print(" zps install <url> - Install plugin from URL")
|
print(" zps install <url> - Install plugin from URL")
|
||||||
print(" time [options] - Display date/time (MM/DD/YY 12h default)")
|
print(" time [options] - Display date/time (MM/DD/YY 12h default)")
|
||||||
print(" statusbar color <name> - Change status bar highlight color")
|
print(" statusbar color <name> - Change status bar highlight color")
|
||||||
|
print(" update - Run the ZDTT updater helper")
|
||||||
print(" exit - Exit ZDTT (return to shell)")
|
print(" exit - Exit ZDTT (return to shell)")
|
||||||
print(" quit - Quit and close terminal window")
|
print(" quit - Quit and close terminal window")
|
||||||
print()
|
print()
|
||||||
@@ -725,7 +748,7 @@ ZDTT Terminal v{self.version}
|
|||||||
print(" date - Display current date/time")
|
print(" date - Display current date/time")
|
||||||
print(" uname [options] - Display system information")
|
print(" uname [options] - Display system information")
|
||||||
print(" nano <file> - Edit file with nano")
|
print(" nano <file> - Edit file with nano")
|
||||||
print(" fastfetch - Display system info (auto-installs)")
|
print(" sysfetch - Display system info (prefers distro tools)")
|
||||||
print()
|
print()
|
||||||
print("Python Commands:")
|
print("Python Commands:")
|
||||||
print(" python [args] - Run Python interpreter")
|
print(" python [args] - Run Python interpreter")
|
||||||
@@ -750,6 +773,7 @@ ZDTT Terminal v{self.version}
|
|||||||
def cmd_exit(self, args):
|
def cmd_exit(self, args):
|
||||||
"""Exit ZDTT Terminal (returns to parent shell)"""
|
"""Exit ZDTT Terminal (returns to parent shell)"""
|
||||||
print("Goodbye!")
|
print("Goodbye!")
|
||||||
|
os.system('clear' if os.name != 'nt' else 'cls')
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
def cmd_quit(self, args):
|
def cmd_quit(self, args):
|
||||||
@@ -823,17 +847,8 @@ ZDTT Terminal v{self.version}
|
|||||||
# Check for reload subcommand
|
# Check for reload subcommand
|
||||||
if args and args[0] == 'reload':
|
if args and args[0] == 'reload':
|
||||||
print("Reloading plugins...")
|
print("Reloading plugins...")
|
||||||
# Remove plugin commands from command dict
|
# Remove plugin commands and reload aliases to avoid conflicts
|
||||||
plugin_commands = []
|
self.unload_plugin_commands()
|
||||||
for cmd_name, cmd_func in list(self.commands.items()):
|
|
||||||
# Check if it's not a built-in command (hacky but works)
|
|
||||||
if hasattr(cmd_func, '__self__') and cmd_func.__self__ != self:
|
|
||||||
plugin_commands.append(cmd_name)
|
|
||||||
|
|
||||||
for cmd in plugin_commands:
|
|
||||||
del self.commands[cmd]
|
|
||||||
|
|
||||||
# Clear aliases to avoid conflicts
|
|
||||||
self.aliases.clear()
|
self.aliases.clear()
|
||||||
self.load_aliases()
|
self.load_aliases()
|
||||||
|
|
||||||
@@ -1213,7 +1228,9 @@ ZDTT Terminal v{self.version}
|
|||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
if os.path.isfile(path):
|
if os.path.islink(path):
|
||||||
|
os.unlink(path)
|
||||||
|
elif os.path.isfile(path):
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
elif os.path.isdir(path):
|
elif os.path.isdir(path):
|
||||||
if recursive:
|
if recursive:
|
||||||
@@ -1331,97 +1348,75 @@ ZDTT Terminal v{self.version}
|
|||||||
|
|
||||||
subprocess.run(['nano'] + args)
|
subprocess.run(['nano'] + args)
|
||||||
|
|
||||||
def cmd_fastfetch(self, args):
|
def cmd_sysfetch(self, args):
|
||||||
"""Display system info with fastfetch (auto-installs if needed)"""
|
"""Display system info using distro-preferred fetch tool."""
|
||||||
def _find_fastfetch_binary():
|
def _find_tool_binary(tool_name):
|
||||||
"""Return absolute path to fastfetch if available."""
|
candidate = shutil.which(tool_name)
|
||||||
fastfetch_path = shutil.which('fastfetch')
|
if candidate:
|
||||||
if fastfetch_path:
|
return candidate
|
||||||
return fastfetch_path
|
for path in (
|
||||||
|
f"/usr/bin/{tool_name}",
|
||||||
# Fallback search in common locations
|
f"/usr/local/bin/{tool_name}",
|
||||||
common_paths = [
|
os.path.expanduser(f"~/.local/bin/{tool_name}"),
|
||||||
'/usr/bin/fastfetch',
|
):
|
||||||
'/usr/local/bin/fastfetch',
|
|
||||||
os.path.expanduser('~/.local/bin/fastfetch'),
|
|
||||||
]
|
|
||||||
for path in common_paths:
|
|
||||||
if os.path.isfile(path) and os.access(path, os.X_OK):
|
if os.path.isfile(path) and os.access(path, os.X_OK):
|
||||||
return path
|
return path
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _build_install_command():
|
def _build_install_command(tool_name):
|
||||||
"""Return (cmd_list, manual_hint) based on distro/privileges."""
|
|
||||||
manual_hint = None
|
manual_hint = None
|
||||||
if self.is_debian:
|
base_cmd = None
|
||||||
base_cmd = ['apt-get', 'install', '-y', 'fastfetch']
|
if tool_name == 'fastfetch' and self.is_arch:
|
||||||
manual_hint = "sudo apt-get install fastfetch"
|
|
||||||
elif self.is_arch:
|
|
||||||
base_cmd = ['pacman', '-S', '--noconfirm', 'fastfetch']
|
base_cmd = ['pacman', '-S', '--noconfirm', 'fastfetch']
|
||||||
manual_hint = "sudo pacman -S fastfetch"
|
manual_hint = "sudo pacman -S fastfetch"
|
||||||
|
elif tool_name == 'neofetch' and self.is_debian:
|
||||||
|
base_cmd = ['apt-get', 'install', '-y', 'neofetch']
|
||||||
|
manual_hint = "sudo apt-get install neofetch"
|
||||||
else:
|
else:
|
||||||
return None, None
|
return None, manual_hint
|
||||||
|
|
||||||
# Determine if sudo is needed
|
|
||||||
geteuid = getattr(os, 'geteuid', None)
|
geteuid = getattr(os, 'geteuid', None)
|
||||||
is_root = geteuid is not None and geteuid() == 0
|
is_root = geteuid is not None and geteuid() == 0
|
||||||
sudo_path = shutil.which('sudo')
|
sudo_path = shutil.which('sudo')
|
||||||
|
|
||||||
if is_root:
|
if is_root:
|
||||||
return base_cmd, manual_hint
|
return base_cmd, manual_hint
|
||||||
|
|
||||||
if sudo_path:
|
if sudo_path:
|
||||||
return [sudo_path] + base_cmd, manual_hint
|
return [sudo_path] + base_cmd, manual_hint
|
||||||
|
|
||||||
# Cannot elevate automatically
|
|
||||||
return None, manual_hint
|
return None, manual_hint
|
||||||
|
|
||||||
# Check if fastfetch is installed
|
tool_name = 'fastfetch' if self.is_arch else 'neofetch' if self.is_debian else None
|
||||||
fastfetch_bin = _find_fastfetch_binary()
|
if not tool_name:
|
||||||
|
print("sysfetch currently supports Debian-based or Arch-based systems only.")
|
||||||
if not fastfetch_bin:
|
|
||||||
if not self.is_supported:
|
|
||||||
print("fastfetch is not installed.")
|
|
||||||
print("Auto-install is only supported on Debian-based and Arch Linux systems.")
|
|
||||||
print("Please install fastfetch manually using your package manager:")
|
|
||||||
print(" • Debian/Ubuntu: sudo apt-get install fastfetch")
|
|
||||||
print(" • Arch/Manjaro: sudo pacman -S fastfetch")
|
|
||||||
print(" • Fedora: sudo dnf install fastfetch")
|
|
||||||
print(" • openSUSE: sudo zypper install fastfetch")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
install_cmd, manual_hint = _build_install_command()
|
tool_bin = _find_tool_binary(tool_name)
|
||||||
if not install_cmd:
|
if not tool_bin:
|
||||||
print("fastfetch is not installed and cannot be auto-installed because elevated privileges")
|
install_cmd, manual_hint = _build_install_command(tool_name)
|
||||||
print("are required but 'sudo' was not found (or you're not running as root).")
|
if install_cmd:
|
||||||
if manual_hint:
|
print(f"{tool_name} is not installed. Installing...")
|
||||||
print(f"Try manually: {manual_hint}")
|
|
||||||
else:
|
|
||||||
print("Please install fastfetch via your package manager.")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("fastfetch is not installed. Installing...")
|
|
||||||
print()
|
print()
|
||||||
try:
|
try:
|
||||||
subprocess.run(install_cmd, check=True)
|
subprocess.run(install_cmd, check=True)
|
||||||
print()
|
print()
|
||||||
print("fastfetch installed successfully!")
|
print(f"{tool_name} installed successfully!")
|
||||||
print()
|
print()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
print("Failed to install fastfetch")
|
print(f"Failed to install {tool_name}")
|
||||||
if manual_hint:
|
if manual_hint:
|
||||||
print(f"Try manually: {manual_hint}")
|
print(f"Try manually: {manual_hint}")
|
||||||
else:
|
else:
|
||||||
print("Please install fastfetch via your package manager.")
|
print("Please install the tool via your package manager.")
|
||||||
|
elif manual_hint:
|
||||||
|
print(manual_hint)
|
||||||
|
tool_bin = _find_tool_binary(tool_name)
|
||||||
|
|
||||||
|
if not tool_bin:
|
||||||
|
print(f"Unable to run {tool_name}. Install it manually and rerun sysfetch.")
|
||||||
return
|
return
|
||||||
|
|
||||||
fastfetch_bin = _find_fastfetch_binary()
|
subprocess.run([tool_bin] + args)
|
||||||
if not fastfetch_bin:
|
print(f"\n(sysfetch used {tool_name})\n")
|
||||||
print("fastfetch installation completed but binary was not found.")
|
|
||||||
print("Ensure fastfetch is in your PATH and try again.")
|
|
||||||
return
|
|
||||||
|
|
||||||
subprocess.run([fastfetch_bin] + args)
|
|
||||||
|
|
||||||
# Python Commands
|
# Python Commands
|
||||||
|
|
||||||
@@ -1449,6 +1444,25 @@ ZDTT Terminal v{self.version}
|
|||||||
print("pip3: command not found")
|
print("pip3: command not found")
|
||||||
print("Try installing with: sudo apt-get install python3-pip")
|
print("Try installing with: sudo apt-get install python3-pip")
|
||||||
|
|
||||||
|
def cmd_update(self, args):
|
||||||
|
"""Trigger the external updater shipping with ZDTT."""
|
||||||
|
zdtt_wrapper = shutil.which('zdtt')
|
||||||
|
installer_script = os.path.join(
|
||||||
|
os.path.expanduser("~/.local/share/zdtt"),
|
||||||
|
'install.sh'
|
||||||
|
)
|
||||||
|
|
||||||
|
if zdtt_wrapper:
|
||||||
|
subprocess.run([zdtt_wrapper, 'update'] + args)
|
||||||
|
return
|
||||||
|
|
||||||
|
if os.path.isfile(installer_script):
|
||||||
|
subprocess.run(['bash', installer_script, 'update'] + args)
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Unable to locate the ZDTT updater.")
|
||||||
|
print("Re-run the installer script or use 'zdtt update' from your shell if available.")
|
||||||
|
|
||||||
def execute_command(self, command_line):
|
def execute_command(self, command_line):
|
||||||
"""Parse and execute a command"""
|
"""Parse and execute a command"""
|
||||||
if not command_line.strip():
|
if not command_line.strip():
|
||||||
@@ -1473,7 +1487,15 @@ ZDTT Terminal v{self.version}
|
|||||||
print("No command specified with -oszdtt flag")
|
print("No command specified with -oszdtt flag")
|
||||||
return
|
return
|
||||||
|
|
||||||
parts = command_line.strip().split()
|
try:
|
||||||
|
parts = shlex.split(command_line)
|
||||||
|
except ValueError as exc:
|
||||||
|
print(f"parse error: {exc}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not parts:
|
||||||
|
return
|
||||||
|
|
||||||
cmd = parts[0].lower()
|
cmd = parts[0].lower()
|
||||||
args = parts[1:] if len(parts) > 1 else []
|
args = parts[1:] if len(parts) > 1 else []
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.1.2.a
|
0.1.2.a.2
|
||||||
Reference in New Issue
Block a user