refactor(session,pdf): simplify git perms + rich text PDF
- claude_session: replace 10 individual git command patterns with single Bash(git *) wildcard - generate_pdf: add italic/bold-oblique font loading and render_rich_text() for inline bold/italic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -53,15 +53,7 @@ _DEFAULT_ALLOWED_TOOLS = [
|
|||||||
"WebFetch", "WebSearch",
|
"WebFetch", "WebSearch",
|
||||||
"Bash(python3 *)", "Bash(.venv/bin/python3 *)",
|
"Bash(python3 *)", "Bash(.venv/bin/python3 *)",
|
||||||
"Bash(pip *)", "Bash(pytest *)",
|
"Bash(pip *)", "Bash(pytest *)",
|
||||||
"Bash(git add *)", "Bash(git commit *)",
|
"Bash(git *)",
|
||||||
"Bash(git push)", "Bash(git push *)",
|
|
||||||
"Bash(git pull)", "Bash(git pull *)",
|
|
||||||
"Bash(git status)", "Bash(git status *)",
|
|
||||||
"Bash(git diff)", "Bash(git diff *)",
|
|
||||||
"Bash(git log)", "Bash(git log *)",
|
|
||||||
"Bash(git checkout *)",
|
|
||||||
"Bash(git branch)", "Bash(git branch *)",
|
|
||||||
"Bash(git stash)", "Bash(git stash *)",
|
|
||||||
"Bash(npm *)", "Bash(node *)", "Bash(npx *)",
|
"Bash(npm *)", "Bash(node *)", "Bash(npx *)",
|
||||||
"Bash(systemctl --user *)",
|
"Bash(systemctl --user *)",
|
||||||
"Bash(trash *)", "Bash(mkdir *)", "Bash(cp *)",
|
"Bash(trash *)", "Bash(mkdir *)", "Bash(cp *)",
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ try:
|
|||||||
if dejavu_path.exists():
|
if dejavu_path.exists():
|
||||||
pdf.add_font("DejaVu", "", str(dejavu_path))
|
pdf.add_font("DejaVu", "", str(dejavu_path))
|
||||||
pdf.add_font("DejaVu", "B", "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf")
|
pdf.add_font("DejaVu", "B", "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf")
|
||||||
|
oblique_path = Path("/usr/share/fonts/truetype/dejavu/DejaVuSans-Oblique.ttf")
|
||||||
|
if oblique_path.exists():
|
||||||
|
pdf.add_font("DejaVu", "I", str(oblique_path))
|
||||||
|
bold_oblique = Path("/usr/share/fonts/truetype/dejavu/DejaVuSans-BoldOblique.ttf")
|
||||||
|
if bold_oblique.exists():
|
||||||
|
pdf.add_font("DejaVu", "BI", str(bold_oblique))
|
||||||
pdf.set_font("DejaVu", "", 10)
|
pdf.set_font("DejaVu", "", 10)
|
||||||
use_dejavu = True
|
use_dejavu = True
|
||||||
else:
|
else:
|
||||||
@@ -37,6 +43,42 @@ try:
|
|||||||
pdf.set_font("Helvetica", "", 10)
|
pdf.set_font("Helvetica", "", 10)
|
||||||
use_dejavu = False
|
use_dejavu = False
|
||||||
|
|
||||||
|
def render_rich_text(pdf, text, use_dejavu, size):
|
||||||
|
"""Render text with inline **bold** and *italic* formatting."""
|
||||||
|
font_name = "DejaVu" if use_dejavu else "Helvetica"
|
||||||
|
# Remove links but keep text
|
||||||
|
text = re.sub(r'\[(.*?)\]\(.*?\)', r'\1', text)
|
||||||
|
# Split on bold/italic markers, process segments
|
||||||
|
# Pattern: **bold**, __bold__, *italic*, _italic_
|
||||||
|
parts = re.split(r'(\*\*.*?\*\*|__.*?__|\*.*?\*|_.*?_)', text)
|
||||||
|
for part in parts:
|
||||||
|
if not part:
|
||||||
|
continue
|
||||||
|
if part.startswith('**') and part.endswith('**'):
|
||||||
|
pdf.set_font(font_name, "B", size)
|
||||||
|
pdf.write(5, part[2:-2])
|
||||||
|
pdf.set_font(font_name, "", size)
|
||||||
|
elif part.startswith('__') and part.endswith('__'):
|
||||||
|
pdf.set_font(font_name, "B", size)
|
||||||
|
pdf.write(5, part[2:-2])
|
||||||
|
pdf.set_font(font_name, "", size)
|
||||||
|
elif part.startswith('*') and part.endswith('*') and len(part) > 2:
|
||||||
|
try:
|
||||||
|
pdf.set_font(font_name, "I", size)
|
||||||
|
except:
|
||||||
|
pass # italic not available, keep current font
|
||||||
|
pdf.write(5, part[1:-1])
|
||||||
|
pdf.set_font(font_name, "", size)
|
||||||
|
elif part.startswith('_') and part.endswith('_') and len(part) > 2:
|
||||||
|
try:
|
||||||
|
pdf.set_font(font_name, "I", size)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
pdf.write(5, part[1:-1])
|
||||||
|
pdf.set_font(font_name, "", size)
|
||||||
|
else:
|
||||||
|
pdf.write(5, part)
|
||||||
|
|
||||||
# Parse markdown line by line
|
# Parse markdown line by line
|
||||||
lines = markdown_content.split('\n')
|
lines = markdown_content.split('\n')
|
||||||
i = 0
|
i = 0
|
||||||
@@ -77,28 +119,25 @@ try:
|
|||||||
# Bullet point
|
# Bullet point
|
||||||
elif line.strip().startswith('- ') or line.strip().startswith('* '):
|
elif line.strip().startswith('- ') or line.strip().startswith('* '):
|
||||||
text = line.strip().lstrip('-*').strip()
|
text = line.strip().lstrip('-*').strip()
|
||||||
# Use simple dash for bullet
|
pdf.write(5, '- ')
|
||||||
pdf.multi_cell(0, 5, '- ' + text, ln=True)
|
render_rich_text(pdf, text, use_dejavu, 10)
|
||||||
|
pdf.ln(5)
|
||||||
|
|
||||||
# Numbered list
|
# Numbered list
|
||||||
elif re.match(r'^\s*\d+\.\s', line):
|
elif re.match(r'^\s*(\d+\.)\s', line):
|
||||||
text = re.sub(r'^\s*\d+\.\s', '', line)
|
m = re.match(r'^\s*(\d+\.)\s(.*)', line)
|
||||||
pdf.multi_cell(0, 5, text, ln=True)
|
prefix = m.group(1) + ' '
|
||||||
|
text = m.group(2)
|
||||||
|
pdf.write(5, prefix)
|
||||||
|
render_rich_text(pdf, text, use_dejavu, 10)
|
||||||
|
pdf.ln(5)
|
||||||
|
|
||||||
# Regular text with formatting
|
# Regular text with formatting
|
||||||
else:
|
else:
|
||||||
# Clean up markdown markers but keep structure
|
|
||||||
text = line.strip()
|
text = line.strip()
|
||||||
|
|
||||||
# Remove inline markdown
|
|
||||||
text = re.sub(r'\*\*(.*?)\*\*', r'\1', text) # Bold
|
|
||||||
text = re.sub(r'__(.*?)__', r'\1', text) # Bold
|
|
||||||
text = re.sub(r'\*(.*?)\*', r'\1', text) # Italic
|
|
||||||
text = re.sub(r'_(.*?)_', r'\1', text) # Italic
|
|
||||||
text = re.sub(r'\[(.*?)\]\(.*?\)', r'\1', text) # Links
|
|
||||||
|
|
||||||
if text:
|
if text:
|
||||||
pdf.multi_cell(0, 5, text, ln=True)
|
render_rich_text(pdf, text, use_dejavu, 10)
|
||||||
|
pdf.ln(5)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user