From d2fef3b7de342618136052db9470657947033bdc Mon Sep 17 00:00:00 2001 From: KeshavAnandCode Date: Sun, 17 May 2026 18:30:32 -0500 Subject: [PATCH] added custom functionality and working with new toml as well, and update cli functions --- pyproject.toml | 3 ++ src/foreignthon/cli.py | 73 +++++++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 094ef9b..5ec18e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,3 +56,6 @@ ignore = ["E501"] [tool.ruff.lint.per-file-ignores] "pack.py" = ["E501"] + +[tool.hatch.build.targets.wheel.force-include] +"src/foreignthon/template.json" = "foreignthon/template.json" diff --git a/src/foreignthon/cli.py b/src/foreignthon/cli.py index 9555de5..682517e 100644 --- a/src/foreignthon/cli.py +++ b/src/foreignthon/cli.py @@ -12,18 +12,16 @@ from .transpiler import run_transpiled, transpile_file CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) - def _load_effective_pack(project: Path, lang: str) -> dict: """ - Load installed pack then merge local custom.json on top if configured. - Walks up from project to find .foreignthon.toml. + Load pack for a file. Priority: + 1. custom_pack in .foreignthon.toml — no installed pack needed + 2. installed pack via entry points """ import json from .pack import load_pack - pack = load_pack(lang) - - # Walk up directories to find .foreignthon.toml + # Walk up to find .foreignthon.toml search = project if project.is_dir() else project.parent toml_path = None for parent in [search, *search.parents]: @@ -32,20 +30,29 @@ def _load_effective_pack(project: Path, lang: str) -> dict: toml_path = candidate break + # Check for custom_pack first — if found, load it directly + # and merge on top of template (no installed pack required) if toml_path: for line in toml_path.read_text(encoding="utf-8").splitlines(): - if line.strip().startswith("custom_pack"): + if line.strip().startswith("custom_pack") and not line.strip().startswith("#"): custom_path = toml_path.parent / line.split("=", 1)[1].strip().strip('"').strip("'") if custom_path.exists(): custom = json.loads(custom_path.read_text(encoding="utf-8")) + # If custom pack has meta with a code, it's a standalone pack + if custom.get("meta", {}).get("code"): + return custom + # Otherwise it's an override — merge on top of installed pack + pack = load_pack(lang) for section in ("keywords", "builtins", "exceptions", "stdlib", "error_messages"): if section in custom: pack[section] = {**pack.get(section, {}), **custom[section]} if "postfix_keywords" in custom: pack["postfix_keywords"] = custom["postfix_keywords"] + return pack break - return pack + # Fall back to installed pack + return load_pack(lang) def _pick(mapping: dict, english: str, fallback: str) -> str: @@ -104,21 +111,41 @@ def new(name: str, lang: str, no_git: bool): click.echo("✗ Current directory is not empty.", err=True) raise SystemExit(1) - try: - pack = _load_effective_pack(project, lang) - except PackNotFoundError: - click.echo(f"✗ Language pack '{lang}' not installed.", err=True) - click.echo(f" Run: pip install foreignthon-{lang}", err=True) - raise SystemExit(1) + is_custom = lang == "custom" + + if is_custom: + lang_code = click.prompt("Language code (e.g. ru, fr, de)") + lang_name_en = click.prompt("Language name in English (e.g. Russian)") + lang_name_native = click.prompt("Language name in its own script (e.g. Русский)") + pack = _make_scaffold_pack(lang_code, lang_name_en, lang_name_native) + lang = lang_code + else: + try: + pack = _load_effective_pack(project, lang) + except PackNotFoundError: + click.echo(f"✗ Language pack '{lang}' not installed.", err=True) + click.echo(f" Run: pip install foreignthon-{lang}", err=True) + raise SystemExit(1) lang_name = pack["meta"]["native_name"] + if is_custom: + import json + (project / "custom.json").write_text( + json.dumps(pack, ensure_ascii=False, indent=2), + encoding="utf-8", + ) + toml_custom_line = 'custom_pack = "custom.json"' + click.echo(" Created custom.json — fill in your translations!") + else: + toml_custom_line = '# custom_pack = "custom.json"' + (project / ".foreignthon.toml").write_text( f'[foreignthon]\n' f'lang = "{lang}"\n' f'\n' f'# Optional: path to a local JSON that overrides pack keywords\n' - f'# custom_pack = "custom.json"\n', + f'{toml_custom_line}\n', encoding="utf-8", ) @@ -301,3 +328,19 @@ def decompile(file: Path, lang: str, postfix: bool, output: str | None): out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text(result, encoding="utf-8") click.echo(f"Decompiled: {out_path}") + + +def _make_scaffold_pack(lang_code: str, lang_name: str, native_name: str) -> dict: + """ + Load template.json — single source of truth for all pack keys. + To add new keywords/builtins, edit template.json only. + """ + import json + from importlib.resources import files + + template_path = files("foreignthon") / "template.json" + pack = json.loads(template_path.read_text(encoding="utf-8")) + pack["meta"]["name"] = lang_name + pack["meta"]["native_name"] = native_name + pack["meta"]["code"] = lang_code + return pack \ No newline at end of file