scriptorium 0.6.1 → 0.7.2

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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/assets/icons/social/reddit.png +0 -0
  3. data/assets/icons/social/x-logo.png +0 -0
  4. data/assets/imagenotfound.jpg +0 -0
  5. data/bin/sblog +84 -5
  6. data/bin/scriptorium +1 -0
  7. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +0 -1
  8. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +0 -29
  9. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +0 -19
  10. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +1 -1
  11. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +1 -1
  12. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +1 -1
  13. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +0 -10
  14. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +1 -4
  15. data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
  16. data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
  17. data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
  18. data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
  19. data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
  20. data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
  21. data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
  22. data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
  23. data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
  24. data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
  25. data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
  26. data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
  27. data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
  28. data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
  29. data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
  30. data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
  31. data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
  32. data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
  33. data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
  34. data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
  35. data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
  36. data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
  37. data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
  38. data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
  39. data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
  40. data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
  41. data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
  42. data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
  43. data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
  44. data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
  45. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
  46. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
  47. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
  48. data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
  49. data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
  50. data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
  51. data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
  52. data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
  53. data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
  54. data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
  55. data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
  56. data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
  57. data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
  58. data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
  59. data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
  60. data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
  61. data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
  62. data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
  63. data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
  64. data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
  65. data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
  66. data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
  67. data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
  68. data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
  69. data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
  70. data/doc/imported/0018-ruby-puns/post.html +46 -0
  71. data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
  72. data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
  73. data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
  74. data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
  75. data/doc/imported/0020-fffff/metadata.txt +7 -0
  76. data/doc/imported/0020-fffff/post.html +24 -0
  77. data/doc/imported/0020-fffff/source.lt3 +12 -0
  78. data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
  79. data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
  80. data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
  81. data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
  82. data/doc/imported/0023-doctor-sleep/post.html +63 -0
  83. data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
  84. data/doc/imported/0024-just-a-test/metadata.txt +7 -0
  85. data/doc/imported/0024-just-a-test/post.html +24 -0
  86. data/doc/imported/0024-just-a-test/source.lt3 +12 -0
  87. data/doc/imported/import_summary.txt +98 -0
  88. data/doc/livetext-informal-spec.txt +65 -0
  89. data/doc/myuserdoc/ch-0.lt3 +31 -0
  90. data/doc/myuserdoc/ch-1.lt3 +37 -0
  91. data/doc/myuserdoc/ch-10.lt3 +22 -0
  92. data/doc/myuserdoc/ch-2.lt3 +37 -0
  93. data/doc/myuserdoc/ch-3.lt3 +19 -0
  94. data/doc/myuserdoc/ch-4.lt3 +43 -0
  95. data/doc/myuserdoc/ch-5.lt3 +22 -0
  96. data/doc/myuserdoc/ch-6.lt3 +19 -0
  97. data/doc/myuserdoc/ch-7.lt3 +16 -0
  98. data/doc/myuserdoc/ch-8.lt3 +13 -0
  99. data/doc/myuserdoc/ch-9.lt3 +19 -0
  100. data/doc/myuserdoc/tweak.rb +18 -0
  101. data/doc/{userdoc-toc.txt → myuserdoc/userdoc-toc.txt} +27 -27
  102. data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
  103. data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
  104. data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
  105. data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
  106. data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
  107. data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
  108. data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
  109. data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
  110. data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
  111. data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
  112. data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
  113. data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
  114. data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
  115. data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
  116. data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
  117. data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
  118. data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
  119. data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
  120. data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
  121. data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
  122. data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
  123. data/doc/old-posts/0024-just-a-test.lt3 +12 -0
  124. data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
  125. data/doc/old-repo +1 -0
  126. data/doc/reddit_integration.md +2 -2
  127. data/doc/user.lt3 +0 -3
  128. data/lib/scriptorium/api.rb +1811 -78
  129. data/lib/scriptorium/banner_svg.rb +55 -68
  130. data/lib/scriptorium/contract.rb +3 -2
  131. data/lib/scriptorium/exceptions.rb +133 -102
  132. data/lib/scriptorium/helpers.rb +282 -82
  133. data/lib/scriptorium/post.rb +81 -17
  134. data/lib/scriptorium/reddit.rb +1 -1
  135. data/lib/scriptorium/repo.rb +478 -164
  136. data/lib/scriptorium/standard_files.rb +30 -396
  137. data/lib/scriptorium/support/common_js/clipboard.js +35 -0
  138. data/lib/scriptorium/support/common_js/content-loader.js +187 -0
  139. data/lib/scriptorium/support/common_js/navigation.js +52 -0
  140. data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
  141. data/lib/scriptorium/support/config/reddit_template.txt +17 -0
  142. data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/social.txt +1 -0
  143. data/lib/scriptorium/support/highlight/css.txt +2 -0
  144. data/lib/scriptorium/support/highlight/custom.css +119 -0
  145. data/lib/scriptorium/support/highlight/js.txt +1 -0
  146. data/lib/scriptorium/support/post_index/config.txt +15 -0
  147. data/lib/scriptorium/support/post_index/style.css +55 -0
  148. data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
  149. data/{test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 → lib/scriptorium/support/templates/initial_post.lt3} +5 -5
  150. data/lib/scriptorium/support/templates/post.lt3 +104 -0
  151. data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt → lib/scriptorium/support/theme/header.lt3} +1 -1
  152. data/lib/scriptorium/theme.rb +83 -70
  153. data/lib/scriptorium/version.rb +2 -2
  154. data/lib/scriptorium/view.rb +194 -149
  155. data/lib/scriptorium.rb +24 -1
  156. data/lib/skeleton.rb +4 -1
  157. data/scriptorium.gemspec +2 -1
  158. data/test/WEB_INTEGRATION_README.md +196 -0
  159. data/test/all +40 -0
  160. data/test/banner_svg/unit.rb +267 -35
  161. data/test/config/deployment.txt +5 -0
  162. data/test/integration/integration_test.rb +7 -7
  163. data/test/integration/preview_flow_test.rb +94 -0
  164. data/test/livetext_plugin_test.rb +453 -182
  165. data/test/manual/banner-tests/test01.html +82 -18
  166. data/test/manual/banner-tests/test02.html +82 -18
  167. data/test/manual/banner-tests/test03.html +82 -18
  168. data/test/manual/banner-tests/test04.html +89 -25
  169. data/test/manual/banner-tests/test05.html +89 -25
  170. data/test/manual/banner-tests/test06.html +89 -25
  171. data/test/manual/banner-tests/test07.html +89 -25
  172. data/test/manual/banner-tests/test08.html +82 -18
  173. data/test/manual/banner-tests/test09.html +82 -18
  174. data/test/manual/banner-tests/test10.html +82 -18
  175. data/test/manual/banner-tests/test11.html +82 -18
  176. data/test/manual/banner-tests/test12.html +82 -18
  177. data/test/manual/banner-tests/test13.html +82 -18
  178. data/test/manual/banner-tests/test14.html +82 -18
  179. data/test/manual/banner-tests/test15.html +82 -18
  180. data/test/manual/banner-tests/test16.html +82 -18
  181. data/test/manual/banner-tests/test17.html +82 -18
  182. data/test/manual/banner-tests/test18.html +90 -26
  183. data/test/manual/banner-tests/test19.html +90 -26
  184. data/test/manual/banner-tests/test20.html +90 -26
  185. data/test/manual/banner-tests/test21.html +90 -26
  186. data/test/manual/banner-tests/test22.html +90 -26
  187. data/test/manual/banner-tests/test23.html +90 -26
  188. data/test/manual/banner-tests/test24.html +90 -26
  189. data/test/manual/banner-tests/test25.html +89 -25
  190. data/test/manual/banner_environment.rb +15 -2
  191. data/test/manual/codemirror_demo.html +773 -0
  192. data/test/manual/create_posts_for_web.rb +114 -0
  193. data/test/manual/preview_manual_test.rb +129 -0
  194. data/test/manual/test_banner_features.rb +14 -14
  195. data/test/manual/test_banner_integration.rb +115 -0
  196. data/test/manual/test_banner_radial.rb +87 -0
  197. data/test/manual/test_syntax_highlighting.rb +60 -40
  198. data/test/support/preview_utils.rb +88 -0
  199. data/test/test_gem_assets.rb +48 -0
  200. data/test/test_helpers.rb +10 -0
  201. data/test/tui_editor_integration_test.rb +15 -15
  202. data/test/tui_integration_test.rb +687 -441
  203. data/test/unit/api.rb +757 -37
  204. data/test/unit/asset_management.rb +195 -221
  205. data/test/unit/backup_test.rb +451 -0
  206. data/test/unit/contract_test.rb +1 -23
  207. data/test/unit/core.rb +415 -61
  208. data/test/unit/deploy_config_test.rb +248 -0
  209. data/test/unit/deploy_test.rb +312 -21
  210. data/test/unit/edit_post_test.rb +168 -0
  211. data/test/unit/gem_asset_management.rb +36 -42
  212. data/test/unit/livetext_basic.rb +23 -35
  213. data/test/unit/livetext_compatibility.rb +7 -14
  214. data/test/unit/parse_cmd_test.rb +260 -0
  215. data/test/unit/{symlink_test.rb → permalink_copy_test.rb} +47 -49
  216. data/test/unit/post.rb +91 -26
  217. data/test/unit/post_index_config_test.rb +258 -0
  218. data/test/unit/post_state_helpers_test.rb +137 -0
  219. data/test/unit/read_commented_file_test.rb +8 -6
  220. data/test/unit/repo.rb +75 -54
  221. data/test/unit/social_test.rb +41 -44
  222. data/test/unit/syntax_highlighting.rb +70 -0
  223. data/test/unit/theme_management_test.rb +91 -0
  224. data/test/unit/view.rb +79 -12
  225. data/test/unit/widgets.rb +8 -8
  226. data/test/web_integration_test.rb +231 -0
  227. data/test/web_test_helper.rb +218 -0
  228. data/test/web_workflow_test.rb +527 -0
  229. data/ui/tui/bin/scriptorium +885 -415
  230. data/ui/web/app/app.rb +1398 -176
  231. data/ui/web/app/assets/livetext_mode.js +244 -0
  232. data/ui/web/app/error_helpers.rb +16 -16
  233. data/ui/web/app/views/advanced_config.erb +8 -2
  234. data/ui/web/app/views/asset_management.erb +56 -0
  235. data/ui/web/app/views/backup_management.erb +238 -0
  236. data/ui/web/app/views/config_widget.erb +232 -0
  237. data/ui/web/app/views/dashboard.erb +64 -72
  238. data/ui/web/app/views/deploy_config.erb +3 -0
  239. data/ui/web/app/views/edit_pages.erb +170 -2
  240. data/ui/web/app/views/edit_post.erb +130 -9
  241. data/ui/web/app/views/edit_theme.erb +73 -0
  242. data/ui/web/app/views/edit_theme_file.erb +74 -0
  243. data/ui/web/app/views/theme_management.erb +130 -0
  244. data/ui/web/app/views/view_dashboard.erb +666 -25
  245. data/ui/web/app/views/widgets.erb +249 -0
  246. data/ui/web/bin/scriptorium-web +35 -24
  247. data/ui/web/tmp/timing.log +17 -0
  248. data/ui/web/tmp/web_server.log +0 -5
  249. metadata +190 -116
  250. data/assets/back-icon.png +0 -0
  251. data/assets/icons/facebook.svg +0 -1
  252. data/assets/icons/github.svg +0 -1
  253. data/assets/icons/instagram.svg +0 -1
  254. data/assets/icons/reddit.svg +0 -1
  255. data/assets/icons/x.svg +0 -1
  256. data/assets/icons/youtube.svg +0 -1
  257. data/bin/scriptorium +0 -1511
  258. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +0 -34
  259. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +0 -50
  260. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +0 -73
  261. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +0 -70
  262. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +0 -110
  263. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +0 -73
  264. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +0 -124
  265. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +0 -46
  266. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +0 -97
  267. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +0 -211
  268. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +0 -141
  269. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +0 -211
  270. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +0 -134
  271. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +0 -41
  272. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +0 -49
  273. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +0 -46
  274. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +0 -41
  275. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +0 -41
  276. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +0 -256
  277. data/lib/scriptorium/syntax_highlighter.rb +0 -234
  278. data/test/manual/deploy_symlink_demo.rb +0 -142
  279. data/test/manual/symlink_demo.rb +0 -117
  280. data/test/manual/test2.rb +0 -12
  281. data/test/manual/test_banner_from_file.rb +0 -150
  282. data/test/manual/test_banner_in_header.rb +0 -35
  283. data/test/manual/test_code_highlighting.rb +0 -68
  284. data/test/manual/test_complex_header.rb +0 -74
  285. data/test/manual/test_empty_header.rb +0 -32
  286. data/test/manual/test_radial_custom.rb +0 -58
  287. data/test/manual/test_radial_large_radius.rb +0 -52
  288. data/test/manual/test_svg_debug.rb +0 -47
  289. data/test/pages-demo/config/currentview.txt +0 -1
  290. data/test/pages-demo/views/demo/config/common.js +0 -57
  291. data/test/pages-demo/views/demo/config/footer.txt +0 -1
  292. data/test/pages-demo/views/demo/config/global-head.txt +0 -8
  293. data/test/pages-demo/views/demo/config/header.txt +0 -1
  294. data/test/pages-demo/views/demo/config/layout.txt +0 -1
  295. data/test/pages-demo/views/demo/config/left.txt +0 -1
  296. data/test/pages-demo/views/demo/config/main.txt +0 -1
  297. data/test/pages-demo/views/demo/config/right.txt +0 -1
  298. data/test/pages-demo/views/demo/config.txt +0 -3
  299. data/test/pages-demo/views/demo/output/panes/footer.html +0 -1
  300. data/test/pages-demo/views/demo/output/panes/header.html +0 -1
  301. data/test/pages-demo/views/demo/output/panes/left.html +0 -1
  302. data/test/pages-demo/views/demo/output/panes/main.html +0 -1
  303. data/test/pages-demo/views/demo/output/panes/right.html +0 -1
  304. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +0 -5
  305. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +0 -4
  306. data/test/scriptorium-TEST-1754622690-146/config/common.js +0 -57
  307. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +0 -1
  308. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +0 -9
  309. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +0 -1
  310. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +0 -4
  311. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +0 -3
  312. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +0 -8
  313. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +0 -6
  314. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +0 -1
  315. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +0 -1
  316. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +0 -1
  317. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +0 -1
  318. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +0 -14
  319. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +0 -13
  320. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +0 -1
  321. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +0 -5
  322. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +0 -4
  323. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +0 -57
  324. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +0 -5
  325. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +0 -2
  326. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +0 -9
  327. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +0 -4
  328. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +0 -5
  329. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +0 -3
  330. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +0 -5
  331. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +0 -3
  332. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +0 -7
  333. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +0 -3
  334. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +0 -3
  335. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +0 -3
  336. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +0 -3
  337. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +0 -3
  338. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +0 -3
  339. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +0 -1
  340. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +0 -1
  341. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +0 -1
  342. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +0 -1
  343. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +0 -1
  344. data/ui/web/tmp/web_server.pid +0 -1
  345. /data/{test/pages-demo/views/demo/config/bootstrap_css.txt → lib/scriptorium/support/bootstrap/css.txt} +0 -0
  346. /data/{test/pages-demo/views/demo/config/bootstrap_js.txt → lib/scriptorium/support/bootstrap/js.txt} +0 -0
  347. /data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/reddit.txt +0 -0
  348. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout → lib/scriptorium/support/templates}/layout.txt +0 -0
  349. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt → lib/scriptorium/support/theme/footer.lt3} +0 -0
  350. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt → lib/scriptorium/support/theme/left.lt3} +0 -0
  351. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt → lib/scriptorium/support/theme/main.lt3} +0 -0
  352. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt → lib/scriptorium/support/theme/right.lt3} +0 -0
  353. /data/test/manual/banner-tests/{config.txt → svg.txt} +0 -0
  354. /data/test/manual/{test6.rb → test_advanced_widgets.rb} +0 -0
  355. /data/test/manual/{test1.rb → test_basic_posts.rb} +0 -0
  356. /data/test/manual/{test4.rb → test_layout_widgets.rb} +0 -0
  357. /data/test/manual/{test5.rb → test_pagination.rb} +0 -0
  358. /data/test/manual/{test3.rb → test_random_posts.rb} +0 -0
