pyDiffTools 0.1.22__tar.gz → 0.1.24__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.22/pyDiffTools.egg-info → pydifftools-0.1.24}/PKG-INFO +1 -1
- {pydifftools-0.1.22 → pydifftools-0.1.24/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/command_line.py +41 -1
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/comment_toggle.js +19 -3
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/comments.css +38 -11
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/continuous.py +76 -14
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/flowchart/watch_graph.py +51 -12
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pyproject.toml +1 -1
- {pydifftools-0.1.22 → pydifftools-0.1.24}/tests/test_continuous_shutdown.py +2 -1
- {pydifftools-0.1.22 → pydifftools-0.1.24}/LICENSE.md +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/MANIFEST.in +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/README.rst +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pyDiffTools.egg-info/SOURCES.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/__init__.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/browser_lifecycle.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/comment_tags.lua +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/doc_contents.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/flowchart/graph.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/match_spaces.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/notebook/fast_build.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/notebook/tex_to_qmd.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/outline.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/separate_comments.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/unseparate_comments.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/update_check.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/wrap_sentences.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/setup.cfg +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/tests/test_browser_lifecycle.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/tests/test_rrng.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/tests/test_tex_to_qmd.py +0 -0
- {pydifftools-0.1.22 → pydifftools-0.1.24}/tests/test_update_check.py +0 -0
|
@@ -796,8 +796,35 @@ def pmd(arguments):
|
|
|
796
796
|
p1.wait()
|
|
797
797
|
|
|
798
798
|
|
|
799
|
+
def _subcommand_help_hint(prog):
|
|
800
|
+
return (
|
|
801
|
+
f"*** Run '{prog} --help <subcommand>' to learn about "
|
|
802
|
+
"subcommand options. ***"
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
class PyDiffArgumentParser(argparse.ArgumentParser):
|
|
807
|
+
"""ArgumentParser with a clearer root-level missing-subcommand hint."""
|
|
808
|
+
|
|
809
|
+
def __init__(self, *args, is_root_parser=False, **kwargs):
|
|
810
|
+
super().__init__(*args, **kwargs)
|
|
811
|
+
self._pydifft_is_root_parser = is_root_parser
|
|
812
|
+
|
|
813
|
+
def error(self, message):
|
|
814
|
+
if self._pydifft_is_root_parser:
|
|
815
|
+
self.print_usage(sys.stderr)
|
|
816
|
+
hint = _subcommand_help_hint(self.prog)
|
|
817
|
+
self.exit(2, f"{self.prog}: error: {message}\n{hint}\n")
|
|
818
|
+
super().error(message)
|
|
819
|
+
|
|
820
|
+
|
|
799
821
|
def build_parser():
|
|
800
|
-
parser =
|
|
822
|
+
parser = PyDiffArgumentParser(
|
|
823
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
824
|
+
is_root_parser=True,
|
|
825
|
+
)
|
|
826
|
+
parser.epilog = _subcommand_help_hint(parser.prog)
|
|
827
|
+
parser._pydifft_subparsers = {}
|
|
801
828
|
subparsers = parser.add_subparsers(dest="command")
|
|
802
829
|
subparsers.required = True
|
|
803
830
|
for name, spec in _COMMAND_SPECS.items():
|
|
@@ -823,10 +850,18 @@ def build_parser():
|
|
|
823
850
|
action.completer = FilesCompleter(
|
|
824
851
|
allowednames=["*.yaml", "*.yml"]
|
|
825
852
|
)
|
|
853
|
+
if (
|
|
854
|
+
FilesCompleter is not None
|
|
855
|
+
and name == "cpb"
|
|
856
|
+
and action.dest == "filename"
|
|
857
|
+
):
|
|
858
|
+
# Provide Markdown-only completions for continuous pandoc build.
|
|
859
|
+
action.completer = FilesCompleter(allowednames=["*.md"])
|
|
826
860
|
if name == "wgrph" and action.dest == "t":
|
|
827
861
|
# Offer case-insensitive completions for incomplete task names.
|
|
828
862
|
action.completer = wgrph_task_completer
|
|
829
863
|
subparser.set_defaults(_handler=spec["handler"])
|
|
864
|
+
parser._pydifft_subparsers[name] = subparser
|
|
830
865
|
return parser
|
|
831
866
|
|
|
832
867
|
|
|
@@ -859,6 +894,11 @@ def main(argv=None):
|
|
|
859
894
|
if not argv:
|
|
860
895
|
parser.print_help()
|
|
861
896
|
return
|
|
897
|
+
if argv[0] in ("-h", "--help") and len(argv) > 1:
|
|
898
|
+
subcommand = argv[1]
|
|
899
|
+
if subcommand in parser._pydifft_subparsers:
|
|
900
|
+
parser._pydifft_subparsers[subcommand].print_help()
|
|
901
|
+
return
|
|
862
902
|
namespace = parser.parse_args(argv)
|
|
863
903
|
handler = namespace._handler
|
|
864
904
|
handler_kwargs = dict(vars(namespace))
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const SELECTOR_BUBBLE =
|
|
4
4
|
"div.comment-left, div.comment-right, " +
|
|
5
5
|
"span.comment-pin > span.comment-left, span.comment-pin > span.comment-right, " +
|
|
6
|
-
"
|
|
6
|
+
".comment-overlay.comment-left, .comment-overlay.comment-right";
|
|
7
7
|
|
|
8
|
-
const SELECTOR_OVERLAY = "
|
|
8
|
+
const SELECTOR_OVERLAY = ".comment-overlay[data-comment-id]";
|
|
9
9
|
const SELECTOR_ANCHOR = 'span.comment-pin-block[data-comment-id]';
|
|
10
10
|
const SELECTOR_INLINE =
|
|
11
11
|
"span.comment-pin > span.comment-right, span.comment-pin > span.comment-left";
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function positionComments() {
|
|
37
|
+
const useMobileFlow = window.matchMedia("(max-width: 900px)").matches;
|
|
37
38
|
// Inline comment bubbles are absolutely positioned relative to a zero-width
|
|
38
39
|
// pin. We nudge overlapping bubbles so adjacent <comment> tags visibly
|
|
39
40
|
// separate, and we raise the bubbles so the pointer aims at the source point.
|
|
@@ -97,6 +98,15 @@
|
|
|
97
98
|
);
|
|
98
99
|
if (!anchor) return;
|
|
99
100
|
|
|
101
|
+
if (useMobileFlow && ov.classList.contains("comment-margin-left")) {
|
|
102
|
+
// Let CSS place margin-mode comments in-flow in narrow layouts.
|
|
103
|
+
ov.style.position = "";
|
|
104
|
+
ov.style.visibility = "";
|
|
105
|
+
ov.style.left = "";
|
|
106
|
+
ov.style.top = "";
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
100
110
|
// Ensure measurable
|
|
101
111
|
ov.style.position = "absolute";
|
|
102
112
|
ov.style.visibility = "hidden";
|
|
@@ -115,9 +125,15 @@
|
|
|
115
125
|
// Anchor point in document coords
|
|
116
126
|
const ax = a.left + window.scrollX;
|
|
117
127
|
const ay = a.top + window.scrollY;
|
|
128
|
+
const bodyRect = document.body.getBoundingClientRect();
|
|
129
|
+
const bodyLeft = bodyRect.left + window.scrollX;
|
|
118
130
|
|
|
119
131
|
let left;
|
|
120
|
-
if (ov.classList.contains("comment-left")) {
|
|
132
|
+
if (ov.classList.contains("comment-margin-left")) {
|
|
133
|
+
// Margin-mode comments should live entirely in the left margin like
|
|
134
|
+
// floated .comment-left bubbles, not just to the left of the anchor.
|
|
135
|
+
left = bodyLeft - gap - ow;
|
|
136
|
+
} else if (ov.classList.contains("comment-left")) {
|
|
121
137
|
left = ax - gap - ow;
|
|
122
138
|
} else {
|
|
123
139
|
// default right; add configurable shift so the arrow points back to
|
|
@@ -189,6 +189,8 @@ div.csl-indent {
|
|
|
189
189
|
/* Shared visual style */
|
|
190
190
|
div.comment-right,
|
|
191
191
|
div.comment-left,
|
|
192
|
+
.comment-overlay.comment-right,
|
|
193
|
+
.comment-overlay.comment-left,
|
|
192
194
|
span.comment-pin > span.comment-right,
|
|
193
195
|
span.comment-pin > span.comment-left {
|
|
194
196
|
box-sizing: border-box;
|
|
@@ -326,14 +328,29 @@ span.comment-pin > span.comment-left::after {
|
|
|
326
328
|
height: auto;
|
|
327
329
|
}
|
|
328
330
|
|
|
331
|
+
.comment-overlay.comment-margin-left {
|
|
332
|
+
position: static !important;
|
|
333
|
+
float: none !important;
|
|
334
|
+
clear: none !important;
|
|
335
|
+
width: 100% !important;
|
|
336
|
+
max-width: 100% !important;
|
|
337
|
+
display: block !important;
|
|
338
|
+
box-sizing: border-box;
|
|
339
|
+
margin: 0.4em 0 !important;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.comment-inline-break-marker {
|
|
343
|
+
display: inline !important;
|
|
344
|
+
}
|
|
345
|
+
|
|
329
346
|
span.comment-pin > span.comment-right::before,
|
|
330
347
|
span.comment-pin > span.comment-right::after,
|
|
331
348
|
span.comment-pin > span.comment-left::before,
|
|
332
349
|
span.comment-pin > span.comment-left::after,
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
350
|
+
.comment-overlay.comment-right::before,
|
|
351
|
+
.comment-overlay.comment-right::after,
|
|
352
|
+
.comment-overlay.comment-left::before,
|
|
353
|
+
.comment-overlay.comment-left::after {
|
|
337
354
|
display: none;
|
|
338
355
|
}
|
|
339
356
|
}
|
|
@@ -342,7 +359,7 @@ span.comment-pin > span.comment-left::after {
|
|
|
342
359
|
}
|
|
343
360
|
/* --- Overlay block comments emitted by Lua (contain ul/paras/etc) --- */
|
|
344
361
|
|
|
345
|
-
|
|
362
|
+
.comment-overlay {
|
|
346
363
|
position: absolute;
|
|
347
364
|
z-index: 100; /* above text */
|
|
348
365
|
margin: 0 !important; /* do not participate in normal layout */
|
|
@@ -351,13 +368,23 @@ div.comment-overlay {
|
|
|
351
368
|
}
|
|
352
369
|
|
|
353
370
|
/* Ensure overlay uses the same visual bubble styling */
|
|
354
|
-
|
|
355
|
-
|
|
371
|
+
.comment-overlay.comment-right,
|
|
372
|
+
.comment-overlay.comment-left {
|
|
356
373
|
width: 22rem; /* match your current bubble width */
|
|
357
374
|
}
|
|
358
375
|
|
|
376
|
+
/* Margin-mode inline comments should use the narrower left-margin bubble size. */
|
|
377
|
+
.comment-overlay.comment-inline-margin,
|
|
378
|
+
.comment-overlay.comment-margin-left {
|
|
379
|
+
width: 11rem;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.comment-inline-break-marker {
|
|
383
|
+
display: none;
|
|
384
|
+
}
|
|
385
|
+
|
|
359
386
|
/* Pointer triangles for overlay block comments */
|
|
360
|
-
|
|
387
|
+
.comment-overlay.comment-right::before {
|
|
361
388
|
content: "";
|
|
362
389
|
position: absolute;
|
|
363
390
|
left: calc(-1 * var(--comment-left-arrow-width));
|
|
@@ -366,7 +393,7 @@ div.comment-overlay.comment-right::before {
|
|
|
366
393
|
border-style: solid;
|
|
367
394
|
border-color: transparent #5aa0ff transparent transparent;
|
|
368
395
|
}
|
|
369
|
-
|
|
396
|
+
.comment-overlay.comment-right::after {
|
|
370
397
|
content: "";
|
|
371
398
|
position: absolute;
|
|
372
399
|
left: calc(-1 * var(--comment-left-arrow-width) + 1px);
|
|
@@ -375,7 +402,7 @@ div.comment-overlay.comment-right::after {
|
|
|
375
402
|
border-style: solid;
|
|
376
403
|
border-color: transparent #eaf3ff transparent transparent;
|
|
377
404
|
}
|
|
378
|
-
|
|
405
|
+
.comment-overlay.comment-left::before {
|
|
379
406
|
content: "";
|
|
380
407
|
position: absolute;
|
|
381
408
|
right: calc(-1 * var(--comment-arrow-width));
|
|
@@ -384,7 +411,7 @@ div.comment-overlay.comment-left::before {
|
|
|
384
411
|
border-style: solid;
|
|
385
412
|
border-color: transparent transparent transparent #5aa0ff;
|
|
386
413
|
}
|
|
387
|
-
|
|
414
|
+
.comment-overlay.comment-left::after {
|
|
388
415
|
content: "";
|
|
389
416
|
position: absolute;
|
|
390
417
|
right: calc(-1 * var(--comment-arrow-width) + 1px);
|
|
@@ -16,6 +16,7 @@ from .browser_lifecycle import browser_window_is_alive, close_browser_window
|
|
|
16
16
|
|
|
17
17
|
FORWARD_SEARCH_HOST = "127.0.0.1"
|
|
18
18
|
FORWARD_SEARCH_PORT = 51235
|
|
19
|
+
MARGIN_COMMENTS_FILTER_MARKER = "-- PYDIFFTOOLS_SPECIAL_MARGIN_COMMENTS_FILTER"
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def forward_search_listener(stop_event, search_queue):
|
|
@@ -44,7 +45,54 @@ def forward_search_listener(stop_event, search_queue):
|
|
|
44
45
|
server.close()
|
|
45
46
|
|
|
46
47
|
|
|
47
|
-
def
|
|
48
|
+
def _file_contains_text(path, text):
|
|
49
|
+
if not os.path.exists(path):
|
|
50
|
+
return False
|
|
51
|
+
with open(path, encoding="utf-8") as fp:
|
|
52
|
+
return text in fp.read()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _is_margin_comments_filter(path):
|
|
56
|
+
return _file_contains_text(path, MARGIN_COMMENTS_FILTER_MARKER)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _set_comment_filter_mode(source_dir, comments_to_margin):
|
|
60
|
+
package_dir = os.path.dirname(os.path.abspath(__file__))
|
|
61
|
+
active_filter = os.path.join(source_dir, "comment_tags.lua")
|
|
62
|
+
inactive_filter = os.path.join(source_dir, "comment_tags.lua.inactive")
|
|
63
|
+
packaged_default = os.path.join(package_dir, "comment_tags.lua")
|
|
64
|
+
packaged_margin = os.path.join(package_dir, "comment_tags_margin.lua")
|
|
65
|
+
|
|
66
|
+
active_is_margin = _is_margin_comments_filter(active_filter)
|
|
67
|
+
inactive_is_margin = _is_margin_comments_filter(inactive_filter)
|
|
68
|
+
|
|
69
|
+
if comments_to_margin:
|
|
70
|
+
if active_is_margin:
|
|
71
|
+
return
|
|
72
|
+
if os.path.exists(active_filter):
|
|
73
|
+
os.replace(active_filter, inactive_filter)
|
|
74
|
+
shutil.copy2(packaged_margin, active_filter)
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
if active_is_margin:
|
|
78
|
+
if os.path.exists(inactive_filter) and not inactive_is_margin:
|
|
79
|
+
temp_filter = active_filter + ".swap_tmp"
|
|
80
|
+
os.replace(active_filter, temp_filter)
|
|
81
|
+
os.replace(inactive_filter, active_filter)
|
|
82
|
+
os.replace(temp_filter, inactive_filter)
|
|
83
|
+
else:
|
|
84
|
+
os.replace(active_filter, inactive_filter)
|
|
85
|
+
shutil.copy2(packaged_default, active_filter)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
if not os.path.exists(active_filter):
|
|
89
|
+
if os.path.exists(inactive_filter) and not inactive_is_margin:
|
|
90
|
+
os.replace(inactive_filter, active_filter)
|
|
91
|
+
else:
|
|
92
|
+
shutil.copy2(packaged_default, active_filter)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def run_pandoc(filename, html_file, comments_to_margin=False):
|
|
48
96
|
# Pandoc and pandoc-crossref must be installed for HTML rendering.
|
|
49
97
|
if shutil.which("pandoc") is None:
|
|
50
98
|
raise RuntimeError(
|
|
@@ -76,17 +124,14 @@ def run_pandoc(filename, html_file):
|
|
|
76
124
|
markdown_text = fp.read()
|
|
77
125
|
if "<comment>" in markdown_text:
|
|
78
126
|
package_dir = os.path.dirname(os.path.abspath(__file__))
|
|
79
|
-
for asset_name in [
|
|
80
|
-
"comments.css",
|
|
81
|
-
"comment_tags.lua",
|
|
82
|
-
"comment_toggle.js",
|
|
83
|
-
]:
|
|
127
|
+
for asset_name in ["comments.css", "comment_toggle.js"]:
|
|
84
128
|
target_path = os.path.join(source_dir, asset_name)
|
|
85
129
|
if not os.path.exists(target_path):
|
|
86
130
|
shutil.copy2(
|
|
87
131
|
os.path.join(package_dir, asset_name),
|
|
88
132
|
target_path,
|
|
89
133
|
)
|
|
134
|
+
_set_comment_filter_mode(source_dir, comments_to_margin)
|
|
90
135
|
localfiles = {}
|
|
91
136
|
for k in ["csl", "bib"]:
|
|
92
137
|
localfiles[k] = [
|
|
@@ -189,9 +234,10 @@ def run_pandoc(filename, html_file):
|
|
|
189
234
|
|
|
190
235
|
|
|
191
236
|
class Handler(FileSystemEventHandler):
|
|
192
|
-
def __init__(self, filename, observer):
|
|
237
|
+
def __init__(self, filename, observer, comments_to_margin=False):
|
|
193
238
|
self.observer = observer
|
|
194
239
|
self.filename = filename
|
|
240
|
+
self.comments_to_margin = comments_to_margin
|
|
195
241
|
self.html_file = filename.rsplit(".", 1)[0] + ".html"
|
|
196
242
|
self.init_firefox()
|
|
197
243
|
|
|
@@ -201,7 +247,11 @@ class Handler(FileSystemEventHandler):
|
|
|
201
247
|
from selenium import webdriver
|
|
202
248
|
|
|
203
249
|
self.firefox = webdriver.Chrome()
|
|
204
|
-
run_pandoc(
|
|
250
|
+
run_pandoc(
|
|
251
|
+
self.filename,
|
|
252
|
+
self.html_file,
|
|
253
|
+
comments_to_margin=self.comments_to_margin,
|
|
254
|
+
)
|
|
205
255
|
if not os.path.exists(self.html_file):
|
|
206
256
|
print("html doesn't exist")
|
|
207
257
|
self.append_autorefresh()
|
|
@@ -213,7 +263,11 @@ class Handler(FileSystemEventHandler):
|
|
|
213
263
|
if os.path.normpath(
|
|
214
264
|
os.path.abspath(event.src_path)
|
|
215
265
|
) == os.path.normpath(os.path.abspath(self.filename)):
|
|
216
|
-
run_pandoc(
|
|
266
|
+
run_pandoc(
|
|
267
|
+
self.filename,
|
|
268
|
+
self.html_file,
|
|
269
|
+
comments_to_margin=self.comments_to_margin,
|
|
270
|
+
)
|
|
217
271
|
self.append_autorefresh()
|
|
218
272
|
try:
|
|
219
273
|
self.firefox.refresh()
|
|
@@ -238,8 +292,8 @@ class Handler(FileSystemEventHandler):
|
|
|
238
292
|
"div.comment-left, div.comment-right, " +
|
|
239
293
|
"span.comment-pin > span.comment-left, " +
|
|
240
294
|
"span.comment-pin > span.comment-right, " +
|
|
241
|
-
"
|
|
242
|
-
"
|
|
295
|
+
".comment-overlay.comment-left, " +
|
|
296
|
+
".comment-overlay.comment-right";
|
|
243
297
|
|
|
244
298
|
// When the page is about to be unloaded, save the current scroll\
|
|
245
299
|
position
|
|
@@ -337,11 +391,19 @@ position
|
|
|
337
391
|
|
|
338
392
|
@register_command(
|
|
339
393
|
"continuous pandoc build. Like latexmk, but for markdown!",
|
|
340
|
-
help={
|
|
394
|
+
help={
|
|
395
|
+
"filename": "Markdown or TeX file to watch for changes",
|
|
396
|
+
"comments_to_margin": (
|
|
397
|
+
"Temporarily replace comment_tags.lua with the special margin "
|
|
398
|
+
"comments filter for printing."
|
|
399
|
+
),
|
|
400
|
+
},
|
|
341
401
|
)
|
|
342
|
-
def cpb(filename):
|
|
402
|
+
def cpb(filename, comments_to_margin=False):
|
|
343
403
|
observer = Observer()
|
|
344
|
-
event_handler = Handler(
|
|
404
|
+
event_handler = Handler(
|
|
405
|
+
filename, observer, comments_to_margin=comments_to_margin
|
|
406
|
+
)
|
|
345
407
|
search_queue = queue.Queue()
|
|
346
408
|
stop_event = threading.Event()
|
|
347
409
|
socket_thread = threading.Thread(
|
|
@@ -185,6 +185,48 @@ def _svg_shape_bounds(shape, namespace):
|
|
|
185
185
|
return None
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
def _svg_parse_viewbox(svg_root):
|
|
189
|
+
viewbox = svg_root.attrib.get("viewBox")
|
|
190
|
+
if viewbox is None:
|
|
191
|
+
return None
|
|
192
|
+
parts = viewbox.replace(",", " ").split()
|
|
193
|
+
if len(parts) != 4:
|
|
194
|
+
return None
|
|
195
|
+
try:
|
|
196
|
+
return tuple(float(part) for part in parts)
|
|
197
|
+
except ValueError:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _svg_add_canvas_padding(svg_root, padding=8.0):
|
|
202
|
+
# Graphviz emits a tight canvas; add small fixed padding so post-processed
|
|
203
|
+
# outlines and anti-aliased strokes are never clipped at edges.
|
|
204
|
+
viewbox = _svg_parse_viewbox(svg_root)
|
|
205
|
+
if viewbox is None:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
view_x, view_y, view_w, view_h = viewbox
|
|
209
|
+
if view_w <= 0.0 or view_h <= 0.0:
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
new_view_x = view_x - padding
|
|
213
|
+
new_view_y = view_y - padding
|
|
214
|
+
new_view_w = view_w + 2.0 * padding
|
|
215
|
+
new_view_h = view_h + 2.0 * padding
|
|
216
|
+
svg_root.set(
|
|
217
|
+
"viewBox",
|
|
218
|
+
f"{new_view_x:.2f} {new_view_y:.2f} {new_view_w:.2f} {new_view_h:.2f}",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _watch_html(svg_file):
|
|
223
|
+
return (
|
|
224
|
+
"<html><body style='margin:0'><embed id='svg-view'"
|
|
225
|
+
" style='display:block;' type='image/svg+xml'"
|
|
226
|
+
f" src='{svg_file.name}?t={time.time()}'/></body></html>"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
188
230
|
def _svg_expanded_outline(
|
|
189
231
|
shape, namespace, expand, stroke_color, stroke_width
|
|
190
232
|
):
|
|
@@ -249,6 +291,12 @@ def build_graph(
|
|
|
249
291
|
["dot", "-Tsvg", str(dot_file), "-o", str(svg_file)],
|
|
250
292
|
check=True,
|
|
251
293
|
)
|
|
294
|
+
svg_tree = ET.parse(str(svg_file))
|
|
295
|
+
svg_root = svg_tree.getroot()
|
|
296
|
+
namespace = ""
|
|
297
|
+
if svg_root.tag.startswith("{"):
|
|
298
|
+
namespace = svg_root.tag[: svg_root.tag.find("}") + 1]
|
|
299
|
+
|
|
252
300
|
if not order_by_date:
|
|
253
301
|
# In dependency view mode, each node explicitly tagged with
|
|
254
302
|
# ``style: endpoint`` defines a project color. A project includes the
|
|
@@ -282,12 +330,6 @@ def build_graph(
|
|
|
282
330
|
for parent in data["nodes"][ancestor]["parents"]:
|
|
283
331
|
ancestors_to_visit.append(parent)
|
|
284
332
|
|
|
285
|
-
svg_tree = ET.parse(str(svg_file))
|
|
286
|
-
svg_root = svg_tree.getroot()
|
|
287
|
-
namespace = ""
|
|
288
|
-
if svg_root.tag.startswith("{"):
|
|
289
|
-
namespace = svg_root.tag[: svg_root.tag.find("}") + 1]
|
|
290
|
-
|
|
291
333
|
title_to_group = {}
|
|
292
334
|
node_title_to_group = {}
|
|
293
335
|
for group in svg_root.iter(f"{namespace}g"):
|
|
@@ -449,7 +491,8 @@ def build_graph(
|
|
|
449
491
|
for insert_index, outline in reversed(inserts):
|
|
450
492
|
group.insert(insert_index, outline)
|
|
451
493
|
|
|
452
|
-
|
|
494
|
+
_svg_add_canvas_padding(svg_root, padding=24.0)
|
|
495
|
+
svg_tree.write(str(svg_file), encoding="utf-8", xml_declaration=True)
|
|
453
496
|
return data
|
|
454
497
|
|
|
455
498
|
|
|
@@ -565,11 +608,7 @@ def wgrph(yaml, wrap_width=55, d=False, t=None):
|
|
|
565
608
|
# Render the initial graph, optionally restricting to incomplete ancestors
|
|
566
609
|
# of a target task.
|
|
567
610
|
data = build_graph(yaml_file, dot_file, svg_file, wrap_width, d, None, t)
|
|
568
|
-
html_file.write_text(
|
|
569
|
-
"<html><body style='margin:0'><embed id='svg-view'"
|
|
570
|
-
" type='image/svg+xml'"
|
|
571
|
-
f" src='{svg_file.name}?t={time.time()}'/></body></html>"
|
|
572
|
-
)
|
|
611
|
+
html_file.write_text(_watch_html(svg_file))
|
|
573
612
|
options = Options()
|
|
574
613
|
driver = start_chrome(webdriver, options, html_file)
|
|
575
614
|
event_handler = GraphEventHandler(
|
|
@@ -35,9 +35,10 @@ class FakeThread:
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class FakeHandler:
|
|
38
|
-
def __init__(self, filename, observer):
|
|
38
|
+
def __init__(self, filename, observer, comments_to_margin=False, **kwargs):
|
|
39
39
|
self.filename = filename
|
|
40
40
|
self.observer = observer
|
|
41
|
+
self.comments_to_margin = comments_to_margin
|
|
41
42
|
self.firefox = object()
|
|
42
43
|
|
|
43
44
|
def forward_search(self, _search_text):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/__version__.txt
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/.jupyter_cache/global.db
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg
RENAMED
|
File without changes
|
{pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/independent.qmd
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/test_include.qmd
RENAMED
|
File without changes
|
{pydifftools-0.1.22 → pydifftools-0.1.24}/example_notebook/project1/subproject1/tryforerror.qmd
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|