Add files via upload
This commit is contained in:
94
example_plugin.py
Normal file
94
example_plugin.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
"""
|
||||||
|
Example ZDTT Plugin
|
||||||
|
This demonstrates how to create a plugin for ZDTT Terminal.
|
||||||
|
|
||||||
|
To install this plugin:
|
||||||
|
1. Copy this file to ~/.zdtt/plugins/
|
||||||
|
2. Restart ZDTT Terminal
|
||||||
|
|
||||||
|
The plugin will be loaded automatically.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_hello(args):
|
||||||
|
"""Say hello to the user"""
|
||||||
|
if args:
|
||||||
|
name = ' '.join(args)
|
||||||
|
print(f"Hello, {name}! Welcome to ZDTT Terminal!")
|
||||||
|
else:
|
||||||
|
print("Hello! Welcome to ZDTT Terminal!")
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_weather(args):
|
||||||
|
"""Display weather information using wttr.in"""
|
||||||
|
location = args[0] if args else ""
|
||||||
|
try:
|
||||||
|
subprocess.run(['curl', f'wttr.in/{location}'])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching weather: {e}")
|
||||||
|
print("Make sure curl is installed: sudo apt-get install curl")
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_sysinfo(args):
|
||||||
|
"""Display detailed system information"""
|
||||||
|
print("\n=== System Information ===\n")
|
||||||
|
|
||||||
|
# Hostname
|
||||||
|
print(f"Hostname: {os.uname().nodename}")
|
||||||
|
|
||||||
|
# OS Info
|
||||||
|
try:
|
||||||
|
with open('/etc/os-release', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('PRETTY_NAME'):
|
||||||
|
os_name = line.split('=')[1].strip().strip('"')
|
||||||
|
print(f"OS: {os_name}")
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Kernel
|
||||||
|
print(f"Kernel: {os.uname().release}")
|
||||||
|
|
||||||
|
# Architecture
|
||||||
|
print(f"Architecture: {os.uname().machine}")
|
||||||
|
|
||||||
|
# CPU Info
|
||||||
|
try:
|
||||||
|
with open('/proc/cpuinfo', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if 'model name' in line:
|
||||||
|
cpu = line.split(':')[1].strip()
|
||||||
|
print(f"CPU: {cpu}")
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Memory Info
|
||||||
|
try:
|
||||||
|
with open('/proc/meminfo', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if 'MemTotal' in line:
|
||||||
|
mem = int(line.split()[1]) // 1024
|
||||||
|
print(f"Memory: {mem} MB")
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def register_commands():
|
||||||
|
"""
|
||||||
|
This function is required for ZDTT to load the plugin.
|
||||||
|
Return a dictionary of command names to functions.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'hello': cmd_hello,
|
||||||
|
'weather': cmd_weather,
|
||||||
|
'sysinfo': cmd_sysinfo,
|
||||||
|
}
|
||||||
|
|
||||||
220
install.sh
Normal file
220
install.sh
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# ZDTT Terminal Installer
|
||||||
|
# Installs ZDTT Terminal and sets up the zdtt command
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo " ZDTT Terminal Installation Script"
|
||||||
|
echo "========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Installation directories
|
||||||
|
INSTALL_DIR="$HOME/.local/share/zdtt"
|
||||||
|
BIN_DIR="$HOME/.local/bin"
|
||||||
|
|
||||||
|
# Check if ZDTT is already installed
|
||||||
|
if [ -f "$BIN_DIR/zdtt" ] || [ -d "$INSTALL_DIR" ]; then
|
||||||
|
echo -e "${YELLOW}ZDTT Terminal is already installed!${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "What would you like to do?"
|
||||||
|
echo " 1) Reinstall ZDTT Terminal"
|
||||||
|
echo " 2) Uninstall ZDTT Terminal"
|
||||||
|
echo " 3) Cancel"
|
||||||
|
echo ""
|
||||||
|
read -p "Enter your choice (1-3): " -n 1 -r
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
case $REPLY in
|
||||||
|
1)
|
||||||
|
echo "Reinstalling ZDTT Terminal..."
|
||||||
|
echo ""
|
||||||
|
# Don't remove the directory if we're running from it
|
||||||
|
# Just overwrite the files instead
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo "Uninstalling ZDTT Terminal..."
|
||||||
|
rm -rf "$INSTALL_DIR"
|
||||||
|
rm -f "$BIN_DIR/zdtt"
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}✓${NC} ZDTT Terminal has been uninstalled successfully."
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
echo "Installation cancelled."
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Invalid choice.${NC} Installation cancelled."
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if running on Debian-based Linux
|
||||||
|
if [ ! -f /etc/debian_version ]; then
|
||||||
|
echo -e "${RED}Error: ZDTT Terminal only works on Debian-based Linux systems.${NC}"
|
||||||
|
echo "This does not appear to be a Debian-based distribution."
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓${NC} Debian-based Linux detected"
|
||||||
|
|
||||||
|
# Check if Python 3 is installed
|
||||||
|
if ! command -v python3 &> /dev/null; then
|
||||||
|
echo -e "${RED}✗${NC} Python 3 is not installed"
|
||||||
|
echo ""
|
||||||
|
echo "Installing Python 3..."
|
||||||
|
|
||||||
|
# Update package list and install Python 3
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y python3
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e "${RED}Failed to install Python 3${NC}"
|
||||||
|
echo "Please install Python 3 manually: sudo apt-get install python3"
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓${NC} Python 3 installed successfully"
|
||||||
|
else
|
||||||
|
PYTHON_VERSION=$(python3 --version 2>&1)
|
||||||
|
echo -e "${GREEN}✓${NC} Python 3 is already installed: ${PYTHON_VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create directories if they don't exist
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
mkdir -p "$BIN_DIR"
|
||||||
|
|
||||||
|
echo "Installing ZDTT Terminal..."
|
||||||
|
|
||||||
|
# Copy the terminal.py and install.sh to the installation directory
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cp "$SCRIPT_DIR/terminal.py" "$INSTALL_DIR/terminal.py"
|
||||||
|
cp "$SCRIPT_DIR/install.sh" "$INSTALL_DIR/install.sh"
|
||||||
|
chmod +x "$INSTALL_DIR/terminal.py"
|
||||||
|
chmod +x "$INSTALL_DIR/install.sh"
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓${NC} ZDTT Terminal files copied to $INSTALL_DIR"
|
||||||
|
|
||||||
|
# Create the zdtt wrapper script
|
||||||
|
cat > "$BIN_DIR/zdtt" << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# ZDTT Terminal Wrapper
|
||||||
|
#
|
||||||
|
|
||||||
|
ZDTT_DIR="$HOME/.local/share/zdtt"
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
# Clear screen before starting ZDTT
|
||||||
|
clear
|
||||||
|
python3 "$ZDTT_DIR/terminal.py"
|
||||||
|
;;
|
||||||
|
installer|install|reinstall)
|
||||||
|
# Run the installer for reinstalling/updating
|
||||||
|
if [ -f "$ZDTT_DIR/install.sh" ]; then
|
||||||
|
bash "$ZDTT_DIR/install.sh"
|
||||||
|
else
|
||||||
|
echo "Error: Installer not found at $ZDTT_DIR/install.sh"
|
||||||
|
echo "Please download the installer from the ZDTT repository."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
uninstall)
|
||||||
|
echo "Uninstalling ZDTT Terminal..."
|
||||||
|
rm -rf "$ZDTT_DIR"
|
||||||
|
rm -f "$HOME/.local/bin/zdtt"
|
||||||
|
echo "ZDTT Terminal has been uninstalled."
|
||||||
|
;;
|
||||||
|
version)
|
||||||
|
echo "ZDTT Terminal v0.0.1.alpha"
|
||||||
|
echo ""
|
||||||
|
echo "Features:"
|
||||||
|
echo " • Command history (↑/↓ navigation)"
|
||||||
|
echo " • Tab completion"
|
||||||
|
echo " • Colorized prompt"
|
||||||
|
echo " • Plugin system"
|
||||||
|
echo " • Native command support"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "ZDTT Terminal"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " zdtt start - Start the ZDTT Terminal"
|
||||||
|
echo " zdtt installer - Run installer (for updates/reinstall)"
|
||||||
|
echo " zdtt version - Display version information"
|
||||||
|
echo " zdtt uninstall - Uninstall ZDTT Terminal"
|
||||||
|
echo ""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x "$BIN_DIR/zdtt"
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓${NC} ZDTT command installed to $BIN_DIR"
|
||||||
|
|
||||||
|
# Check if ~/.local/bin is in PATH
|
||||||
|
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}Warning: $HOME/.local/bin is not in your PATH${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "To use the 'zdtt' command, add the following line to your ~/.bashrc:"
|
||||||
|
echo ""
|
||||||
|
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||||
|
echo ""
|
||||||
|
echo "Then run: source ~/.bashrc"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Ask if user wants to add it automatically
|
||||||
|
read -p "Would you like to add it to your ~/.bashrc now? (y/n) " -n 1 -r
|
||||||
|
echo ""
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "" >> "$HOME/.bashrc"
|
||||||
|
echo "# Added by ZDTT Terminal installer" >> "$HOME/.bashrc"
|
||||||
|
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "$HOME/.bashrc"
|
||||||
|
echo -e "${GREEN}✓${NC} Added to ~/.bashrc"
|
||||||
|
echo "Please run: source ~/.bashrc"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓${NC} ~/.local/bin is already in your PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "========================================="
|
||||||
|
echo -e "${GREEN}Installation complete!${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
echo ""
|
||||||
|
echo "To start ZDTT Terminal, run:"
|
||||||
|
echo " zdtt start"
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
|
||||||
598
terminal.py
Normal file
598
terminal.py
Normal file
@@ -0,0 +1,598 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
ZDTT Terminal - A custom terminal interface
|
||||||
|
Only works on Debian-based Linux systems
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import getpass
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import readline
|
||||||
|
import glob
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
|
||||||
|
def check_debian_based():
|
||||||
|
"""Check if the system is Debian-based Linux"""
|
||||||
|
# Check if running on Linux
|
||||||
|
if sys.platform != 'linux':
|
||||||
|
print("Error: ZDTT Terminal only works on Debian-based Linux systems.")
|
||||||
|
print(f"Detected platform: {sys.platform}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Check for Debian-specific file
|
||||||
|
if not os.path.exists('/etc/debian_version'):
|
||||||
|
print("Error: ZDTT Terminal only works on Debian-based Linux systems.")
|
||||||
|
print("This does not appear to be a Debian-based distribution.")
|
||||||
|
print("(Debian, Ubuntu, Linux Mint, Pop!_OS, etc.)")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Optionally, display the Debian version
|
||||||
|
try:
|
||||||
|
with open('/etc/debian_version', 'r') as f:
|
||||||
|
debian_version = f.read().strip()
|
||||||
|
# Silently note the version (for debugging if needed)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ZDTTTerminal:
|
||||||
|
def __init__(self):
|
||||||
|
self.username = getpass.getuser()
|
||||||
|
self.running = True
|
||||||
|
self.current_dir = os.getcwd()
|
||||||
|
self.history_file = os.path.expanduser("~/.zdtt_history")
|
||||||
|
self.plugin_dir = os.path.expanduser("~/.zdtt/plugins")
|
||||||
|
|
||||||
|
# ANSI color codes
|
||||||
|
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.commands = {
|
||||||
|
'help': self.cmd_help,
|
||||||
|
'clear': self.cmd_clear,
|
||||||
|
'exit': self.cmd_exit,
|
||||||
|
'quit': self.cmd_quit,
|
||||||
|
'about': self.cmd_about,
|
||||||
|
'echo': self.cmd_echo,
|
||||||
|
'history': self.cmd_history,
|
||||||
|
'plugins': self.cmd_plugins,
|
||||||
|
# System commands
|
||||||
|
'ls': self.cmd_ls,
|
||||||
|
'pwd': self.cmd_pwd,
|
||||||
|
'cd': self.cmd_cd,
|
||||||
|
'cat': self.cmd_cat,
|
||||||
|
'nano': self.cmd_nano,
|
||||||
|
'neofetch': self.cmd_neofetch,
|
||||||
|
'mkdir': self.cmd_mkdir,
|
||||||
|
'touch': self.cmd_touch,
|
||||||
|
'rm': self.cmd_rm,
|
||||||
|
'mv': self.cmd_mv,
|
||||||
|
'cp': self.cmd_cp,
|
||||||
|
'whoami': self.cmd_whoami,
|
||||||
|
'date': self.cmd_date,
|
||||||
|
'uname': self.cmd_uname,
|
||||||
|
'grep': self.cmd_grep,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup readline history and tab completion
|
||||||
|
self.setup_readline()
|
||||||
|
|
||||||
|
# Load plugins
|
||||||
|
self.load_plugins()
|
||||||
|
|
||||||
|
def display_banner(self):
|
||||||
|
"""Display the ZDTT ASCII art banner"""
|
||||||
|
banner = """
|
||||||
|
░█████████ ░███████ ░██████████░██████████
|
||||||
|
░██ ░██ ░██ ░██ ░██
|
||||||
|
░██ ░██ ░██ ░██ ░██
|
||||||
|
░███ ░██ ░██ ░██ ░██
|
||||||
|
░██ ░██ ░██ ░██ ░██
|
||||||
|
░██ ░██ ░██ ░██ ░██
|
||||||
|
░█████████ ░███████ ░██ ░██
|
||||||
|
|
||||||
|
|
||||||
|
ZDTT Terminal v0.0.1.alpha
|
||||||
|
"""
|
||||||
|
print(banner)
|
||||||
|
|
||||||
|
def setup_readline(self):
|
||||||
|
"""Setup readline for history and tab completion"""
|
||||||
|
# Setup history
|
||||||
|
try:
|
||||||
|
readline.read_history_file(self.history_file)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Set history length
|
||||||
|
readline.set_history_length(1000)
|
||||||
|
|
||||||
|
# Save history on exit
|
||||||
|
atexit.register(readline.write_history_file, self.history_file)
|
||||||
|
|
||||||
|
# Setup tab completion
|
||||||
|
readline.set_completer(self.complete)
|
||||||
|
readline.parse_and_bind("tab: complete")
|
||||||
|
|
||||||
|
# Enable arrow key navigation in history
|
||||||
|
readline.parse_and_bind("set editing-mode emacs")
|
||||||
|
|
||||||
|
def complete(self, text, state):
|
||||||
|
"""Tab completion function"""
|
||||||
|
# Get all possible completions
|
||||||
|
options = []
|
||||||
|
|
||||||
|
# Get the full line buffer
|
||||||
|
line = readline.get_line_buffer()
|
||||||
|
|
||||||
|
# If we're at the start or completing a command
|
||||||
|
if line.startswith(text) or ' ' not in line[:readline.get_begidx()]:
|
||||||
|
# Complete command names
|
||||||
|
options = [cmd for cmd in self.commands.keys() if cmd.startswith(text)]
|
||||||
|
else:
|
||||||
|
# Complete filenames/directories
|
||||||
|
if text.startswith('~'):
|
||||||
|
text = os.path.expanduser(text)
|
||||||
|
|
||||||
|
# Add glob pattern
|
||||||
|
if not text:
|
||||||
|
pattern = '*'
|
||||||
|
else:
|
||||||
|
pattern = text + '*'
|
||||||
|
|
||||||
|
try:
|
||||||
|
matches = glob.glob(pattern)
|
||||||
|
options = matches
|
||||||
|
except:
|
||||||
|
options = []
|
||||||
|
|
||||||
|
# Return the state-th option
|
||||||
|
if state < len(options):
|
||||||
|
return options[state]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load_plugins(self):
|
||||||
|
"""Load plugin commands from the plugins directory"""
|
||||||
|
if not os.path.exists(self.plugin_dir):
|
||||||
|
os.makedirs(self.plugin_dir, exist_ok=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Look for Python files in the plugins directory
|
||||||
|
plugin_files = glob.glob(os.path.join(self.plugin_dir, "*.py"))
|
||||||
|
|
||||||
|
for plugin_file in plugin_files:
|
||||||
|
try:
|
||||||
|
# Get plugin name
|
||||||
|
plugin_name = os.path.basename(plugin_file)[:-3]
|
||||||
|
|
||||||
|
# Read and execute plugin file
|
||||||
|
with open(plugin_file, 'r') as f:
|
||||||
|
plugin_code = f.read()
|
||||||
|
|
||||||
|
# Create a namespace for the plugin
|
||||||
|
plugin_namespace = {}
|
||||||
|
exec(plugin_code, plugin_namespace)
|
||||||
|
|
||||||
|
# Look for register_command function
|
||||||
|
if 'register_commands' in plugin_namespace:
|
||||||
|
plugin_commands = plugin_namespace['register_commands']()
|
||||||
|
if isinstance(plugin_commands, dict):
|
||||||
|
self.commands.update(plugin_commands)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: Failed to load plugin {plugin_name}: {e}")
|
||||||
|
|
||||||
|
def get_prompt(self):
|
||||||
|
"""Return the custom prompt string with colors"""
|
||||||
|
# Show current directory in prompt
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# Show ~ for home directory
|
||||||
|
home = os.path.expanduser("~")
|
||||||
|
if cwd.startswith(home):
|
||||||
|
display_path = "~" + cwd[len(home):]
|
||||||
|
else:
|
||||||
|
display_path = cwd
|
||||||
|
|
||||||
|
# Create colorized prompt
|
||||||
|
# [username in green @ ZDTT path in blue]=>
|
||||||
|
prompt = (f"[{self.COLOR_GREEN}{self.username}{self.COLOR_RESET}"
|
||||||
|
f"@{self.COLOR_CYAN}ZDTT{self.COLOR_RESET} "
|
||||||
|
f"{self.COLOR_BLUE}{display_path}{self.COLOR_RESET}]=> ")
|
||||||
|
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 <message> - Echo a message")
|
||||||
|
print(" about - About ZDTT Terminal")
|
||||||
|
print(" history - Show command history")
|
||||||
|
print(" plugins - List loaded plugins")
|
||||||
|
print(" exit - Exit ZDTT (return to shell)")
|
||||||
|
print(" quit - Quit and close terminal window")
|
||||||
|
print()
|
||||||
|
print("File System Commands:")
|
||||||
|
print(" ls [options] - List directory contents")
|
||||||
|
print(" pwd - Print working directory")
|
||||||
|
print(" cd <directory> - Change directory")
|
||||||
|
print(" cat <file> - Display file contents")
|
||||||
|
print(" mkdir <directory> - Create directory")
|
||||||
|
print(" touch <file> - Create empty file")
|
||||||
|
print(" rm [-r] <file> - Remove file or directory")
|
||||||
|
print(" mv <src> <dest> - Move/rename file")
|
||||||
|
print(" cp [-r] <src> <dest> - Copy file")
|
||||||
|
print(" grep <pattern> <file> - Search for pattern in file")
|
||||||
|
print()
|
||||||
|
print("System Commands:")
|
||||||
|
print(" whoami - Display current user")
|
||||||
|
print(" date - Display current date/time")
|
||||||
|
print(" uname [options] - Display system information")
|
||||||
|
print(" nano <file> - Edit file with nano")
|
||||||
|
print(" neofetch - Display system info (auto-installs)")
|
||||||
|
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()
|
||||||
|
|
||||||
|
def cmd_clear(self, args):
|
||||||
|
"""Clear the terminal screen"""
|
||||||
|
os.system('clear' if os.name != 'nt' else 'cls')
|
||||||
|
self.display_banner()
|
||||||
|
|
||||||
|
def cmd_exit(self, args):
|
||||||
|
"""Exit ZDTT Terminal (returns to parent shell)"""
|
||||||
|
print("Goodbye!")
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def cmd_quit(self, args):
|
||||||
|
"""Quit and close the terminal window completely"""
|
||||||
|
print("Closing terminal window...")
|
||||||
|
# Exit the Python process with code 0
|
||||||
|
# This will return control to the parent shell, which will then exit
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def cmd_about(self, args):
|
||||||
|
"""Display information about ZDTT Terminal"""
|
||||||
|
print("\nZDTT Terminal v0.0.1.alpha")
|
||||||
|
print("A custom terminal interface for Debian-based Linux")
|
||||||
|
print()
|
||||||
|
print("Features:")
|
||||||
|
print(" • Command history with ↑/↓ navigation")
|
||||||
|
print(" • Tab completion for commands and files")
|
||||||
|
print(" • Colorized prompt")
|
||||||
|
print(" • Plugin system for extensibility")
|
||||||
|
print(" • Native command support")
|
||||||
|
print(" • System command execution via -oszdtt flag")
|
||||||
|
print(" • Clean, premium interface")
|
||||||
|
print()
|
||||||
|
|
||||||
|
def cmd_history(self, args):
|
||||||
|
"""Display command history"""
|
||||||
|
history_length = readline.get_current_history_length()
|
||||||
|
|
||||||
|
if history_length == 0:
|
||||||
|
print("No history available")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Show last 50 commands by default
|
||||||
|
limit = 50
|
||||||
|
if args and args[0].isdigit():
|
||||||
|
limit = int(args[0])
|
||||||
|
|
||||||
|
start = max(1, history_length - limit + 1)
|
||||||
|
|
||||||
|
print()
|
||||||
|
for i in range(start, history_length + 1):
|
||||||
|
cmd = readline.get_history_item(i)
|
||||||
|
if cmd:
|
||||||
|
print(f"{i:4d} {cmd}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
def cmd_plugins(self, args):
|
||||||
|
"""List loaded plugins"""
|
||||||
|
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()
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\nLoaded Plugins ({len(plugin_files)}):")
|
||||||
|
for plugin_file in plugin_files:
|
||||||
|
plugin_name = os.path.basename(plugin_file)[:-3]
|
||||||
|
print(f" • {plugin_name}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
def cmd_echo(self, args):
|
||||||
|
"""Echo the provided arguments"""
|
||||||
|
if args:
|
||||||
|
print(' '.join(args))
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
|
||||||
|
# File System Commands
|
||||||
|
|
||||||
|
def cmd_ls(self, args):
|
||||||
|
"""List directory contents"""
|
||||||
|
cmd = ['ls', '--color=auto'] + args
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
def cmd_pwd(self, args):
|
||||||
|
"""Print working directory"""
|
||||||
|
print(os.getcwd())
|
||||||
|
|
||||||
|
def cmd_cd(self, args):
|
||||||
|
"""Change directory"""
|
||||||
|
if not args:
|
||||||
|
# Go to home directory
|
||||||
|
target = os.path.expanduser("~")
|
||||||
|
else:
|
||||||
|
target = args[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Expand ~ and handle relative paths
|
||||||
|
target = os.path.expanduser(target)
|
||||||
|
os.chdir(target)
|
||||||
|
self.current_dir = os.getcwd()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"cd: {target}: No such file or directory")
|
||||||
|
except NotADirectoryError:
|
||||||
|
print(f"cd: {target}: Not a directory")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"cd: {target}: Permission denied")
|
||||||
|
|
||||||
|
def cmd_cat(self, args):
|
||||||
|
"""Display file contents"""
|
||||||
|
if not args:
|
||||||
|
print("cat: missing file operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
for filename in args:
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
print(f.read(), end='')
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"cat: {filename}: No such file or directory")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"cat: {filename}: Permission denied")
|
||||||
|
except IsADirectoryError:
|
||||||
|
print(f"cat: {filename}: Is a directory")
|
||||||
|
|
||||||
|
def cmd_mkdir(self, args):
|
||||||
|
"""Create directory"""
|
||||||
|
if not args:
|
||||||
|
print("mkdir: missing operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
for directory in args:
|
||||||
|
try:
|
||||||
|
os.makedirs(directory, exist_ok=False)
|
||||||
|
except FileExistsError:
|
||||||
|
print(f"mkdir: cannot create directory '{directory}': File exists")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"mkdir: cannot create directory '{directory}': Permission denied")
|
||||||
|
|
||||||
|
def cmd_touch(self, args):
|
||||||
|
"""Create empty file"""
|
||||||
|
if not args:
|
||||||
|
print("touch: missing file operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
for filename in args:
|
||||||
|
try:
|
||||||
|
open(filename, 'a').close()
|
||||||
|
except PermissionError:
|
||||||
|
print(f"touch: cannot touch '{filename}': Permission denied")
|
||||||
|
|
||||||
|
def cmd_rm(self, args):
|
||||||
|
"""Remove file or directory"""
|
||||||
|
if not args:
|
||||||
|
print("rm: missing operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Separate flags from paths
|
||||||
|
flags = [arg for arg in args if arg.startswith('-')]
|
||||||
|
paths = [arg for arg in args if not arg.startswith('-')]
|
||||||
|
|
||||||
|
if not paths:
|
||||||
|
print("rm: missing operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for recursive flag
|
||||||
|
recursive = '-r' in flags or '-rf' in flags or '-fr' in flags
|
||||||
|
force = '-f' in flags or '-rf' in flags or '-fr' in flags
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
try:
|
||||||
|
if os.path.isfile(path):
|
||||||
|
os.remove(path)
|
||||||
|
elif os.path.isdir(path):
|
||||||
|
if recursive:
|
||||||
|
shutil.rmtree(path)
|
||||||
|
else:
|
||||||
|
print(f"rm: cannot remove '{path}': Is a directory")
|
||||||
|
print("rm: use 'rm -r' to remove directories")
|
||||||
|
else:
|
||||||
|
if not force:
|
||||||
|
print(f"rm: cannot remove '{path}': No such file or directory")
|
||||||
|
except PermissionError:
|
||||||
|
if not force:
|
||||||
|
print(f"rm: cannot remove '{path}': Permission denied")
|
||||||
|
except Exception as e:
|
||||||
|
if not force:
|
||||||
|
print(f"rm: error removing '{path}': {e}")
|
||||||
|
|
||||||
|
def cmd_mv(self, args):
|
||||||
|
"""Move/rename file"""
|
||||||
|
if len(args) < 2:
|
||||||
|
print("mv: missing file operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
src = args[0]
|
||||||
|
dest = args[1]
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.move(src, dest)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"mv: cannot stat '{src}': No such file or directory")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"mv: cannot move '{src}': Permission denied")
|
||||||
|
|
||||||
|
def cmd_cp(self, args):
|
||||||
|
"""Copy file"""
|
||||||
|
if len(args) < 2:
|
||||||
|
print("cp: missing file operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Separate flags from paths
|
||||||
|
flags = [arg for arg in args if arg.startswith('-')]
|
||||||
|
paths = [arg for arg in args if not arg.startswith('-')]
|
||||||
|
|
||||||
|
if len(paths) < 2:
|
||||||
|
print("cp: missing destination file operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
src = paths[0]
|
||||||
|
dest = paths[1]
|
||||||
|
|
||||||
|
# Check for recursive flag
|
||||||
|
recursive = '-r' in flags or '-R' in flags
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.isfile(src):
|
||||||
|
shutil.copy2(src, dest)
|
||||||
|
elif os.path.isdir(src):
|
||||||
|
if recursive:
|
||||||
|
shutil.copytree(src, dest)
|
||||||
|
else:
|
||||||
|
print(f"cp: -r not specified; omitting directory '{src}'")
|
||||||
|
else:
|
||||||
|
print(f"cp: cannot stat '{src}': No such file or directory")
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"cp: cannot stat '{src}': No such file or directory")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"cp: cannot create '{dest}': Permission denied")
|
||||||
|
except FileExistsError:
|
||||||
|
print(f"cp: cannot create directory '{dest}': File exists")
|
||||||
|
|
||||||
|
def cmd_grep(self, args):
|
||||||
|
"""Search for pattern in file"""
|
||||||
|
if len(args) < 2:
|
||||||
|
print("grep: missing pattern or file")
|
||||||
|
return
|
||||||
|
|
||||||
|
cmd = ['grep', '--color=auto'] + args
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
# System Commands
|
||||||
|
|
||||||
|
def cmd_whoami(self, args):
|
||||||
|
"""Display current user"""
|
||||||
|
print(self.username)
|
||||||
|
|
||||||
|
def cmd_date(self, args):
|
||||||
|
"""Display current date/time"""
|
||||||
|
subprocess.run(['date'] + args)
|
||||||
|
|
||||||
|
def cmd_uname(self, args):
|
||||||
|
"""Display system information"""
|
||||||
|
subprocess.run(['uname'] + args)
|
||||||
|
|
||||||
|
def cmd_nano(self, args):
|
||||||
|
"""Edit file with nano"""
|
||||||
|
if not args:
|
||||||
|
print("nano: missing file operand")
|
||||||
|
return
|
||||||
|
|
||||||
|
subprocess.run(['nano'] + args)
|
||||||
|
|
||||||
|
def cmd_neofetch(self, args):
|
||||||
|
"""Display system info with neofetch (auto-installs if needed)"""
|
||||||
|
# Check if neofetch is installed
|
||||||
|
if not shutil.which('neofetch'):
|
||||||
|
print("neofetch is not installed. Installing...")
|
||||||
|
print()
|
||||||
|
try:
|
||||||
|
subprocess.run(['sudo', 'apt-get', 'install', '-y', 'neofetch'], check=True)
|
||||||
|
print()
|
||||||
|
print("neofetch installed successfully!")
|
||||||
|
print()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("Failed to install neofetch")
|
||||||
|
return
|
||||||
|
|
||||||
|
subprocess.run(['neofetch'] + args)
|
||||||
|
|
||||||
|
def execute_command(self, command_line):
|
||||||
|
"""Parse and execute a command"""
|
||||||
|
if not command_line.strip():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for -oszdtt flag (Outside ZDTT)
|
||||||
|
if '-oszdtt' in command_line:
|
||||||
|
# Remove the -oszdtt flag and execute as system command
|
||||||
|
system_command = command_line.replace('-oszdtt', '').strip()
|
||||||
|
if system_command:
|
||||||
|
try:
|
||||||
|
result = os.system(system_command)
|
||||||
|
# os.system returns the exit code
|
||||||
|
if result != 0:
|
||||||
|
pass # Command already displayed its error
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error executing command: {e}")
|
||||||
|
else:
|
||||||
|
print("No command specified with -oszdtt flag")
|
||||||
|
return
|
||||||
|
|
||||||
|
parts = command_line.strip().split()
|
||||||
|
cmd = parts[0].lower()
|
||||||
|
args = parts[1:] if len(parts) > 1 else []
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Main terminal loop"""
|
||||||
|
# Clear screen and display banner
|
||||||
|
os.system('clear' if os.name != 'nt' else 'cls')
|
||||||
|
self.display_banner()
|
||||||
|
|
||||||
|
# Main command loop
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
command = input(self.get_prompt())
|
||||||
|
self.execute_command(command)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nUse 'exit' to return to shell, or 'quit' to close the window.")
|
||||||
|
except EOFError:
|
||||||
|
print("\nGoodbye!")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Check if running on Debian-based Linux
|
||||||
|
check_debian_based()
|
||||||
|
|
||||||
|
terminal = ZDTTTerminal()
|
||||||
|
terminal.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
Reference in New Issue
Block a user