@@ -4,16 +4,24 @@ manual_setup
4
4
 
5
5
  @repo.create_view("testview", "Test View", "A test view for manual inspection")
6
6
 
7
- # Enable syntax highlighting for this test by adding it to global-head.txt
7
+ # Ensure Highlight.js is enabled via global-head.txt
8
8
  global_head_file = "test/scriptorium-TEST/views/testview/config/global-head.txt"
9
- File.open(global_head_file, "a") { |f| f.puts "syntax # Enable Rouge syntax highlighting" }
10
-
11
- # Post with Rouge syntax highlighting for multiple languages
9
+ head_contents = File.exist?(global_head_file) ? File.read(global_head_file) : ""
10
+ add_lines = []
11
+ add_lines << "highlight # Enable Highlight.js assets" unless head_contents.include?("\nhighlight")
12
+ add_lines << "highlight_custom # Optional Highlight.js CSS overrides" unless head_contents.include?("\nhighlight_custom")
13
+ unless add_lines.empty?
14
+ File.open(global_head_file, "a") { |f| add_lines.each { |ln| f.puts ln } }
15
+ end
16
+
17
+ # Post with comprehensive syntax highlighting tests
12
18
  draft_body = <<~'BODY'
13
- .blurb Testing Rouge syntax highlighting for Ruby, Elixir, and JavaScript.
14
- This post tests the integrated Rouge syntax highlighter with three different programming languages.
19
+ .blurb
20
+ Testing Highlight.js syntax highlighting with multiple languages.
21
+ .end
22
+ This post tests the integrated syntax highlighters with Ruby, Elixir, JavaScript, and plain text.
15
23
 
