scitex 2.10.3__py3-none-any.whl → 2.13.0__py3-none-any.whl

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 (504) hide show
  1. scitex/__init__.py +1 -4
  2. scitex/__main__.py +24 -5
  3. scitex/__version__.py +1 -1
  4. scitex/_install_guide.py +14 -2
  5. scitex/_optional_deps.py +33 -0
  6. scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
  7. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
  8. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
  9. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
  10. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
  11. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
  12. scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
  13. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
  14. scitex/ai/plt/_plot_feature_importance.py +1 -1
  15. scitex/ai/plt/_plot_learning_curve.py +1 -1
  16. scitex/ai/plt/_plot_optuna_study.py +1 -1
  17. scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
  18. scitex/ai/plt/_plot_roc_curve.py +1 -1
  19. scitex/ai/plt/_stx_conf_mat.py +1 -1
  20. scitex/ai/training/_LearningCurveLogger.py +1 -1
  21. scitex/audio/mcp_server.py +38 -8
  22. scitex/bridge/_figrecipe.py +1 -1
  23. scitex/bridge/_helpers.py +1 -1
  24. scitex/bridge/_plt_vis.py +1 -1
  25. scitex/bridge/_stats_plt.py +1 -1
  26. scitex/bridge/_stats_vis.py +2 -2
  27. scitex/browser/automation/CookieHandler.py +1 -1
  28. scitex/browser/core/BrowserMixin.py +1 -1
  29. scitex/browser/core/ChromeProfileManager.py +1 -1
  30. scitex/browser/debugging/_browser_logger.py +1 -1
  31. scitex/browser/debugging/_highlight_element.py +1 -1
  32. scitex/browser/debugging/_show_grid.py +1 -1
  33. scitex/browser/interaction/click_center.py +1 -1
  34. scitex/browser/interaction/click_with_fallbacks.py +1 -1
  35. scitex/browser/interaction/close_popups.py +1 -1
  36. scitex/browser/interaction/fill_with_fallbacks.py +1 -1
  37. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
  38. scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
  39. scitex/browser/stealth/HumanBehavior.py +1 -1
  40. scitex/browser/stealth/StealthManager.py +1 -1
  41. scitex/{fig → canvas}/__init__.py +84 -96
  42. scitex/canvas/_mcp_handlers.py +372 -0
  43. scitex/canvas/_mcp_tool_schemas.py +219 -0
  44. scitex/{fig → canvas}/backend/_parser.py +1 -1
  45. scitex/{fig → canvas}/canvas.py +13 -14
  46. scitex/{fts/_fig/_editor → canvas/editor}/_defaults.py +2 -2
  47. scitex/{fig → canvas}/editor/edit/__init__.py +11 -14
  48. scitex/{fig → canvas}/editor/edit/bundle_resolver.py +56 -48
  49. scitex/{fig → canvas}/editor/edit/editor_launcher.py +79 -26
  50. scitex/{fts/_fig/_editor/_cui/_panel_loader.py → canvas/editor/edit/panel_loader.py} +8 -8
  51. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_bbox.py +2 -1
  52. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_core.py +84 -84
  53. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_renderer.py +7 -6
  54. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/static/css/features/canvas.css +2 -2
  55. scitex/{fig → canvas}/editor/flask_editor/static/css/features/panel-grid.css +1 -1
  56. scitex/{fig → canvas}/editor/flask_editor/static/js/core/api.js +3 -4
  57. scitex/{fig → canvas}/editor/flask_editor/static/js/editor/preview.js +5 -5
  58. scitex/{fig → canvas}/editor/flask_editor/templates/_html.py +3 -3
  59. scitex/{fig → canvas}/editor/flask_editor/templates/_scripts.py +10 -10
  60. scitex/{fig → canvas}/editor/flask_editor/templates/_styles.py +3 -3
  61. scitex/{fig → canvas}/io/__init__.py +32 -38
  62. scitex/{fig → canvas}/io/_bundle.py +217 -154
  63. scitex/{fig → canvas}/io/_canvas.py +1 -1
  64. scitex/{fig → canvas}/io/_data.py +1 -1
  65. scitex/{fig → canvas}/io/_export.py +1 -1
  66. scitex/{fig → canvas}/io/_load.py +1 -1
  67. scitex/{fig → canvas}/io/_panel.py +1 -1
  68. scitex/{fig → canvas}/io/_save.py +1 -1
  69. scitex/canvas/mcp_server.py +151 -0
  70. scitex/{fig → canvas}/model/__init__.py +1 -1
  71. scitex/{fig → canvas}/model/_annotations.py +1 -1
  72. scitex/{fig → canvas}/model/_axes.py +1 -1
  73. scitex/{fig → canvas}/model/_figure.py +1 -1
  74. scitex/{fig → canvas}/model/_guides.py +1 -1
  75. scitex/{fig → canvas}/model/_plot.py +1 -1
  76. scitex/{fig → canvas}/model/_styles.py +1 -1
  77. scitex/{fig → canvas}/utils/__init__.py +1 -1
  78. scitex/capture/mcp_server.py +41 -12
  79. scitex/cli/audio.py +233 -0
  80. scitex/cli/capture.py +307 -0
  81. scitex/cli/convert.py +10 -6
  82. scitex/cli/main.py +27 -4
  83. scitex/cli/repro.py +233 -0
  84. scitex/cli/resource.py +240 -0
  85. scitex/cli/stats.py +325 -0
  86. scitex/cli/template.py +236 -0
  87. scitex/cli/tex.py +286 -0
  88. scitex/cli/web.py +11 -12
  89. scitex/dev/__init__.py +3 -0
  90. scitex/dev/_pyproject.py +405 -0
  91. scitex/dev/plt/__init__.py +2 -2
  92. scitex/dev/plt/mpl/get_dir_ax.py +1 -1
  93. scitex/dev/plt/mpl/get_signatures.py +1 -1
  94. scitex/dev/plt/mpl/get_signatures_details.py +1 -1
  95. scitex/diagram/README.md +7 -7
  96. scitex/diagram/_mcp_handlers.py +400 -0
  97. scitex/diagram/_mcp_tool_schemas.py +157 -0
  98. scitex/diagram/mcp_server.py +151 -0
  99. scitex/dsp/_demo_sig.py +51 -5
  100. scitex/dsp/_mne.py +13 -2
  101. scitex/dsp/_modulation_index.py +15 -3
  102. scitex/dsp/_pac.py +23 -5
  103. scitex/dsp/_psd.py +16 -4
  104. scitex/dsp/_resample.py +24 -4
  105. scitex/dsp/_transform.py +16 -3
  106. scitex/dsp/add_noise.py +15 -1
  107. scitex/dsp/norm.py +17 -2
  108. scitex/dsp/reference.py +17 -1
  109. scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
  110. scitex/dsp/utils/_zero_pad.py +18 -4
  111. scitex/dt/_normalize_timestamp.py +1 -1
  112. scitex/git/_session.py +1 -1
  113. scitex/io/__init__.py +7 -19
  114. scitex/io/_load.py +15 -19
  115. scitex/io/_load_modules/_canvas.py +2 -2
  116. scitex/io/_load_modules/_con.py +17 -6
  117. scitex/io/_load_modules/_eeg.py +28 -13
  118. scitex/io/_load_modules/_optuna.py +21 -63
  119. scitex/io/_load_modules/_torch.py +11 -3
  120. scitex/io/_save.py +11 -16
  121. scitex/io/_save_modules/__init__.py +6 -10
  122. scitex/io/_save_modules/_canvas.py +3 -3
  123. scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
  124. scitex/io/_save_modules/_plot_bundle.py +112 -0
  125. scitex/io/_save_modules/{_pltz_stx.py → _plot_scitex.py} +7 -7
  126. scitex/io/_save_modules/_stx_bundle.py +16 -16
  127. scitex/io/_save_modules/_torch.py +11 -3
  128. scitex/io/bundle/README.md +89 -80
  129. scitex/{fts/_bundle/_FTS.py → io/bundle/_Bundle.py} +197 -95
  130. scitex/io/bundle/__init__.py +67 -35
  131. scitex/{fts/_bundle → io/bundle}/_children.py +32 -40
  132. scitex/io/bundle/_core.py +184 -97
  133. scitex/{fts/_bundle/_dataclasses/_Node.py → io/bundle/_dataclasses/_Spec.py} +29 -23
  134. scitex/{fts/_bundle/_dataclasses/_NodeRefs.py → io/bundle/_dataclasses/_SpecRefs.py} +6 -6
  135. scitex/{fts/_bundle → io/bundle}/_dataclasses/__init__.py +4 -4
  136. scitex/{fts/_bundle → io/bundle}/_loader.py +19 -19
  137. scitex/io/bundle/_manifest.py +99 -0
  138. scitex/{fts/_bundle → io/bundle}/_mpl_helpers.py +119 -28
  139. scitex/io/bundle/_nested.py +113 -100
  140. scitex/{fts/_bundle → io/bundle}/_saver.py +13 -14
  141. scitex/{fts/_bundle → io/bundle}/_storage.py +3 -3
  142. scitex/io/bundle/_types.py +41 -16
  143. scitex/{fts/_bundle → io/bundle}/_validation.py +20 -18
  144. scitex/io/bundle/_zip.py +21 -31
  145. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_backend/_parser.py +1 -1
  146. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Annotations.py +1 -1
  147. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Axes.py +1 -1
  148. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Figure.py +1 -1
  149. scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_Guides.py +1 -1
  150. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Plot.py +1 -1
  151. scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_Styles.py +1 -1
  152. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_utils/_plot_layout.py +1 -1
  153. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/__init__.py +1 -1
  154. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_editor/_app.py +1 -1
  155. scitex/{fts/_tables → io/bundle/kinds/_table}/_latex/_export.py +1 -1
  156. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_figure_exporter.py +1 -1
  157. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_table_exporter.py +1 -1
  158. scitex/io/bundle/schemas/__init__.py +30 -0
  159. scitex/mcp_server.py +159 -0
  160. scitex/parallel/_run.py +5 -4
  161. scitex/path/_find.py +60 -83
  162. scitex/path/_get_module_path.py +23 -21
  163. scitex/path/_get_spath.py +6 -27
  164. scitex/path/_getsize.py +23 -9
  165. scitex/path/_increment_version.py +31 -38
  166. scitex/path/_mk_spath.py +26 -29
  167. scitex/path/_path.py +5 -12
  168. scitex/path/_split.py +27 -15
  169. scitex/path/_this_path.py +23 -9
  170. scitex/plt/_mcp_handlers.py +361 -0
  171. scitex/plt/_mcp_tool_schemas.py +169 -0
  172. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +2 -1
  173. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +2 -2
  174. scitex/plt/gallery/_generate.py +76 -50
  175. scitex/plt/io/__init__.py +17 -19
  176. scitex/plt/io/_bundle.py +99 -52
  177. scitex/plt/io/_layered_bundle.py +303 -168
  178. scitex/plt/mcp_server.py +205 -0
  179. scitex/plt/utils/_csv_column_naming.py +250 -118
  180. scitex/repro/README_RandomStateManager.md +3 -3
  181. scitex/repro/_RandomStateManager.py +14 -14
  182. scitex/repro/_gen_ID.py +1 -1
  183. scitex/repro/_gen_timestamp.py +1 -1
  184. scitex/repro/_hash_array.py +4 -4
  185. scitex/schema/__init__.py +69 -73
  186. scitex/schema/_canvas.py +1 -1
  187. scitex/schema/_stats.py +2 -2
  188. scitex/scholar/__main__.py +24 -2
  189. scitex/scholar/_mcp_handlers.py +685 -0
  190. scitex/scholar/_mcp_tool_schemas.py +339 -0
  191. scitex/scholar/docs/template.py +1 -1
  192. scitex/scholar/examples/07_storage_integration.py +1 -1
  193. scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
  194. scitex/scholar/impact_factor/jcr/build_database.py +1 -1
  195. scitex/scholar/mcp_server.py +315 -0
  196. scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
  197. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
  198. scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
  199. scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
  200. scitex/scholar/storage/PaperIO.py +1 -1
  201. scitex/session/README.md +4 -4
  202. scitex/session/__init__.py +1 -1
  203. scitex/session/_decorator.py +9 -9
  204. scitex/session/_lifecycle.py +5 -5
  205. scitex/session/template.py +1 -1
  206. scitex/stats/__init__.py +30 -33
  207. scitex/stats/__main__.py +281 -0
  208. scitex/stats/_mcp_handlers.py +1191 -0
  209. scitex/stats/_mcp_tool_schemas.py +384 -0
  210. scitex/stats/_schema.py +1 -1
  211. scitex/stats/correct/_correct_bonferroni.py +1 -1
  212. scitex/stats/correct/_correct_fdr.py +1 -1
  213. scitex/stats/correct/_correct_fdr_.py +1 -1
  214. scitex/stats/correct/_correct_holm.py +1 -1
  215. scitex/stats/correct/_correct_sidak.py +1 -1
  216. scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
  217. scitex/stats/effect_sizes/_cohens_d.py +1 -1
  218. scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
  219. scitex/stats/effect_sizes/_eta_squared.py +1 -1
  220. scitex/stats/effect_sizes/_prob_superiority.py +1 -1
  221. scitex/stats/io/__init__.py +10 -11
  222. scitex/stats/io/_bundle.py +16 -16
  223. scitex/stats/mcp_server.py +405 -0
  224. scitex/stats/posthoc/_dunnett.py +1 -1
  225. scitex/stats/posthoc/_games_howell.py +1 -1
  226. scitex/stats/posthoc/_tukey_hsd.py +1 -1
  227. scitex/stats/power/_power.py +1 -1
  228. scitex/stats/utils/_effect_size.py +1 -1
  229. scitex/stats/utils/_formatters.py +1 -1
  230. scitex/stats/utils/_power.py +1 -1
  231. scitex/template/_mcp_handlers.py +259 -0
  232. scitex/template/_mcp_tool_schemas.py +112 -0
  233. scitex/template/mcp_server.py +186 -0
  234. scitex/utils/_verify_scitex_format.py +2 -2
  235. scitex/utils/template.py +1 -1
  236. scitex/web/__init__.py +12 -11
  237. scitex/web/_scraping.py +26 -265
  238. scitex/web/download_images.py +316 -0
  239. scitex/writer/Writer.py +1 -1
  240. scitex/writer/_clone_writer_project.py +1 -1
  241. scitex/writer/_validate_tree_structures.py +1 -1
  242. scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
  243. scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
  244. scitex/writer/dataclasses/core/_Document.py +1 -1
  245. scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
  246. scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
  247. scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
  248. scitex/writer/utils/.legacy_git_retry.py +7 -5
  249. scitex/writer/utils/_parse_latex_logs.py +1 -1
  250. scitex-2.13.0.dist-info/METADATA +1231 -0
  251. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/RECORD +376 -470
  252. scitex-2.13.0.dist-info/entry_points.txt +11 -0
  253. scitex/fig/editor/_defaults.py +0 -300
  254. scitex/fig/editor/edit/panel_loader.py +0 -232
  255. scitex/fig/editor/flask_editor/_bbox.py +0 -1299
  256. scitex/fig/editor/flask_editor/_core.py +0 -1429
  257. scitex/fig/editor/flask_editor/_renderer.py +0 -813
  258. scitex/fig/editor/flask_editor/static/css/features/canvas.css +0 -176
  259. scitex/fts/README.md +0 -262
  260. scitex/fts/TODO.md +0 -66
  261. scitex/fts/__init__.py +0 -90
  262. scitex/fts/_bundle/README_IN_BUNDLE.md +0 -102
  263. scitex/fts/_bundle/__init__.py +0 -38
  264. scitex/fts/_bundle/_utils/__init__.py +0 -55
  265. scitex/fts/_bundle/_utils/_const.py +0 -26
  266. scitex/fts/_bundle/_utils/_errors.py +0 -73
  267. scitex/fts/_bundle/_utils/_generate.py +0 -21
  268. scitex/fts/_bundle/_utils/_types.py +0 -76
  269. scitex/fts/_bundle/_zipbundle.py +0 -165
  270. scitex/fts/_fig/__init__.py +0 -22
  271. scitex/fts/_fig/_backend/_parser.py +0 -188
  272. scitex/fts/_fig/_editor/__init__.py +0 -14
  273. scitex/fts/_fig/_editor/_cui/__init__.py +0 -33
  274. scitex/fts/_fig/_editor/_cui/_backend_detector.py +0 -39
  275. scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +0 -366
  276. scitex/fts/_fig/_editor/_cui/_editor_launcher.py +0 -175
  277. scitex/fts/_fig/_editor/_cui/_manual_handler.py +0 -52
  278. scitex/fts/_fig/_editor/_cui/_path_resolver.py +0 -66
  279. scitex/fts/_fig/_editor/_gui/__init__.py +0 -11
  280. scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +0 -20
  281. scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +0 -664
  282. scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +0 -79
  283. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +0 -41
  284. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +0 -16
  285. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +0 -85
  286. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +0 -217
  287. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +0 -93
  288. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +0 -57
  289. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +0 -112
  290. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +0 -59
  291. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +0 -212
  292. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +0 -190
  293. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +0 -59
  294. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +0 -45
  295. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +0 -95
  296. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +0 -101
  297. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +0 -138
  298. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +0 -31
  299. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +0 -7
  300. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +0 -56
  301. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +0 -78
  302. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +0 -314
  303. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +0 -107
  304. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +0 -54
  305. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +0 -172
  306. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +0 -258
  307. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +0 -48
  308. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +0 -71
  309. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +0 -288
  310. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +0 -143
  311. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +0 -245
  312. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +0 -992
  313. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +0 -339
  314. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +0 -286
  315. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +0 -371
  316. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +0 -293
  317. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +0 -426
  318. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +0 -152
  319. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +0 -265
  320. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +0 -184
  321. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +0 -57
  322. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +0 -100
  323. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +0 -34
  324. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +0 -124
  325. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +0 -851
  326. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +0 -4932
  327. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +0 -1657
  328. scitex/fts/_fig/_editor/_gui/_flask_editor.py +0 -36
  329. scitex/fts/_fig/_models/_Annotations.py +0 -115
  330. scitex/fts/_fig/_models/_Axes.py +0 -152
  331. scitex/fts/_fig/_models/_Figure.py +0 -138
  332. scitex/fts/_fig/_models/_Plot.py +0 -123
  333. scitex/fts/_fig/_utils/_plot_layout.py +0 -397
  334. scitex/fts/_kinds/_figure/_composite.py +0 -345
  335. scitex/fts/_kinds/_plot/_backend/__init__.py +0 -53
  336. scitex/fts/_kinds/_plot/_backend/_export.py +0 -165
  337. scitex/fts/_kinds/_plot/_backend/_render.py +0 -538
  338. scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +0 -46
  339. scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +0 -82
  340. scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +0 -441
  341. scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +0 -52
  342. scitex/fts/_kinds/_plot/_dataclasses/__init__.py +0 -47
  343. scitex/fts/_kinds/_plot/_models/_Guides.py +0 -104
  344. scitex/fts/_kinds/_plot/_models/_Styles.py +0 -245
  345. scitex/fts/_kinds/_plot/_models/__init__.py +0 -80
  346. scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +0 -156
  347. scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +0 -43
  348. scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +0 -38
  349. scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +0 -36
  350. scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +0 -60
  351. scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +0 -30
  352. scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +0 -61
  353. scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +0 -57
  354. scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +0 -30
  355. scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +0 -121
  356. scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +0 -36
  357. scitex/fts/_kinds/_plot/_utils/__init__.py +0 -129
  358. scitex/fts/_kinds/_plot/_utils/_auto_layout.py +0 -127
  359. scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +0 -111
  360. scitex/fts/_kinds/_plot/_utils/_const_sizes.py +0 -48
  361. scitex/fts/_kinds/_plot/_utils/_convert_coords.py +0 -77
  362. scitex/fts/_kinds/_plot/_utils/_get_template.py +0 -178
  363. scitex/fts/_kinds/_plot/_utils/_normalize.py +0 -73
  364. scitex/fts/_kinds/_plot/_utils/_validate.py +0 -197
  365. scitex/fts/_kinds/_table/_latex/_export.py +0 -279
  366. scitex/fts/_stats/__init__.py +0 -48
  367. scitex/fts/_stats/_dataclasses/_Stats.py +0 -423
  368. scitex/fts/_stats/_dataclasses/__init__.py +0 -48
  369. scitex/fts/_tables/__init__.py +0 -65
  370. scitex/fts/_tables/_latex/__init__.py +0 -93
  371. scitex/fts/_tables/_latex/_editor/__init__.py +0 -11
  372. scitex/fts/_tables/_latex/_editor/_app.py +0 -725
  373. scitex/fts/_tables/_latex/_figure_exporter.py +0 -153
  374. scitex/fts/_tables/_latex/_stats_formatter.py +0 -274
  375. scitex/fts/_tables/_latex/_table_exporter.py +0 -362
  376. scitex/fts/_tables/_latex/_utils.py +0 -369
  377. scitex/fts/_tables/_latex/_validator.py +0 -445
  378. scitex/io/_save_modules/_pltz_bundle.py +0 -356
  379. scitex-2.10.3.dist-info/METADATA +0 -952
  380. scitex-2.10.3.dist-info/entry_points.txt +0 -2
  381. /scitex/{fig → canvas}/README.md +0 -0
  382. /scitex/{fig → canvas}/backend/__init__.py +0 -0
  383. /scitex/{fig → canvas}/backend/_export.py +0 -0
  384. /scitex/{fig → canvas}/backend/_render.py +0 -0
  385. /scitex/{fig → canvas}/docs/CANVAS_ARCHITECTURE.md +0 -0
  386. /scitex/{fig → canvas}/editor/__init__.py +0 -0
  387. /scitex/{fig → canvas}/editor/_dearpygui_editor.py +0 -0
  388. /scitex/{fig → canvas}/editor/_flask_editor.py +0 -0
  389. /scitex/{fig → canvas}/editor/_mpl_editor.py +0 -0
  390. /scitex/{fig → canvas}/editor/_qt_editor.py +0 -0
  391. /scitex/{fig → canvas}/editor/_tkinter_editor.py +0 -0
  392. /scitex/{fig → canvas}/editor/edit/backend_detector.py +0 -0
  393. /scitex/{fig → canvas}/editor/edit/manual_handler.py +0 -0
  394. /scitex/{fig → canvas}/editor/edit/path_resolver.py +0 -0
  395. /scitex/{fig → canvas}/editor/flask_editor/__init__.py +0 -0
  396. /scitex/{fig → canvas}/editor/flask_editor/_plotter.py +0 -0
  397. /scitex/{fig → canvas}/editor/flask_editor/_utils.py +0 -0
  398. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/reset.css +0 -0
  399. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/typography.css +0 -0
  400. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/variables.css +0 -0
  401. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/buttons.css +0 -0
  402. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/context-menu.css +0 -0
  403. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/dropdown.css +0 -0
  404. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/forms.css +0 -0
  405. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/modal.css +0 -0
  406. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/sections.css +0 -0
  407. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/element-inspector.css +0 -0
  408. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/loading.css +0 -0
  409. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/overlay.css +0 -0
  410. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/selection.css +0 -0
  411. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/statistics.css +0 -0
  412. /scitex/{fig → canvas}/editor/flask_editor/static/css/index.css +0 -0
  413. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/container.css +0 -0
  414. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/controls.css +0 -0
  415. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/preview.css +0 -0
  416. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/axis.js +0 -0
  417. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/basic.js +0 -0
  418. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/distribute.js +0 -0
  419. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/canvas.js +0 -0
  420. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/dragging.js +0 -0
  421. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/resize.js +0 -0
  422. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/selection.js +0 -0
  423. /scitex/{fig → canvas}/editor/flask_editor/static/js/core/state.js +0 -0
  424. /scitex/{fig → canvas}/editor/flask_editor/static/js/core/utils.js +0 -0
  425. /scitex/{fig → canvas}/editor/flask_editor/static/js/dev/element-inspector.js +0 -0
  426. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/bbox.js +0 -0
  427. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/element-drag.js +0 -0
  428. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/overlay.js +0 -0
  429. /scitex/{fig → canvas}/editor/flask_editor/static/js/main.js +0 -0
  430. /scitex/{fig → canvas}/editor/flask_editor/static/js/shortcuts/context-menu.js +0 -0
  431. /scitex/{fig → canvas}/editor/flask_editor/static/js/shortcuts/keyboard.js +0 -0
  432. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/controls.js +0 -0
  433. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/download.js +0 -0
  434. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/help.js +0 -0
  435. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/theme.js +0 -0
  436. /scitex/{fig → canvas}/editor/flask_editor/templates/__init__.py +0 -0
  437. /scitex/{fig → canvas}/io/_directory.py +0 -0
  438. /scitex/{fig → canvas}/model/_plot_types.py +0 -0
  439. /scitex/{fig → canvas}/utils/_defaults.py +0 -0
  440. /scitex/{fig → canvas}/utils/_validate.py +0 -0
  441. /scitex/{fts/_bundle → io/bundle}/_conversion/__init__.py +0 -0
  442. /scitex/{fts/_bundle → io/bundle}/_conversion/_bundle2dict.py +0 -0
  443. /scitex/{fts/_bundle → io/bundle}/_conversion/_dict2bundle.py +0 -0
  444. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_Axes.py +0 -0
  445. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_BBox.py +0 -0
  446. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_ColumnDef.py +0 -0
  447. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataFormat.py +0 -0
  448. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataInfo.py +0 -0
  449. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataSource.py +0 -0
  450. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_SizeMM.py +0 -0
  451. /scitex/{fts/_bundle → io/bundle}/_extractors/__init__.py +0 -0
  452. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_bar.py +0 -0
  453. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_line.py +0 -0
  454. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_scatter.py +0 -0
  455. /scitex/{fts/_kinds → io/bundle/kinds}/__init__.py +0 -0
  456. /scitex/{fts/_kinds → io/bundle/kinds}/_figure/__init__.py +0 -0
  457. /scitex/{fts/_fig → io/bundle/kinds/_figure}/_composite.py +0 -0
  458. /scitex/{fts/_kinds → io/bundle/kinds}/_plot/__init__.py +0 -0
  459. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/__init__.py +0 -0
  460. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/_export.py +0 -0
  461. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/_render.py +0 -0
  462. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_ChannelEncoding.py +0 -0
  463. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_Encoding.py +0 -0
  464. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_Theme.py +0 -0
  465. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_TraceEncoding.py +0 -0
  466. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/__init__.py +0 -0
  467. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/__init__.py +0 -0
  468. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/__init__.py +0 -0
  469. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_bar.py +0 -0
  470. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_box.py +0 -0
  471. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_distribution.py +0 -0
  472. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_errorbar.py +0 -0
  473. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_histogram.py +0 -0
  474. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_image.py +0 -0
  475. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_line.py +0 -0
  476. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_scatter.py +0 -0
  477. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_seaborn.py +0 -0
  478. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_violin.py +0 -0
  479. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/__init__.py +0 -0
  480. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_auto_layout.py +0 -0
  481. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_calc_bounds.py +0 -0
  482. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_const_sizes.py +0 -0
  483. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_convert_coords.py +0 -0
  484. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_get_template.py +0 -0
  485. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_normalize.py +0 -0
  486. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_validate.py +0 -0
  487. /scitex/{fts/_kinds → io/bundle/kinds}/_shape/__init__.py +0 -0
  488. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/__init__.py +0 -0
  489. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/_dataclasses/_Stats.py +0 -0
  490. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/_dataclasses/__init__.py +0 -0
  491. /scitex/{fts/_kinds → io/bundle/kinds}/_table/__init__.py +0 -0
  492. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_editor/__init__.py +0 -0
  493. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_stats_formatter.py +0 -0
  494. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_utils.py +0 -0
  495. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_validator.py +0 -0
  496. /scitex/{fts/_kinds → io/bundle/kinds}/_text/__init__.py +0 -0
  497. /scitex/{fts/_schemas → io/bundle/schemas}/data_info.schema.json +0 -0
  498. /scitex/{fts/_schemas → io/bundle/schemas}/encoding.schema.json +0 -0
  499. /scitex/{fts/_schemas → io/bundle/schemas}/node.schema.json +0 -0
  500. /scitex/{fts/_schemas → io/bundle/schemas}/render_manifest.schema.json +0 -0
  501. /scitex/{fts/_schemas → io/bundle/schemas}/stats.schema.json +0 -0
  502. /scitex/{fts/_schemas → io/bundle/schemas}/theme.schema.json +0 -0
  503. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
  504. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,725 +0,0 @@
