scriptorium 0.0.3 → 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.
- checksums.yaml +4 -4
- data/README.lt3 +324 -0
- data/README.md +3155 -1
- data/assets/.DS_Store +0 -0
- data/assets/README.md +44 -0
- data/assets/icons/social/reddit.png +0 -0
- data/assets/icons/social/x-logo.png +0 -0
- data/assets/icons/ui/.DS_Store +0 -0
- data/assets/icons/ui/back.png +0 -0
- data/assets/icons/ui/copy.png +0 -0
- data/assets/icons/ui/down.png +0 -0
- data/assets/icons/ui/end.png +0 -0
- data/assets/icons/ui/exit.png +0 -0
- data/assets/icons/ui/foo +10 -0
- data/assets/icons/ui/home.png +0 -0
- data/assets/icons/ui/left.png +0 -0
- data/assets/icons/ui/next.png +0 -0
- data/assets/icons/ui/right.png +0 -0
- data/assets/icons/ui/start.png +0 -0
- data/assets/icons/ui/up.png +0 -0
- data/assets/imagenotfound.jpg +0 -0
- data/assets/samples/placeholder.svg +9 -0
- data/assets/themes/standard/favicon.svg +6 -0
- data/bin/sblog +84 -5
- data/bin/scriptorium +1 -0
- data/doc/README.txt +6 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +94 -0
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +2 -0
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +45 -0
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +35 -0
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +27 -0
- data/doc/anti-amnesia/20250807-213025.md +116 -0
- data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
- data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
- data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
- data/doc/banner_svg_config.md +114 -0
- data/doc/contrib.lt3 +8 -0
- data/doc/dependencies.md +281 -0
- data/doc/hacker.lt3 +5 -0
- data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
- data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
- data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
- data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
- data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
- data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
- data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
- data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
- data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
- data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
- data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
- data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
- data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
- data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
- data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
- data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
- data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
- data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
- data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
- data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
- data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
- data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
- data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
- data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
- data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
- data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
- data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
- data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
- data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
- data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
- data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
- data/doc/imported/0018-ruby-puns/post.html +46 -0
- data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
- data/doc/imported/0020-fffff/metadata.txt +7 -0
- data/doc/imported/0020-fffff/post.html +24 -0
- data/doc/imported/0020-fffff/source.lt3 +12 -0
- data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
- data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
- data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
- data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
- data/doc/imported/0023-doctor-sleep/post.html +63 -0
- data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
- data/doc/imported/0024-just-a-test/metadata.txt +7 -0
- data/doc/imported/0024-just-a-test/post.html +24 -0
- data/doc/imported/0024-just-a-test/source.lt3 +12 -0
- data/doc/imported/import_summary.txt +98 -0
- data/doc/livetext-informal-spec.txt +65 -0
- data/doc/myuserdoc/ch-0.lt3 +31 -0
- data/doc/myuserdoc/ch-1.lt3 +37 -0
- data/doc/myuserdoc/ch-10.lt3 +22 -0
- data/doc/myuserdoc/ch-2.lt3 +37 -0
- data/doc/myuserdoc/ch-3.lt3 +19 -0
- data/doc/myuserdoc/ch-4.lt3 +43 -0
- data/doc/myuserdoc/ch-5.lt3 +22 -0
- data/doc/myuserdoc/ch-6.lt3 +19 -0
- data/doc/myuserdoc/ch-7.lt3 +16 -0
- data/doc/myuserdoc/ch-8.lt3 +13 -0
- data/doc/myuserdoc/ch-9.lt3 +19 -0
- data/doc/myuserdoc/tweak.rb +18 -0
- data/doc/myuserdoc/userdoc-toc.txt +88 -0
- data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
- data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
- data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
- data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
- data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
- data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
- data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
- data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
- data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
- data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
- data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
- data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
- data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
- data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
- data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
- data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
- data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
- data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
- data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
- data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
- data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
- data/doc/old-posts/0024-just-a-test.lt3 +12 -0
- data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
- data/doc/old-repo +1 -0
- data/doc/reddit_credentials_template.json +8 -0
- data/doc/reddit_integration.md +207 -0
- data/doc/user.lt3 +35 -0
- data/doc/user_guide_section_1.md +137 -0
- data/doc/user_guide_section_10.md +515 -0
- data/doc/user_guide_section_11.md +708 -0
- data/doc/user_guide_section_2.md +233 -0
- data/doc/user_guide_section_3.md +5 -0
- data/doc/user_guide_section_4.md +221 -0
- data/doc/user_guide_section_5.md +243 -0
- data/doc/user_guide_section_6.md +147 -0
- data/doc/user_guide_section_7.md +311 -0
- data/doc/user_guide_section_8.md +224 -0
- data/doc/user_guide_section_9.md +375 -0
- data/lib/rouge/lexers/livetext.rb +74 -0
- data/lib/scriptorium/api.rb +2373 -0
- data/lib/scriptorium/banner_svg.rb +729 -0
- data/lib/scriptorium/contract.rb +34 -0
- data/lib/scriptorium/exceptions.rb +201 -1
- data/lib/scriptorium/helpers.rb +675 -0
- data/lib/scriptorium/post.rb +259 -0
- data/lib/scriptorium/reddit.rb +83 -0
- data/lib/scriptorium/repo.rb +938 -0
- data/lib/scriptorium/standard_files.rb +149 -0
- data/lib/scriptorium/support/bootstrap/css.txt +5 -0
- data/lib/scriptorium/support/bootstrap/js.txt +4 -0
- data/lib/scriptorium/support/common_js/clipboard.js +35 -0
- data/lib/scriptorium/support/common_js/content-loader.js +187 -0
- data/lib/scriptorium/support/common_js/navigation.js +52 -0
- data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
- data/lib/scriptorium/support/config/reddit.txt +10 -0
- data/lib/scriptorium/support/config/reddit_template.txt +17 -0
- data/lib/scriptorium/support/config/social.txt +8 -0
- data/lib/scriptorium/support/highlight/css.txt +2 -0
- data/lib/scriptorium/support/highlight/custom.css +119 -0
- data/lib/scriptorium/support/highlight/js.txt +1 -0
- data/lib/scriptorium/support/post_index/config.txt +15 -0
- data/lib/scriptorium/support/post_index/style.css +55 -0
- data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
- data/lib/scriptorium/support/templates/initial_post.lt3 +12 -0
- data/lib/scriptorium/support/templates/layout.txt +5 -0
- data/lib/scriptorium/support/templates/post.lt3 +104 -0
- data/lib/scriptorium/support/theme/footer.lt3 +2 -0
- data/lib/scriptorium/support/theme/header.lt3 +4 -0
- data/lib/scriptorium/support/theme/left.lt3 +3 -0
- data/lib/scriptorium/support/theme/main.lt3 +5 -0
- data/lib/scriptorium/support/theme/right.lt3 +3 -0
- data/lib/scriptorium/theme.rb +192 -0
- data/lib/scriptorium/version.rb +1 -1
- data/lib/scriptorium/view.rb +1021 -0
- data/lib/scriptorium/widgets/featured_posts.rb +149 -0
- data/lib/scriptorium/widgets/links.rb +112 -0
- data/lib/scriptorium/widgets/pages.rb +133 -0
- data/lib/scriptorium/widgets/widget.rb +133 -0
- data/lib/scriptorium.rb +38 -34
- data/lib/skeleton.rb +10 -1
- data/scriptorium.gemspec +17 -5
- data/test/README.md +69 -0
- data/test/WEB_INTEGRATION_README.md +196 -0
- data/test/all +83 -0
- data/test/api_demo.rb +99 -0
- data/test/assets/imagenotfound.jpg +0 -0
- data/test/assets/images/.DS_Store +0 -0
- data/test/assets/images/README.md +27 -0
- data/test/assets/images/odd_aspect.png +0 -0
- data/test/assets/images/perfect.png +0 -0
- data/test/assets/images/small.png +0 -0
- data/test/assets/images/tall.png +0 -0
- data/test/assets/images/very_tall.png +0 -0
- data/test/assets/images/very_wide.png +0 -0
- data/test/assets/images/wide.png +0 -0
- data/test/assets/testbanner.jpg +0 -0
- data/test/banner_svg/simple_helpers.rb +13 -0
- data/test/banner_svg/unit.rb +1000 -0
- data/test/config/deployment.txt +5 -0
- data/test/ed_test.rb +204 -0
- data/test/integration/cursor_banner_combinations.rb +193 -0
- data/test/integration/cursor_banner_features.rb +374 -0
- data/test/integration/integration_test.rb +326 -0
- data/test/integration/preview_flow_test.rb +94 -0
- data/test/livetext_plugin_test.rb +500 -0
- data/test/manual/asset_mgmt.rb +67 -0
- data/test/manual/banner-tests/index.html +45 -0
- data/test/manual/banner-tests/svg.txt +3 -0
- data/test/manual/banner-tests/test01.html +122 -0
- data/test/manual/banner-tests/test02.html +122 -0
- data/test/manual/banner-tests/test03.html +122 -0
- data/test/manual/banner-tests/test04.html +129 -0
- data/test/manual/banner-tests/test05.html +129 -0
- data/test/manual/banner-tests/test06.html +129 -0
- data/test/manual/banner-tests/test07.html +129 -0
- data/test/manual/banner-tests/test08.html +123 -0
- data/test/manual/banner-tests/test09.html +123 -0
- data/test/manual/banner-tests/test10.html +123 -0
- data/test/manual/banner-tests/test11.html +123 -0
- data/test/manual/banner-tests/test12.html +123 -0
- data/test/manual/banner-tests/test13.html +123 -0
- data/test/manual/banner-tests/test14.html +123 -0
- data/test/manual/banner-tests/test15.html +122 -0
- data/test/manual/banner-tests/test16.html +122 -0
- data/test/manual/banner-tests/test17.html +122 -0
- data/test/manual/banner-tests/test18.html +132 -0
- data/test/manual/banner-tests/test19.html +132 -0
- data/test/manual/banner-tests/test20.html +132 -0
- data/test/manual/banner-tests/test21.html +132 -0
- data/test/manual/banner-tests/test22.html +132 -0
- data/test/manual/banner-tests/test23.html +132 -0
- data/test/manual/banner-tests/test24.html +132 -0
- data/test/manual/banner-tests/test25.html +131 -0
- data/test/manual/banner_environment.rb +205 -0
- data/test/manual/codemirror_demo.html +773 -0
- data/test/manual/create_posts_for_web.rb +114 -0
- data/test/manual/environment.rb +67 -0
- data/test/manual/make_banner.rb +153 -0
- data/test/manual/preview_manual_test.rb +129 -0
- data/test/manual/sample_banner_config.txt +12 -0
- data/test/manual/test_advanced_widgets.rb +73 -0
- data/test/manual/test_banner_combinations.rb +120 -0
- data/test/manual/test_banner_features.rb +306 -0
- data/test/manual/test_banner_integration.rb +115 -0
- data/test/manual/test_banner_radial.rb +87 -0
- data/test/manual/test_basic_posts.rb +47 -0
- data/test/manual/test_layout_widgets.rb +40 -0
- data/test/manual/test_pagination.rb +24 -0
- data/test/manual/test_random_posts.rb +38 -0
- data/test/manual/test_syntax_highlighting.rb +167 -0
- data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
- data/test/rubytext/rubytext_demo_test.rb +42 -0
- data/test/rubytext/rubytext_testing_guide.md +277 -0
- data/test/run_automated_tests.rb +45 -0
- data/test/staging/.DS_Store +0 -0
- data/test/support/preview_utils.rb +88 -0
- data/test/syntax_highlighting_test.lt3 +124 -0
- data/test/test_gem_assets.rb +48 -0
- data/test/test_helpers.rb +240 -0
- data/test/tui_editor_integration_test.rb +296 -0
- data/test/tui_integration_test.rb +883 -0
- data/test/unit/api.rb +1776 -0
- data/test/unit/asset_management.rb +219 -0
- data/test/unit/backup_test.rb +451 -0
- data/test/unit/clipboard_test.rb +60 -0
- data/test/unit/contract_test.rb +69 -0
- data/test/unit/core.rb +1211 -0
- data/test/unit/deploy_config_test.rb +248 -0
- data/test/unit/deploy_test.rb +478 -0
- data/test/unit/edit_post_test.rb +168 -0
- data/test/unit/gem_asset_management.rb +183 -0
- data/test/unit/livetext_basic.rb +57 -0
- data/test/unit/livetext_compatibility.rb +82 -0
- data/test/unit/parse_cmd_test.rb +260 -0
- data/test/unit/permalink_copy_test.rb +211 -0
- data/test/unit/post.rb +309 -0
- data/test/unit/post_index_config_test.rb +258 -0
- data/test/unit/post_state_helpers_test.rb +137 -0
- data/test/unit/read_commented_file_test.rb +278 -0
- data/test/unit/reddit_test.rb +235 -0
- data/test/unit/repo.rb +569 -0
- data/test/unit/social_test.rb +366 -0
- data/test/unit/syntax_highlighting.rb +70 -0
- data/test/unit/theme_management_test.rb +91 -0
- data/test/unit/view.rb +498 -0
- data/test/unit/widgets.rb +669 -0
- data/test/web_integration_test.rb +231 -0
- data/test/web_test_helper.rb +218 -0
- data/test/web_workflow_test.rb +527 -0
- data/test/wizard_test.rb +123 -0
- data/ui/README.md +67 -0
- data/ui/common/lib/ui_common.rb +8 -0
- data/ui/rubytext/README.md +191 -0
- data/ui/rubytext/bin/scriptorium-rubytext +402 -0
- data/ui/rubytext/lib/rubytext_ui.rb +300 -0
- data/ui/tui/bin/scriptorium +1890 -0
- data/ui/tui/test/tui_test.rb +23 -0
- data/ui/web/app/app.rb +2600 -0
- data/ui/web/app/assets/livetext_mode.js +244 -0
- data/ui/web/app/error_helpers.rb +150 -0
- data/ui/web/app/views/advanced_config.erb +196 -0
- data/ui/web/app/views/asset_management.erb +645 -0
- data/ui/web/app/views/backup_management.erb +238 -0
- data/ui/web/app/views/banner_config.erb +200 -0
- data/ui/web/app/views/config_widget.erb +232 -0
- data/ui/web/app/views/configure_view.erb +401 -0
- data/ui/web/app/views/dashboard.erb +154 -0
- data/ui/web/app/views/deploy_config.erb +149 -0
- data/ui/web/app/views/edit_pages.erb +363 -0
- data/ui/web/app/views/edit_post.erb +175 -0
- data/ui/web/app/views/edit_theme.erb +73 -0
- data/ui/web/app/views/edit_theme_file.erb +74 -0
- data/ui/web/app/views/error_page.erb +29 -0
- data/ui/web/app/views/header_config.erb +155 -0
- data/ui/web/app/views/layout_config.erb +147 -0
- data/ui/web/app/views/navbar_config.erb +411 -0
- data/ui/web/app/views/theme_management.erb +130 -0
- data/ui/web/app/views/view_dashboard.erb +779 -0
- data/ui/web/app/views/widgets.erb +249 -0
- data/ui/web/bin/scriptorium-web +164 -0
- data/ui/web/test/web_basic_test.rb +38 -0
- data/ui/web/test_navbar.txt +7 -0
- data/ui/web/tmp/timing.log +17 -0
- data/ui/web/tmp/web_server.log +0 -0
- metadata +434 -8
- data/lib/scriptorium/engine.rb +0 -22
- data/test/engine/unit.rb +0 -44
@@ -0,0 +1,773 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>CodeMirror + LiveText Demo</title>
|
7
|
+
|
8
|
+
<!-- CodeMirror CDN -->
|
9
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
|
10
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
|
11
|
+
|
12
|
+
<!-- CodeMirror themes -->
|
13
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/monokai.min.css">
|
14
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/eclipse.min.css">
|
15
|
+
|
16
|
+
<style>
|
17
|
+
body {
|
18
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
19
|
+
margin: 20px;
|
20
|
+
background: #f5f5f5;
|
21
|
+
}
|
22
|
+
|
23
|
+
.container {
|
24
|
+
max-width: 1200px;
|
25
|
+
margin: 0 auto;
|
26
|
+
background: white;
|
27
|
+
border-radius: 8px;
|
28
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
29
|
+
overflow: hidden;
|
30
|
+
}
|
31
|
+
|
32
|
+
.header {
|
33
|
+
background: #2c3e50;
|
34
|
+
color: white;
|
35
|
+
padding: 20px;
|
36
|
+
}
|
37
|
+
|
38
|
+
.header h1 {
|
39
|
+
margin: 0;
|
40
|
+
font-size: 24px;
|
41
|
+
}
|
42
|
+
|
43
|
+
.controls {
|
44
|
+
background: #ecf0f1;
|
45
|
+
padding: 15px;
|
46
|
+
border-bottom: 1px solid #bdc3c7;
|
47
|
+
}
|
48
|
+
|
49
|
+
.control-group {
|
50
|
+
display: inline-block;
|
51
|
+
margin-right: 20px;
|
52
|
+
}
|
53
|
+
|
54
|
+
.control-group label {
|
55
|
+
font-weight: bold;
|
56
|
+
margin-right: 8px;
|
57
|
+
}
|
58
|
+
|
59
|
+
.control-group select, .control-group button {
|
60
|
+
padding: 5px 10px;
|
61
|
+
border: 1px solid #bdc3c7;
|
62
|
+
border-radius: 4px;
|
63
|
+
background: white;
|
64
|
+
}
|
65
|
+
|
66
|
+
.macro-toolbar {
|
67
|
+
background: #f8f9fa;
|
68
|
+
padding: 10px 15px;
|
69
|
+
border-bottom: 1px solid #dee2e6;
|
70
|
+
display: flex;
|
71
|
+
align-items: center;
|
72
|
+
gap: 10px;
|
73
|
+
}
|
74
|
+
|
75
|
+
.toolbar-label {
|
76
|
+
font-weight: bold;
|
77
|
+
color: #495057;
|
78
|
+
margin-right: 10px;
|
79
|
+
}
|
80
|
+
|
81
|
+
.macro-btn {
|
82
|
+
padding: 8px 12px;
|
83
|
+
border: 1px solid #ced4da;
|
84
|
+
border-radius: 4px;
|
85
|
+
background: white;
|
86
|
+
cursor: pointer;
|
87
|
+
font-size: 16px;
|
88
|
+
transition: all 0.2s;
|
89
|
+
}
|
90
|
+
|
91
|
+
.macro-btn:hover {
|
92
|
+
background: #e9ecef;
|
93
|
+
border-color: #adb5bd;
|
94
|
+
transform: translateY(-1px);
|
95
|
+
}
|
96
|
+
|
97
|
+
.macro-btn:active {
|
98
|
+
transform: translateY(0);
|
99
|
+
background: #dee2e6;
|
100
|
+
}
|
101
|
+
|
102
|
+
.editor-container {
|
103
|
+
padding: 20px;
|
104
|
+
}
|
105
|
+
|
106
|
+
.CodeMirror {
|
107
|
+
height: 500px;
|
108
|
+
border: 1px solid #ddd;
|
109
|
+
border-radius: 4px;
|
110
|
+
font-size: 14px;
|
111
|
+
}
|
112
|
+
|
113
|
+
/* LiveText syntax highlighting */
|
114
|
+
.cm-strong { color: #e74c3c; font-weight: bold; }
|
115
|
+
.cm-em { color: #8e44ad; font-style: italic; }
|
116
|
+
.cm-string-2 { background: #f8f9fa; color: #495057; font-family: monospace; }
|
117
|
+
.cm-strikethrough { color: #95a5a6; text-decoration: line-through; }
|
118
|
+
.cm-variable { color: #3498db; font-weight: bold; }
|
119
|
+
.cm-function { color: #27ae60; font-weight: bold; }
|
120
|
+
.cm-keyword { color: #e67e22; font-weight: bold; }
|
121
|
+
.cm-comment { color: #7f8c8d; font-style: italic; }
|
122
|
+
.cm-bracket { color: #f39c12; font-weight: bold; }
|
123
|
+
|
124
|
+
.info {
|
125
|
+
background: #e8f4fd;
|
126
|
+
border: 1px solid #bee5eb;
|
127
|
+
border-radius: 4px;
|
128
|
+
padding: 15px;
|
129
|
+
margin: 20px;
|
130
|
+
}
|
131
|
+
|
132
|
+
.info h3 {
|
133
|
+
margin-top: 0;
|
134
|
+
color: #0c5460;
|
135
|
+
}
|
136
|
+
|
137
|
+
.features {
|
138
|
+
display: grid;
|
139
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
140
|
+
gap: 20px;
|
141
|
+
margin: 20px;
|
142
|
+
}
|
143
|
+
|
144
|
+
.feature {
|
145
|
+
background: #f8f9fa;
|
146
|
+
border: 1px solid #dee2e6;
|
147
|
+
border-radius: 4px;
|
148
|
+
padding: 15px;
|
149
|
+
}
|
150
|
+
|
151
|
+
.feature h4 {
|
152
|
+
margin-top: 0;
|
153
|
+
color: #495057;
|
154
|
+
}
|
155
|
+
</style>
|
156
|
+
</head>
|
157
|
+
<body>
|
158
|
+
<div class="container">
|
159
|
+
<div class="header">
|
160
|
+
<h1>CodeMirror + LiveText Demo</h1>
|
161
|
+
</div>
|
162
|
+
|
163
|
+
<div class="controls">
|
164
|
+
<div class="control-group">
|
165
|
+
<label>Theme:</label>
|
166
|
+
<select id="theme-selector">
|
167
|
+
<option value="default">Default</option>
|
168
|
+
<option value="monokai">Monokai (Dark)</option>
|
169
|
+
<option value="eclipse">Eclipse</option>
|
170
|
+
</select>
|
171
|
+
</div>
|
172
|
+
|
173
|
+
<div class="control-group">
|
174
|
+
<label>Mode:</label>
|
175
|
+
<select id="mode-selector">
|
176
|
+
<option value="livetext">LiveText</option>
|
177
|
+
<option value="markdown">Markdown</option>
|
178
|
+
<option value="html">HTML</option>
|
179
|
+
<option value="css">CSS</option>
|
180
|
+
<option value="javascript">JavaScript</option>
|
181
|
+
</select>
|
182
|
+
</div>
|
183
|
+
|
184
|
+
<div class="control-group">
|
185
|
+
<button id="toggle-linenumbers">Toggle Line Numbers</button>
|
186
|
+
</div>
|
187
|
+
|
188
|
+
<div class="control-group">
|
189
|
+
<button id="toggle-wordwrap">Toggle Word Wrap</button>
|
190
|
+
</div>
|
191
|
+
</div>
|
192
|
+
|
193
|
+
<div class="macro-toolbar">
|
194
|
+
<span class="toolbar-label">Macros:</span>
|
195
|
+
<button onclick="runMacro('format_list')" title="Format as list" class="macro-btn">📋</button>
|
196
|
+
<button onclick="runMacro('add_metadata')" title="Add metadata block" class="macro-btn">📝</button>
|
197
|
+
<button onclick="runMacro('wrap_code')" title="Wrap in code block" class="macro-btn">💻</button>
|
198
|
+
<button onclick="runMacro('bold_selection')" title="Make bold" class="macro-btn">**</button>
|
199
|
+
<button onclick="runMacro('italic_selection')" title="Make italic" class="macro-btn">__</button>
|
200
|
+
<button onclick="runMacro('code_selection')" title="Make code" class="macro-btn">``</button>
|
201
|
+
</div>
|
202
|
+
|
203
|
+
<div class="editor-container">
|
204
|
+
<textarea id="editor" style="display: block; height: 500px; font-family: monospace; font-size: 14px; width: 100%; border: 1px solid #ddd; border-radius: 4px; padding: 10px;">
|
205
|
+
.h1 Sample LiveText Post
|
206
|
+
|
207
|
+
This is a sample LiveText post that demonstrates how CodeMirror could enhance the editing experience in Scriptorium.
|
208
|
+
|
209
|
+
.h3 Features Demonstrated
|
210
|
+
|
211
|
+
.list
|
212
|
+
*Syntax highlighting for LiveText syntax
|
213
|
+
**Line numbers for easy navigation
|
214
|
+
`Multiple themes (light/dark)
|
215
|
+
~Word wrap toggle
|
216
|
+
**Search and replace (Ctrl+F/Cmd+F)
|
217
|
+
**Multiple editing modes
|
218
|
+
.end
|
219
|
+
|
220
|
+
.h3 Variables and Functions
|
221
|
+
|
222
|
+
The current user is $username and their role is $user.role.
|
223
|
+
We can call $$max($count, 10) to get the maximum value.
|
224
|
+
Use $$link:https://scriptorium.dev for the main site.
|
225
|
+
Learn $$index[functional programming] today!
|
226
|
+
|
227
|
+
.h3 Dot Commands
|
228
|
+
|
229
|
+
.banner Welcome to Scriptorium!
|
230
|
+
.index web development
|
231
|
+
.comment This is a block comment that won't be processed
|
232
|
+
.end
|
233
|
+
$.banner This is an indented banner command
|
234
|
+
|
235
|
+
.h3 Code and Formatting
|
236
|
+
|
237
|
+
This is `inline code and this is **bold text.
|
238
|
+
Here's some _italic content and ~~strikethrough text.
|
239
|
+
|
240
|
+
You can also use brackets for multi-word formatting:
|
241
|
+
*[This entire phrase is bold] and _[this entire phrase is italic].
|
242
|
+
For code: `[multiple words of code] and ~[strikethrough text].
|
243
|
+
|
244
|
+
For longer code blocks, we can use brackets:
|
245
|
+
`[def create_post(title, content)
|
246
|
+
post = Post.new
|
247
|
+
post.title = title
|
248
|
+
post.content = content
|
249
|
+
post.save
|
250
|
+
end]`
|
251
|
+
|
252
|
+
.h3 Lists and Structure
|
253
|
+
|
254
|
+
.list
|
255
|
+
**First item with *emphasis
|
256
|
+
`Second item with code
|
257
|
+
Third item with $variable reference
|
258
|
+
.end
|
259
|
+
|
260
|
+
.list
|
261
|
+
Numbered item with $$function call
|
262
|
+
Another item with _italic text
|
263
|
+
.end
|
264
|
+
|
265
|
+
.h3 Metadata
|
266
|
+
|
267
|
+
.list
|
268
|
+
**Author: $current_user
|
269
|
+
**Created: $$date
|
270
|
+
**Status: Draft
|
271
|
+
**Tags: demo, codemirror, livetext
|
272
|
+
.end
|
273
|
+
|
274
|
+
.h3 Content
|
275
|
+
|
276
|
+
This is the main content area where you would write your blog post. CodeMirror provides:
|
277
|
+
|
278
|
+
.list
|
279
|
+
**Better editing experience than basic textareas
|
280
|
+
*Syntax highlighting for LiveText syntax
|
281
|
+
`Line numbers for easy reference
|
282
|
+
**Multiple themes for different preferences
|
283
|
+
**Keyboard shortcuts for power users
|
284
|
+
**Search and replace functionality
|
285
|
+
**Word wrap for long lines
|
286
|
+
**Multiple language modes for different content types
|
287
|
+
.end
|
288
|
+
|
289
|
+
The editor automatically handles indentation, provides visual feedback, and makes editing much more pleasant than a basic HTML textarea.
|
290
|
+
|
291
|
+
.comment This is a comment line that shows comment highlighting
|
292
|
+
|
293
|
+
.raw
|
294
|
+
This is raw content that won't be processed.
|
295
|
+
It can contain $variables and $$functions that won't expand.
|
296
|
+
It can even have .banner commands that won't execute.
|
297
|
+
Even .code ruby blocks are treated as plain text here.
|
298
|
+
__RAW__
|
299
|
+
|
300
|
+
.h3 Code Examples
|
301
|
+
|
302
|
+
.def
|
303
|
+
def create_post(title, content)
|
304
|
+
post = Post.new
|
305
|
+
post.title = title
|
306
|
+
post.content = content
|
307
|
+
post.save
|
308
|
+
end
|
309
|
+
.end
|
310
|
+
|
311
|
+
.code elixir
|
312
|
+
defmodule Post do
|
313
|
+
def create(title, content) do
|
314
|
+
%Post{title: title, content: content}
|
315
|
+
end
|
316
|
+
end
|
317
|
+
.end
|
318
|
+
|
319
|
+
.code bash
|
320
|
+
#!/bin/bash
|
321
|
+
for file in *.lt3; do
|
322
|
+
echo "Processing $file"
|
323
|
+
./process.sh "$file"
|
324
|
+
done
|
325
|
+
.end
|
326
|
+
</textarea>
|
327
|
+
</div>
|
328
|
+
|
329
|
+
<div class="info">
|
330
|
+
<h3>What You're Seeing</h3>
|
331
|
+
<p>This is a standalone demo of CodeMirror integrated with LiveText-like content. It shows exactly what you'd get if you added CodeMirror to your Scriptorium web interface.</p>
|
332
|
+
</div>
|
333
|
+
|
334
|
+
<div class="features">
|
335
|
+
<div class="feature">
|
336
|
+
<h4>Immediate Benefits</h4>
|
337
|
+
<ul>
|
338
|
+
<li>Better editing experience</li>
|
339
|
+
<li>Syntax highlighting</li>
|
340
|
+
<li>Line numbers</li>
|
341
|
+
<li>Multiple themes</li>
|
342
|
+
</ul>
|
343
|
+
</div>
|
344
|
+
|
345
|
+
<div class="feature">
|
346
|
+
<h4>Advanced Features</h4>
|
347
|
+
<ul>
|
348
|
+
<li>Search & replace</li>
|
349
|
+
<li>Keyboard shortcuts</li>
|
350
|
+
<li>Word wrap</li>
|
351
|
+
<li>Multiple modes</li>
|
352
|
+
</ul>
|
353
|
+
</div>
|
354
|
+
|
355
|
+
<div class="feature">
|
356
|
+
<h4>Integration Points</h4>
|
357
|
+
<ul>
|
358
|
+
<li>Post editing</li>
|
359
|
+
<li>Configuration editing</li>
|
360
|
+
<li>Template editing</li>
|
361
|
+
<li>Asset editing</li>
|
362
|
+
</ul>
|
363
|
+
</div>
|
364
|
+
</div>
|
365
|
+
</div>
|
366
|
+
|
367
|
+
<script>
|
368
|
+
// Custom LiveText syntax highlighting mode
|
369
|
+
CodeMirror.defineMode("livetext", function() {
|
370
|
+
return {
|
371
|
+
startState: function() {
|
372
|
+
return {
|
373
|
+
inRaw: false,
|
374
|
+
inCodeBody: false,
|
375
|
+
codeLanguage: null,
|
376
|
+
inBracket: false,
|
377
|
+
bracketDepth: 0
|
378
|
+
};
|
379
|
+
},
|
380
|
+
|
381
|
+
token: function(stream, state) {
|
382
|
+
// Skip whitespace
|
383
|
+
if (stream.eatSpace()) return null;
|
384
|
+
|
385
|
+
// Raw blocks override everything else
|
386
|
+
if (state.inRaw) {
|
387
|
+
if (stream.match(/^__RAW__/) || stream.match(/^\.end$/)) {
|
388
|
+
state.inRaw = false;
|
389
|
+
return "keyword";
|
390
|
+
}
|
391
|
+
stream.skipToEnd();
|
392
|
+
return "comment"; // Plain text in raw blocks
|
393
|
+
}
|
394
|
+
|
395
|
+
// Check for .raw command
|
396
|
+
if (stream.match(/^\.raw$/)) {
|
397
|
+
state.inRaw = true;
|
398
|
+
return "keyword";
|
399
|
+
}
|
400
|
+
|
401
|
+
// Check for .comment command
|
402
|
+
if (stream.match(/^\.comment$/)) {
|
403
|
+
state.inRaw = true; // Use same state as raw for plain text
|
404
|
+
return "keyword";
|
405
|
+
}
|
406
|
+
|
407
|
+
// Code body blocks
|
408
|
+
if (state.inCodeBody) {
|
409
|
+
if (stream.match(/^\.end$/)) {
|
410
|
+
state.inCodeBody = false;
|
411
|
+
state.codeLanguage = null;
|
412
|
+
return "keyword";
|
413
|
+
}
|
414
|
+
|
415
|
+
// Use appropriate language highlighting
|
416
|
+
if (state.codeLanguage === "ruby") {
|
417
|
+
// Ruby syntax highlighting
|
418
|
+
if (stream.match(/^#/)) {
|
419
|
+
stream.skipToEnd();
|
420
|
+
return "comment";
|
421
|
+
}
|
422
|
+
if (stream.match(/^def\b/)) return "def";
|
423
|
+
if (stream.match(/^end\b/)) return "keyword";
|
424
|
+
if (stream.match(/^class\b/)) return "def";
|
425
|
+
if (stream.match(/^module\b/)) return "def";
|
426
|
+
if (stream.match(/^require\b/)) return "keyword";
|
427
|
+
if (stream.match(/^puts\b/)) return "keyword";
|
428
|
+
if (stream.match(/^[A-Z][a-zA-Z0-9_]*/)) return "variable-2"; // Constants
|
429
|
+
if (stream.match(/^[a-z_][a-zA-Z0-9_]*/)) return "variable"; // Variables
|
430
|
+
if (stream.match(/^[0-9]+/)) return "number";
|
431
|
+
if (stream.match(/^["']/)) {
|
432
|
+
stream.skipTo(/["']/);
|
433
|
+
return "string";
|
434
|
+
}
|
435
|
+
} else if (state.codeLanguage === "elixir") {
|
436
|
+
// Elixir syntax highlighting
|
437
|
+
if (stream.match(/^#/)) {
|
438
|
+
stream.skipToEnd();
|
439
|
+
return "comment";
|
440
|
+
}
|
441
|
+
if (stream.match(/^def\b/)) return "def";
|
442
|
+
if (stream.match(/^end\b/)) return "keyword";
|
443
|
+
if (stream.match(/^defmodule\b/)) return "def";
|
444
|
+
if (stream.match(/^defp\b/)) return "def";
|
445
|
+
if (stream.match(/^IO\.puts\b/)) return "keyword";
|
446
|
+
if (stream.match(/^[A-Z][a-zA-Z0-9_]*/)) return "variable-2"; // Modules
|
447
|
+
if (stream.match(/^[a-z_][a-zA-Z0-9_]*/)) return "keyword"; // Functions
|
448
|
+
if (stream.match(/^[0-9]+/)) return "number";
|
449
|
+
if (stream.match(/^["']/)) {
|
450
|
+
stream.skipTo(/["']/);
|
451
|
+
return "string";
|
452
|
+
}
|
453
|
+
} else if (state.codeLanguage === "bash") {
|
454
|
+
// Bash syntax highlighting
|
455
|
+
if (stream.match(/^#/)) {
|
456
|
+
stream.skipToEnd();
|
457
|
+
return "comment";
|
458
|
+
}
|
459
|
+
if (stream.match(/^if\b/)) return "keyword";
|
460
|
+
if (stream.match(/^then\b/)) return "keyword";
|
461
|
+
if (stream.match(/^fi\b/)) return "keyword";
|
462
|
+
if (stream.match(/^for\b/)) return "keyword";
|
463
|
+
if (stream.match(/^do\b/)) return "keyword";
|
464
|
+
if (stream.match(/^done\b/)) return "keyword";
|
465
|
+
if (stream.match(/^\$[A-Z_]+/)) return "variable"; // Environment variables
|
466
|
+
if (stream.match(/^[0-9]+/)) return "number";
|
467
|
+
if (stream.match(/^["']/)) {
|
468
|
+
stream.skipTo(/["']/);
|
469
|
+
return "string";
|
470
|
+
}
|
471
|
+
}
|
472
|
+
|
473
|
+
stream.next();
|
474
|
+
return null;
|
475
|
+
}
|
476
|
+
|
477
|
+
// Check for code body commands
|
478
|
+
if (stream.match(/^\.(def|func)$/)) {
|
479
|
+
state.inCodeBody = true;
|
480
|
+
state.codeLanguage = "ruby";
|
481
|
+
return "keyword";
|
482
|
+
}
|
483
|
+
|
484
|
+
let codeMatch = stream.match(/^\.code\s+(ruby|elixir|bash)/);
|
485
|
+
if (codeMatch) {
|
486
|
+
state.inCodeBody = true;
|
487
|
+
state.codeLanguage = codeMatch[1];
|
488
|
+
return "keyword";
|
489
|
+
}
|
490
|
+
|
491
|
+
// One-line comments (. comment)
|
492
|
+
if (stream.match(/^\.\s/)) {
|
493
|
+
stream.skipToEnd();
|
494
|
+
return "comment";
|
495
|
+
}
|
496
|
+
|
497
|
+
// Dot commands (.command or $.command)
|
498
|
+
if (stream.match(/^\.\w+/)) {
|
499
|
+
return "keyword";
|
500
|
+
}
|
501
|
+
if (stream.match(/^\s+\$\.[\w.]+/)) {
|
502
|
+
return "keyword";
|
503
|
+
}
|
504
|
+
|
505
|
+
// Variables ($foo, $foo.bar) - stop at invalid characters
|
506
|
+
if (stream.match(/^\$/)) {
|
507
|
+
let name = "";
|
508
|
+
let ch = stream.next();
|
509
|
+
if (ch && /[a-zA-Z]/.test(ch)) {
|
510
|
+
name += ch;
|
511
|
+
while (stream.peek() && /[\w.]/.test(stream.peek())) {
|
512
|
+
ch = stream.next();
|
513
|
+
name += ch;
|
514
|
+
}
|
515
|
+
// Check if next character is invalid for a name
|
516
|
+
if (stream.peek() && !/[\w.]/.test(stream.peek())) {
|
517
|
+
return "variable";
|
518
|
+
}
|
519
|
+
}
|
520
|
+
return "variable";
|
521
|
+
}
|
522
|
+
|
523
|
+
// Functions ($$foo, $$foo:param, $$foo[param])
|
524
|
+
if (stream.match(/^\$\$/)) {
|
525
|
+
let name = "";
|
526
|
+
let ch = stream.next();
|
527
|
+
if (ch && /[a-zA-Z]/.test(ch)) {
|
528
|
+
name += ch;
|
529
|
+
while (stream.peek() && /[\w.]/.test(stream.peek())) {
|
530
|
+
ch = stream.next();
|
531
|
+
name += ch;
|
532
|
+
}
|
533
|
+
// Check for colon parameter
|
534
|
+
if (stream.peek() === ":") {
|
535
|
+
stream.next();
|
536
|
+
stream.skipToEnd();
|
537
|
+
}
|
538
|
+
return "function";
|
539
|
+
}
|
540
|
+
return "function";
|
541
|
+
}
|
542
|
+
|
543
|
+
// Bracketed content [content]
|
544
|
+
if (stream.match(/^\[/)) {
|
545
|
+
state.inBracket = true;
|
546
|
+
state.bracketDepth = 1;
|
547
|
+
return "bracket";
|
548
|
+
}
|
549
|
+
|
550
|
+
if (state.inBracket) {
|
551
|
+
if (stream.match(/^\]/)) {
|
552
|
+
state.inBracket = false;
|
553
|
+
state.bracketDepth = 0;
|
554
|
+
return "bracket";
|
555
|
+
}
|
556
|
+
// Continue reading bracket content
|
557
|
+
stream.next();
|
558
|
+
return "string";
|
559
|
+
}
|
560
|
+
|
561
|
+
// Bracketed formatting: *[text] _[text] `[text] ~[text]
|
562
|
+
if (stream.match(/^(\*|_|`|~)\[/)) {
|
563
|
+
state.inBracket = true;
|
564
|
+
state.bracketDepth = 1;
|
565
|
+
return "strong"; // All bracketed content gets same treatment for now
|
566
|
+
}
|
567
|
+
|
568
|
+
// Markers (* _ ` ~) - single and doubled
|
569
|
+
// Note: LiveText markers only initiate, never terminate
|
570
|
+
if (stream.match(/^\*\*/)) {
|
571
|
+
// Doubled marker - read until space, comma, or period
|
572
|
+
stream.eatWhile(/[^\s,.]/);
|
573
|
+
return "strong";
|
574
|
+
}
|
575
|
+
if (stream.match(/^__/)) {
|
576
|
+
stream.eatWhile(/[^\s,.]/);
|
577
|
+
return "em";
|
578
|
+
}
|
579
|
+
if (stream.match(/^``/)) {
|
580
|
+
stream.eatWhile(/[^\s,.]/);
|
581
|
+
return "string-2";
|
582
|
+
}
|
583
|
+
if (stream.match(/^~~/)) {
|
584
|
+
stream.eatWhile(/[^\s,.]/);
|
585
|
+
return "strikethrough";
|
586
|
+
}
|
587
|
+
|
588
|
+
// Single markers
|
589
|
+
if (stream.match(/^\*/)) {
|
590
|
+
stream.eatWhile(/[^\s]/);
|
591
|
+
return "strong";
|
592
|
+
}
|
593
|
+
if (stream.match(/^_/)) {
|
594
|
+
stream.eatWhile(/[^\s]/);
|
595
|
+
return "em";
|
596
|
+
}
|
597
|
+
if (stream.match(/^`/)) {
|
598
|
+
stream.eatWhile(/[^\s]/);
|
599
|
+
return "string-2";
|
600
|
+
}
|
601
|
+
if (stream.match(/^~/)) {
|
602
|
+
stream.eatWhile(/[^\s]/);
|
603
|
+
return "strikethrough";
|
604
|
+
}
|
605
|
+
|
606
|
+
// Continue reading
|
607
|
+
stream.next();
|
608
|
+
return null;
|
609
|
+
}
|
610
|
+
};
|
611
|
+
});
|
612
|
+
|
613
|
+
// Initialize CodeMirror
|
614
|
+
let editor;
|
615
|
+
try {
|
616
|
+
editor = CodeMirror.fromTextArea(document.getElementById('editor'), {
|
617
|
+
mode: 'livetext', // Use our custom LiveText mode
|
618
|
+
theme: 'default',
|
619
|
+
lineNumbers: true,
|
620
|
+
lineWrapping: false,
|
621
|
+
indentUnit: 2,
|
622
|
+
tabSize: 2,
|
623
|
+
indentWithTabs: false,
|
624
|
+
scrollbarStyle: 'native',
|
625
|
+
viewportMargin: Infinity,
|
626
|
+
extraKeys: {
|
627
|
+
"Ctrl-S": function(cm) {
|
628
|
+
// Simulate save
|
629
|
+
console.log("Save triggered");
|
630
|
+
},
|
631
|
+
"Cmd-S": function(cm) {
|
632
|
+
// Simulate save on Mac
|
633
|
+
console.log("Save triggered");
|
634
|
+
}
|
635
|
+
}
|
636
|
+
});
|
637
|
+
console.log("CodeMirror initialized successfully");
|
638
|
+
// Hide the original textarea since CodeMirror is now handling it
|
639
|
+
document.getElementById('editor').style.display = 'none';
|
640
|
+
} catch (error) {
|
641
|
+
console.error("CodeMirror initialization failed:", error);
|
642
|
+
// Fallback: show the textarea content
|
643
|
+
document.getElementById('editor').style.display = 'block';
|
644
|
+
document.getElementById('editor').style.height = '500px';
|
645
|
+
document.getElementById('editor').style.fontFamily = 'monospace';
|
646
|
+
document.getElementById('editor').style.fontSize = '14px';
|
647
|
+
}
|
648
|
+
|
649
|
+
// Theme selector
|
650
|
+
document.getElementById('theme-selector').addEventListener('change', function() {
|
651
|
+
console.log('Theme changed to:', this.value);
|
652
|
+
editor.setOption('theme', this.value);
|
653
|
+
});
|
654
|
+
|
655
|
+
// Mode selector
|
656
|
+
document.getElementById('mode-selector').addEventListener('change', function() {
|
657
|
+
let mode = this.value;
|
658
|
+
console.log('Mode changed to:', mode);
|
659
|
+
editor.setOption('mode', mode);
|
660
|
+
});
|
661
|
+
|
662
|
+
// Toggle line numbers
|
663
|
+
document.getElementById('toggle-linenumbers').addEventListener('click', function() {
|
664
|
+
let current = editor.getOption('lineNumbers');
|
665
|
+
console.log('Line numbers:', current, '->', !current);
|
666
|
+
editor.setOption('lineNumbers', !current);
|
667
|
+
});
|
668
|
+
|
669
|
+
// Toggle word wrap
|
670
|
+
document.getElementById('toggle-wordwrap').addEventListener('click', function() {
|
671
|
+
let current = editor.getOption('lineWrapping');
|
672
|
+
console.log('Word wrap:', current, '->', !current);
|
673
|
+
editor.setOption('lineWrapping', !current);
|
674
|
+
});
|
675
|
+
|
676
|
+
// Set initial size
|
677
|
+
editor.setSize('100%', '500px');
|
678
|
+
|
679
|
+
// Macro system
|
680
|
+
const macros = {
|
681
|
+
format_list: function(editor) {
|
682
|
+
const selection = editor.getSelection();
|
683
|
+
if (selection) {
|
684
|
+
const lines = selection.split('\n').filter(line => line.trim());
|
685
|
+
const formatted = lines.map(line => `*${line.trim()}`).join('\n');
|
686
|
+
editor.replaceSelection(formatted);
|
687
|
+
} else {
|
688
|
+
// If no selection, format current line
|
689
|
+
const line = editor.getLine(editor.getCursor().line);
|
690
|
+
if (line.trim()) {
|
691
|
+
editor.replaceRange(`*${line.trim()}`,
|
692
|
+
{line: editor.getCursor().line, ch: 0},
|
693
|
+
{line: editor.getCursor().line, ch: line.length});
|
694
|
+
}
|
695
|
+
}
|
696
|
+
},
|
697
|
+
|
698
|
+
add_metadata: function(editor) {
|
699
|
+
const metadata = `.metadata\n**Author: $username\n**Date: $$date\n**Status: Draft\n**Tags: \n.end`;
|
700
|
+
editor.replaceSelection(metadata);
|
701
|
+
},
|
702
|
+
|
703
|
+
wrap_code: function(editor) {
|
704
|
+
const selection = editor.getSelection();
|
705
|
+
if (selection) {
|
706
|
+
editor.replaceSelection(`\`[${selection}]`);
|
707
|
+
} else {
|
708
|
+
// If no selection, wrap current word
|
709
|
+
const cursor = editor.getCursor();
|
710
|
+
const word = editor.findWordAt(cursor);
|
711
|
+
if (word) {
|
712
|
+
const text = editor.getRange(word.anchor, word.head);
|
713
|
+
editor.replaceRange(`\`[${text}]`, word.anchor, word.head);
|
714
|
+
}
|
715
|
+
}
|
716
|
+
},
|
717
|
+
|
718
|
+
bold_selection: function(editor) {
|
719
|
+
const selection = editor.getSelection();
|
720
|
+
if (selection) {
|
721
|
+
editor.replaceSelection(`*[${selection}]`);
|
722
|
+
} else {
|
723
|
+
const cursor = editor.getCursor();
|
724
|
+
const word = editor.findWordAt(cursor);
|
725
|
+
if (word) {
|
726
|
+
const text = editor.getRange(word.anchor, word.head);
|
727
|
+
editor.replaceRange(`*[${text}]`, word.anchor, word.head);
|
728
|
+
}
|
729
|
+
}
|
730
|
+
},
|
731
|
+
|
732
|
+
italic_selection: function(editor) {
|
733
|
+
const selection = editor.getSelection();
|
734
|
+
if (selection) {
|
735
|
+
editor.replaceSelection(`_[${selection}]`);
|
736
|
+
} else {
|
737
|
+
const cursor = editor.getCursor();
|
738
|
+
const word = editor.findWordAt(cursor);
|
739
|
+
if (word) {
|
740
|
+
const text = editor.getRange(word.anchor, word.head);
|
741
|
+
editor.replaceRange(`_[${text}]`, word.anchor, word.head);
|
742
|
+
}
|
743
|
+
}
|
744
|
+
},
|
745
|
+
|
746
|
+
code_selection: function(editor) {
|
747
|
+
const selection = editor.getSelection();
|
748
|
+
if (selection) {
|
749
|
+
editor.replaceSelection(`\`[${selection}]`);
|
750
|
+
} else {
|
751
|
+
const cursor = editor.getCursor();
|
752
|
+
const word = editor.findWordAt(cursor);
|
753
|
+
if (word) {
|
754
|
+
const text = editor.getRange(word.anchor, word.head);
|
755
|
+
editor.replaceRange(`\`[${text}]`, word.anchor, word.head);
|
756
|
+
}
|
757
|
+
}
|
758
|
+
}
|
759
|
+
};
|
760
|
+
|
761
|
+
function runMacro(macroName) {
|
762
|
+
const macro = macros[macroName];
|
763
|
+
if (macro) {
|
764
|
+
macro(editor);
|
765
|
+
editor.focus(); // Return focus to editor
|
766
|
+
}
|
767
|
+
}
|
768
|
+
|
769
|
+
// Focus the editor
|
770
|
+
editor.focus();
|
771
|
+
</script>
|
772
|
+
</body>
|
773
|
+
</html>
|