codeannex 0.4.3__tar.gz → 0.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codeannex-0.4.3 → codeannex-0.4.4}/PKG-INFO +6 -2
- {codeannex-0.4.3 → codeannex-0.4.4}/README.md +5 -1
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/__main__.py +7 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/interface/cli.py +30 -9
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/renderer/fonts.py +7 -1
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/renderer/text_utils.py +29 -14
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex.egg-info/PKG-INFO +6 -2
- {codeannex-0.4.3 → codeannex-0.4.4}/pyproject.toml +1 -1
- {codeannex-0.4.3 → codeannex-0.4.4}/LICENSE +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/__init__.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/core/__init__.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/core/config.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/core/pdf_builder.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/interface/__init__.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/io/__init__.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/io/file_utils.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/io/git_utils.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/renderer/__init__.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex/renderer/highlight.py +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex.egg-info/SOURCES.txt +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex.egg-info/dependency_links.txt +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex.egg-info/entry_points.txt +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex.egg-info/requires.txt +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/codeannex.egg-info/top_level.txt +0 -0
- {codeannex-0.4.3 → codeannex-0.4.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeannex
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Generates a professional PDF source code annex with Smart Index, Images and Emoji support.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/tanhleno/codeannex
|
|
@@ -36,6 +36,8 @@ Generates a professional PDF annex from a project's source code — featuring sy
|
|
|
36
36
|
## 🚀 Key Features
|
|
37
37
|
|
|
38
38
|
- **Interactive Wizard 2.0** — Step-by-step configuration with smart sections (Project, Style, Typography, Layout, Filters) and explicit default prompts.
|
|
39
|
+
- **Smart Emoji Support** — Automatic discovery of standard emoji fonts (**Segoe UI Emoji** on Windows, **DejaVu Sans** on Linux).
|
|
40
|
+
- **Graceful Emoji Fallback** — If no emoji font is found, it uses official Unicode names (e.g., `[ROCKET]`) for perfect readability.
|
|
39
41
|
- **Git Version Tracking** — Automatically detects **Repository URL**, **Branch**, and **Commit SHA**. Smart root detection avoids Git metadata on subdirectories.
|
|
40
42
|
- **Smart SVG Rendering** — Files are rendered as both a high-quality image and XML code. Entries are intelligently deduplicated in the summary.
|
|
41
43
|
- **Improved Document Structure** — Subdirectories and their contents are listed before root files for better organization.
|
|
@@ -58,7 +60,7 @@ For full SVG support (required for crisp line numbers and SVG image rendering):
|
|
|
58
60
|
pipx install "codeannex[svg]"
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
*
|
|
63
|
+
*Note: For best emoji rendering on Linux, you may want to install `fonts-noto-color-emoji` or `ttf-dejavu`.*
|
|
62
64
|
|
|
63
65
|
## 📖 Usage
|
|
64
66
|
|
|
@@ -102,6 +104,8 @@ Default output filename is `{project_name}_code_annex.pdf`.
|
|
|
102
104
|
### Fonts
|
|
103
105
|
- `--font-path PATH` — Additional directory to search for `.ttf`/`.otf` files.
|
|
104
106
|
- `--title-font` / `--normal-font` / `--mono-font` — System font names.
|
|
107
|
+
- `--emoji-font NAME` — Custom font for emojis.
|
|
108
|
+
- `--emoji-description` — Force textual descriptions (e.g., `[GRINNING FACE]`) instead of glyphs.
|
|
105
109
|
|
|
106
110
|
## 🧪 Testing
|
|
107
111
|
|
|
@@ -5,6 +5,8 @@ Generates a professional PDF annex from a project's source code — featuring sy
|
|
|
5
5
|
## 🚀 Key Features
|
|
6
6
|
|
|
7
7
|
- **Interactive Wizard 2.0** — Step-by-step configuration with smart sections (Project, Style, Typography, Layout, Filters) and explicit default prompts.
|
|
8
|
+
- **Smart Emoji Support** — Automatic discovery of standard emoji fonts (**Segoe UI Emoji** on Windows, **DejaVu Sans** on Linux).
|
|
9
|
+
- **Graceful Emoji Fallback** — If no emoji font is found, it uses official Unicode names (e.g., `[ROCKET]`) for perfect readability.
|
|
8
10
|
- **Git Version Tracking** — Automatically detects **Repository URL**, **Branch**, and **Commit SHA**. Smart root detection avoids Git metadata on subdirectories.
|
|
9
11
|
- **Smart SVG Rendering** — Files are rendered as both a high-quality image and XML code. Entries are intelligently deduplicated in the summary.
|
|
10
12
|
- **Improved Document Structure** — Subdirectories and their contents are listed before root files for better organization.
|
|
@@ -27,7 +29,7 @@ For full SVG support (required for crisp line numbers and SVG image rendering):
|
|
|
27
29
|
pipx install "codeannex[svg]"
|
|
28
30
|
```
|
|
29
31
|
|
|
30
|
-
*
|
|
32
|
+
*Note: For best emoji rendering on Linux, you may want to install `fonts-noto-color-emoji` or `ttf-dejavu`.*
|
|
31
33
|
|
|
32
34
|
## 📖 Usage
|
|
33
35
|
|
|
@@ -71,6 +73,8 @@ Default output filename is `{project_name}_code_annex.pdf`.
|
|
|
71
73
|
### Fonts
|
|
72
74
|
- `--font-path PATH` — Additional directory to search for `.ttf`/`.otf` files.
|
|
73
75
|
- `--title-font` / `--normal-font` / `--mono-font` — System font names.
|
|
76
|
+
- `--emoji-font NAME` — Custom font for emojis.
|
|
77
|
+
- `--emoji-description` — Force textual descriptions (e.g., `[GRINNING FACE]`) instead of glyphs.
|
|
74
78
|
|
|
75
79
|
## 🧪 Testing
|
|
76
80
|
|
|
@@ -36,6 +36,13 @@ def check_emoji_font_style():
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def main():
|
|
39
|
+
try:
|
|
40
|
+
_main_impl()
|
|
41
|
+
except KeyboardInterrupt:
|
|
42
|
+
print(f"\n\n\033[33m⚠️ Operation aborted by user (Ctrl+C).\033[0m")
|
|
43
|
+
sys.exit(0)
|
|
44
|
+
|
|
45
|
+
def _main_impl():
|
|
39
46
|
args, unknown = parse_args()
|
|
40
47
|
is_interactive = len(sys.argv) <= 2 and not args.no_input
|
|
41
48
|
if is_interactive: run_interactive_wizard(args)
|
|
@@ -2,6 +2,7 @@ import argparse
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from ..core.config import PDFConfig
|
|
4
4
|
from ..io.git_utils import get_git_info, get_git_remotes
|
|
5
|
+
from ..renderer.fonts import register_emoji_font
|
|
5
6
|
|
|
6
7
|
# ANSI Colors for a better CLI experience
|
|
7
8
|
BOLD = "\033[1m"
|
|
@@ -96,19 +97,27 @@ def run_interactive_wizard(args):
|
|
|
96
97
|
if has_git:
|
|
97
98
|
if len(remotes) > 1:
|
|
98
99
|
_print_header(2, total_steps, "Repository Info", "Multiple Git remotes detected")
|
|
99
|
-
print(f" Available remotes:")
|
|
100
100
|
remote_names = list(remotes.keys())
|
|
101
|
+
|
|
102
|
+
# Identify default index
|
|
103
|
+
default_idx = 1
|
|
104
|
+
if "origin" in remote_names:
|
|
105
|
+
default_idx = remote_names.index("origin") + 1
|
|
106
|
+
|
|
101
107
|
for i, name in enumerate(remote_names, 1):
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
108
|
+
marker = f"{GREEN}*{RESET}" if i == default_idx else " "
|
|
109
|
+
print(f" {i}. {marker} {name} ({remotes[name]})")
|
|
110
|
+
print(f" 0. [ Manual / None ]")
|
|
111
|
+
|
|
112
|
+
choice = _input_field(f"Select remote (1-{len(remote_names)}) or '0' for manual", str(default_idx))
|
|
113
|
+
|
|
114
|
+
if choice == "0":
|
|
115
|
+
git_url = None
|
|
116
|
+
elif choice.isdigit() and 1 <= int(choice) <= len(remote_names):
|
|
106
117
|
selected_remote = remote_names[int(choice)-1]
|
|
107
118
|
git_url = remotes[selected_remote]
|
|
108
|
-
elif "origin" in remotes:
|
|
109
|
-
git_url = remotes["origin"]
|
|
110
119
|
else:
|
|
111
|
-
git_url = remotes[remote_names[
|
|
120
|
+
git_url = remotes[remote_names[default_idx-1]]
|
|
112
121
|
elif len(remotes) == 1:
|
|
113
122
|
git_url = list(remotes.values())[0]
|
|
114
123
|
|
|
@@ -137,11 +146,23 @@ def run_interactive_wizard(args):
|
|
|
137
146
|
args.normal_font = _input_field("Normal Font", args.normal_font or 'Helvetica') or args.normal_font
|
|
138
147
|
args.mono_font = _input_field("Monospace Font", args.mono_font or 'Auto') or args.mono_font
|
|
139
148
|
args.code_size = int(_input_field("Code Font Size", args.code_size) or args.code_size)
|
|
140
|
-
|
|
149
|
+
|
|
141
150
|
paths = _input_field("Additional Font Paths (comma-separated)", "None")
|
|
142
151
|
if paths:
|
|
143
152
|
args.font_path = [p.strip() for p in paths.split(",") if p.strip()]
|
|
144
153
|
|
|
154
|
+
# Emoji Font Check & Support
|
|
155
|
+
emoji_f, emoji_p = register_emoji_font()
|
|
156
|
+
if not emoji_f:
|
|
157
|
+
print(f"\n {YELLOW}⚠️ No emoji font detected!{RESET}")
|
|
158
|
+
print(f" To render emojis, install {BOLD}Symbola{RESET} or {BOLD}Google Noto Emoji{RESET}.")
|
|
159
|
+
print(f" Or provide a custom path above.")
|
|
160
|
+
|
|
161
|
+
choice = input(f" Use text descriptions for emojis (e.g. [smile])? (y/{GREEN}N{RESET}): ").strip().lower()
|
|
162
|
+
if choice == 'y':
|
|
163
|
+
args.emoji_description = True
|
|
164
|
+
else:
|
|
165
|
+
print(f" {GREEN}✅ Emoji font detected:{RESET} {emoji_f} ({emoji_p or 'System'})")
|
|
145
166
|
# 5. Page Layout
|
|
146
167
|
if _ask_section(5, total_steps, "Page Layout & Margins", "Margins, Paper Size, Page Numbering"):
|
|
147
168
|
args.margin_top = float(_input_field("Top Margin (cm)", args.margin_top or 2.0) or (args.margin_top or 2.0))
|
|
@@ -86,7 +86,13 @@ TTF_SEARCH_PATHS = [
|
|
|
86
86
|
"/usr/share/fonts/truetype/noto/NotoSansMono-Regular.ttf", "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", "/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf",
|
|
87
87
|
"C:\\Windows\\Fonts\\consola.ttf", "C:\\Windows\\Fonts\\cour.ttf", "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", "C:\\Windows\\Fonts\\arial.ttf"
|
|
88
88
|
]
|
|
89
|
-
EMOJI_SEARCH_PATHS = [
|
|
89
|
+
EMOJI_SEARCH_PATHS = [
|
|
90
|
+
"C:\\Windows\\Fonts\\seguiemj.ttf", # Windows Standard Emoji
|
|
91
|
+
"C:\\Windows\\Fonts\\seguisym.ttf", # Windows Standard Symbol
|
|
92
|
+
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", # Linux Standard Fallback
|
|
93
|
+
"/usr/share/fonts/truetype/noto/NotoEmoji-Regular.ttf",
|
|
94
|
+
"/usr/share/fonts/truetype/ancient-scripts/Symbola_hint.ttf"
|
|
95
|
+
]
|
|
90
96
|
|
|
91
97
|
def _register_font(name: str, paths: list, fallback):
|
|
92
98
|
for p in paths:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import unicodedata
|
|
2
3
|
from reportlab.lib import colors
|
|
3
4
|
from reportlab.pdfbase import pdfmetrics
|
|
4
5
|
|
|
@@ -7,16 +8,29 @@ def sanitize_text(text: str) -> str:
|
|
|
7
8
|
if not text: return ""
|
|
8
9
|
return re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f]', '', text)
|
|
9
10
|
|
|
11
|
+
def _get_emoji_label(char: str) -> str:
|
|
12
|
+
"""Returns a textual label for an emoji character."""
|
|
13
|
+
try:
|
|
14
|
+
name = unicodedata.name(char)
|
|
15
|
+
return f"[{name}]"
|
|
16
|
+
except (ValueError, KeyError):
|
|
17
|
+
return f"[Emoji-{ord(char):X}]"
|
|
18
|
+
|
|
10
19
|
def get_safe_string_width(text, font_name, font_size, emoji_font=None, emoji_description=False):
|
|
11
20
|
from .fonts import is_char_supported
|
|
12
21
|
total_w = 0.0
|
|
13
22
|
for char in text:
|
|
14
23
|
if is_char_supported(char, font_name):
|
|
15
24
|
total_w += pdfmetrics.stringWidth(char, font_name, font_size)
|
|
25
|
+
elif emoji_description:
|
|
26
|
+
label = _get_emoji_label(char)
|
|
27
|
+
total_w += pdfmetrics.stringWidth(label, font_name, font_size)
|
|
16
28
|
elif emoji_font:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
total_w += pdfmetrics.stringWidth(char, emoji_font, font_size)
|
|
30
|
+
else:
|
|
31
|
+
# Fallback to description if no font is available, even if emoji_description=False
|
|
32
|
+
label = _get_emoji_label(char)
|
|
33
|
+
total_w += pdfmetrics.stringWidth(label, font_name, font_size)
|
|
20
34
|
return total_w
|
|
21
35
|
|
|
22
36
|
def draw_text_with_fallback(canvas, x, y, text, font_name, font_size, emoji_font=None, color=None, emoji_description=False):
|
|
@@ -28,20 +42,21 @@ def draw_text_with_fallback(canvas, x, y, text, font_name, font_size, emoji_font
|
|
|
28
42
|
canvas.setFont(font_name, font_size)
|
|
29
43
|
canvas.drawString(curr_x, y, char)
|
|
30
44
|
curr_x += pdfmetrics.stringWidth(char, font_name, font_size)
|
|
45
|
+
elif emoji_description:
|
|
46
|
+
canvas.setFont(font_name, font_size)
|
|
47
|
+
label = _get_emoji_label(char)
|
|
48
|
+
canvas.drawString(curr_x, y, label)
|
|
49
|
+
curr_x += pdfmetrics.stringWidth(label, font_name, font_size)
|
|
31
50
|
elif emoji_font:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
canvas.drawString(curr_x, y, label)
|
|
36
|
-
curr_x += pdfmetrics.stringWidth(label, font_name, font_size)
|
|
37
|
-
else:
|
|
38
|
-
canvas.setFont(emoji_font, font_size)
|
|
39
|
-
canvas.drawString(curr_x, y, char)
|
|
40
|
-
curr_x += pdfmetrics.stringWidth(char, emoji_font, font_size)
|
|
51
|
+
canvas.setFont(emoji_font, font_size)
|
|
52
|
+
canvas.drawString(curr_x, y, char)
|
|
53
|
+
curr_x += pdfmetrics.stringWidth(char, emoji_font, font_size)
|
|
41
54
|
else:
|
|
55
|
+
# Fallback to description if no font is available
|
|
42
56
|
canvas.setFont(font_name, font_size)
|
|
43
|
-
|
|
44
|
-
|
|
57
|
+
label = _get_emoji_label(char)
|
|
58
|
+
canvas.drawString(curr_x, y, label)
|
|
59
|
+
curr_x += pdfmetrics.stringWidth(label, font_name, font_size)
|
|
45
60
|
return curr_x
|
|
46
61
|
|
|
47
62
|
def draw_centred_text_with_fallback(canvas, x, y, text, font_name, font_size, emoji_font=None, color=None, emoji_description=False):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeannex
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Generates a professional PDF source code annex with Smart Index, Images and Emoji support.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/tanhleno/codeannex
|
|
@@ -36,6 +36,8 @@ Generates a professional PDF annex from a project's source code — featuring sy
|
|
|
36
36
|
## 🚀 Key Features
|
|
37
37
|
|
|
38
38
|
- **Interactive Wizard 2.0** — Step-by-step configuration with smart sections (Project, Style, Typography, Layout, Filters) and explicit default prompts.
|
|
39
|
+
- **Smart Emoji Support** — Automatic discovery of standard emoji fonts (**Segoe UI Emoji** on Windows, **DejaVu Sans** on Linux).
|
|
40
|
+
- **Graceful Emoji Fallback** — If no emoji font is found, it uses official Unicode names (e.g., `[ROCKET]`) for perfect readability.
|
|
39
41
|
- **Git Version Tracking** — Automatically detects **Repository URL**, **Branch**, and **Commit SHA**. Smart root detection avoids Git metadata on subdirectories.
|
|
40
42
|
- **Smart SVG Rendering** — Files are rendered as both a high-quality image and XML code. Entries are intelligently deduplicated in the summary.
|
|
41
43
|
- **Improved Document Structure** — Subdirectories and their contents are listed before root files for better organization.
|
|
@@ -58,7 +60,7 @@ For full SVG support (required for crisp line numbers and SVG image rendering):
|
|
|
58
60
|
pipx install "codeannex[svg]"
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
*
|
|
63
|
+
*Note: For best emoji rendering on Linux, you may want to install `fonts-noto-color-emoji` or `ttf-dejavu`.*
|
|
62
64
|
|
|
63
65
|
## 📖 Usage
|
|
64
66
|
|
|
@@ -102,6 +104,8 @@ Default output filename is `{project_name}_code_annex.pdf`.
|
|
|
102
104
|
### Fonts
|
|
103
105
|
- `--font-path PATH` — Additional directory to search for `.ttf`/`.otf` files.
|
|
104
106
|
- `--title-font` / `--normal-font` / `--mono-font` — System font names.
|
|
107
|
+
- `--emoji-font NAME` — Custom font for emojis.
|
|
108
|
+
- `--emoji-description` — Force textual descriptions (e.g., `[GRINNING FACE]`) instead of glyphs.
|
|
105
109
|
|
|
106
110
|
## 🧪 Testing
|
|
107
111
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codeannex"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.4"
|
|
8
8
|
description = "Generates a professional PDF source code annex with Smart Index, Images and Emoji support."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|