16
- ## Ruby Code Example
24
+ ## Ruby Code Example (Rouge)
17
25
 
18
26
  .code ruby
19
27
  class User
@@ -37,7 +45,7 @@ draft_body = <<~'BODY'
37
45
  user.greet
38
46
  .end
39
47
 
40
- ## Elixir Code Example
48
+ ## Elixir Code Example (Rouge)
41
49
 
42
50
  .code elixir
43
51
  defmodule Calculator do
@@ -62,7 +70,7 @@ draft_body = <<~'BODY'
62
70
  IO.puts("5 + 3 = 8")
63
71
  .end
64
72
 
65
- ## JavaScript Code Example
73
+ ## JavaScript Code Example (Highlight.js)
66
74
 
67
75
  .code javascript
68
76
  class TodoList {
@@ -90,58 +98,70 @@ draft_body = <<~'BODY'
90
98
  }
91
99
  return todo;
92
100
  }
93
-
94
- removeTodo(id) {
95
- const index = this.todos.findIndex(t => t.id === id);
96
- if (index > -1) {
97
- return this.todos.splice(index, 1)[0];
98
- }
99
- return null;
100
- }
101
-
102
- getCompletedTodos() {
103
- return this.todos.filter(t => t.completed);
104
- }
105
-
106
- getPendingTodos() {
107
- return this.todos.filter(t => !t.completed);
108
- }
109
101
  }
