pyDiffTools 0.1.26__tar.gz → 0.1.28__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.
- {pydifftools-0.1.26 → pydifftools-0.1.28}/MANIFEST.in +2 -0
- {pydifftools-0.1.26/pyDiffTools.egg-info → pydifftools-0.1.28}/PKG-INFO +1 -1
- {pydifftools-0.1.26 → pydifftools-0.1.28/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pyDiffTools.egg-info/SOURCES.txt +2 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/command_line.py +9 -0
- pydifftools-0.1.28/pydifftools/comment_tags_margin.lua +411 -0
- pydifftools-0.1.28/pydifftools/comment_tags_no_comments.lua +328 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/continuous.py +96 -42
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/flowchart/graph.py +252 -69
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/flowchart/watch_graph.py +117 -47
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pyproject.toml +3 -1
- {pydifftools-0.1.26 → pydifftools-0.1.28}/tests/test_command_line_help.py +14 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/LICENSE.md +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/README.rst +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/__init__.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/browser_lifecycle.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/comment_tags.lua +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/comment_toggle.js +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/comments.css +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/doc_contents.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/git_gd.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/git_gd_qt.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/log_example.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/match_spaces.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/notebook/fast_build.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/notebook/tex_to_qmd.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/outline.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/separate_comments.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/unseparate_comments.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/update_check.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/wrap_sentences.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/setup.cfg +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/tests/test_browser_lifecycle.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/tests/test_continuous_shutdown.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/tests/test_rrng.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/tests/test_tex_to_qmd.py +0 -0
- {pydifftools-0.1.26 → pydifftools-0.1.28}/tests/test_update_check.py +0 -0
|
@@ -5,5 +5,7 @@ include pydifftools/diff-doc.js
|
|
|
5
5
|
include pydifftools/xml2xlsx.vbs
|
|
6
6
|
include pydifftools/comments.css
|
|
7
7
|
include pydifftools/comment_tags.lua
|
|
8
|
+
include pydifftools/comment_tags_margin.lua
|
|
9
|
+
include pydifftools/comment_tags_no_comments.lua
|
|
8
10
|
include pydifftools/comment_toggle.js
|
|
9
11
|
recursive-include example_notebook *
|
|
@@ -51,6 +51,8 @@ pydifftools/command_line.py
|
|
|
51
51
|
pydifftools/command_registry.py
|
|
52
52
|
pydifftools/comment_functions.py
|
|
53
53
|
pydifftools/comment_tags.lua
|
|
54
|
+
pydifftools/comment_tags_margin.lua
|
|
55
|
+
pydifftools/comment_tags_no_comments.lua
|
|
54
56
|
pydifftools/comment_toggle.js
|
|
55
57
|
pydifftools/comments.css
|
|
56
58
|
pydifftools/continuous.py
|
|
@@ -934,6 +934,15 @@ def main(argv=None):
|
|
|
934
934
|
parser._pydifft_subparsers[subcommand].print_help()
|
|
935
935
|
return
|
|
936
936
|
namespace = parser.parse_args(argv)
|
|
937
|
+
if (
|
|
938
|
+
namespace.command == "cpb"
|
|
939
|
+
and namespace.comments_to_margin
|
|
940
|
+
and namespace.no_comments
|
|
941
|
+
):
|
|
942
|
+
parser._pydifft_subparsers["cpb"].error(
|
|
943
|
+
"argument --no-comments: not allowed with argument "
|
|
944
|
+
"--comments-to-margin"
|
|
945
|
+
)
|
|
937
946
|
handler = namespace._handler
|
|
938
947
|
handler_kwargs = dict(vars(namespace))
|
|
939
948
|
handler_kwargs.pop("_handler", None)
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
-- comment_tags_margin.lua
|
|
2
|
+
-- PYDIFFTOOLS_SPECIAL_MARGIN_COMMENTS_FILTER
|
|
3
|
+
-- Supports:
|
|
4
|
+
-- Inline: <comment>...</comment>, <comment-left>...</comment-left>,
|
|
5
|
+
-- <comment-right>...</comment-right>
|
|
6
|
+
-- Block: same tags wrapping block content (lists, multiple paras, etc.)
|
|
7
|
+
--
|
|
8
|
+
-- Inline output:
|
|
9
|
+
-- <span class="comment-pin"><span class="comment-right|left">...</span></span>
|
|
10
|
+
--
|
|
11
|
+
-- Block output:
|
|
12
|
+
-- <span class="comment-pin comment-pin-block" data-comment-id="cN"></span>
|
|
13
|
+
-- <div class="comment-overlay comment-right|left" data-comment-id="cN"> ...block content... </div>
|
|
14
|
+
--
|
|
15
|
+
-- Requires JS to position .comment-overlay.
|
|
16
|
+
|
|
17
|
+
local function raw_inline_html(el)
|
|
18
|
+
if el and el.t == "RawInline" and el.format == "html" then
|
|
19
|
+
return el.text:lower()
|
|
20
|
+
end
|
|
21
|
+
return nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
local function raw_block_html(el)
|
|
25
|
+
if el and el.t == "RawBlock" and el.format == "html" then
|
|
26
|
+
return el.text:lower()
|
|
27
|
+
end
|
|
28
|
+
return nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
local OPENERS = {
|
|
32
|
+
["<comment>"] = { side = "comment-left", close = "</comment>" },
|
|
33
|
+
["<comment-right>"] = { side = "comment-left", close = "</comment-right>" },
|
|
34
|
+
["<comment-left>"] = { side = "comment-left", close = "</comment-left>" },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
local comment_id = 0
|
|
38
|
+
local function next_id()
|
|
39
|
+
comment_id = comment_id + 1
|
|
40
|
+
return "c" .. tostring(comment_id)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
local function make_inline_comment(side, content_inlines)
|
|
44
|
+
-- Emit inline comments as overlay-positioned margin bubbles so they stay in
|
|
45
|
+
-- the left margin without forcing a paragraph break at the insertion point.
|
|
46
|
+
local id = next_id()
|
|
47
|
+
local out = pandoc.List()
|
|
48
|
+
out:insert(
|
|
49
|
+
pandoc.RawInline(
|
|
50
|
+
"html",
|
|
51
|
+
'<span class="comment-inline-break-marker comment-inline-break-before">...</span>'
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
out:insert(
|
|
55
|
+
pandoc.RawInline(
|
|
56
|
+
"html",
|
|
57
|
+
'<span class="comment-pin comment-pin-block" data-comment-id="' .. id .. '"></span>'
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
out:insert(
|
|
61
|
+
pandoc.Span(
|
|
62
|
+
content_inlines,
|
|
63
|
+
pandoc.Attr(
|
|
64
|
+
"",
|
|
65
|
+
{ "comment-overlay", side, "comment-inline-margin", "comment-margin-left" },
|
|
66
|
+
{ ["data-comment-id"] = id, ["style"] = "font-size: 6pt;" }
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
out:insert(
|
|
71
|
+
pandoc.RawInline(
|
|
72
|
+
"html",
|
|
73
|
+
'<span class="comment-inline-break-marker comment-inline-break-after">...</span>'
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
return out
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
local function make_block_anchor(id)
|
|
80
|
+
-- RawBlock so we don't introduce a <p> wrapper that changes spacing.
|
|
81
|
+
return pandoc.RawBlock("html",
|
|
82
|
+
'<span class="comment-pin comment-pin-block" data-comment-id="' .. id .. '"></span>')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
local function make_block_overlay(side, id, content_blocks)
|
|
86
|
+
-- Div can contain BulletList/Para/etc. JS will position this overlay.
|
|
87
|
+
return pandoc.Div(
|
|
88
|
+
content_blocks,
|
|
89
|
+
pandoc.Attr(
|
|
90
|
+
"",
|
|
91
|
+
{ "comment-overlay", side, "comment-margin-left" },
|
|
92
|
+
{ ["data-comment-id"] = id, ["style"] = "font-size: 6pt;" }
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
local function para_like_t(block)
|
|
98
|
+
return block and (block.t == "Para" or block.t == "Plain")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
local function clone_para_like(block, inlines)
|
|
102
|
+
if block.t == "Para" then
|
|
103
|
+
return pandoc.Para(inlines)
|
|
104
|
+
else
|
|
105
|
+
return pandoc.Plain(inlines)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
local function split_inline_block_at_tag(block, tag)
|
|
110
|
+
if not para_like_t(block) then
|
|
111
|
+
return false, nil, nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
local tag_index = nil
|
|
115
|
+
for j = 1, #block.content do
|
|
116
|
+
if raw_inline_html(block.content[j]) == tag then
|
|
117
|
+
tag_index = j
|
|
118
|
+
break
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
if not tag_index then
|
|
122
|
+
return false, nil, nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
local before = pandoc.List()
|
|
126
|
+
local after = pandoc.List()
|
|
127
|
+
for j = 1, tag_index - 1 do
|
|
128
|
+
before:insert(block.content[j])
|
|
129
|
+
end
|
|
130
|
+
for j = tag_index + 1, #block.content do
|
|
131
|
+
after:insert(block.content[j])
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
-- Avoid creating hard visual breaks around opener/closer tags when those
|
|
135
|
+
-- tags sit at line boundaries in markdown source.
|
|
136
|
+
while #before > 0 and (
|
|
137
|
+
before[#before].t == "SoftBreak"
|
|
138
|
+
or before[#before].t == "LineBreak"
|
|
139
|
+
or before[#before].t == "Space"
|
|
140
|
+
) do
|
|
141
|
+
before:remove(#before)
|
|
142
|
+
end
|
|
143
|
+
while #after > 0 and (
|
|
144
|
+
after[1].t == "SoftBreak"
|
|
145
|
+
or after[1].t == "LineBreak"
|
|
146
|
+
or after[1].t == "Space"
|
|
147
|
+
) do
|
|
148
|
+
after:remove(1)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
local before_block = nil
|
|
152
|
+
local after_block = nil
|
|
153
|
+
if #before > 0 then
|
|
154
|
+
before_block = clone_para_like(block, before)
|
|
155
|
+
end
|
|
156
|
+
if #after > 0 then
|
|
157
|
+
after_block = clone_para_like(block, after)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
return true, before_block, after_block
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
local function split_block_at_closer(block, close_tag)
|
|
165
|
+
-- Handle direct Para/Plain closer first.
|
|
166
|
+
if para_like_t(block) then
|
|
167
|
+
local found, before, after = split_inline_block_at_tag(block, close_tag)
|
|
168
|
+
if found then
|
|
169
|
+
local after_blocks = pandoc.List()
|
|
170
|
+
if after then
|
|
171
|
+
after_blocks:insert(after)
|
|
172
|
+
end
|
|
173
|
+
return true, before, after_blocks
|
|
174
|
+
end
|
|
175
|
+
return false, nil, pandoc.List()
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
-- Handle list blocks where the closer can appear inside a list item.
|
|
179
|
+
if block.t == "BulletList" then
|
|
180
|
+
local before_items = pandoc.List()
|
|
181
|
+
local after_blocks = pandoc.List()
|
|
182
|
+
|
|
183
|
+
for item_index = 1, #block.content do
|
|
184
|
+
local this_item = block.content[item_index]
|
|
185
|
+
local before_item_blocks = pandoc.List()
|
|
186
|
+
|
|
187
|
+
for block_index = 1, #this_item do
|
|
188
|
+
local found, before, nested_after =
|
|
189
|
+
split_block_at_closer(this_item[block_index], close_tag)
|
|
190
|
+
if found then
|
|
191
|
+
if before then
|
|
192
|
+
before_item_blocks:insert(before)
|
|
193
|
+
end
|
|
194
|
+
if #before_item_blocks > 0 then
|
|
195
|
+
before_items:insert(before_item_blocks)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
-- Once the comment closes, flatten the remaining list content back
|
|
199
|
+
-- into normal blocks so we do not leak list text into body lists.
|
|
200
|
+
for nested_index = 1, #nested_after do
|
|
201
|
+
after_blocks:insert(nested_after[nested_index])
|
|
202
|
+
end
|
|
203
|
+
for k = block_index + 1, #this_item do
|
|
204
|
+
after_blocks:insert(this_item[k])
|
|
205
|
+
end
|
|
206
|
+
for item_tail = item_index + 1, #block.content do
|
|
207
|
+
for tail_block_index = 1, #block.content[item_tail] do
|
|
208
|
+
after_blocks:insert(block.content[item_tail][tail_block_index])
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
local before_block = nil
|
|
213
|
+
if #before_items > 0 then
|
|
214
|
+
before_block = pandoc.BulletList(before_items)
|
|
215
|
+
end
|
|
216
|
+
return true, before_block, after_blocks
|
|
217
|
+
else
|
|
218
|
+
before_item_blocks:insert(this_item[block_index])
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
if #before_item_blocks > 0 then
|
|
223
|
+
before_items:insert(before_item_blocks)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
return false, nil, pandoc.List()
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
return false, nil, pandoc.List()
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
-- Detect opener at block level:
|
|
234
|
+
-- 1) RawBlock("<comment>")
|
|
235
|
+
-- 2) anywhere inside Para/Plain as RawInline("<comment>")
|
|
236
|
+
-- Returns: spec, before_block_or_nil, after_block_or_nil
|
|
237
|
+
local function detect_block_opener(block)
|
|
238
|
+
local t = raw_block_html(block)
|
|
239
|
+
local spec = t and OPENERS[t] or nil
|
|
240
|
+
if spec then
|
|
241
|
+
return spec, nil, nil
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
if para_like_t(block) then
|
|
245
|
+
for k, opener_spec in pairs(OPENERS) do
|
|
246
|
+
local found, before, after = split_inline_block_at_tag(block, k)
|
|
247
|
+
if found then
|
|
248
|
+
return opener_spec, before, after
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
return nil, nil, nil
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
-- Detect closer at block level:
|
|
257
|
+
-- 1) RawBlock("</comment>")
|
|
258
|
+
-- 2) anywhere inside Para/Plain as RawInline("</comment>")
|
|
259
|
+
-- Returns: found_bool, before_block_or_nil, after_block_or_nil
|
|
260
|
+
local function strip_block_closer(block, close_tag)
|
|
261
|
+
local t = raw_block_html(block)
|
|
262
|
+
if t == close_tag then
|
|
263
|
+
return true, nil, pandoc.List()
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
local found, before, after_blocks = split_block_at_closer(block, close_tag)
|
|
267
|
+
if found then
|
|
268
|
+
return true, before, after_blocks
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
return false, nil, pandoc.List()
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
-- Inline comments (mid-paragraph)
|
|
275
|
+
function Inlines(inlines)
|
|
276
|
+
local out = pandoc.List()
|
|
277
|
+
local i, n = 1, #inlines
|
|
278
|
+
|
|
279
|
+
while i <= n do
|
|
280
|
+
local t = raw_inline_html(inlines[i])
|
|
281
|
+
local spec = t and OPENERS[t] or nil
|
|
282
|
+
|
|
283
|
+
if not spec then
|
|
284
|
+
out:insert(inlines[i])
|
|
285
|
+
i = i + 1
|
|
286
|
+
else
|
|
287
|
+
local buf = pandoc.List()
|
|
288
|
+
local j = i + 1
|
|
289
|
+
local found = false
|
|
290
|
+
|
|
291
|
+
while j <= n do
|
|
292
|
+
local tj = raw_inline_html(inlines[j])
|
|
293
|
+
if tj == spec.close then
|
|
294
|
+
found = true
|
|
295
|
+
break
|
|
296
|
+
end
|
|
297
|
+
buf:insert(inlines[j])
|
|
298
|
+
j = j + 1
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
if found then
|
|
302
|
+
local margin_comment = make_inline_comment(spec.side, buf)
|
|
303
|
+
for k = 1, #margin_comment do
|
|
304
|
+
out:insert(margin_comment[k])
|
|
305
|
+
end
|
|
306
|
+
i = j + 1
|
|
307
|
+
else
|
|
308
|
+
-- unmatched: leave literal
|
|
309
|
+
out:insert(inlines[i])
|
|
310
|
+
i = i + 1
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
return out
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
-- Block comments (lists / multi-paragraph inside <comment> ... </comment>)
|
|
319
|
+
function Blocks(blocks)
|
|
320
|
+
local out = pandoc.List()
|
|
321
|
+
local i, n = 1, #blocks
|
|
322
|
+
|
|
323
|
+
while i <= n do
|
|
324
|
+
local spec, before_open, after_open = detect_block_opener(blocks[i])
|
|
325
|
+
|
|
326
|
+
if not spec then
|
|
327
|
+
out:insert(blocks[i])
|
|
328
|
+
i = i + 1
|
|
329
|
+
else
|
|
330
|
+
local buf = pandoc.List()
|
|
331
|
+
local inserted_before_open = false
|
|
332
|
+
if before_open then
|
|
333
|
+
-- Keep text before the opener in the main document flow.
|
|
334
|
+
out:insert(before_open)
|
|
335
|
+
inserted_before_open = true
|
|
336
|
+
end
|
|
337
|
+
if after_open then
|
|
338
|
+
-- Everything after the opener belongs inside the bubble body.
|
|
339
|
+
buf:insert(after_open)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
local j = i + 1
|
|
343
|
+
local found = false
|
|
344
|
+
local after_close_blocks = pandoc.List()
|
|
345
|
+
|
|
346
|
+
while j <= n do
|
|
347
|
+
local is_close, before_close, after_close_candidate =
|
|
348
|
+
strip_block_closer(blocks[j], spec.close)
|
|
349
|
+
if is_close then
|
|
350
|
+
if before_close then
|
|
351
|
+
buf:insert(before_close)
|
|
352
|
+
end
|
|
353
|
+
found = true
|
|
354
|
+
after_close_blocks = after_close_candidate
|
|
355
|
+
break
|
|
356
|
+
else
|
|
357
|
+
buf:insert(blocks[j])
|
|
358
|
+
end
|
|
359
|
+
j = j + 1
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
if found then
|
|
363
|
+
local id = next_id()
|
|
364
|
+
local merged_with_inline_anchor = false
|
|
365
|
+
|
|
366
|
+
-- If the comment opens mid-paragraph and closes before trailing prose,
|
|
367
|
+
-- merge the surrounding prose back into one paragraph and place the
|
|
368
|
+
-- anchor inline at the split point so there is no forced line break.
|
|
369
|
+
if inserted_before_open and #after_close_blocks > 0 then
|
|
370
|
+
if para_like_t(out[#out]) and para_like_t(after_close_blocks[1]) then
|
|
371
|
+
local merged_inlines = pandoc.List()
|
|
372
|
+
for k = 1, #out[#out].content do
|
|
373
|
+
merged_inlines:insert(out[#out].content[k])
|
|
374
|
+
end
|
|
375
|
+
merged_inlines:insert(
|
|
376
|
+
pandoc.RawInline(
|
|
377
|
+
"html",
|
|
378
|
+
'<span class="comment-pin comment-pin-block" data-comment-id="'
|
|
379
|
+
.. id .. '"></span>'
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
merged_inlines:insert(pandoc.Space())
|
|
383
|
+
for k = 1, #after_close_blocks[1].content do
|
|
384
|
+
merged_inlines:insert(after_close_blocks[1].content[k])
|
|
385
|
+
end
|
|
386
|
+
out[#out] = clone_para_like(out[#out], merged_inlines)
|
|
387
|
+
after_close_blocks:remove(1)
|
|
388
|
+
merged_with_inline_anchor = true
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
if not merged_with_inline_anchor then
|
|
393
|
+
out:insert(make_block_anchor(id))
|
|
394
|
+
end
|
|
395
|
+
out:insert(make_block_overlay(spec.side, id, buf))
|
|
396
|
+
|
|
397
|
+
-- Keep trailing content after the closer in main flow.
|
|
398
|
+
for after_index = 1, #after_close_blocks do
|
|
399
|
+
out:insert(after_close_blocks[after_index])
|
|
400
|
+
end
|
|
401
|
+
i = j + 1
|
|
402
|
+
else
|
|
403
|
+
-- unmatched opener: preserve original block
|
|
404
|
+
out:insert(blocks[i])
|
|
405
|
+
i = i + 1
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
return out
|
|
411
|
+
end
|