pyact-cli 0.7.1__tar.gz → 0.7.3__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.
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/PKG-INFO +1 -1
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pamd_helpers/__init__.py +10 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/mdTOword.py +71 -7
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/py2tex.py +18 -1
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact_cli.egg-info/PKG-INFO +1 -1
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/setup.py +1 -1
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/README.md +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/__init__.py +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/cli.py +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/core.py +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/css2json.py +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact/linter.py +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact_cli.egg-info/SOURCES.txt +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact_cli.egg-info/dependency_links.txt +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact_cli.egg-info/entry_points.txt +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact_cli.egg-info/requires.txt +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/pyact_cli.egg-info/top_level.txt +0 -0
- {pyact_cli-0.7.1 → pyact_cli-0.7.3}/setup.cfg +0 -0
|
@@ -21,6 +21,16 @@ def equation(func: Callable, values: List[Any]) -> str:
|
|
|
21
21
|
value = func(*values)
|
|
22
22
|
name, sep, tail = source.rpartition("=")
|
|
23
23
|
head, sep, equ = tail.rpartition(":")
|
|
24
|
+
|
|
25
|
+
name = name.strip()
|
|
26
|
+
if "_" in name:
|
|
27
|
+
parts = name.split("_", 1)
|
|
28
|
+
name = f"{parts[0]}_{{{parts[1]}}}"
|
|
29
|
+
|
|
30
|
+
import re
|
|
31
|
+
greek_pattern = r'(?<![a-zA-Z])(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Alpha|Beta|Gamma|Delta|Epsilon|Zeta|Eta|Theta|Iota|Kappa|Lambda|Mu|Nu|Xi|Omicron|Pi|Rho|Sigma|Tau|Upsilon|Phi|Chi|Psi|Omega)(?![a-zA-Z])'
|
|
32
|
+
name = re.sub(greek_pattern, r'\\\1', name)
|
|
33
|
+
|
|
24
34
|
return f"$$ {name} = {py2tex(equ.replace(chr(10), ''))} = {value} $$"
|
|
25
35
|
|
|
26
36
|
def image(link: str, caption: str) -> str:
|
|
@@ -82,11 +82,11 @@ def markdown_parser(md_text: str) -> list:
|
|
|
82
82
|
blocks.append(('list', text, 'unordered'))
|
|
83
83
|
|
|
84
84
|
elif re.match(r'^\d+\.\s+', line_s):
|
|
85
|
-
m = re.match(r'
|
|
86
|
-
blocks.append(('list', m.group(
|
|
85
|
+
m = re.match(r'^(\d+)\.\s+(.*)', line_s)
|
|
86
|
+
blocks.append(('list', m.group(2), 'ordered', int(m.group(1))))
|
|
87
87
|
|
|
88
88
|
# Math Block Parsing
|
|
89
|
-
elif line_s.startswith('$$') and line_s.endswith('$$'):
|
|
89
|
+
elif (line_s.startswith('$$') and line_s.endswith('$$')) or (line_s.startswith('$') and line_s.endswith('$') and len(line_s) >= 2):
|
|
90
90
|
blocks.append(('math', line_s.strip('$').strip()))
|
|
91
91
|
|
|
92
92
|
# Standard Paragraph
|
|
@@ -312,15 +312,17 @@ def _add_image(paragraph, url, caption, styles):
|
|
|
312
312
|
def _process_inline(paragraph, text, styles, tag):
|
|
313
313
|
"""Parses text for images, links, math, and bold/italic."""
|
|
314
314
|
# Simple regex to split by math, image, or link. Captures the match as a group.
|
|
315
|
-
# Group
|
|
316
|
-
# Group
|
|
317
|
-
|
|
315
|
+
# Group 1: Double $$ math
|
|
316
|
+
# Group 2: Single $ math
|
|
317
|
+
# Group 6: Footnote definition [^1]: ...
|
|
318
|
+
# Group 7: Footnote annotation [^1]
|
|
319
|
+
pattern = r'(\$\$.*?\$\$)|(\$.*?\$)|(!\[.*?\]\(.*?\))|(\[.*?\]\(.*?\))|(<span.*?>.*?</span>)|(\[\^.*?\]:.*?$)|(\[\^.*?\])'
|
|
318
320
|
parts = re.split(pattern, text)
|
|
319
321
|
|
|
320
322
|
for part in parts:
|
|
321
323
|
if not part: continue
|
|
322
324
|
|
|
323
|
-
if part.startswith('$$') and part.endswith('$$'):
|
|
325
|
+
if (part.startswith('$$') and part.endswith('$$')) or (part.startswith('$') and part.endswith('$') and len(part) >= 2):
|
|
324
326
|
math_text = part.strip('$').strip()
|
|
325
327
|
try:
|
|
326
328
|
math2docx.add_math(paragraph, math_text)
|
|
@@ -381,6 +383,48 @@ def _process_inline(paragraph, text, styles, tag):
|
|
|
381
383
|
run = paragraph.add_run(subpart)
|
|
382
384
|
if tag in styles: _apply_css_to_run(run, styles[tag])
|
|
383
385
|
|
|
386
|
+
def _restart_list_numbering(doc, p):
|
|
387
|
+
try:
|
|
388
|
+
num_part = doc.part.numbering_part
|
|
389
|
+
numbering = num_part.numbering_definitions._numbering
|
|
390
|
+
nums = numbering.xpath('w:num')
|
|
391
|
+
if not nums: return None
|
|
392
|
+
max_id = max([int(n.get(qn('w:numId'))) for n in nums])
|
|
393
|
+
new_id = max_id + 1
|
|
394
|
+
|
|
395
|
+
list_num = numbering.xpath('w:num[@w:numId="5"]')
|
|
396
|
+
if not list_num: list_num = nums
|
|
397
|
+
abstract_id = list_num[0].xpath('w:abstractNumId/@w:val')[0]
|
|
398
|
+
|
|
399
|
+
new_num = OxmlElement('w:num')
|
|
400
|
+
new_num.set(qn('w:numId'), str(new_id))
|
|
401
|
+
ab_num_id = OxmlElement('w:abstractNumId')
|
|
402
|
+
ab_num_id.set(qn('w:val'), abstract_id)
|
|
403
|
+
new_num.append(ab_num_id)
|
|
404
|
+
|
|
405
|
+
lvl_override = OxmlElement('w:lvlOverride')
|
|
406
|
+
lvl_override.set(qn('w:ilvl'), "0")
|
|
407
|
+
start_override = OxmlElement('w:startOverride')
|
|
408
|
+
start_override.set(qn('w:val'), "1")
|
|
409
|
+
lvl_override.append(start_override)
|
|
410
|
+
new_num.append(lvl_override)
|
|
411
|
+
|
|
412
|
+
numbering.append(new_num)
|
|
413
|
+
|
|
414
|
+
pPr = p._p.get_or_add_pPr()
|
|
415
|
+
numPr = OxmlElement('w:numPr')
|
|
416
|
+
ilvl = OxmlElement('w:ilvl')
|
|
417
|
+
ilvl.set(qn('w:val'), "0")
|
|
418
|
+
numId_el = OxmlElement('w:numId')
|
|
419
|
+
numId_el.set(qn('w:val'), str(new_id))
|
|
420
|
+
numPr.append(ilvl)
|
|
421
|
+
numPr.append(numId_el)
|
|
422
|
+
pPr.append(numPr)
|
|
423
|
+
|
|
424
|
+
return new_id
|
|
425
|
+
except Exception:
|
|
426
|
+
return None
|
|
427
|
+
|
|
384
428
|
def docx_writer(blocks: list, styles: dict, output_file: str):
|
|
385
429
|
"""
|
|
386
430
|
Translates parsed markdown blocks into a Word document and applies CSS styling.
|
|
@@ -399,6 +443,7 @@ def docx_writer(blocks: list, styles: dict, output_file: str):
|
|
|
399
443
|
None: This function does not return a value, but it writes a binary .docx file to disk.
|
|
400
444
|
"""
|
|
401
445
|
doc = Document()
|
|
446
|
+
current_ordered_numId = None
|
|
402
447
|
|
|
403
448
|
# Global body style
|
|
404
449
|
if 'body' in styles:
|
|
@@ -426,8 +471,27 @@ def docx_writer(blocks: list, styles: dict, output_file: str):
|
|
|
426
471
|
elif btype == 'list':
|
|
427
472
|
text = block[1]
|
|
428
473
|
list_type = block[2] if len(block) > 2 else 'unordered'
|
|
474
|
+
num_val = block[3] if len(block) > 3 else None
|
|
475
|
+
|
|
429
476
|
style = 'List Number' if list_type == 'ordered' else 'List Bullet'
|
|
430
477
|
p = doc.add_paragraph(style=style)
|
|
478
|
+
|
|
479
|
+
if list_type == 'ordered':
|
|
480
|
+
if num_val == 1:
|
|
481
|
+
new_id = _restart_list_numbering(doc, p)
|
|
482
|
+
if new_id:
|
|
483
|
+
current_ordered_numId = new_id
|
|
484
|
+
elif current_ordered_numId:
|
|
485
|
+
pPr = p._p.get_or_add_pPr()
|
|
486
|
+
numPr = OxmlElement('w:numPr')
|
|
487
|
+
ilvl = OxmlElement('w:ilvl')
|
|
488
|
+
ilvl.set(qn('w:val'), "0")
|
|
489
|
+
numId_el = OxmlElement('w:numId')
|
|
490
|
+
numId_el.set(qn('w:val'), str(current_ordered_numId))
|
|
491
|
+
numPr.append(ilvl)
|
|
492
|
+
numPr.append(numId_el)
|
|
493
|
+
pPr.append(numPr)
|
|
494
|
+
|
|
431
495
|
if 'list' in styles:
|
|
432
496
|
_apply_paragraph_formatting(p, styles['list'])
|
|
433
497
|
_process_inline(p, text, styles, 'list')
|
|
@@ -17,7 +17,24 @@ class LatexVisitor(ast.NodeVisitor):
|
|
|
17
17
|
return 1000
|
|
18
18
|
|
|
19
19
|
def visit_Name(self, n):
|
|
20
|
-
|
|
20
|
+
name = n.id
|
|
21
|
+
if "_" in name:
|
|
22
|
+
parts = name.split('_', 1)
|
|
23
|
+
name = f"{parts[0]}_{{{parts[1]}}}"
|
|
24
|
+
|
|
25
|
+
greek_letters = [
|
|
26
|
+
'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota',
|
|
27
|
+
'kappa', 'lambda', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau',
|
|
28
|
+
'upsilon', 'phi', 'chi', 'psi', 'omega',
|
|
29
|
+
'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', 'Iota',
|
|
30
|
+
'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau',
|
|
31
|
+
'Upsilon', 'Phi', 'Chi', 'Psi', 'Omega'
|
|
32
|
+
]
|
|
33
|
+
import re
|
|
34
|
+
greek_pattern = r'(?<![a-zA-Z])(' + '|'.join(greek_letters) + r')(?![a-zA-Z])'
|
|
35
|
+
name = re.sub(greek_pattern, r'\\\1', name)
|
|
36
|
+
|
|
37
|
+
return name
|
|
21
38
|
|
|
22
39
|
def prec_Name(self, n):
|
|
23
40
|
return 1000
|
|
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
|