From ea04c29d2937c81a19fcb501ccd9efd42f7f4e56 Mon Sep 17 00:00:00 2001 From: Tobia Rigon <42972324+TobiaRigon@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:01:48 +0200 Subject: [PATCH] Aggiunge supporto HTML e PDF --- README.md | 6 +++--- promptpack/cli.py | 6 +++++- promptpack/gui/preview.py | 16 ++++++++++++-- promptpack/gui/settings_dialog.py | 10 ++++++--- promptpack/utils.py | 36 +++++++++++++++++++++++++++++-- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7e572dd..3853610 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - Live preview window to see the generated output before exporting - Default filters for file extensions and folders (e.g., skip `.env`, `node_modules`, `.git`, etc.) - Saves and loads user settings to/from a JSON file -- Choose export format (TXT, Markdown or JSON) and optionally include code blocks and headings +- Choose export format (TXT, Markdown, JSON, HTML or PDF) and optionally include code blocks and headings - Optionally export only the file tree without contents - Switch between dark and light mode, with buttons and fields adopting dark colors when the theme is set to "dark" - Files listed in a `.gitignore` file are automatically deselected @@ -59,7 +59,7 @@ The file `promptpack.py` simply launches the application. 2. **Select Files**: Opens an expandable tree of all folders and files. You can include/exclude each item via checkboxes. - Default selections are based on the current settings. 3. **Settings**: Define default allowed extensions, excluded folders and files. Also choose: - - Export format (txt, md, json) + - Export format (txt, md, json, html, pdf) - Include file headings - Use code blocks for each file (Markdown only) - Export only the file tree @@ -138,7 +138,7 @@ python -m promptpack.cli ./input ./out --no-heading --no-code-block | ----------------- | ------------------------------------------------------------------- | | `source` | Source folder to analyze | | `dest` | Destination folder for the generated output | -| `--format` | Export format: `txt`, `md`, `json` | +| `--format` | Export format: `txt`, `md`, `json`, `html`, `pdf` | | `--tree-only` | Export only the folder structure, without file contents | | `--no-heading` | Do not include headings for each file | | `--no-code-block` | Do not wrap contents in code blocks (Markdown only) | diff --git a/promptpack/cli.py b/promptpack/cli.py index 64db4da..d48a2c1 100644 --- a/promptpack/cli.py +++ b/promptpack/cli.py @@ -29,7 +29,11 @@ def main(): parser = argparse.ArgumentParser(description="PromptPack CLI") parser.add_argument("source", help="cartella sorgente") parser.add_argument("dest", help="cartella di destinazione") - parser.add_argument("--format", choices=["txt", "md", "json"], dest="format") + parser.add_argument( + "--format", + choices=["txt", "md", "json", "html", "pdf"], + dest="format", + ) parser.add_argument("--tree-only", action="store_true") parser.add_argument("--no-heading", action="store_true") parser.add_argument("--no-code-block", action="store_true") diff --git a/promptpack/gui/preview.py b/promptpack/gui/preview.py index 1d757f6..a0d2995 100644 --- a/promptpack/gui/preview.py +++ b/promptpack/gui/preview.py @@ -171,7 +171,10 @@ def generate_preview_lines(app, start_folder, included_files, warn_on_limit=True for path in sorted(included_files): rel_path = path.relative_to(start_folder) if app.tree_only.get(): - line = f"{rel_path.as_posix()}\n" + if app.export_format.get() == "html": + line = f"
{rel_path.as_posix()}
\n" + else: + line = f"{rel_path.as_posix()}\n" tokens = estimate_token_count(line) if token_count + tokens > max_tokens: break @@ -185,10 +188,19 @@ def generate_preview_lines(app, start_folder, included_files, warn_on_limit=True content = sanitize_sensitive_data(content) chunk = [] if app.include_heading.get(): - chunk.append(f"## {rel_path.as_posix()}\n") + if app.export_format.get() == "html": + chunk.append(f"" + content + "\n")
+ else:
+ chunk.append(f"{content}\n")
else:
chunk.append(f"{content}\n")
text = ''.join(chunk)
diff --git a/promptpack/gui/settings_dialog.py b/promptpack/gui/settings_dialog.py
index 2983b02..7093204 100644
--- a/promptpack/gui/settings_dialog.py
+++ b/promptpack/gui/settings_dialog.py
@@ -93,9 +93,13 @@ def prompt_list(title, key):
ttk.Label(scrollable, text=app.t("output_opts"), style="Heading.TLabel").pack(padx=10, pady=(20, 5))
ttk.Label(scrollable, text=app.t("export_format")).pack(pady=(5, 0))
- ttk.Radiobutton(scrollable, text="TXT", variable=app.export_format, value="txt").pack(pady=2)
- ttk.Radiobutton(scrollable, text="Markdown", variable=app.export_format, value="md").pack(pady=2)
- ttk.Radiobutton(scrollable, text="JSON", variable=app.export_format, value="json").pack(pady=2)
+ format_options = ["txt", "md", "json", "html", "pdf"]
+ format_menu = ttk.OptionMenu(scrollable, app.export_format, app.export_format.get(), *format_options)
+ format_menu.pack(pady=5)
+ menu_widget = format_menu["menu"]
+ bg = "#2d2d2d" if app.theme.get() == "dark" else "#ffffff"
+ fg = "#dcdcdc" if app.theme.get() == "dark" else "#000000"
+ menu_widget.configure(bg=bg, fg=fg, activebackground=bg, activeforeground=fg)
ttk.Checkbutton(scrollable, text=app.t("include_headings"), variable=app.include_heading).pack(pady=5)
ttk.Checkbutton(scrollable, text=app.t("use_code"), variable=app.use_code_block).pack(pady=5)
ttk.Checkbutton(scrollable, text=app.t("tree_only"), variable=app.tree_only).pack(pady=5)
diff --git a/promptpack/utils.py b/promptpack/utils.py
index d176e8a..52ae15b 100644
--- a/promptpack/utils.py
+++ b/promptpack/utils.py
@@ -93,6 +93,10 @@ def generate_output(
lines = []
header = ""
token_count = 0
+ elif export_format == "html":
+ lines = [f"{rel_path.as_posix()}
\n" + else: + line = f"{rel_path.as_posix()}\n" block_tokens = estimate_token_count(line) if token_count + block_tokens > max_tokens: output_files.append(_flush()) @@ -156,10 +179,19 @@ def _flush(): else: new_lines = [] if include_heading: - new_lines.append(f"## {rel_path.as_posix()}\n") + if export_format == "html": + new_lines.append(f"" + content + "\n\n")
+ else:
+ new_lines.append(f"{content}\n\n")
else:
new_lines.append(f"{content}\n\n")
block = ''.join(new_lines)