pyDiffTools 0.1.7__tar.gz → 0.1.10__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.7/pyDiffTools.egg-info → pydifftools-0.1.10}/PKG-INFO +1 -1
- {pydifftools-0.1.7 → pydifftools-0.1.10/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/SOURCES.txt +4 -1
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/__init__.py +1 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/command_line.py +98 -21
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/continuous.py +43 -14
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/doc_contents.py +62 -22
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/graph.py +300 -67
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/watch_graph.py +53 -20
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/notebook/fast_build.py +310 -82
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/notebook/tex_to_qmd.py +13 -2
- pydifftools-0.1.10/pydifftools/outline.py +173 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/separate_comments.py +0 -4
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/unseparate_comments.py +3 -6
- pydifftools-0.1.10/pydifftools/update_check.py +31 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pyproject.toml +1 -1
- {pydifftools-0.1.7 → pydifftools-0.1.10}/tests/test_rrng.py +42 -32
- pydifftools-0.1.10/tests/test_tex_to_qmd.py +13 -0
- pydifftools-0.1.10/tests/test_update_check.py +85 -0
- pydifftools-0.1.7/pydifftools/outline.py +0 -81
- {pydifftools-0.1.7 → pydifftools-0.1.10}/LICENSE.md +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/MANIFEST.in +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/README.rst +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/match_spaces.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/wrap_sentences.py +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.7 → pydifftools-0.1.10}/setup.cfg +0 -0
|
@@ -64,6 +64,7 @@ pydifftools/searchacro.py
|
|
|
64
64
|
pydifftools/separate_comments.py
|
|
65
65
|
pydifftools/split_conflict.py
|
|
66
66
|
pydifftools/unseparate_comments.py
|
|
67
|
+
pydifftools/update_check.py
|
|
67
68
|
pydifftools/wrap_sentences.py
|
|
68
69
|
pydifftools/xml2xlsx.vbs
|
|
69
70
|
pydifftools/flowchart/__init__.py
|
|
@@ -73,4 +74,6 @@ pydifftools/flowchart/watch_graph.py
|
|
|
73
74
|
pydifftools/notebook/__init__.py
|
|
74
75
|
pydifftools/notebook/fast_build.py
|
|
75
76
|
pydifftools/notebook/tex_to_qmd.py
|
|
76
|
-
tests/test_rrng.py
|
|
77
|
+
tests/test_rrng.py
|
|
78
|
+
tests/test_tex_to_qmd.py
|
|
79
|
+
tests/test_update_check.py
|
|
@@ -10,11 +10,13 @@ import re
|
|
|
10
10
|
import nbformat
|
|
11
11
|
import difflib
|
|
12
12
|
import shutil
|
|
13
|
+
import importlib.util
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from . import (
|
|
15
16
|
match_spaces,
|
|
16
17
|
split_conflict,
|
|
17
18
|
outline,
|
|
19
|
+
update_check,
|
|
18
20
|
)
|
|
19
21
|
from .continuous import cpb
|
|
20
22
|
from .wrap_sentences import wr as wrap_sentences_wr # registers wrap command
|
|
@@ -25,12 +27,31 @@ from .copy_files import copy_image_files
|
|
|
25
27
|
from .searchacro import replace_acros
|
|
26
28
|
from .rearrange_tex import run as rearrange_tex_run
|
|
27
29
|
from .flowchart.watch_graph import wgrph
|
|
30
|
+
from .flowchart.graph import load_graph_yaml
|
|
28
31
|
from .notebook.tex_to_qmd import tex2qmd
|
|
29
32
|
from .notebook.fast_build import qmdb, qmdinit
|
|
30
33
|
|
|
31
|
-
|
|
32
34
|
from .command_registry import _COMMAND_SPECS, register_command
|
|
33
35
|
|
|
36
|
+
_ARGCOMPLETE_SPEC = importlib.util.find_spec("argcomplete")
|
|
37
|
+
if (
|
|
38
|
+
_ARGCOMPLETE_SPEC is not None
|
|
39
|
+
and _ARGCOMPLETE_SPEC.submodule_search_locations is not None
|
|
40
|
+
):
|
|
41
|
+
_ARGCOMPLETE_COMPLETERS_SPEC = importlib.util.find_spec(
|
|
42
|
+
"argcomplete.completers"
|
|
43
|
+
)
|
|
44
|
+
else:
|
|
45
|
+
_ARGCOMPLETE_COMPLETERS_SPEC = None
|
|
46
|
+
if _ARGCOMPLETE_SPEC is not None:
|
|
47
|
+
import argcomplete
|
|
48
|
+
else:
|
|
49
|
+
argcomplete = None
|
|
50
|
+
if _ARGCOMPLETE_COMPLETERS_SPEC is not None:
|
|
51
|
+
from argcomplete.completers import FilesCompleter
|
|
52
|
+
else:
|
|
53
|
+
FilesCompleter = None
|
|
54
|
+
|
|
34
55
|
|
|
35
56
|
def printed_exec(cmd):
|
|
36
57
|
print("about to execute:\n", cmd)
|
|
@@ -57,6 +78,37 @@ def get_data(path):
|
|
|
57
78
|
return os.path.join(_ROOT, path)
|
|
58
79
|
|
|
59
80
|
|
|
81
|
+
def wgrph_task_completer(prefix, parsed_args, **kwargs):
|
|
82
|
+
# Provide case-insensitive task name completions for wgrph -t.
|
|
83
|
+
if parsed_args is None or not hasattr(parsed_args, "yaml"):
|
|
84
|
+
return []
|
|
85
|
+
yaml_path = Path(parsed_args.yaml)
|
|
86
|
+
if not yaml_path.exists():
|
|
87
|
+
return []
|
|
88
|
+
try:
|
|
89
|
+
data = load_graph_yaml(str(yaml_path))
|
|
90
|
+
except Exception:
|
|
91
|
+
return []
|
|
92
|
+
if "nodes" not in data:
|
|
93
|
+
return []
|
|
94
|
+
prefix_lower = prefix.lower()
|
|
95
|
+
matches = []
|
|
96
|
+
for name in data["nodes"]:
|
|
97
|
+
if (
|
|
98
|
+
"style" in data["nodes"][name]
|
|
99
|
+
and data["nodes"][name]["style"] == "completed"
|
|
100
|
+
):
|
|
101
|
+
continue
|
|
102
|
+
if name.lower().startswith(prefix_lower):
|
|
103
|
+
# Preserve case-insensitive matches even when the typed prefix
|
|
104
|
+
# doesn't match case so argcomplete still accepts the suggestion.
|
|
105
|
+
if name.startswith(prefix):
|
|
106
|
+
matches.append(name)
|
|
107
|
+
else:
|
|
108
|
+
matches.append(prefix + name[len(prefix) :])
|
|
109
|
+
return matches
|
|
110
|
+
|
|
111
|
+
|
|
60
112
|
def recursive_include_search(directory, basename, does_it_input):
|
|
61
113
|
with open(
|
|
62
114
|
os.path.join(directory, basename + ".tex"), "r", encoding="utf-8"
|
|
@@ -119,7 +171,8 @@ def look_for_pdf(directory, origbasename):
|
|
|
119
171
|
def nb2py(arguments):
|
|
120
172
|
assert arguments[0].endswith(".ipynb"), (
|
|
121
173
|
"this is supposed to be called with a .ipynb file argument! (arguments"
|
|
122
|
-
" are %s)"
|
|
174
|
+
" are %s)"
|
|
175
|
+
% repr(arguments)
|
|
123
176
|
)
|
|
124
177
|
nb = nbformat.read(arguments[0], nbformat.NO_CONVERT)
|
|
125
178
|
last_was_markdown = False
|
|
@@ -176,7 +229,8 @@ def py2nb(arguments):
|
|
|
176
229
|
assert len(arguments) == 1, "py2nb should only be called with one argument"
|
|
177
230
|
assert arguments[0].endswith(".py"), (
|
|
178
231
|
"this is supposed to be called with a .py file argument! (arguments"
|
|
179
|
-
" are %s)"
|
|
232
|
+
" are %s)"
|
|
233
|
+
% repr(arguments)
|
|
180
234
|
)
|
|
181
235
|
with open(arguments[0], encoding="utf-8") as fpin:
|
|
182
236
|
text = fpin.read()
|
|
@@ -232,15 +286,13 @@ def py2nb(arguments):
|
|
|
232
286
|
nbook = nbformat.v3.reads_py(text)
|
|
233
287
|
|
|
234
288
|
nbook = nbformat.v4.upgrade(nbook) # Upgrade nbformat.v3 to nbformat.v4
|
|
235
|
-
nbook.metadata.update(
|
|
236
|
-
{
|
|
237
|
-
"
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
"language": "python",
|
|
241
|
-
}
|
|
289
|
+
nbook.metadata.update({
|
|
290
|
+
"kernelspec": {
|
|
291
|
+
"name": "Python [Anaconda2]",
|
|
292
|
+
"display_name": "Python [Anaconda2]",
|
|
293
|
+
"language": "python",
|
|
242
294
|
}
|
|
243
|
-
)
|
|
295
|
+
})
|
|
244
296
|
|
|
245
297
|
jsonform = nbformat.v4.writes(nbook) + "\n"
|
|
246
298
|
with open(
|
|
@@ -687,15 +739,6 @@ def pmd(arguments):
|
|
|
687
739
|
p1.wait()
|
|
688
740
|
|
|
689
741
|
|
|
690
|
-
@register_command(
|
|
691
|
-
"Save tex file as outline, with filename_outline.pickle storing content"
|
|
692
|
-
" and filename_outline.md giving outline."
|
|
693
|
-
)
|
|
694
|
-
def xo(arguments):
|
|
695
|
-
assert len(arguments) == 1
|
|
696
|
-
outline.extract_outline(arguments[0])
|
|
697
|
-
|
|
698
|
-
|
|
699
742
|
def build_parser():
|
|
700
743
|
parser = argparse.ArgumentParser()
|
|
701
744
|
subparsers = parser.add_subparsers(dest="command")
|
|
@@ -713,7 +756,19 @@ def build_parser():
|
|
|
713
756
|
for argument in arguments:
|
|
714
757
|
flags = argument["flags"]
|
|
715
758
|
kwargs = dict(argument["kwargs"])
|
|
716
|
-
subparser.add_argument(*flags, **kwargs)
|
|
759
|
+
action = subparser.add_argument(*flags, **kwargs)
|
|
760
|
+
if (
|
|
761
|
+
FilesCompleter is not None
|
|
762
|
+
and name == "wgrph"
|
|
763
|
+
and action.dest == "yaml"
|
|
764
|
+
):
|
|
765
|
+
# Provide YAML-only completions for the flowchart watcher.
|
|
766
|
+
action.completer = FilesCompleter(
|
|
767
|
+
allowednames=["*.yaml", "*.yml"]
|
|
768
|
+
)
|
|
769
|
+
if name == "wgrph" and action.dest == "t":
|
|
770
|
+
# Offer case-insensitive completions for incomplete task names.
|
|
771
|
+
action.completer = wgrph_task_completer
|
|
717
772
|
subparser.set_defaults(_handler=spec["handler"])
|
|
718
773
|
return parser
|
|
719
774
|
|
|
@@ -721,7 +776,29 @@ def build_parser():
|
|
|
721
776
|
def main(argv=None):
|
|
722
777
|
if argv is None:
|
|
723
778
|
argv = sys.argv[1:]
|
|
779
|
+
# Run the PyPI update check once per UTC day so users see a notice but
|
|
780
|
+
# startup stays fast when offline. The date is stored in the
|
|
781
|
+
# PYDIFFTOOLS_UPDATE_CHECK_LAST_RAN_UTC_DATE environment variable.
|
|
782
|
+
today = time.strftime("%Y-%m-%d", time.gmtime())
|
|
783
|
+
already_checked_today = (
|
|
784
|
+
"PYDIFFTOOLS_UPDATE_CHECK_LAST_RAN_UTC_DATE" in os.environ
|
|
785
|
+
and os.environ["PYDIFFTOOLS_UPDATE_CHECK_LAST_RAN_UTC_DATE"] == today
|
|
786
|
+
)
|
|
787
|
+
if not already_checked_today:
|
|
788
|
+
os.environ["PYDIFFTOOLS_UPDATE_CHECK_LAST_RAN_UTC_DATE"] = today
|
|
789
|
+
current_version, latest_version, is_outdated = (
|
|
790
|
+
update_check.check_update("pyDiffTools")
|
|
791
|
+
)
|
|
792
|
+
if is_outdated and latest_version is not None:
|
|
793
|
+
print(
|
|
794
|
+
"A new pyDiffTools version is available "
|
|
795
|
+
f"(installed {current_version}, latest {latest_version}).",
|
|
796
|
+
file=sys.stderr,
|
|
797
|
+
)
|
|
724
798
|
parser = build_parser()
|
|
799
|
+
if argcomplete is not None:
|
|
800
|
+
# Enable argcomplete integration when the dependency is available.
|
|
801
|
+
argcomplete.autocomplete(parser)
|
|
725
802
|
if not argv:
|
|
726
803
|
parser.print_help()
|
|
727
804
|
return
|
|
@@ -5,14 +5,25 @@ import subprocess
|
|
|
5
5
|
import sys
|
|
6
6
|
import os
|
|
7
7
|
import re
|
|
8
|
-
import
|
|
9
|
-
from selenium import webdriver
|
|
8
|
+
import shutil
|
|
10
9
|
from watchdog.events import FileSystemEventHandler
|
|
11
10
|
from watchdog.observers import Observer
|
|
12
11
|
from .command_registry import register_command
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def run_pandoc(filename, html_file):
|
|
15
|
+
# Pandoc and pandoc-crossref must be installed for HTML rendering.
|
|
16
|
+
if shutil.which("pandoc") is None:
|
|
17
|
+
raise RuntimeError(
|
|
18
|
+
"Pandoc must be installed to render HTML output. Install pandoc"
|
|
19
|
+
" so the 'pandoc' executable is available on your PATH."
|
|
20
|
+
)
|
|
21
|
+
if shutil.which("pandoc-crossref") is None:
|
|
22
|
+
raise RuntimeError(
|
|
23
|
+
"Pandoc-crossref must be installed to render HTML output. Install"
|
|
24
|
+
" pandoc-crossref so the 'pandoc-crossref' executable is available"
|
|
25
|
+
" on your PATH."
|
|
26
|
+
)
|
|
16
27
|
if os.path.exists("MathJax-3.1.2"):
|
|
17
28
|
has_local_jax = True
|
|
18
29
|
else:
|
|
@@ -34,7 +45,8 @@ def run_pandoc(filename, html_file):
|
|
|
34
45
|
else:
|
|
35
46
|
raise ValueError(
|
|
36
47
|
f"You have more than one (or no) {k} file in this directory!"
|
|
37
|
-
" Get rid of all but one! of "
|
|
48
|
+
" Get rid of all but one! of "
|
|
49
|
+
+ "and".join(localfiles[k])
|
|
38
50
|
)
|
|
39
51
|
command = [
|
|
40
52
|
"pandoc",
|
|
@@ -71,6 +83,21 @@ def run_pandoc(filename, html_file):
|
|
|
71
83
|
with open(html_file, "w", encoding="utf-8") as fp:
|
|
72
84
|
fp.write(text)
|
|
73
85
|
# }}}
|
|
86
|
+
with open(html_file, encoding="utf-8") as fp:
|
|
87
|
+
text = fp.read()
|
|
88
|
+
style_block = (
|
|
89
|
+
'\n<style id="pydifftools-hide-low-headers">\n'
|
|
90
|
+
"h5, h6 { display: none; }\n"
|
|
91
|
+
"</style>\n"
|
|
92
|
+
)
|
|
93
|
+
if style_block not in text:
|
|
94
|
+
# hide organizational headers while keeping higher levels visible
|
|
95
|
+
if "</head>" in text:
|
|
96
|
+
text = text.replace("</head>", style_block + "</head>", 1)
|
|
97
|
+
else:
|
|
98
|
+
text = style_block + text
|
|
99
|
+
with open(html_file, "w", encoding="utf-8") as fp:
|
|
100
|
+
fp.write(text)
|
|
74
101
|
return
|
|
75
102
|
|
|
76
103
|
|
|
@@ -82,6 +109,10 @@ class Handler(FileSystemEventHandler):
|
|
|
82
109
|
self.init_firefox()
|
|
83
110
|
|
|
84
111
|
def init_firefox(self):
|
|
112
|
+
# apparently, selenium breaks stdin/out for tests, so it must be
|
|
113
|
+
# imported here
|
|
114
|
+
from selenium import webdriver
|
|
115
|
+
|
|
85
116
|
self.firefox = webdriver.Chrome()
|
|
86
117
|
run_pandoc(self.filename, self.html_file)
|
|
87
118
|
if not os.path.exists(self.html_file):
|
|
@@ -90,6 +121,8 @@ class Handler(FileSystemEventHandler):
|
|
|
90
121
|
self.firefox.get("file://" + os.path.abspath(self.html_file))
|
|
91
122
|
|
|
92
123
|
def on_modified(self, event):
|
|
124
|
+
from selenium.common.exceptions import WebDriverException
|
|
125
|
+
|
|
93
126
|
if os.path.normpath(
|
|
94
127
|
os.path.abspath(event.src_path)
|
|
95
128
|
) == os.path.normpath(os.path.abspath(self.filename)):
|
|
@@ -97,7 +130,7 @@ class Handler(FileSystemEventHandler):
|
|
|
97
130
|
self.append_autorefresh()
|
|
98
131
|
try:
|
|
99
132
|
self.firefox.refresh()
|
|
100
|
-
except
|
|
133
|
+
except WebDriverException:
|
|
101
134
|
print(
|
|
102
135
|
"I'm quitting!! You probably suspended the computer, which"
|
|
103
136
|
" seems to freak selenium out. Just restart"
|
|
@@ -136,7 +169,11 @@ position
|
|
|
136
169
|
fp.write(all_data)
|
|
137
170
|
|
|
138
171
|
|
|
139
|
-
|
|
172
|
+
@register_command(
|
|
173
|
+
"continuous pandoc build. Like latexmk, but for markdown!",
|
|
174
|
+
help={"filename": "Markdown or TeX file to watch for changes"},
|
|
175
|
+
)
|
|
176
|
+
def cpb(filename):
|
|
140
177
|
observer = Observer()
|
|
141
178
|
event_handler = Handler(filename, observer)
|
|
142
179
|
observer.schedule(event_handler, path=".", recursive=False)
|
|
@@ -151,15 +188,7 @@ def watch(filename):
|
|
|
151
188
|
observer.join()
|
|
152
189
|
|
|
153
190
|
|
|
154
|
-
@register_command(
|
|
155
|
-
"continuous pandoc build. Like latexmk, but for markdown!",
|
|
156
|
-
help={"filename": "Markdown or TeX file to watch for changes"},
|
|
157
|
-
)
|
|
158
|
-
def cpb(filename):
|
|
159
|
-
watch(filename)
|
|
160
|
-
|
|
161
|
-
|
|
162
191
|
if __name__ == "__main__":
|
|
163
192
|
filename = sys.argv[1]
|
|
164
|
-
|
|
193
|
+
cpb(filename)
|
|
165
194
|
# Open the HTML file in the default web browser
|
|
@@ -3,21 +3,41 @@ from fuzzywuzzy import process
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class doc_contents_class(object):
|
|
6
|
-
|
|
7
|
-
"section": "",
|
|
8
|
-
"subsection": "\t",
|
|
9
|
-
"subsubsection": 2 * "\t",
|
|
10
|
-
"paragraph": 3 * "\t",
|
|
11
|
-
}
|
|
12
|
-
inv_prefix = {v: k for k, v in prefix.items()}
|
|
13
|
-
|
|
14
|
-
def __init__(self):
|
|
6
|
+
def __init__(self, format_type="latex"):
|
|
15
7
|
self.contents = OrderedDict()
|
|
16
8
|
self.contents["header"] = ""
|
|
17
9
|
self.types = {}
|
|
18
10
|
self.types["header"] = "header"
|
|
19
11
|
self._reordering_started = False
|
|
20
12
|
self._aliases = {}
|
|
13
|
+
self._processed_titles = []
|
|
14
|
+
self.set_format(format_type)
|
|
15
|
+
|
|
16
|
+
def set_format(self, format_type):
|
|
17
|
+
if format_type == "markdown":
|
|
18
|
+
# markdown levels go deeper, so include subparagraph mapping
|
|
19
|
+
self.level_numbers = {
|
|
20
|
+
"section": 1,
|
|
21
|
+
"subsection": 2,
|
|
22
|
+
"subsubsection": 3,
|
|
23
|
+
"paragraph": 4,
|
|
24
|
+
"subparagraph": 5,
|
|
25
|
+
}
|
|
26
|
+
else:
|
|
27
|
+
# default to latex behavior
|
|
28
|
+
self.level_numbers = {
|
|
29
|
+
"section": 1,
|
|
30
|
+
"subsection": 2,
|
|
31
|
+
"subsubsection": 3,
|
|
32
|
+
"paragraph": 4,
|
|
33
|
+
"subparagraph": 5,
|
|
34
|
+
}
|
|
35
|
+
# map indentation back to section type for outline parsing
|
|
36
|
+
self.inv_prefix = {
|
|
37
|
+
(level - 1) * "\t": section
|
|
38
|
+
for section, level in self.level_numbers.items()
|
|
39
|
+
}
|
|
40
|
+
self.format_type = format_type
|
|
21
41
|
|
|
22
42
|
def start_sec(self, thistype, thistitle):
|
|
23
43
|
assert thistitle not in self.contents.keys(), (
|
|
@@ -31,8 +51,13 @@ class doc_contents_class(object):
|
|
|
31
51
|
"set the info from a pickle"
|
|
32
52
|
self.contents = d["contents"]
|
|
33
53
|
self.types = d["types"]
|
|
34
|
-
self._aliases = {}
|
|
54
|
+
self._aliases = {} # doesn't exist, but still needed
|
|
35
55
|
self._reordering_started = False
|
|
56
|
+
self._processed_titles = []
|
|
57
|
+
if "format_type" in d:
|
|
58
|
+
self.set_format(d["format_type"])
|
|
59
|
+
else:
|
|
60
|
+
self.set_format("latex")
|
|
36
61
|
return
|
|
37
62
|
|
|
38
63
|
def __getstate__(self):
|
|
@@ -40,6 +65,7 @@ class doc_contents_class(object):
|
|
|
40
65
|
return {
|
|
41
66
|
"contents": self.contents,
|
|
42
67
|
"types": self.types,
|
|
68
|
+
"format_type": self.format_type,
|
|
43
69
|
}
|
|
44
70
|
|
|
45
71
|
def __iadd__(self, value):
|
|
@@ -48,16 +74,23 @@ class doc_contents_class(object):
|
|
|
48
74
|
|
|
49
75
|
def __str__(self):
|
|
50
76
|
if len(self._processed_titles) > 0:
|
|
51
|
-
raise ValueError(
|
|
52
|
-
|
|
53
|
-
|
|
77
|
+
raise ValueError(
|
|
78
|
+
"the following section"
|
|
79
|
+
" titles were not utilized -- this program is"
|
|
80
|
+
" for reordering, not dropping!:\n"
|
|
81
|
+
+ str(self._processed_titles)
|
|
82
|
+
)
|
|
54
83
|
retval = ""
|
|
55
84
|
for j in self.contents.keys():
|
|
56
85
|
if self.types[j] != "header":
|
|
57
86
|
new_name = j
|
|
58
87
|
if j in self._aliases.keys():
|
|
59
88
|
new_name = self._aliases[j]
|
|
60
|
-
|
|
89
|
+
if self.format_type == "markdown":
|
|
90
|
+
retval += "#" * self.level_numbers[self.types[j]]
|
|
91
|
+
retval += f" {new_name}\n\n"
|
|
92
|
+
else:
|
|
93
|
+
retval += f"\\{self.types[j]}{{{new_name}}}"
|
|
61
94
|
retval += f"{self.contents[j]}"
|
|
62
95
|
return retval
|
|
63
96
|
|
|
@@ -66,15 +99,17 @@ class doc_contents_class(object):
|
|
|
66
99
|
retval = []
|
|
67
100
|
for j in self.contents.keys():
|
|
68
101
|
if self.types[j] != "header":
|
|
69
|
-
|
|
70
|
-
|
|
102
|
+
indent = (self.level_numbers[self.types[j]] - 1) * "\t"
|
|
103
|
+
thistitle = (indent + "\t").join(j.split("\n"))
|
|
104
|
+
retval.append(indent + "*\t" + thistitle)
|
|
71
105
|
self._reordering_started = False
|
|
72
106
|
return "\n".join(retval)
|
|
73
107
|
|
|
74
108
|
def outline_in_order(self, thisline):
|
|
75
109
|
if not self._reordering_started:
|
|
76
|
-
self._processed_titles = [
|
|
77
|
-
|
|
110
|
+
self._processed_titles = [
|
|
111
|
+
j for j in self.contents.keys() if self.types[j] != "header"
|
|
112
|
+
]
|
|
78
113
|
self._reordering_started = True
|
|
79
114
|
ilevel = 0
|
|
80
115
|
spacelevel = 0
|
|
@@ -95,10 +130,15 @@ class doc_contents_class(object):
|
|
|
95
130
|
if not hitmarker:
|
|
96
131
|
raise ValueError("somehow, there wasn't a * marker!")
|
|
97
132
|
if title not in self.contents.keys():
|
|
98
|
-
best_match, match_quality = process.extractOne(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
133
|
+
best_match, match_quality = process.extractOne(
|
|
134
|
+
title, self.contents.keys()
|
|
135
|
+
)
|
|
136
|
+
yesorno = input(
|
|
137
|
+
f"didn't find\n\t{title}\nin keys, maybe you"
|
|
138
|
+
f" want\n\t{best_match}\nsay y or n"
|
|
139
|
+
)
|
|
140
|
+
if yesorno == "y":
|
|
141
|
+
self._aliases[best_match] = title # will be replaced later
|
|
102
142
|
title = best_match
|
|
103
143
|
else:
|
|
104
144
|
raise ValueError("problem with replacement")
|