110
102
 
111
103
  // Usage example
112
104
  const todoList = new TodoList();
113
- todoList.addTodo("Learn Rouge syntax highlighting");
105
+ todoList.addTodo("Learn syntax highlighting");
114
106
  todoList.addTodo("Test multiple languages");
115
- todoList.addTodo("Write documentation", true);
107
+ .end
108
+
109
+ ## Simple Ruby Example
110
+
111
+ .code ruby
112
+ def hello_world
113
+ puts "Hello, World!"
114
+ @greeting = "Welcome to Scriptorium"
115
+ return @greeting
116
+ end
117
+ .end
116
118
 
117
- console.log("Pending todos:", todoList.getPendingTodos().length);
118
- console.log("Completed todos:", todoList.getCompletedTodos().length);
119
+ ## Plain Text Example
120
+
121
+ .code text
122
+ This is just plain text
123
+ No syntax highlighting needed
124
+ But it should still be in a code block
119
125
  .end
120
126
 
121
127
  ## Test Results
122
128
 
123
129
  Each code block above should display with proper syntax highlighting:
124
130
 
125
- - **Ruby**: Keywords in red, strings in blue, variables in orange
126
- - **Elixir**: Functions in purple, atoms in green, strings in blue
127
- - **JavaScript**: Keywords in red, functions in purple, strings in blue
131
+ - **Ruby (Rouge)**: Keywords in red, strings in blue, variables in orange
132
+ - **Elixir (Rouge)**: Functions in purple, atoms in green, strings in blue
133
+ - **JavaScript (Highlight.js)**: Keywords in red, functions in purple, strings in blue
134
+ - **Plain text**: No highlighting, just code block formatting
128
135
 
