2b29a5cf48
- core/snippets.py: SnippetManager with 20 prebuilt sysadmin commands, CRUD + reorder, persisted to ~/.sshclient/snippets.json - ui/snippet_dialog.py: SnippetDialog (add/edit) + SnippetManagerDialog (table view with add/edit/delete/move up/down) - ui/terminal_panel.py: snippet combo box in toolbar, send_command() method to inject commands into interactive shell, snippet manager button - README.md: updated feature table, usage section, project structure - test_ui.py: added [2/4] checks for sparkline/snippets/theme, added [4/4] theme toggle verification
87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
"""
|
|
命令片段管理:保存常用命令,快速发送到终端。
|
|
持久化到 ~/.sshclient/snippets.json
|
|
"""
|
|
import json
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
CONFIG_DIR = Path.home() / ".sshclient"
|
|
SNIPPETS_FILE = CONFIG_DIR / "snippets.json"
|
|
|
|
# 预置片段(首次运行时自动添加)
|
|
DEFAULT_SNIPPETS = [
|
|
{"name": "系统信息", "cmd": "uname -a && cat /etc/os-release"},
|
|
{"name": "磁盘使用", "cmd": "df -h"},
|
|
{"name": "内存使用", "cmd": "free -h"},
|
|
{"name": "CPU 信息", "cmd": "lscpu | head -20"},
|
|
{"name": "监听端口", "cmd": "ss -tlnp"},
|
|
{"name": "所有连接", "cmd": "ss -tnp"},
|
|
{"name": "进程 TOP10", "cmd": "ps aux --sort=-%cpu | head -11"},
|
|
{"name": "内存 TOP10", "cmd": "ps aux --sort=-%mem | head -11"},
|
|
{"name": "最近登录", "cmd": "last -10"},
|
|
{"name": "系统日志", "cmd": "journalctl -n 50 --no-pager"},
|
|
{"name": "DNS 解析", "cmd": "dig +short"},
|
|
{"name": "网络路由", "cmd": "ip route show"},
|
|
{"name": "网卡信息", "cmd": "ip addr show"},
|
|
{"name": "防火墙状态", "cmd": "iptables -L -n --line-numbers"},
|
|
{"name": "Docker 容器", "cmd": "docker ps -a"},
|
|
{"name": "Docker 日志", "cmd": "docker logs --tail 50"},
|
|
{"name": "systemctl 状态", "cmd": "systemctl status"},
|
|
{"name": "重启服务", "cmd": "systemctl restart"},
|
|
{"name": "定时任务", "cmd": "crontab -l"},
|
|
{"name": "大文件 TOP10", "cmd": "find / -type f -size +100M 2>/dev/null | head -10"},
|
|
]
|
|
|
|
|
|
class SnippetManager:
|
|
"""命令片段的增删改查 + 持久化"""
|
|
|
|
def __init__(self):
|
|
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
self._snippets: List[dict] = []
|
|
self._load()
|
|
|
|
def _load(self):
|
|
if SNIPPETS_FILE.exists():
|
|
try:
|
|
with open(SNIPPETS_FILE, "r", encoding="utf-8") as f:
|
|
self._snippets = json.load(f)
|
|
except Exception:
|
|
self._snippets = []
|
|
if not self._snippets:
|
|
self._snippets = [dict(s) for s in DEFAULT_SNIPPETS]
|
|
self._save()
|
|
|
|
def _save(self):
|
|
with open(SNIPPETS_FILE, "w", encoding="utf-8") as f:
|
|
json.dump(self._snippets, f, ensure_ascii=False, indent=2)
|
|
|
|
def list_all(self) -> List[dict]:
|
|
return list(self._snippets)
|
|
|
|
def add(self, name: str, cmd: str) -> int:
|
|
"""添加片段,返回新索引"""
|
|
snippet = {"name": name.strip(), "cmd": cmd}
|
|
self._snippets.append(snippet)
|
|
self._save()
|
|
return len(self._snippets) - 1
|
|
|
|
def update(self, index: int, name: str, cmd: str):
|
|
if 0 <= index < len(self._snippets):
|
|
self._snippets[index] = {"name": name.strip(), "cmd": cmd}
|
|
self._save()
|
|
|
|
def remove(self, index: int):
|
|
if 0 <= index < len(self._snippets):
|
|
del self._snippets[index]
|
|
self._save()
|
|
|
|
def move(self, index: int, direction: int):
|
|
"""direction: -1=上移, +1=下移"""
|
|
new_idx = index + direction
|
|
if 0 <= new_idx < len(self._snippets):
|
|
self._snippets[index], self._snippets[new_idx] = \
|
|
self._snippets[new_idx], self._snippets[index]
|
|
self._save()
|