1
- #!/usr/bin/env python3
2
- # Timestamp: 2025-12-20
3
- # File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_editor/_app.py
4
-
5
- """Flask application for LaTeX error editor."""
6
-
7
- import json
8
- import socket
9
- import subprocess
10
- import tempfile
11
- import webbrowser
12
- from pathlib import Path
13
- from typing import TYPE_CHECKING, Optional
14
-
15
- from flask import Flask, jsonify, render_template_string, request
16
-
17
- from .._validator import ValidationResult, validate_latex
18
-
19
- if TYPE_CHECKING:
20
- from scitex.fts import FTS
21
-
22
-
23
- # HTML template with CodeMirror editor
24
- EDITOR_TEMPLATE = """
25
- <!DOCTYPE html>
26
- <html lang="en">
27
- <head>
28
- <meta charset="UTF-8">
29
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
30
- <title>LaTeX Editor - FTS</title>
31
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
32
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/monokai.min.css">
33
- <style>
34
- :root {
35
- --bg-primary: #1e1e1e;
36
- --bg-secondary: #252526;
37
- --bg-tertiary: #2d2d30;
38
- --text-primary: #d4d4d4;
39
- --text-secondary: #808080;
40
- --accent: #569cd6;
41
- --error: #f44747;
42
- --warning: #ffcc00;
43
- --success: #4ec9b0;
44
- --border: #3c3c3c;
45
- }
46
-
47
- * {
48
- box-sizing: border-box;
49
- margin: 0;
50
- padding: 0;
51
- }
52
-
53
- body {
54
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
55
- background: var(--bg-primary);
56
- color: var(--text-primary);
57
- height: 100vh;
58
- display: flex;
59
- flex-direction: column;
60
- }
61
-
62
- header {
63
- background: var(--bg-secondary);
64
- padding: 12px 20px;
65
- display: flex;
66
- justify-content: space-between;
67
- align-items: center;
68
- border-bottom: 1px solid var(--border);
69
- }
70
-
71
- header h1 {
72
- font-size: 16px;
73
- font-weight: 500;
74
- }
75
-
76
- .controls {
77
- display: flex;
78
- gap: 10px;
79
- }
80
-
81
- button {
82
- background: var(--bg-tertiary);
83
- color: var(--text-primary);
84
- border: 1px solid var(--border);
85
- padding: 8px 16px;
86
- border-radius: 4px;
87
- cursor: pointer;
88
- font-size: 13px;
89
- transition: background 0.2s;
90
- }
91
-
92
- button:hover {
93
- background: var(--accent);
94
- color: #fff;
95
- }
96
-
97
- button.primary {
98
- background: var(--accent);
99
- color: #fff;
100
- border-color: var(--accent);
101
- }
102
-
103
- button.primary:hover {
104
- background: #4a8bc9;
105
- }
106
-
107
- .main-container {
108
- flex: 1;
109
- display: flex;
110
- overflow: hidden;
111
- }
112
-
113
- .editor-panel {
114
- flex: 1;
115
- display: flex;
116
- flex-direction: column;
117
- border-right: 1px solid var(--border);
118
- }
119
-
120
- .CodeMirror {
121
- flex: 1;
122
- font-family: 'Fira Code', 'Consolas', monospace;
123
- font-size: 14px;
124
- line-height: 1.6;
125
- }
126
-
127
- .error-panel {
128
- width: 350px;
129
- background: var(--bg-secondary);
130
- display: flex;
131
- flex-direction: column;
132
- }
133
-
134
- .error-panel h2 {
135
- padding: 12px 16px;
136
- font-size: 14px;
137
- font-weight: 500;
138
- background: var(--bg-tertiary);
139
- border-bottom: 1px solid var(--border);
140
- }
141
-
142
- .error-list {
143
- flex: 1;
144
- overflow-y: auto;
145
- padding: 8px;
146
- }
147
-
148
- .error-item {
149
- padding: 10px 12px;
150
- margin-bottom: 8px;
151
- border-radius: 4px;
152
- cursor: pointer;
153
- transition: background 0.2s;
154
- }
155
-
156
- .error-item:hover {
157
- background: var(--bg-tertiary);
158
- }
159
-
160
- .error-item.error {
161
- border-left: 3px solid var(--error);
162
- }
163
-
164
- .error-item.warning {
165
- border-left: 3px solid var(--warning);
166
- }
167
-
168
- .error-item.info {
169
- border-left: 3px solid var(--accent);
170
- }
171
-
172
- .error-code {
173
- display: inline-block;
174
- background: var(--bg-tertiary);
175
- padding: 2px 6px;
176
- border-radius: 3px;
177
- font-size: 11px;
178
- margin-right: 8px;
179
- }
180
-
181
- .error-location {
182
- color: var(--text-secondary);
183
- font-size: 12px;
184
- margin-top: 4px;
185
- }
186
-
187
- .error-message {
188
- font-size: 13px;
189
- margin-top: 4px;
190
- }
191
-
192
- .error-suggestion {
193
- color: var(--success);
194
- font-size: 12px;
195
- margin-top: 6px;
196
- }
197
-
198
- .no-errors {
199
- padding: 20px;
200
- text-align: center;
201
- color: var(--success);
202
- }
203
-
204
- .status-bar {
205
- background: var(--bg-secondary);
206
- padding: 6px 16px;
207
- font-size: 12px;
208
- display: flex;
209
- justify-content: space-between;
210
- border-top: 1px solid var(--border);
211
- }
212
-
213
- .status-item {
214
- display: flex;
215
- align-items: center;
216
- gap: 6px;
217
- }
218
-
219
- .status-dot {
220
- width: 8px;
221
- height: 8px;
222
- border-radius: 50%;
223
- }
224
-
225
- .status-dot.valid {
226
- background: var(--success);
227
- }
228
-
229
- .status-dot.invalid {
230
- background: var(--error);
231
- }
232
-
233
- .cm-error-line {
234
- background: rgba(244, 71, 71, 0.15) !important;
235
- }
236
-
237
- .cm-warning-line {
238
- background: rgba(255, 204, 0, 0.1) !important;
239
- }
240
-
241
- /* Loading spinner */
242
- .loading {
243
- display: none;
244
- position: fixed;
245
- top: 50%;
246
- left: 50%;
247
- transform: translate(-50%, -50%);
248
- background: var(--bg-secondary);
249
- padding: 20px 40px;
250
- border-radius: 8px;
251
- box-shadow: 0 4px 20px rgba(0,0,0,0.5);
252
- }
253
-
254
- .loading.active {
255
- display: block;
256
- }
257
- </style>
258
- </head>
259
- <body>
260
- <header>
261
- <h1>LaTeX Editor - {{ bundle_name }}</h1>
262
- <div class="controls">
263
- <button onclick="validateCode()">Validate</button>
264
- <button onclick="compilePreview()">Compile Preview</button>
265
- <button class="primary" onclick="saveCode()">Save</button>
266
- </div>
267
- </header>
268
-
269
- <div class="main-container">
270
- <div class="editor-panel">
271
- <textarea id="latex-editor">{{ latex_code }}</textarea>
272
- </div>
273
-
274
- <div class="error-panel">
275
- <h2>Issues <span id="issue-count">({{ error_count }})</span></h2>
276
- <div class="error-list" id="error-list">
277
- {% if errors %}
278
- {% for error in errors %}
279
- <div class="error-item {{ error.severity.value }}"
280
- onclick="goToLine({{ error.line }}, {{ error.column }})">
281
- <span class="error-code">{{ error.code }}</span>
282
- <span class="error-severity">{{ error.severity.value }}</span>
283
- <div class="error-location">Line {{ error.line }}, Col {{ error.column }}</div>
284
- <div class="error-message">{{ error.message }}</div>
285
- {% if error.suggestion %}
286
- <div class="error-suggestion">Fix: {{ error.suggestion }}</div>
287
- {% endif %}
288
- </div>
289
- {% endfor %}
290
- {% else %}
291
- <div class="no-errors">No issues found</div>
292
- {% endif %}
293
- </div>
294
- </div>
295
- </div>
296
-
297
- <div class="status-bar">
298
- <div class="status-item">
299
- <span class="status-dot {{ 'valid' if is_valid else 'invalid' }}"></span>
300
- <span id="status-text">{{ 'Valid' if is_valid else 'Has issues' }}</span>
301
- </div>
302
- <div class="status-item">
303
- <span id="cursor-pos">Line 1, Col 1</span>
304
- </div>
305
- </div>
306
-
307
- <div class="loading" id="loading">Processing...</div>
308
-
309
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
310
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/stex/stex.min.js"></script>
311
- <script>
312
- let editor;
313
- let lineWidgets = [];
314
-
315
- document.addEventListener('DOMContentLoaded', function() {
316
- editor = CodeMirror.fromTextArea(document.getElementById('latex-editor'), {
317
- mode: 'stex',
318
- theme: 'monokai',
319
- lineNumbers: true,
320
- lineWrapping: true,
321
- indentUnit: 4,
322
- tabSize: 4,
323
- indentWithTabs: false,
324
- matchBrackets: true,
325
- autoCloseBrackets: true
326
- });
327
-
328
- editor.on('cursorActivity', function() {
329
- const pos = editor.getCursor();
330
- document.getElementById('cursor-pos').textContent =
331
- `Line ${pos.line + 1}, Col ${pos.ch + 1}`;
332
- });
333
-
334
- // Highlight initial errors
335
- highlightErrors({{ errors_json|safe }});
336
- });
337
-
338
- function goToLine(line, col) {
339
- editor.setCursor(line - 1, col - 1);
340
- editor.focus();
341
- }
342
-
343
- function highlightErrors(errors) {
344
- // Clear previous highlights
345
- lineWidgets.forEach(w => w.clear());
346
- lineWidgets = [];
347
-
348
- errors.forEach(error => {
349
- if (error.line > 0) {
350
- const className = error.severity === 'error' ? 'cm-error-line' : 'cm-warning-line';
351
- const handle = editor.addLineClass(error.line - 1, 'background', className);
352
- lineWidgets.push({
353
- clear: () => editor.removeLineClass(handle, 'background', className)
354
- });
355
- }
356
- });
357
- }
358
-
359
- function showLoading(show) {
360
- document.getElementById('loading').classList.toggle('active', show);
361
- }
362
-
363
- async function validateCode() {
364
- showLoading(true);
365
- try {
366
- const response = await fetch('/validate', {
367
- method: 'POST',
368
- headers: {'Content-Type': 'application/json'},
369
- body: JSON.stringify({
370
- code: editor.getValue(),
371
- level: 'semantic'
372
- })
373
- });
374
- const data = await response.json();
375
- updateErrors(data.errors);
376
- updateStatus(data.is_valid);
377
- } catch (e) {
378
- console.error('Validation failed:', e);
379
- }
380
- showLoading(false);
381
- }
382
-
383
- async function saveCode() {
384
- showLoading(true);
385
- try {
386
- const response = await fetch('/save', {
387
- method: 'POST',
388
- headers: {'Content-Type': 'application/json'},
389
- body: JSON.stringify({
390
- code: editor.getValue()
391
- })
392
- });
393
- const data = await response.json();
394
- if (data.success) {
395
- alert('Saved successfully!');
396
- } else {
397
- alert('Save failed: ' + data.error);
398
- }
399
- } catch (e) {
400
- alert('Save failed: ' + e.message);
401
- }
402
- showLoading(false);
403
- }
404
-
405
- async function compilePreview() {
406
- showLoading(true);
407
- try {
408
- const response = await fetch('/compile', {
409
- method: 'POST',
410
- headers: {'Content-Type': 'application/json'},
411
- body: JSON.stringify({
412
- code: editor.getValue()
413
- })
414
- });
415
- const data = await response.json();
416
- if (data.success) {
417
- window.open('/preview', '_blank');
418
- } else {
419
- updateErrors(data.errors || []);
420
- alert('Compilation failed. See errors panel.');
421
- }
422
- } catch (e) {
423
- alert('Compilation failed: ' + e.message);
424
- }
425
- showLoading(false);
426
- }
427
-
428
- function updateErrors(errors) {
429
- const list = document.getElementById('error-list');
430
- const count = document.getElementById('issue-count');
431
-
432
- count.textContent = `(${errors.length})`;
433
-
434
- if (errors.length === 0) {
435
- list.innerHTML = '<div class="no-errors">No issues found</div>';
436
- } else {
437
- list.innerHTML = errors.map(e => `
438
- <div class="error-item ${e.severity}" onclick="goToLine(${e.line}, ${e.column})">
439
- <span class="error-code">${e.code}</span>
440
- <span class="error-severity">${e.severity}</span>
441
- <div class="error-location">Line ${e.line}, Col ${e.column}</div>
442
- <div class="error-message">${e.message}</div>
443
- ${e.suggestion ? `<div class="error-suggestion">Fix: ${e.suggestion}</div>` : ''}
444
- </div>
445
- `).join('');
446
- }
447
-
448
- highlightErrors(errors);
449
- }
450
-
451
- function updateStatus(isValid) {
452
- const dot = document.querySelector('.status-dot');
453
- const text = document.getElementById('status-text');
454
-
455
- dot.className = 'status-dot ' + (isValid ? 'valid' : 'invalid');
456
- text.textContent = isValid ? 'Valid' : 'Has issues';
457
- }
458
- </script>
459
- </body>
460
- </html>
461
- """
462
-
463
-
464
- class LaTeXEditor:
465
- """Flask-based LaTeX editor with error highlighting."""
466
-
467
- def __init__(
468
- self,
469
- latex_code: str,
470
- bundle: Optional["FTS"] = None,
471
- output_path: Optional[Path] = None,
472
- ):
473
- """Initialize editor.
474
-
475
- Args:
476
- latex_code: Initial LaTeX code
477
- bundle: Associated FTS bundle
478
- output_path: Where to save edits
479
- """
480
- self.latex_code = latex_code
481
- self.bundle = bundle
482
- self.output_path = output_path
483
- self.app = Flask(__name__)
484
- self._setup_routes()
485
- self._validation_result: Optional[ValidationResult] = None
486
- self._compiled_pdf: Optional[Path] = None
487
-
488
- def _setup_routes(self) -> None:
489
- """Setup Flask routes."""
490
-
491
- @self.app.route("/")
492
- def index():
493
- # Validate code
494
- self._validation_result = validate_latex(self.latex_code, level="semantic")
495
-
496
- errors = self._validation_result.all_issues
497
- errors_json = json.dumps(
498
- [
499
- {
500
- "line": e.line,
501
- "column": e.column,
502
- "message": e.message,
503
- "severity": e.severity.value,
504
- "code": e.code,
505
- "suggestion": e.suggestion,
506
- }
507
- for e in errors
508
- ]
509
- )
510
-
511
- bundle_name = "Untitled"
512
- if self.bundle:
513
- bundle_name = self.bundle.node.name or self.bundle.node.id
514
-
515
- return render_template_string(
516
- EDITOR_TEMPLATE,
517
- latex_code=self.latex_code,
518
- errors=errors,
519
- errors_json=errors_json,
520
- error_count=len(errors),
521
- is_valid=self._validation_result.is_valid,
522
- bundle_name=bundle_name,
523
- )
524
-
525
- @self.app.route("/validate", methods=["POST"])
526
- def validate():
527
- data = request.get_json()
528
- code = data.get("code", "")
529
- level = data.get("level", "semantic")
530
-
531
- result = validate_latex(code, level=level)
532
- self.latex_code = code
533
-
534
- return jsonify(
535
- {
536
- "is_valid": result.is_valid,
537
- "errors": [
538
- {
539
- "line": e.line,
540
- "column": e.column,
541
- "message": e.message,
542
- "severity": e.severity.value,
543
- "code": e.code,
544
- "suggestion": e.suggestion,
545
- }
546
- for e in result.all_issues
547
- ],
548
- }
549
- )
550
-
551
- @self.app.route("/save", methods=["POST"])
552
- def save():
553
- data = request.get_json()
554
- code = data.get("code", "")
555
-
556
- try:
557
- if self.output_path:
558
- self.output_path.write_text(code, encoding="utf-8")
559
- self.latex_code = code
560
- return jsonify({"success": True})
561
- elif self.bundle:
562
- # Save to bundle exports
563
- exports_dir = self.bundle.path / "exports"
564
- exports_dir.mkdir(exist_ok=True)
565
- tex_path = exports_dir / f"{self.bundle.node.id}.tex"
566
- tex_path.write_text(code, encoding="utf-8")
567
- self.latex_code = code
568
- return jsonify({"success": True, "path": str(tex_path)})
569
- else:
570
- return jsonify({"success": False, "error": "No output path configured"})
571
- except Exception as e:
572
- return jsonify({"success": False, "error": str(e)})
573
-
574
- @self.app.route("/compile", methods=["POST"])
575
- def compile():
576
- data = request.get_json()
577
- code = data.get("code", "")
578
-
579
- # Wrap in document if needed
580
- if "\\documentclass" not in code:
581
- code = _wrap_in_document(code)
582
-
583
- try:
584
- with tempfile.TemporaryDirectory() as tmpdir:
585
- tex_path = Path(tmpdir) / "document.tex"
586
- tex_path.write_text(code, encoding="utf-8")
587
-
588
- proc = subprocess.run(
589
- ["pdflatex", "-interaction=nonstopmode", str(tex_path)],
590
- cwd=tmpdir,
591
- capture_output=True,
592
- text=True,
593
- timeout=30,
594
- )
595
-
596
- pdf_path = Path(tmpdir) / "document.pdf"
597
- if pdf_path.exists():
598
- # Copy to temp location accessible by preview route
599
- import shutil
600
-
601
- self._compiled_pdf = Path(tempfile.gettempdir()) / "fsb_preview.pdf"
602
- shutil.copy(pdf_path, self._compiled_pdf)
603
- return jsonify({"success": True})
604
- else:
605
- # Parse errors
606
- result = validate_latex(code, level="compile")
607
- return jsonify(
608
- {
609
- "success": False,
610
- "errors": [
611
- {
612
- "line": e.line,
613
- "column": e.column,
614
- "message": e.message,
615
- "severity": e.severity.value,
616
- "code": e.code,
617
- "suggestion": e.suggestion,
618
- }
619
- for e in result.all_issues
620
- ],
621
- }
622
- )
623
-
624
- except FileNotFoundError:
625
- return jsonify({"success": False, "error": "pdflatex not found"})
626
- except subprocess.TimeoutExpired:
627
- return jsonify({"success": False, "error": "Compilation timed out"})
628
- except Exception as e:
629
- return jsonify({"success": False, "error": str(e)})
630
-
631
- @self.app.route("/preview")
632
- def preview():
633
- if self._compiled_pdf and self._compiled_pdf.exists():
634
- from flask import send_file
635
-
636
- return send_file(self._compiled_pdf, mimetype="application/pdf")
637
- return "No preview available", 404
638
-
639
- @self.app.route("/shutdown", methods=["POST"])
640
- def shutdown():
641
- func = request.environ.get("werkzeug.server.shutdown")
642
- if func:
643
- func()
644
- return "Shutting down..."
645
-
646
- def run(self, port: int = 5051, open_browser: bool = True) -> None:
647
- """Run the editor server.
648
-
649
- Args:
650
- port: Port to run on
651
- open_browser: Whether to open browser automatically
652
- """
653
- # Find available port
654
- port = _find_available_port(port)
655
-
656
- url = f"http://127.0.0.1:{port}"
657
- print(f"LaTeX Editor running at {url}")
658
-
659
- if open_browser:
660
- webbrowser.open(url)
661
-
662
- self.app.run(host="127.0.0.1", port=port, debug=False, use_reloader=False)
663
-
664
-
665
- def _find_available_port(start_port: int = 5051) -> int:
666
- """Find an available port.
667
-
668
- Args:
669
- start_port: Port to start searching from
670
-
671
- Returns:
672
- Available port number
673
- """
674
- for port in range(start_port, start_port + 100):
675
- try:
676
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
677
- s.bind(("127.0.0.1", port))
678
- return port
679
- except OSError:
680
- continue
681
- raise RuntimeError("No available ports found")
682
-
683
-
684
- def _wrap_in_document(content: str) -> str:
685
- """Wrap content in a minimal LaTeX document.
686
-
687
- Args:
688
- content: LaTeX content
689
-
690
- Returns:
691
- Complete document string
692
- """
693
- return f"""\\documentclass{{article}}
694
- \\usepackage{{graphicx}}
695
- \\usepackage{{booktabs}}
696
- \\usepackage{{amsmath}}
697
- \\begin{{document}}
698
- {content}
699
- \\end{{document}}
700
- """
701
-
702
-
703
- def launch_editor(
704
- latex_code: str,
705
- bundle: Optional["FTS"] = None,
706
- output_path: Optional[Path] = None,
707
- port: int = 5051,
708
- open_browser: bool = True,
709
- ) -> None:
710
- """Launch the LaTeX editor.
711
-
712
- Args:
713
- latex_code: LaTeX code to edit
714
- bundle: Associated FTS bundle
715
- output_path: Where to save edits
716
- port: Port to run on
717
- open_browser: Whether to open browser
718
- """
719
- editor = LaTeXEditor(latex_code, bundle, output_path)
720
- editor.run(port=port, open_browser=open_browser)
721
-
722
-
723
- __all__ = ["LaTeXEditor", "launch_editor"]
724
-
725
- # EOF