129
- The highlighting should work automatically thanks to our Rouge integration!
136
+ Rouge and Highlight.js highlighting should work automatically!
130
137
  BODY
131
138
 
132
- name = @repo.create_draft(title: "Rouge Syntax Highlighting Test", views: ["testview"], body: draft_body)
139
+ name = @repo.create_draft(title: "Comprehensive Syntax Highlighting Test", views: ["testview"], body: draft_body)
133
140
  num = @repo.finish_draft(name)
134
141
  @repo.generate_post(num)
135
142
 
136
143
  @repo.generate_front_page("testview")
137
144
 
145
+ # Open the generated post directly (works under simple httpd without SPA)
146
+ unless ARGV.include?("--automated")
147
+ post_url = "http://127.0.0.1:8000/scriptorium-TEST/views/testview/output/posts/0001-comprehensive-syntax-highlighting-test.html"
148
+ puts "Press Enter to open the post directly to verify highlighting."
149
+ STDIN.gets
150
+ system("open #{post_url}")
151
+ end
152
+
138
153
  instruct <<~EOS
139
- Front page should have one post with Rouge syntax highlighting.
140
- Ruby code should be highlighted with Ruby syntax (keywords red, strings blue, variables orange).
141
- Elixir code should be highlighted with Elixir syntax (functions purple, atoms green, strings blue).
142
- JavaScript code should be highlighted with JS syntax (keywords red, functions purple, strings blue).
143
- Check that Rouge CSS is included in the generated HTML.
154
+ Front page should have one post with comprehensive syntax highlighting.
155
+
156
+ Highlight.js (Ruby, Elixir, JavaScript):
157
+ - Ruby/Elixir/JS: Token colors applied client-side
158
+
159
+ Plain text: No highlighting, just code block formatting
160
+
161
+ Check that Highlight.js CSS/JS are included in the generated HTML.
144
162
  All code blocks should have proper token classes and syntax highlighting.
