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.
Files changed (82) hide show
  1. {pydifftools-0.1.7/pyDiffTools.egg-info → pydifftools-0.1.10}/PKG-INFO +1 -1
  2. {pydifftools-0.1.7 → pydifftools-0.1.10/pyDiffTools.egg-info}/PKG-INFO +1 -1
  3. {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/SOURCES.txt +4 -1
  4. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/__init__.py +1 -0
  5. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/command_line.py +98 -21
  6. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/continuous.py +43 -14
  7. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/doc_contents.py +62 -22
  8. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/graph.py +300 -67
  9. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/watch_graph.py +53 -20
  10. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/notebook/fast_build.py +310 -82
  11. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/notebook/tex_to_qmd.py +13 -2
  12. pydifftools-0.1.10/pydifftools/outline.py +173 -0
  13. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/separate_comments.py +0 -4
  14. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/unseparate_comments.py +3 -6
  15. pydifftools-0.1.10/pydifftools/update_check.py +31 -0
  16. {pydifftools-0.1.7 → pydifftools-0.1.10}/pyproject.toml +1 -1
  17. {pydifftools-0.1.7 → pydifftools-0.1.10}/tests/test_rrng.py +42 -32
  18. pydifftools-0.1.10/tests/test_tex_to_qmd.py +13 -0
  19. pydifftools-0.1.10/tests/test_update_check.py +85 -0
  20. pydifftools-0.1.7/pydifftools/outline.py +0 -81
  21. {pydifftools-0.1.7 → pydifftools-0.1.10}/LICENSE.md +0 -0
  22. {pydifftools-0.1.7 → pydifftools-0.1.10}/MANIFEST.in +0 -0
  23. {pydifftools-0.1.7 → pydifftools-0.1.10}/README.rst +0 -0
  24. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/_quarto.yml +0 -0
  25. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
  26. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
  27. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
  28. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
  29. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
  30. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
  31. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
  32. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
  33. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
  34. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
  35. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
  36. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
  37. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
  38. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
  39. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
  40. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
  41. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
  42. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
  43. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
  44. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
  45. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
  46. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/.jupyter_cache/global.db +0 -0
  47. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/example.qmd +0 -0
  48. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/example.tex +0 -0
  49. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/index.qmd +0 -0
  50. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
  51. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
  52. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
  53. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
  54. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/independent.qmd +0 -0
  55. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/index.qmd +0 -0
  56. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/tasks.qmd +0 -0
  57. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/test_include.qmd +0 -0
  58. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
  59. {pydifftools-0.1.7 → pydifftools-0.1.10}/example_notebook/project1/test_include.qmd +0 -0
  60. {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/dependency_links.txt +0 -0
  61. {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/entry_points.txt +0 -0
  62. {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/requires.txt +0 -0
  63. {pydifftools-0.1.7 → pydifftools-0.1.10}/pyDiffTools.egg-info/top_level.txt +0 -0
  64. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/check_numbers.py +0 -0
  65. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/command_registry.py +0 -0
  66. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/comment_functions.py +0 -0
  67. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/copy_files.py +0 -0
  68. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/diff-doc.js +0 -0
  69. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/__init__.py +0 -0
  70. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/flowchart/dot_to_yaml.py +0 -0
  71. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/html_comments.py +0 -0
  72. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/html_uncomments.py +0 -0
  73. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/match_spaces.py +0 -0
  74. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/notebook/__init__.py +0 -0
  75. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/onewordify.py +0 -0
  76. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/onewordify_undo.py +0 -0
  77. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/rearrange_tex.py +0 -0
  78. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/searchacro.py +0 -0
  79. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/split_conflict.py +0 -0
  80. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/wrap_sentences.py +0 -0
  81. {pydifftools-0.1.7 → pydifftools-0.1.10}/pydifftools/xml2xlsx.vbs +0 -0
  82. {pydifftools-0.1.7 → pydifftools-0.1.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDiffTools
3
- Version: 0.1.7
3
+ Version: 0.1.10
4
4
  Summary: Diff tools
5
5
  Author: J M Franck
6
6
  License: Copyright (c) 2015, jmfranck
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDiffTools
3
- Version: 0.1.7
3
+ Version: 0.1.10
4
4
  Summary: Diff tools
5
5
  Author: J M Franck
6
6
  License: Copyright (c) 2015, jmfranck
@@ -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
@@ -7,4 +7,5 @@ __all__ = [
7
7
  "wrap_sentences",
8
8
  "rearrange_tex",
9
9
  "outline",
10
+ "update_check",
10
11
  ]
@@ -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)" % repr(arguments)
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)" % repr(arguments)
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
- "kernelspec": {
238
- "name": "Python [Anaconda2]",
239
- "display_name": "Python [Anaconda2]",
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 selenium
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 " + "and".join(localfiles[k])
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 selenium.common.exceptions.WebDriverException:
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
- def watch(filename):
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
- watch(filename)
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
- prefix = {
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 = {} # doesn't exist, but still needed
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("the following section"
52
- " titles were not utilized -- this program is"
53
- " for reordering, not dropping!:\n"+str(self._processed_titles))
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
- retval += f"\\{self.types[j]}{{{new_name}}}"
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
- thistitle = (self.prefix[self.types[j]] + "\t").join(j.split("\n"))
70
- retval.append(self.prefix[self.types[j]] + "*\t" + thistitle)
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 = [j for j in self.contents.keys()
77
- if self.types[j] != 'header']
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(title, self.contents.keys())
99
- yesorno = input(f"didn't find\n\t{title}\nin keys, maybe you want\n\t{best_match}\nsay y or n")
100
- if yesorno == 'y':
101
- self._aliases[best_match] = title # will be replaced later
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")