- das-shell 0.1.0: the Das two-line bash prompt by default (replaces the PS1 of Void's skel .bashrc once), dprompt (Textual prompt builder with presets and live preview) and dbanner (SSH login banner editor: canvas tools, fields with values, widgets, das-banner service for cached ones, Das OS logo and tryzub pictures). Python tests in make test. - das-server 0.3.0 depends on das-shell; the server installer mentions dprompt and dbanner; the desktop image includes it. - run-qemu.sh forwards the guest's SSH to localhost:2222. - Hardware fixes: Ventoy menu icon, boot menu titles "Das OS <version>". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
"""dprompt: builds the bash prompt. Without arguments it opens the editor."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from . import ETC_DIR, config_dir, prompt
|
||||
from .cli import die, need_root, resolve, run_tui, write_file
|
||||
from .i18n import t
|
||||
|
||||
PROG = "dprompt"
|
||||
|
||||
|
||||
def targets(system):
|
||||
"""(prompt.sh, design json) of the user or of the whole system."""
|
||||
base = ETC_DIR if system else config_dir()
|
||||
return os.path.join(base, "prompt.sh"), os.path.join(base, "prompt.json")
|
||||
|
||||
|
||||
def current():
|
||||
"""The design in effect for this user: their own, the system one or the stock one."""
|
||||
for system in (False, True):
|
||||
path = targets(system)[1]
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
return prompt.load_file(path), path
|
||||
except (OSError, ValueError):
|
||||
continue
|
||||
return prompt.load_preset("das"), None
|
||||
|
||||
|
||||
def apply(design, system):
|
||||
sh, js = targets(system)
|
||||
design = prompt.normalize(design)
|
||||
write_file(js, prompt.dumps(design))
|
||||
write_file(sh, prompt.script(design))
|
||||
return sh
|
||||
|
||||
|
||||
def reset(system):
|
||||
for path in targets(system):
|
||||
try:
|
||||
os.remove(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
USAGE = t("""Використання: dprompt [команда]
|
||||
(без команди) редактор запрошення з переглядом
|
||||
list готові запрошення
|
||||
show [НАЗВА|ФАЙЛ] як виглядає запрошення (типово — поточне)
|
||||
--script код для bash замість вигляду
|
||||
apply НАЗВА|ФАЙЛ застосувати для себе (~/.config/das/prompt.sh)
|
||||
--system для всіх користувачів (/etc/das/prompt.sh, через sudo)
|
||||
reset [--system] повернути стандартне запрошення
|
||||
Нове запрошення діє в нових вікнах терміналу або після exec bash.""",
|
||||
"""Usage: dprompt [command]
|
||||
(no command) prompt editor with a live preview
|
||||
list ready-made prompts
|
||||
show [NAME|FILE] what the prompt looks like (default: the current one)
|
||||
--script the bash code instead
|
||||
apply NAME|FILE use it yourself (~/.config/das/prompt.sh)
|
||||
--system for every user (/etc/das/prompt.sh, through sudo)
|
||||
reset [--system] back to the stock prompt
|
||||
A new prompt works in new terminal windows or after exec bash.""")
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
if not argv:
|
||||
from . import prompt_app
|
||||
return run_tui(PROG, prompt_app.PromptApp)
|
||||
cmd, args = argv[0], argv[1:]
|
||||
system = "--system" in args
|
||||
args = [a for a in args if a != "--system"]
|
||||
try:
|
||||
if cmd in ("-h", "--help", "help"):
|
||||
print(USAGE)
|
||||
elif cmd == "list":
|
||||
for name, title in prompt.list_presets():
|
||||
print(f"{name:<12} {title}")
|
||||
elif cmd == "show":
|
||||
script = "--script" in args
|
||||
args = [a for a in args if a != "--script"]
|
||||
design = prompt.load(args[0]) if args else current()[0]
|
||||
if script:
|
||||
sys.stdout.write(prompt.script(design))
|
||||
else:
|
||||
for state in (prompt.sample_state(), prompt.sample_state(rc=1, git="main*", venv=".venv"),
|
||||
prompt.sample_state(root=True)):
|
||||
print(_ansi(design, state))
|
||||
print()
|
||||
elif cmd == "apply":
|
||||
if not args:
|
||||
die(PROG, "вкажіть назву або файл", "name a preset or a file")
|
||||
spec = resolve(args[0])
|
||||
if system:
|
||||
need_root(["apply", spec, "--system"])
|
||||
path = apply(prompt.load(spec), system)
|
||||
print(t(f"Запрошення записано в {path}. Відкрийте новий термінал або виконайте: exec bash",
|
||||
f"The prompt is written to {path}. Open a new terminal or run: exec bash"))
|
||||
elif cmd == "reset":
|
||||
if system:
|
||||
need_root(["reset", "--system"])
|
||||
reset(system)
|
||||
print(t("Повернуто стандартне запрошення (діє в новому терміналі).",
|
||||
"The stock prompt is back (in new terminals)."))
|
||||
else:
|
||||
die(PROG, f"невідома команда: {cmd}\n{USAGE}", f"unknown command: {cmd}\n{USAGE}", 2)
|
||||
except FileNotFoundError as e:
|
||||
die(PROG, f"не знайдено: {e.filename or e}", f"not found: {e.filename or e}")
|
||||
except (ValueError, json.JSONDecodeError) as e:
|
||||
die(PROG, f"помилка у файлі: {e}", f"bad file: {e}")
|
||||
except PermissionError as e:
|
||||
die(PROG, f"немає доступу: {e.filename}", f"permission denied: {e.filename}")
|
||||
return 0
|
||||
|
||||
|
||||
def _ansi(design, state):
|
||||
from . import colors
|
||||
out = []
|
||||
for text, style in prompt.preview(design, state):
|
||||
if style:
|
||||
words = style.split()
|
||||
out.append(colors.sgr(words[-1] if words[-1] != "default" else None, None, "bold" in words))
|
||||
else:
|
||||
out.append(colors.RESET)
|
||||
out.append(text)
|
||||
return "".join(out) + colors.RESET
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user