163
+ Then open the post directly to verify:
164
+ http://127.0.0.1:8000/scriptorium-TEST/views/testview/output/posts/0001-comprehensive-syntax-highlighting-test.html
145
165
  EOS
146
166
 
147
- examine("testview")
167
+ examine("testview")
@@ -0,0 +1,88 @@
1
+ require 'fileutils'
2
+ require 'shellwords'
3
+
4
+ module PreviewUtils
5
+ DEFAULT_CONFIG = {
6
+ "posts.per.page" => "5",
7
+ "entry.title.size" => "1.1em",
8
+ "entry.blurb.size" => "0.75em",
9
+ "entry.date.size" => "0.7em",
10
+ "entry.date.width" => "14%",
11
+ "entry.cellpadding" => "6",
12
+ "entry.margin.bottom" => "6px",
13
+ "entry.title.color" => "#000000",
14
+ "entry.blurb.color" => "#666666",
15
+ "entry.date.color" => "#888888",
16
+ "entry.line.height" => "1.1",
17
+ "entry.date.alignment"=> "right",
18
+ "entry.date.spacing" => "0.1em",
19
+ "entry.date.format" => "month dd break yyyy",
20
+ "index.margin.top" => "10px"
21
+ }.freeze
22
+
23
+ def self.write_post_index_config(repo_path, view_name, overrides = {})
24
+ config = DEFAULT_CONFIG.merge(overrides.transform_keys(&:to_s))
25
+ cfg_dir = File.join(repo_path, 'views', view_name, 'config')
26
+ FileUtils.mkdir_p(cfg_dir)
27
+ lines = config.map { |k,v| "#{k} #{v}" }.join("\n") + "\n"
28
+ File.write(File.join(cfg_dir, 'post_index.txt'), lines)
29
+ end
30
+
31
+ def self.seed_posts(api, titles_and_blurbs)
32
+ Array(titles_and_blurbs).each do |tb|
33
+ if tb.is_a?(Array)
34
+ api.create_post(tb[0], tb[1] || "")
35
+ else
36
+ api.create_post(tb.to_s, "")
37
+ end
38
+ end
39
+ end
40
+
41
+ def self.reference_image_in_post(repo_path, post_id4, filename)
42
+ src = File.join(repo_path, 'posts', post_id4, 'source.lt3')
43
+ File.write(src, ".image #{filename}\n\nHello")
44
+ end
45
+
46
+ def self.paths(repo_path, view_name)
47
+ base = File.expand_path(File.join(repo_path, 'views', view_name))
48
+ index_file = File.join(base, 'output', 'index.html')
49
+ post_index = File.join(base, 'output', 'post_index.html')
50
+ page1 = File.join(base, 'output', 'page1.html')
51
+
52
+ # Try to find first post slug from 0001
53
+ slug = nil
54
+ meta = File.join(repo_path, 'posts', '0001', 'meta.txt')
55
+ if File.exist?(meta)
56
+ line = File.read(meta).lines.grep(/^post.slug\s+/).first
57
+ slug = line.split.last if line
58
+ end
59
+ post_html = slug ? File.join(base, 'output', 'posts', slug) : nil
60
+
61
+ {
62
+ index_file: index_file,
63
+ post_index: post_index,
64
+ page1: page1,
65
+ post_html: post_html,
66
+ preview_index_url: "http://localhost:4567/preview/#{view_name}/index.html",
67
+ preview_post_url: (slug ? "http://localhost:4567/preview/#{view_name}/posts/#{slug}" : nil)
68
+ }
69
+ end
70
+
71
+ def self.interactive_open(label:, paths: [], urls: [])
72
+ puts "\n[Manual] Opening #{label}..."
73
+ # Always open local files
74
+ paths.compact.each do |target|
75
+ next if target.to_s.empty?
76
+ system("open #{Shellwords.escape(target)}")
77
+ end
78
+ # Also open server URLs (user asked to issue open commands)
79
+ urls.compact.each do |u|
80
+ next if u.to_s.empty?
81
+ system("open #{Shellwords.escape(u)}")
82
+ end
83
+ puts "[Manual] Press Enter to continue..."
84
+ STDIN.gets
85
+ end
86
+ end
87
+
88
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/scriptorium'
4
+
5
+ puts "=== Scriptorium Gem Asset Test ==="
6
+ puts "Gem version: #{Scriptorium::VERSION}"
7
+ puts
8
+
9
+ # Test that we can access the StandardFiles class
10
+ predef = Scriptorium::StandardFiles.new
11
+ puts "✅ StandardFiles class accessible"
12
+
13
+ # Test post template generation
14
+ template = predef.support_data('templates/post.lt3')
15
+ puts "✅ Post template generated (#{template.lines.count} lines)"
16
+
17
+ # Test that clipboard function is in common.js
18
+ common_js = predef.common_js
19
+ if common_js.include?('copyPermalinkToClipboard')
20
+ puts "✅ Clipboard function found in common.js"
21
+ else
22
+ puts "❌ Clipboard function NOT found in common.js"
23
+ end
24
+
25
+ # Test template with variables
26
+ vars = {
27
+ :'post.title' => 'Test Post',
28
+ :'post.pubdate' => '2025-08-14',
29
+ :'post.date' => '2025-08-14',
30
+ :'post.tags' => 'test, gem',
31
+ :'post.body' => 'This is a test post from the installed gem.',
32
+ :reddit_button => ''
33
+ }
34
+
35
+ result = template % vars
36
+ puts "✅ Template variable substitution works"
37
+ puts "✅ Generated HTML contains copy button: #{result.include?('copyPermalinkToClipboard')}"
38
+
39
+ # Test that the copy button is present
40
+ if result.include?('Copy link')
41
+ puts "✅ Copy link button present in generated HTML"
42
+ else
43
+ puts "❌ Copy link button NOT present in generated HTML"
44
+ end
45
+
46
+ puts
47
+ puts "=== Asset Test Complete ==="
48
+ puts "All gem assets are working correctly!"
data/test/test_helpers.rb CHANGED
@@ -27,6 +27,16 @@ module TestHelpers
27
27
  assert lines.size == num, "Expected #{num} lines in #{file}; found #{lines.size}"
