"""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())