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
data/ui/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Scriptorium UI Directory
|
2
|
+
|
3
|
+
This directory contains all user interface implementations for Scriptorium.
|
4
|
+
|
5
|
+
## Structure
|
6
|
+
|
7
|
+
```
|
8
|
+
ui/
|
9
|
+
├── tui/ # Terminal User Interface
|
10
|
+
│ ├── bin/scriptorium # TUI executable
|
11
|
+
│ ├── lib/ # TUI-specific code
|
12
|
+
│ └── test/ # TUI-specific tests
|
13
|
+
├── web/ # Web User Interface (future)
|
14
|
+
│ ├── app/ # Web app code
|
15
|
+
│ ├── public/ # Static assets
|
16
|
+
│ └── test/ # Web-specific tests
|
17
|
+
└── common/ # Shared UI utilities
|
18
|
+
├── lib/ # Common UI libraries
|
19
|
+
└── test/ # Common UI tests
|
20
|
+
```
|
21
|
+
|
22
|
+
## TUI (Terminal User Interface)
|
23
|
+
|
24
|
+
The current TUI implementation provides a command-line interface for Scriptorium.
|
25
|
+
|
26
|
+
- **Location**: `ui/tui/bin/scriptorium`
|
27
|
+
- **Features**: Interactive commands, view management, post creation, deployment
|
28
|
+
- **Dependencies**: Readline (optional), core Scriptorium library
|
29
|
+
|
30
|
+
## Web UI (Future)
|
31
|
+
|
32
|
+
Planned web interface for Scriptorium.
|
33
|
+
|
34
|
+
- **Status**: Not yet implemented
|
35
|
+
- **Planned Features**: Web-based post editing, view management, real-time preview
|
36
|
+
- **Technology**: To be determined (Sinatra, Rails, or other framework)
|
37
|
+
|
38
|
+
## Common Utilities
|
39
|
+
|
40
|
+
Shared code that can be used by multiple UI implementations.
|
41
|
+
|
42
|
+
- **Location**: `ui/common/lib/`
|
43
|
+
- **Purpose**: API wrappers, validation, common UI patterns
|
44
|
+
- **Usage**: Imported by TUI, Web UI, and future interfaces
|
45
|
+
|
46
|
+
## Development
|
47
|
+
|
48
|
+
### Adding a new UI
|
49
|
+
|
50
|
+
1. Create a new directory under `ui/`
|
51
|
+
2. Follow the established structure (bin/, lib/, test/)
|
52
|
+
3. Import common utilities from `ui/common/lib/`
|
53
|
+
4. Update the gemspec to include the new UI files
|
54
|
+
|
55
|
+
### Testing
|
56
|
+
|
57
|
+
Each UI has its own test directory for UI-specific tests. Common functionality is tested in `ui/common/test/`.
|
58
|
+
|
59
|
+
### Dependencies
|
60
|
+
|
61
|
+
- **TUI**: Minimal dependencies, uses core Scriptorium library
|
62
|
+
- **Web UI**: Will have additional web framework dependencies
|
63
|
+
- **Common**: No additional dependencies beyond core Scriptorium
|
64
|
+
|
65
|
+
## Migration Notes
|
66
|
+
|
67
|
+
The TUI was moved from `bin/scriptorium` to `ui/tui/bin/scriptorium` to better organize the codebase and prepare for multiple UI implementations.
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# Scriptorium RubyText UI
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
The RubyText UI brings back the sophisticated interactive interface from Runeblog, providing a middle ground between the simple TUI and the web app. It offers:
|
6
|
+
|
7
|
+
- **Rich interactive menus** - File selection, configuration, widget management
|
8
|
+
- **Context-aware interface** - Shows current view, status, and available actions
|
9
|
+
- **Direct file editing** - Integrated editor support with syntax highlighting
|
10
|
+
- **Visual feedback** - Colors, bold text, clear screens, progress indicators
|
11
|
+
- **Widget management** - Manage pages, links, navbar, and other widgets
|
12
|
+
- **Real-time preview** - Live preview of changes as you make them
|
13
|
+
|
14
|
+
## Architecture
|
15
|
+
|
16
|
+
### Core Components
|
17
|
+
|
18
|
+
1. **Main Interface** (`ui/rubytext/bin/scriptorium-rubytext`)
|
19
|
+
- Entry point with auto-discovery and setup
|
20
|
+
- Context display and command processing
|
21
|
+
- Error handling and recovery
|
22
|
+
|
23
|
+
2. **Menu System** (`ui/rubytext/lib/menus.rb`)
|
24
|
+
- Interactive menus for file selection
|
25
|
+
- Configuration management
|
26
|
+
- Widget management interfaces
|
27
|
+
|
28
|
+
3. **REPL System** (`ui/rubytext/lib/repl.rb`)
|
29
|
+
- Command processing and execution
|
30
|
+
- Context management
|
31
|
+
- Help system and documentation
|
32
|
+
|
33
|
+
4. **Editor Integration** (`ui/rubytext/lib/editor.rb`)
|
34
|
+
- Direct file editing with syntax highlighting
|
35
|
+
- Editor selection and configuration
|
36
|
+
- File validation and error handling
|
37
|
+
|
38
|
+
5. **Widget Management** (`ui/rubytext/lib/widgets.rb`)
|
39
|
+
- Page management
|
40
|
+
- Link management
|
41
|
+
- Navbar configuration
|
42
|
+
- Asset management
|
43
|
+
|
44
|
+
## Key Features
|
45
|
+
|
46
|
+
### Interactive Menus
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
# File selection menu
|
50
|
+
files = Dir.glob("*.rb")
|
51
|
+
num, selected = STDSCR.menu(title: "Select file:", items: files)
|
52
|
+
edit_file(selected) if selected
|
53
|
+
|
54
|
+
# Configuration menu
|
55
|
+
config_items = {
|
56
|
+
"General Settings" => "config/general.txt",
|
57
|
+
"View Settings" => "config/view.txt",
|
58
|
+
"Theme Settings" => "config/theme.txt"
|
59
|
+
}
|
60
|
+
num, target = STDSCR.menu(title: "Edit configuration:", items: config_items)
|
61
|
+
edit_file(target) if target
|
62
|
+
```
|
63
|
+
|
64
|
+
### Context-Aware Interface
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
# Shows current context in prompt
|
68
|
+
def display_context
|
69
|
+
view_name = @repo.current_view&.name || "No view"
|
70
|
+
print fx("[#{view_name}] ", Red, :bold)
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
### Direct File Editing
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
# Integrated editor with syntax highlighting
|
78
|
+
def edit_file(file, editor: nil)
|
79
|
+
editor ||= @repo.config.editor || "vim"
|
80
|
+
system("#{editor} #{file}")
|
81
|
+
refresh_screen
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
### Widget Management
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# Manage pages widget
|
89
|
+
def manage_pages
|
90
|
+
pages_dir = @view.dir/"pages"
|
91
|
+
files = Dir.glob("#{pages_dir}/*.html")
|
92
|
+
|
93
|
+
menu_items = files.map { |f| File.basename(f) } + ["[New Page]"]
|
94
|
+
num, selected = STDSCR.menu(title: "Manage Pages:", items: menu_items)
|
95
|
+
|
96
|
+
case selected
|
97
|
+
when "[New Page]"
|
98
|
+
create_new_page
|
99
|
+
else
|
100
|
+
edit_page(selected)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
## Implementation Plan
|
106
|
+
|
107
|
+
### Phase 1: Core Interface
|
108
|
+
- [ ] Basic RubyText integration
|
109
|
+
- [ ] Context display and command processing
|
110
|
+
- [ ] Simple menu system
|
111
|
+
- [ ] File editing integration
|
112
|
+
|
113
|
+
### Phase 2: Rich Menus
|
114
|
+
- [ ] Interactive file selection
|
115
|
+
- [ ] Configuration management
|
116
|
+
- [ ] Widget management interfaces
|
117
|
+
- [ ] Help system
|
118
|
+
|
119
|
+
### Phase 3: Advanced Features
|
120
|
+
- [ ] Real-time preview
|
121
|
+
- [ ] Asset management
|
122
|
+
- [ ] Deployment integration
|
123
|
+
- [ ] Performance optimization
|
124
|
+
|
125
|
+
## Usage Examples
|
126
|
+
|
127
|
+
### Basic Usage
|
128
|
+
|
129
|
+
```bash
|
130
|
+
# Start RubyText UI
|
131
|
+
scriptorium-rubytext
|
132
|
+
|
133
|
+
# Context-aware prompt
|
134
|
+
[sample] help # Show help
|
135
|
+
[sample] new post # Create new post
|
136
|
+
[sample] list posts # List posts in current view
|
137
|
+
[sample] config # Edit configuration
|
138
|
+
[sample] manage pages # Manage pages widget
|
139
|
+
```
|
140
|
+
|
141
|
+
### Interactive Menus
|
142
|
+
|
143
|
+
```
|
144
|
+
Select file:
|
145
|
+
1. config/general.txt
|
146
|
+
2. config/view.txt
|
147
|
+
3. config/theme.txt
|
148
|
+
4. [Cancel]
|
149
|
+
|
150
|
+
Enter choice (1-4): 2
|
151
|
+
```
|
152
|
+
|
153
|
+
### Widget Management
|
154
|
+
|
155
|
+
```
|
156
|
+
Manage Pages:
|
157
|
+
1. about.html
|
158
|
+
2. contact.html
|
159
|
+
3. [New Page]
|
160
|
+
4. [Cancel]
|
161
|
+
|
162
|
+
Enter choice (1-4): 3
|
163
|
+
```
|
164
|
+
|
165
|
+
## Benefits Over Current TUI
|
166
|
+
|
167
|
+
1. **More Interactive** - Rich menus vs. command-line only
|
168
|
+
2. **Better Visual Feedback** - Colors, bold text, clear screens
|
169
|
+
3. **Direct File Editing** - Integrated editor support
|
170
|
+
4. **Widget Management** - Visual management of pages, links, etc.
|
171
|
+
5. **Context Awareness** - Always shows current view and status
|
172
|
+
6. **Error Recovery** - Better error handling and recovery
|
173
|
+
|
174
|
+
## Benefits Over Web App
|
175
|
+
|
176
|
+
1. **Lighter Weight** - No web server, no browser needed
|
177
|
+
2. **Faster** - Direct file system access
|
178
|
+
3. **SSH Friendly** - Works over SSH connections
|
179
|
+
4. **Offline** - No internet connection required
|
180
|
+
5. **Familiar** - Terminal-based interface for command-line users
|
181
|
+
|
182
|
+
## Dependencies
|
183
|
+
|
184
|
+
- `rubytext` gem - Curses-based UI framework
|
185
|
+
- `scriptorium` core - Core Scriptorium functionality
|
186
|
+
- `livetext` - Content processing and generation
|
187
|
+
|
188
|
+
## Testing
|
189
|
+
|
190
|
+
See `test/rubytext/` for comprehensive testing strategy and implementation.
|
191
|
+
|
@@ -0,0 +1,402 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Scriptorium RubyText UI
|
4
|
+
# Brings back the sophisticated interactive interface from Runeblog
|
5
|
+
|
6
|
+
require 'rubytext'
|
7
|
+
require_relative '../../lib/scriptorium'
|
8
|
+
require_relative '../lib/rubytext_ui'
|
9
|
+
|
10
|
+
# Set up environment
|
11
|
+
ENV['DBC_DISABLED'] = 'true' if ENV['RACK_ENV'] == 'test'
|
12
|
+
|
13
|
+
class ScriptoriumRubyTextUI
|
14
|
+
include Scriptorium::Exceptions
|
15
|
+
include Scriptorium::Helpers
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@repo = nil
|
19
|
+
@current_view = nil
|
20
|
+
@editor = ENV['EDITOR'] || 'vim'
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
setup_rubytext
|
25
|
+
check_repository
|
26
|
+
main_loop
|
27
|
+
rescue => e
|
28
|
+
handle_error(e)
|
29
|
+
ensure
|
30
|
+
cleanup
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def setup_rubytext
|
36
|
+
RubyText.start(:_echo, :keypad, scroll: true, fg: :blue, bg: :white)
|
37
|
+
puts fx("Scriptorium RubyText UI", :bold)
|
38
|
+
puts fx("v #{Scriptorium::VERSION}", :red)
|
39
|
+
puts
|
40
|
+
end
|
41
|
+
|
42
|
+
def check_repository
|
43
|
+
if Scriptorium::Repo.exist?
|
44
|
+
@repo = Scriptorium::Repo.new
|
45
|
+
@current_view = @repo.current_view
|
46
|
+
puts fx("Repository found: #{@repo.root}", :green)
|
47
|
+
puts fx("Current view: #{@current_view&.name || 'None'}", :green)
|
48
|
+
else
|
49
|
+
puts fx("No repository found.", :yellow)
|
50
|
+
if yesno("Create new repository?")
|
51
|
+
create_repository
|
52
|
+
else
|
53
|
+
puts "Exiting..."
|
54
|
+
exit 0
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_repository
|
60
|
+
puts fx("Creating new repository...", :bold)
|
61
|
+
@repo = Scriptorium::Repo.create
|
62
|
+
puts fx("Repository created successfully!", :green)
|
63
|
+
|
64
|
+
if yesno("Create your first view?")
|
65
|
+
create_first_view
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_first_view
|
70
|
+
print "View name: "
|
71
|
+
view_name = gets.chomp.strip
|
72
|
+
return if view_name.empty?
|
73
|
+
|
74
|
+
print "View title: "
|
75
|
+
view_title = gets.chomp.strip
|
76
|
+
return if view_title.empty?
|
77
|
+
|
78
|
+
print "View subtitle (optional): "
|
79
|
+
view_subtitle = gets.chomp.strip
|
80
|
+
|
81
|
+
@current_view = @repo.create_view(view_name, view_title, view_subtitle)
|
82
|
+
puts fx("View '#{view_name}' created successfully!", :green)
|
83
|
+
end
|
84
|
+
|
85
|
+
def main_loop
|
86
|
+
loop do
|
87
|
+
display_context
|
88
|
+
command = gets.chomp.strip
|
89
|
+
|
90
|
+
case command.downcase
|
91
|
+
when 'q', 'quit', 'exit'
|
92
|
+
break
|
93
|
+
when 'h', 'help'
|
94
|
+
show_help
|
95
|
+
when 'v', 'version'
|
96
|
+
show_version
|
97
|
+
when 'new post'
|
98
|
+
create_post
|
99
|
+
when 'list posts'
|
100
|
+
list_posts
|
101
|
+
when 'list views'
|
102
|
+
list_views
|
103
|
+
when 'change view'
|
104
|
+
change_view
|
105
|
+
when 'config'
|
106
|
+
edit_config
|
107
|
+
when 'manage pages'
|
108
|
+
manage_pages
|
109
|
+
when 'manage links'
|
110
|
+
manage_links
|
111
|
+
when 'rebuild'
|
112
|
+
rebuild_view
|
113
|
+
when 'preview'
|
114
|
+
preview_view
|
115
|
+
when 'publish'
|
116
|
+
publish_view
|
117
|
+
when ''
|
118
|
+
# Empty command, continue
|
119
|
+
else
|
120
|
+
puts fx("Unknown command: #{command}", :red)
|
121
|
+
puts "Type 'help' for available commands"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def display_context
|
127
|
+
view_name = @current_view&.name || "No view"
|
128
|
+
print fx("[#{view_name}] ", :red, :bold)
|
129
|
+
end
|
130
|
+
|
131
|
+
def show_help
|
132
|
+
help_text = <<~HELP
|
133
|
+
Available Commands:
|
134
|
+
|
135
|
+
Basics:
|
136
|
+
h, help Show this help
|
137
|
+
q, quit, exit Exit the program
|
138
|
+
v, version Show version information
|
139
|
+
|
140
|
+
Posts:
|
141
|
+
new post Create a new post
|
142
|
+
list posts List posts in current view
|
143
|
+
edit <id> Edit a specific post
|
144
|
+
|
145
|
+
Views:
|
146
|
+
list views List all views
|
147
|
+
change view Change current view
|
148
|
+
new view Create a new view
|
149
|
+
|
150
|
+
Configuration:
|
151
|
+
config Edit configuration files
|
152
|
+
manage pages Manage pages widget
|
153
|
+
manage links Manage links widget
|
154
|
+
|
155
|
+
Generation:
|
156
|
+
rebuild Rebuild current view
|
157
|
+
preview Preview current view
|
158
|
+
publish Publish current view
|
159
|
+
HELP
|
160
|
+
|
161
|
+
puts help_text
|
162
|
+
end
|
163
|
+
|
164
|
+
def show_version
|
165
|
+
puts fx("Scriptorium", :bold), fx(" v #{Scriptorium::VERSION}", :red)
|
166
|
+
end
|
167
|
+
|
168
|
+
def create_post
|
169
|
+
return unless check_view
|
170
|
+
|
171
|
+
print "Post title: "
|
172
|
+
title = gets.chomp.strip
|
173
|
+
return if title.empty?
|
174
|
+
|
175
|
+
print "Post body (optional): "
|
176
|
+
body = gets.chomp.strip
|
177
|
+
|
178
|
+
draft_name = @repo.create_draft(title: title, body: body)
|
179
|
+
post_num = @repo.finish_draft(draft_name)
|
180
|
+
|
181
|
+
puts fx("Post ##{post_num} created successfully!", :green)
|
182
|
+
end
|
183
|
+
|
184
|
+
def list_posts
|
185
|
+
return unless check_view
|
186
|
+
|
187
|
+
posts = @repo.all_posts(@current_view)
|
188
|
+
if posts.empty?
|
189
|
+
puts "No posts in current view."
|
190
|
+
else
|
191
|
+
puts fx("Posts in #{@current_view.name}:", :bold)
|
192
|
+
posts.each do |post|
|
193
|
+
puts " #{post.id}: #{post.title}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def list_views
|
199
|
+
views = @repo.views
|
200
|
+
if views.empty?
|
201
|
+
puts "No views found."
|
202
|
+
else
|
203
|
+
puts fx("Available views:", :bold)
|
204
|
+
views.each do |view|
|
205
|
+
current = view == @current_view ? " (current)" : ""
|
206
|
+
puts " #{view.name}#{current}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def change_view
|
212
|
+
views = @repo.views
|
213
|
+
return puts("No views available.") if views.empty?
|
214
|
+
|
215
|
+
puts fx("Available views:", :bold)
|
216
|
+
views.each_with_index do |view, i|
|
217
|
+
current = view == @current_view ? " (current)" : ""
|
218
|
+
puts " #{i + 1}. #{view.name}#{current}"
|
219
|
+
end
|
220
|
+
|
221
|
+
print "Select view (1-#{views.length}): "
|
222
|
+
choice = gets.chomp.strip.to_i
|
223
|
+
|
224
|
+
if choice >= 1 && choice <= views.length
|
225
|
+
@current_view = views[choice - 1]
|
226
|
+
@repo.current_view = @current_view
|
227
|
+
puts fx("Switched to view: #{@current_view.name}", :green)
|
228
|
+
else
|
229
|
+
puts fx("Invalid choice.", :red)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def edit_config
|
234
|
+
config_items = {
|
235
|
+
"General Settings" => "config/general.txt",
|
236
|
+
"View Settings" => "config/view.txt",
|
237
|
+
"Theme Settings" => "config/theme.txt"
|
238
|
+
}
|
239
|
+
|
240
|
+
puts fx("Configuration files:", :bold)
|
241
|
+
config_items.each_with_index do |(name, path), i|
|
242
|
+
puts " #{i + 1}. #{name}"
|
243
|
+
end
|
244
|
+
|
245
|
+
print "Select file (1-#{config_items.length}): "
|
246
|
+
choice = gets.chomp.strip.to_i
|
247
|
+
|
248
|
+
if choice >= 1 && choice <= config_items.length
|
249
|
+
file_path = config_items.values[choice - 1]
|
250
|
+
edit_file(file_path)
|
251
|
+
else
|
252
|
+
puts fx("Invalid choice.", :red)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def manage_pages
|
257
|
+
return unless check_view
|
258
|
+
|
259
|
+
pages_dir = @current_view.dir/"pages"
|
260
|
+
files = Dir.glob("#{pages_dir}/*.html") if Dir.exist?(pages_dir)
|
261
|
+
files ||= []
|
262
|
+
|
263
|
+
menu_items = files.map { |f| File.basename(f) } + ["[New Page]", "[Cancel]"]
|
264
|
+
|
265
|
+
puts fx("Manage Pages:", :bold)
|
266
|
+
menu_items.each_with_index do |item, i|
|
267
|
+
puts " #{i + 1}. #{item}"
|
268
|
+
end
|
269
|
+
|
270
|
+
print "Select option (1-#{menu_items.length}): "
|
271
|
+
choice = gets.chomp.strip.to_i
|
272
|
+
|
273
|
+
if choice >= 1 && choice <= menu_items.length
|
274
|
+
selected = menu_items[choice - 1]
|
275
|
+
case selected
|
276
|
+
when "[New Page]"
|
277
|
+
create_new_page
|
278
|
+
when "[Cancel]"
|
279
|
+
return
|
280
|
+
else
|
281
|
+
edit_page(selected)
|
282
|
+
end
|
283
|
+
else
|
284
|
+
puts fx("Invalid choice.", :red)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def manage_links
|
289
|
+
return unless check_view
|
290
|
+
|
291
|
+
links_dir = @current_view.dir/"widgets"/"links"
|
292
|
+
list_file = links_dir/"list.txt" if Dir.exist?(links_dir)
|
293
|
+
|
294
|
+
if list_file && File.exist?(list_file)
|
295
|
+
edit_file(list_file)
|
296
|
+
else
|
297
|
+
puts "No links widget found. Create one first."
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def rebuild_view
|
302
|
+
return unless check_view
|
303
|
+
|
304
|
+
puts fx("Rebuilding view...", :bold)
|
305
|
+
@repo.generate_view(@current_view)
|
306
|
+
puts fx("View rebuilt successfully!", :green)
|
307
|
+
end
|
308
|
+
|
309
|
+
def preview_view
|
310
|
+
return unless check_view
|
311
|
+
|
312
|
+
puts fx("Starting preview server...", :bold)
|
313
|
+
# Implementation would start a local server
|
314
|
+
puts "Preview available at: http://localhost:8000"
|
315
|
+
end
|
316
|
+
|
317
|
+
def publish_view
|
318
|
+
return unless check_view
|
319
|
+
|
320
|
+
puts fx("Publishing view...", :bold)
|
321
|
+
# Implementation would handle deployment
|
322
|
+
puts fx("View published successfully!", :green)
|
323
|
+
end
|
324
|
+
|
325
|
+
def create_new_page
|
326
|
+
print "Page title: "
|
327
|
+
title = gets.chomp.strip
|
328
|
+
return if title.empty?
|
329
|
+
|
330
|
+
print "Page filename (without .html): "
|
331
|
+
filename = gets.chomp.strip
|
332
|
+
return if filename.empty?
|
333
|
+
|
334
|
+
filename += ".html" unless filename.end_with?(".html")
|
335
|
+
page_path = @current_view.dir/"pages"/filename
|
336
|
+
|
337
|
+
content = <<~HTML
|
338
|
+
<!DOCTYPE html>
|
339
|
+
<html>
|
340
|
+
<head>
|
341
|
+
<title>#{title}</title>
|
342
|
+
</head>
|
343
|
+
<body>
|
344
|
+
<h1>#{title}</h1>
|
345
|
+
<p>Page content goes here.</p>
|
346
|
+
</body>
|
347
|
+
</html>
|
348
|
+
HTML
|
349
|
+
|
350
|
+
File.write(page_path, content)
|
351
|
+
puts fx("Page '#{filename}' created successfully!", :green)
|
352
|
+
end
|
353
|
+
|
354
|
+
def edit_page(filename)
|
355
|
+
page_path = @current_view.dir/"pages"/filename
|
356
|
+
if File.exist?(page_path)
|
357
|
+
edit_file(page_path)
|
358
|
+
else
|
359
|
+
puts fx("Page '#{filename}' not found.", :red)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def edit_file(file_path)
|
364
|
+
full_path = File.expand_path(file_path, @repo.root)
|
365
|
+
if File.exist?(full_path)
|
366
|
+
system("#{@editor} #{full_path}")
|
367
|
+
else
|
368
|
+
puts fx("File '#{file_path}' not found.", :red)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def check_view
|
373
|
+
unless @current_view
|
374
|
+
puts fx("No view selected. Use 'change view' first.", :red)
|
375
|
+
return false
|
376
|
+
end
|
377
|
+
true
|
378
|
+
end
|
379
|
+
|
380
|
+
def yesno(question)
|
381
|
+
print fx("#{question} (y/n): ", :bold)
|
382
|
+
response = gets.chomp.strip.downcase
|
383
|
+
response == 'y' || response == 'yes'
|
384
|
+
end
|
385
|
+
|
386
|
+
def handle_error(error)
|
387
|
+
puts fx("Error: #{error.message}", :red)
|
388
|
+
puts error.backtrace if ENV['DEBUG']
|
389
|
+
end
|
390
|
+
|
391
|
+
def cleanup
|
392
|
+
RubyText.stop
|
393
|
+
puts "\nGoodbye!"
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# Main execution
|
398
|
+
if __FILE__ == $0
|
399
|
+
ui = ScriptoriumRubyTextUI.new
|
400
|
+
ui.start
|
401
|
+
end
|
402
|
+
|