28
28
  end
29
29
 
30
+ # Assert that a string includes text, with concise error message
31
+ def assert_includes_concise_string(content, text, description)
32
+ unless content.include?(text)
33
+ # Show content size and a snippet for debugging
34
+ size = content.size
35
+ snippet = content[0, 300].gsub(/\s+/, ' ').strip
36
+ flunk "#{description} - Expected to find '#{text}' in content (#{size} bytes). Content snippet: #{snippet}..."
37
+ end
38
+ end
39
+
30
40
  def assert_file_newer?(f1, f2)
31
41
  assert File.mtime(f1) > File.mtime(f2), "File #{f1} is not newer than #{f2}"
32
42
  end
@@ -27,7 +27,7 @@ class TUIEditorIntegrationTest < Minitest::Test
27
27
 
28
28
  ENV['NOREADLINE'] = '1'
29
29
 
30
- PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium') do |read, write, pid|
30
+ PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium --test') do |read, write, pid|
31
31
  begin
32
32
  run_links_widget_workflow(read, write)
33
33
  ensure
@@ -44,7 +44,7 @@ class TUIEditorIntegrationTest < Minitest::Test
44
44
  # Test basic TUI flow without complex wizard
45
45
  ENV['NOREADLINE'] = '1'
46
46
 
47
- PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium') do |read, write, pid|
47
+ PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium --test') do |read, write, pid|
48
48
  begin
49
49
  run_basic_tui_workflow(read, write)
50
50
 
@@ -62,7 +62,7 @@ class TUIEditorIntegrationTest < Minitest::Test
62
62
  # Test creating a post through the TUI
63
63
  ENV['NOREADLINE'] = '1'
64
64
 
65
- PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium') do |read, write, pid|
65
+ PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium --test') do |read, write, pid|
66
66
  begin
67
67
  run_create_post_workflow(read, write)
68
68
  ensure
@@ -84,10 +84,10 @@ class TUIEditorIntegrationTest < Minitest::Test
84
84
  if output
85
85
  puts "Found: #{output[0].strip}" if ENV['VERBOSE']
86
86
  else
87
- puts "Failed to find pattern: #{pattern}"
87
+ # Pattern not found
88
88
  # Read what we actually got
89
89
  available = read.read_nonblock(1000) rescue ""
90
- puts "Available output: #{available.inspect}"
90
+ # Available output logged above
91
91
  end
92
92
  assert output, message
93
93
  output[0] # Return the matched string
@@ -126,7 +126,7 @@ class TUIEditorIntegrationTest < Minitest::Test
126
126
  get_string(read, /No repository found\./, "Should show 'No repository found'")
127
127
 
128
128
  # Send 'y' to create new repository
129
- send_and_expect(read, write, "y", "Created repository successfully.",
129
+ send_and_expect(read, write, "y", "Created test repository successfully.",
130
130
  "Should show repository created")
131
131
 
132
132
  # Wait for editor setup
@@ -144,18 +144,18 @@ class TUIEditorIntegrationTest < Minitest::Test
144
144
  get_string(read, "Setup complete", "Should show setup completion")
145
145
 
146
146
  # Wait for assistance question
147
- get_string(read, "Do you want assistance in creating your first view", "Should ask about assistance")
147
+ get_string(read, /Do you want assistance/, "Should ask about assistance")
148
148
 
149
149
  # Send 'y' for assistance
150
- send_and_expect(read, write, "y", "Enter view name",
150
+ send_and_expect(read, write, "y", /Enter view name/,
151
151
  "Should prompt for view name")
152
152
 
153
153
  # Send view name
154
- send_and_expect(read, write, "testview", "Enter view title",
154
+ send_and_expect(read, write, "testview", /Enter view title/,
155
155
  "Should prompt for view title")
156
156
 
157
157
  # Send view title
158
- send_and_expect(read, write, "Test View", "Enter subtitle",
158
+ send_and_expect(read, write, "Test View", /Enter subtitle/,
159
159
  "Should prompt for subtitle")
160
160
 
161
161
  # Send subtitle
@@ -211,7 +211,7 @@ class TUIEditorIntegrationTest < Minitest::Test
211
211
  get_string(read, "No repository found.", "Should show 'No repository found'")
212
212
 
213
213
  # Send 'y' to create new repository
214
- send_and_expect(read, write, "y", "Created repository successfully.",
214
+ send_and_expect(read, write, "y", "Created test repository successfully.",
215
215
  "Should show repository created")
216
216
 
217
217
  # Wait for editor setup
@@ -229,7 +229,7 @@ class TUIEditorIntegrationTest < Minitest::Test
229
229
  get_string(read, "Setup complete", "Should show setup completion")
230
230
 
231
231
  # Wait for assistance question
232
- get_string(read, "Do you want assistance in creating your first view", "Should ask about assistance")
232
+ get_string(read, /Do you want assistance/, "Should ask about assistance")
233
233
 
234
234
  # Send 'n' to skip assistance
235
235
  send_and_expect(read, write, "n", "[sample]", "Should show main prompt")
@@ -244,7 +244,7 @@ class TUIEditorIntegrationTest < Minitest::Test
244
244
  get_string(read, "No repository found.", "Should show 'No repository found'")
245
245
 
246
246
  # Send 'y' to create new repository
247
- send_and_expect(read, write, "y", "Created repository successfully.",
247
+ send_and_expect(read, write, "y", "Created test repository successfully.",
248
248
  "Should show repository created")
249
249
 
250
250
  # Wait for editor setup
@@ -262,13 +262,13 @@ class TUIEditorIntegrationTest < Minitest::Test
262
262
  get_string(read, "Setup complete", "Should show setup completion")
263
263
 
264
264
  # Wait for assistance question
265
- get_string(read, "Do you want assistance in creating your first view", "Should ask about assistance")
265
+ get_string(read, /Do you want assistance/, "Should ask about assistance")
266
266
 
267
267
  # Send 'n' to skip assistance
268
268
  send_and_expect(read, write, "n", "[sample]", "Should show main prompt")
269
269
 
270
270
  # Create a post
271
- send_and_expect(read, write, "new post Test Post", "Created draft",
271
+ send_and_expect(read, write, "new post Test Post", /Created draft:/,
272
272
  "Should show draft created")
273
273
 
274
274
  # Wait for editor opening