shoko 0.1.3 → 0.1.5
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/.bundle/config +0 -1
- data/.rubocop.yml +35 -4
- data/Gemfile +2 -0
- data/README.md +100 -1
- data/Rakefile +80 -1
- data/Shoko.gemspec +34 -0
- data/bin/shoko +11 -5
- data/bin/start +11 -5
- data/docs/architecture/hexagonal-adherence-checklist.md +173 -0
- data/lib/shoko/adapters/base_adapter.rb +30 -0
- data/lib/{zip.rb → shoko/adapters/book_sources/archive/zip_reader.rb} +46 -32
- data/lib/shoko/adapters/book_sources/book_document.rb +177 -0
- data/lib/shoko/adapters/book_sources/book_file_probe.rb +24 -0
- data/lib/shoko/adapters/book_sources/book_finder/directory_scanner.rb +152 -0
- data/lib/shoko/adapters/book_sources/book_finder/scanner_context.rb +30 -0
- data/lib/shoko/adapters/book_sources/{epub_finder.rb → book_finder.rb} +62 -46
- data/lib/shoko/adapters/book_sources/cache_import_adapter.rb +30 -0
- data/lib/shoko/adapters/book_sources/document_loader_adapter.rb +72 -0
- data/lib/shoko/adapters/book_sources/document_service.rb +133 -169
- data/lib/shoko/adapters/book_sources/download_service.rb +22 -21
- data/lib/shoko/adapters/book_sources/epub/epub_importer.rb +266 -0
- data/lib/shoko/adapters/book_sources/epub/epub_resource_loader.rb +138 -127
- data/lib/shoko/adapters/book_sources/fb2/fb2_importer.rb +336 -0
- data/lib/shoko/adapters/book_sources/folder_scanner.rb +92 -0
- data/lib/shoko/adapters/book_sources/gutendex_client.rb +137 -110
- data/lib/shoko/adapters/book_sources/kindle/kindle_importer.rb +422 -0
- data/lib/shoko/adapters/book_sources/library_scanner.rb +144 -71
- data/lib/shoko/adapters/book_sources/metadata_reader_adapter.rb +72 -0
- data/lib/shoko/adapters/book_sources/pdf/pdf_importer.rb +364 -0
- data/lib/shoko/adapters/book_sources/rtf/rtf_importer.rb +303 -0
- data/lib/shoko/adapters/input/annotations/mouse_handler.rb +130 -126
- data/lib/shoko/adapters/input/cli.rb +439 -0
- data/lib/shoko/adapters/input/command_factory.rb +276 -201
- data/lib/shoko/adapters/input/commands.rb +77 -47
- data/lib/shoko/adapters/input/controllers/annotation_overlay_controller.rb +362 -0
- data/lib/shoko/adapters/input/controllers/dependencies/menu_controller_dependencies.rb +134 -0
- data/lib/shoko/adapters/input/controllers/dependencies/reader_controller_dependencies.rb +390 -0
- data/lib/shoko/adapters/input/controllers/dictionary/constants.rb +80 -0
- data/lib/shoko/adapters/input/controllers/dictionary/controller_support.rb +117 -0
- data/lib/shoko/adapters/input/controllers/dictionary/display_mode_support.rb +65 -0
- data/lib/shoko/adapters/input/controllers/dictionary/index.rb +7 -0
- data/lib/shoko/adapters/input/controllers/dictionary/language_pair_support.rb +190 -0
- data/lib/shoko/adapters/input/controllers/dictionary/setup_flow/download_support.rb +97 -0
- data/lib/shoko/adapters/input/controllers/dictionary/setup_flow/interaction_handlers.rb +106 -0
- data/lib/shoko/adapters/input/controllers/dictionary/setup_flow/lookup_flow.rb +106 -0
- data/lib/shoko/adapters/input/controllers/dictionary/setup_flow/popup_state_support.rb +99 -0
- data/lib/shoko/adapters/input/controllers/dictionary/setup_flow/submission_flow.rb +100 -0
- data/lib/shoko/adapters/input/controllers/dictionary/setup_flow_support.rb +26 -0
- data/lib/shoko/adapters/input/controllers/dictionary_controller.rb +304 -0
- data/lib/shoko/adapters/input/controllers/in_book_search_controller.rb +202 -0
- data/lib/shoko/adapters/input/controllers/menu/actions/dictionary_actions.rb +121 -0
- data/lib/shoko/adapters/input/controllers/menu/actions/download_actions.rb +74 -0
- data/lib/shoko/adapters/input/controllers/menu/actions/lifecycle_actions.rb +157 -0
- data/lib/shoko/adapters/input/controllers/menu/actions/navigation_actions.rb +141 -0
- data/lib/shoko/adapters/input/controllers/menu/actions/settings_actions.rb +128 -0
- data/lib/shoko/adapters/input/controllers/menu/controller.rb +430 -0
- data/lib/shoko/adapters/input/controllers/menu/input_controller.rb +210 -0
- data/lib/shoko/adapters/input/controllers/menu/intent_executor_bridge.rb +115 -0
- data/lib/shoko/adapters/input/controllers/menu/menu_workflow_bridges.rb +100 -0
- data/lib/shoko/adapters/input/controllers/menu/reader_launch_bridges.rb +78 -0
- data/lib/shoko/adapters/input/controllers/menu/state_controller.rb +123 -0
- data/lib/shoko/adapters/input/controllers/mouseable_reader.rb +243 -0
- data/lib/shoko/adapters/input/controllers/reader/event_loop.rb +100 -0
- data/lib/shoko/adapters/input/controllers/reader/input_router.rb +68 -0
- data/lib/shoko/adapters/input/controllers/reader/intent_executor_bridge.rb +107 -0
- data/lib/shoko/adapters/input/controllers/reader/lifecycle_runner.rb +117 -0
- data/lib/shoko/adapters/input/controllers/reader/render_metrics.rb +54 -0
- data/lib/shoko/adapters/input/controllers/reader/render_requester_bridge.rb +35 -0
- data/lib/shoko/adapters/input/controllers/reader/startup_loader.rb +61 -0
- data/lib/shoko/adapters/input/controllers/reader/startup_sequence.rb +64 -0
- data/lib/shoko/adapters/input/controllers/reader_controller.rb +519 -0
- data/lib/shoko/adapters/input/controllers/selection_mouse_handler.rb +212 -0
- data/lib/shoko/adapters/input/controllers/sidebar/anchor_resolver.rb +88 -0
- data/lib/shoko/adapters/input/controllers/sidebar/tab_state_orchestrator.rb +151 -0
- data/lib/shoko/adapters/input/controllers/sidebar/toc_facade.rb +71 -0
- data/lib/shoko/adapters/input/controllers/sidebar/toc_navigation.rb +77 -0
- data/lib/shoko/adapters/input/controllers/sidebar_controller.rb +309 -0
- data/lib/shoko/adapters/input/controllers/sidebar_mouse_handler.rb +201 -0
- data/lib/shoko/adapters/input/controllers/state_controller/annotation_actions.rb +119 -0
- data/lib/shoko/adapters/input/controllers/state_controller/bookmark_actions.rb +154 -0
- data/lib/shoko/adapters/input/controllers/state_controller/progress_actions.rb +149 -0
- data/lib/shoko/adapters/input/controllers/state_controller.rb +97 -0
- data/lib/shoko/adapters/input/controllers/support/message_notifier.rb +29 -0
- data/lib/shoko/adapters/input/controllers/ui_controller/delegation_facade.rb +325 -0
- data/lib/shoko/adapters/input/controllers/ui_controller/mode_switching.rb +62 -0
- data/lib/shoko/adapters/input/controllers/ui_controller/popup_actions.rb +84 -0
- data/lib/shoko/adapters/input/controllers/ui_controller.rb +109 -0
- data/lib/shoko/adapters/input/dispatcher.rb +50 -48
- data/lib/shoko/adapters/input/input_system_factory_adapter.rb +33 -0
- data/lib/shoko/adapters/input/key_classifier_adapter.rb +64 -0
- data/lib/shoko/adapters/input/reader_input_controller.rb +342 -0
- data/lib/shoko/adapters/input/validators/file_path_validator.rb +70 -63
- data/lib/shoko/adapters/input/validators/terminal_size_validator.rb +65 -60
- data/lib/shoko/adapters/monitoring/logger_adapter.rb +161 -0
- data/lib/shoko/adapters/monitoring/perf_tracer.rb +146 -142
- data/lib/shoko/adapters/monitoring/performance_monitor.rb +19 -24
- data/lib/shoko/adapters/output/clipboard/clipboard_service.rb +80 -90
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/image_builder.rb +118 -118
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/table_renderer.rb +365 -0
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/text_wrapper.rb +167 -103
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/tokenizer.rb +213 -61
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler.rb +288 -109
- data/lib/shoko/adapters/output/formatting/formatting_service/plain_lines_builder.rb +48 -40
- data/lib/shoko/adapters/output/formatting/formatting_service.rb +243 -196
- data/lib/shoko/adapters/output/formatting/wrapped_lines_provider_adapter.rb +43 -0
- data/lib/shoko/adapters/output/formatting/wrapping_service.rb +203 -180
- data/lib/shoko/adapters/output/instrumentation_service.rb +58 -23
- data/lib/shoko/adapters/output/kitty/display_capabilities.rb +21 -0
- data/lib/shoko/adapters/output/kitty/image_transcoder.rb +53 -49
- data/lib/shoko/adapters/output/kitty/kitty_graphics.rb +96 -92
- data/lib/shoko/adapters/output/kitty/kitty_image_renderer.rb +215 -226
- data/lib/shoko/adapters/output/kitty/kitty_unicode_placeholders.rb +4 -129
- data/lib/shoko/adapters/output/kitty/resource_loader.rb +34 -0
- data/lib/shoko/adapters/output/layout/layout_metrics_adapter.rb +68 -0
- data/lib/shoko/adapters/output/notification_service.rb +19 -17
- data/lib/shoko/adapters/output/terminal/buffer.rb +364 -218
- data/lib/shoko/adapters/output/terminal/cli_progress_renderer.rb +104 -0
- data/lib/shoko/adapters/output/terminal/constants/terminal_defaults.rb +9 -5
- data/lib/shoko/adapters/output/terminal/input/decoder.rb +375 -373
- data/lib/shoko/adapters/output/terminal/input.rb +204 -123
- data/lib/shoko/adapters/output/terminal/null_runtime_config.rb +23 -0
- data/lib/shoko/adapters/output/terminal/output.rb +43 -96
- data/lib/shoko/adapters/output/terminal/terminal.rb +202 -144
- data/lib/shoko/adapters/output/terminal/terminal_sanitizer.rb +7 -232
- data/lib/shoko/adapters/output/terminal/terminal_service.rb +121 -105
- data/lib/shoko/adapters/output/terminal/terminal_session_adapter.rb +32 -0
- data/lib/shoko/adapters/output/terminal/text_metrics.rb +4 -263
- data/lib/shoko/adapters/output/terminal/text_metrics_port_adapter.rb +41 -0
- data/lib/shoko/adapters/output/terminal/text_sanitizer_adapter.rb +23 -0
- data/lib/shoko/adapters/output/terminal_capabilities_adapter.rb +23 -0
- data/lib/shoko/adapters/runtime/app_mode_runner_adapter.rb +27 -0
- data/lib/shoko/adapters/runtime/env_runtime_config_adapter.rb +169 -0
- data/lib/shoko/adapters/runtime/monotonic_clock_adapter.rb +18 -0
- data/lib/shoko/adapters/runtime/null_runtime_config.rb +21 -0
- data/lib/shoko/adapters/runtime/process_control_adapter.rb +18 -0
- data/lib/shoko/adapters/runtime/rexml_security_limits_adapter.rb +35 -0
- data/lib/shoko/adapters/runtime/session_state/actions/base_action.rb +28 -0
- data/lib/shoko/adapters/runtime/session_state/actions/quit_to_menu_action.rb +20 -0
- data/lib/shoko/adapters/runtime/session_state/actions/switch_reader_mode_action.rb +26 -0
- data/lib/shoko/adapters/runtime/session_state/actions/toggle_view_mode_action.rb +35 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_config_action.rb +30 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_field_helpers.rb +30 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_menu_action.rb +21 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_message_action.rb +26 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_pagination_state_action.rb +23 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_reader_meta_action.rb +23 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_rendered_lines_action.rb +34 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_sidebar_action.rb +42 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_state_action.rb +76 -0
- data/lib/shoko/adapters/runtime/session_state/actions/update_ui_loading_action.rb +23 -0
- data/lib/shoko/adapters/runtime/session_state/config_reader_adapter.rb +82 -0
- data/lib/shoko/adapters/runtime/session_state/event_bus.rb +85 -0
- data/lib/shoko/adapters/runtime/session_state/event_publisher_adapter.rb +24 -0
- data/lib/shoko/adapters/runtime/session_state/menu_launch_state_adapter.rb +32 -0
- data/lib/shoko/adapters/runtime/session_state/menu_state_reader_adapter.rb +246 -0
- data/lib/shoko/adapters/runtime/session_state/menu_state_writer_adapter.rb +157 -0
- data/lib/shoko/adapters/runtime/session_state/notification_writer_adapter.rb +39 -0
- data/lib/shoko/adapters/runtime/session_state/observer_registry_adapter.rb +32 -0
- data/lib/shoko/adapters/runtime/session_state/observer_state_store.rb +129 -0
- data/lib/shoko/adapters/runtime/session_state/reader_launch_state_adapter.rb +45 -0
- data/lib/shoko/adapters/runtime/session_state/reader_state_reader_adapter.rb +162 -0
- data/lib/shoko/adapters/runtime/session_state/render_state_writer_adapter.rb +58 -0
- data/lib/shoko/adapters/runtime/session_state/rendered_content_reader_adapter.rb +29 -0
- data/lib/shoko/adapters/runtime/session_state/selectors/config_selectors.rb +82 -0
- data/lib/shoko/adapters/runtime/session_state/selectors/menu_selectors.rb +90 -0
- data/lib/shoko/adapters/runtime/session_state/selectors/reader_selectors.rb +191 -0
- data/lib/shoko/adapters/runtime/session_state/sidebar_state_reader_adapter.rb +67 -0
- data/lib/shoko/adapters/runtime/session_state/state_store/change_event_builder.rb +35 -0
- data/lib/shoko/adapters/runtime/session_state/state_store/config_persistence.rb +91 -0
- data/lib/shoko/adapters/runtime/session_state/state_store/initial_state_builder.rb +113 -0
- data/lib/shoko/adapters/runtime/session_state/state_store/transition_validator.rb +83 -0
- data/lib/shoko/adapters/runtime/session_state/state_store.rb +328 -0
- data/lib/shoko/adapters/runtime/session_state/state_writer_adapter.rb +134 -0
- data/lib/shoko/adapters/runtime/session_state/ui_state_reader_adapter.rb +50 -0
- data/lib/shoko/adapters/runtime/system_wall_clock_adapter.rb +18 -0
- data/lib/shoko/adapters/runtime/uuid_generator_adapter.rb +19 -0
- data/lib/shoko/adapters/storage/atomic_file_writer.rb +52 -24
- data/lib/shoko/adapters/storage/background_worker.rb +49 -43
- data/lib/shoko/adapters/storage/background_worker_builder_adapter.rb +24 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/cache_integrity_checker.rb +36 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/cache_session.rb +150 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/cache_status.rb +34 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/fingerprint_filter.rb +52 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/load_error_handler.rb +25 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/manifest_row.rb +74 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/manifest_sha_finder.rb +169 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/payload_context.rb +21 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline/pointer_file_ensurer.rb +49 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline.rb +122 -596
- data/lib/shoko/adapters/storage/book_cache_pipeline_factory_adapter.rb +23 -0
- data/lib/shoko/adapters/storage/cache/epub/memory_cache.rb +73 -71
- data/lib/shoko/adapters/storage/cache/epub/persistence.rb +124 -122
- data/lib/shoko/adapters/storage/cache/epub/serializer/deserialize.rb +195 -191
- data/lib/shoko/adapters/storage/cache/epub/serializer/helpers.rb +54 -47
- data/lib/shoko/adapters/storage/cache/epub/serializer/serialize.rb +65 -62
- data/lib/shoko/adapters/storage/cache/epub/source_reference.rb +43 -41
- data/lib/shoko/adapters/storage/cache_availability_adapter.rb +105 -0
- data/lib/shoko/adapters/storage/cache_manager_adapter.rb +28 -0
- data/lib/shoko/adapters/storage/cache_paths.rb +15 -13
- data/lib/shoko/adapters/storage/cache_pointer_manager.rb +42 -40
- data/lib/shoko/adapters/storage/cache_pointer_resolver.rb +35 -0
- data/lib/shoko/adapters/storage/config_paths.rb +22 -20
- data/lib/shoko/adapters/storage/config_storage_adapter.rb +73 -0
- data/lib/shoko/adapters/storage/data_cleanup_adapter.rb +83 -0
- data/lib/shoko/adapters/storage/dictionary_availability_adapter.rb +23 -0
- data/lib/shoko/adapters/storage/dictionary_catalog_service.rb +148 -0
- data/lib/shoko/adapters/storage/dictionary_storage_adapter.rb +84 -0
- data/lib/shoko/adapters/storage/epub_cache.rb +137 -152
- data/lib/shoko/adapters/storage/file_probe_adapter.rb +26 -0
- data/lib/shoko/adapters/storage/file_writer_service.rb +18 -22
- data/lib/shoko/adapters/storage/json_cache_store/chapters.rb +104 -102
- data/lib/shoko/adapters/storage/json_cache_store/layouts.rb +52 -49
- data/lib/shoko/adapters/storage/json_cache_store/manifest.rb +125 -30
- data/lib/shoko/adapters/storage/json_cache_store/payload_helpers.rb +109 -106
- data/lib/shoko/adapters/storage/json_cache_store/resources.rb +62 -60
- data/lib/shoko/adapters/storage/json_cache_store.rb +138 -134
- data/lib/shoko/adapters/storage/lazy_file_string.rb +40 -51
- data/lib/shoko/adapters/storage/pagination_cache.rb +107 -97
- data/lib/shoko/adapters/storage/path_ops_adapter.rb +30 -0
- data/lib/shoko/adapters/storage/recent_files.rb +96 -58
- data/lib/shoko/adapters/storage/recent_files_repository.rb +27 -0
- data/lib/shoko/adapters/storage/repositories/annotation_repository.rb +144 -156
- data/lib/shoko/adapters/storage/repositories/base_repository.rb +68 -63
- data/lib/shoko/adapters/storage/repositories/bookmark_repository.rb +111 -106
- data/lib/shoko/adapters/storage/repositories/cached_library_repository.rb +100 -97
- data/lib/shoko/adapters/storage/repositories/progress_repository.rb +128 -142
- data/lib/shoko/adapters/storage/repositories/storage/annotation_file_store.rb +92 -118
- data/lib/shoko/adapters/storage/repositories/storage/base_file_store.rb +40 -0
- data/lib/shoko/adapters/storage/repositories/storage/bookmark_file_store.rb +77 -92
- data/lib/shoko/adapters/storage/repositories/storage/file_store_utils.rb +13 -9
- data/lib/shoko/adapters/storage/repositories/storage/progress_file_store.rb +34 -50
- data/lib/shoko/adapters/storage/sqlite_dictionary_adapter.rb +301 -0
- data/lib/shoko/adapters/support/lifecycle_helpers.rb +73 -0
- data/lib/shoko/adapters/ui/builders/page_setup_builder.rb +51 -0
- data/lib/shoko/adapters/ui/component_factory.rb +103 -0
- data/lib/shoko/adapters/ui/components/annotation_editor_overlay/footer_renderer.rb +84 -0
- data/lib/shoko/adapters/ui/components/annotation_editor_overlay/geometry.rb +65 -0
- data/lib/shoko/adapters/ui/components/annotation_editor_overlay/note_renderer.rb +91 -0
- data/lib/shoko/adapters/ui/components/annotation_editor_overlay_component.rb +415 -0
- data/lib/shoko/adapters/ui/components/annotations_overlay/list_renderer.rb +148 -0
- data/lib/shoko/adapters/ui/components/annotations_overlay_component.rb +210 -0
- data/lib/shoko/adapters/ui/components/base_component.rb +118 -0
- data/lib/shoko/adapters/ui/components/content_component.rb +67 -0
- data/lib/shoko/adapters/ui/components/dictionary/entry_formatter.rb +232 -0
- data/lib/shoko/adapters/ui/components/dictionary_panel_component.rb +290 -0
- data/lib/shoko/adapters/ui/components/dictionary_popup/results_flow.rb +122 -0
- data/lib/shoko/adapters/ui/components/dictionary_popup/setup_flow.rb +479 -0
- data/lib/shoko/adapters/ui/components/dictionary_popup_component.rb +280 -0
- data/lib/shoko/adapters/ui/components/enhanced_popup_menu.rb +345 -0
- data/lib/shoko/adapters/ui/components/footer_component.rb +126 -0
- data/lib/shoko/adapters/ui/components/header_component.rb +48 -0
- data/lib/shoko/adapters/ui/components/in_book_search_popup_component.rb +509 -0
- data/lib/shoko/adapters/ui/components/layouts/horizontal.rb +67 -0
- data/lib/shoko/adapters/ui/components/layouts/horizontal_three.rb +94 -0
- data/lib/shoko/adapters/ui/components/layouts/vertical.rb +77 -0
- data/lib/shoko/adapters/ui/components/main_menu_component.rb +130 -0
- data/lib/shoko/adapters/ui/components/menu_design/frame_renderer.rb +93 -0
- data/lib/shoko/adapters/ui/components/menu_design/icon_set.rb +69 -0
- data/lib/shoko/adapters/ui/components/menu_design/layout.rb +33 -0
- data/lib/shoko/adapters/ui/components/menu_design/progress_renderer.rb +36 -0
- data/lib/shoko/adapters/ui/components/menu_design/search_field_renderer.rb +41 -0
- data/lib/shoko/adapters/ui/components/menu_design/status_renderer.rb +49 -0
- data/lib/shoko/adapters/ui/components/menu_design/table_renderer.rb +59 -0
- data/lib/shoko/adapters/ui/components/menu_design/theme_tokens.rb +73 -0
- data/lib/shoko/adapters/ui/components/rect.rb +19 -0
- data/lib/shoko/adapters/ui/components/render_style.rb +125 -0
- data/lib/shoko/adapters/ui/components/screen_component.rb +28 -0
- data/lib/shoko/adapters/ui/components/screens/annotation_detail_screen_component.rb +193 -0
- data/lib/shoko/adapters/ui/components/screens/annotation_edit_screen_component.rb +298 -0
- data/lib/shoko/adapters/ui/components/screens/annotation_editor_screen_component.rb +268 -0
- data/lib/shoko/adapters/ui/components/screens/annotation_rendering_helpers.rb +462 -0
- data/lib/shoko/adapters/ui/components/screens/annotations_screen_component.rb +398 -0
- data/lib/shoko/adapters/ui/components/screens/base_screen_component.rb +53 -0
- data/lib/shoko/adapters/ui/components/screens/browse_screen_component.rb +384 -0
- data/lib/shoko/adapters/ui/components/screens/dictionary_settings_screen_component.rb +501 -0
- data/lib/shoko/adapters/ui/components/screens/download_books_screen_component.rb +352 -0
- data/lib/shoko/adapters/ui/components/screens/library_screen_component.rb +383 -0
- data/lib/shoko/adapters/ui/components/screens/loading_overlay_component.rb +63 -0
- data/lib/shoko/adapters/ui/components/screens/menu_screen_component.rb +103 -0
- data/lib/shoko/adapters/ui/components/screens/settings_screen_component.rb +324 -0
- data/lib/shoko/adapters/ui/components/sidebar/annotations_tab_renderer.rb +170 -0
- data/lib/shoko/adapters/ui/components/sidebar/bookmarks_tab_renderer.rb +160 -0
- data/lib/shoko/adapters/ui/components/sidebar/tab_header_component.rb +168 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/constants.rb +23 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/context.rb +101 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/document_model.rb +59 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/entries_calculator.rb +99 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/entry_rendering.rb +185 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/index.rb +11 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/layout/entries_list_layout.rb +81 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/layout/entry_layout_helper.rb +48 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/layout/line_index.rb +63 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/layout/visible_entry_item.rb +97 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/layout/visible_items_calculator.rb +87 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/layout.rb +7 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers/component_orchestrator.rb +27 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers/empty_state_renderer.rb +51 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers/entries_list_renderer.rb +28 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers/filter_input_renderer.rb +52 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers/header_renderer.rb +176 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers/scrollbar_renderer.rb +51 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/renderers.rb +8 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/scroll_metrics.rb +152 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc/tree_formatting.rb +202 -0
- data/lib/shoko/adapters/ui/components/sidebar/toc_tab_renderer.rb +132 -0
- data/lib/shoko/adapters/ui/components/sidebar_panel_component.rb +229 -0
- data/lib/shoko/adapters/ui/components/surface.rb +92 -0
- data/lib/shoko/adapters/ui/components/tooltip_overlay_component.rb +251 -0
- data/lib/shoko/adapters/ui/components/ui/annotation_list_input.rb +102 -0
- data/lib/shoko/adapters/ui/components/ui/annotation_markup.rb +456 -0
- data/lib/shoko/adapters/ui/components/ui/box_drawer.rb +37 -0
- data/lib/shoko/adapters/ui/components/ui/cursor_blink.rb +104 -0
- data/lib/shoko/adapters/ui/components/ui/list_helpers.rb +37 -0
- data/lib/shoko/adapters/ui/components/ui/overlay_layout.rb +92 -0
- data/lib/shoko/adapters/ui/components/ui/text_utils.rb +50 -0
- data/lib/shoko/adapters/ui/constants/highlighting.rb +23 -0
- data/lib/shoko/adapters/ui/constants/messages.rb +14 -0
- data/lib/shoko/adapters/ui/constants/themes.rb +81 -0
- data/lib/shoko/adapters/ui/constants/ui_constants.rb +155 -0
- data/lib/shoko/adapters/ui/dependency_sets.rb +49 -0
- data/lib/shoko/adapters/ui/menu_visual_profile.rb +10 -0
- data/lib/shoko/adapters/ui/render_registry.rb +42 -0
- data/lib/shoko/adapters/ui/rendering/frame_coordinator.rb +55 -0
- data/lib/shoko/adapters/ui/rendering/line/config_helpers.rb +58 -0
- data/lib/shoko/adapters/ui/rendering/line/inline_segment_highlighter.rb +163 -0
- data/lib/shoko/adapters/ui/rendering/line/kitty_image_line_renderer.rb +256 -0
- data/lib/shoko/adapters/ui/rendering/line/line_content_composer.rb +253 -0
- data/lib/shoko/adapters/ui/rendering/line/line_drawer.rb +96 -0
- data/lib/shoko/adapters/ui/rendering/line/line_geometry_builder.rb +133 -0
- data/lib/shoko/adapters/ui/rendering/line/render_dependencies.rb +30 -0
- data/lib/shoko/adapters/ui/rendering/line/rendered_lines_recorder.rb +73 -0
- data/lib/shoko/adapters/ui/rendering/line/wrapped_lines_fetcher.rb +140 -0
- data/lib/shoko/adapters/{output → ui}/rendering/models/line_geometry.rb +4 -4
- data/lib/shoko/adapters/{output → ui}/rendering/models/page_rendering_context.rb +1 -1
- data/lib/shoko/adapters/{output → ui}/rendering/models/render_params.rb +1 -1
- data/lib/shoko/adapters/ui/rendering/models/rendering_context.rb +67 -0
- data/lib/shoko/adapters/ui/rendering/reader_render_coordinator.rb +272 -0
- data/lib/shoko/adapters/ui/rendering/render_pipeline.rb +75 -0
- data/lib/shoko/adapters/ui/rendering/views/base_view_renderer.rb +218 -0
- data/lib/shoko/adapters/ui/rendering/views/help_renderer.rb +67 -0
- data/lib/shoko/adapters/ui/rendering/views/single_view_renderer.rb +190 -0
- data/lib/shoko/adapters/ui/rendering/views/split_view_renderer.rb +261 -0
- data/lib/shoko/adapters/ui/rendering/views/view_renderer_factory.rb +27 -0
- data/lib/shoko/adapters/ui/rendering_factory.rb +48 -0
- data/lib/shoko/adapters/ui/sessions/annotation_editor_launcher_adapter.rb +29 -0
- data/lib/shoko/adapters/ui/sessions/annotation_overlay_ui_session_adapter.rb +294 -0
- data/lib/shoko/adapters/ui/sessions/dictionary_ui_session_adapter.rb +342 -0
- data/lib/shoko/adapters/ui/sessions/in_book_search_ui_session_adapter.rb +189 -0
- data/lib/shoko/adapters/ui/view_models/reader_view_model.rb +179 -0
- data/lib/shoko/adapters/ui/view_models/reader_view_model_builder.rb +64 -0
- data/lib/shoko/application/cli_progress_presenter.rb +48 -0
- data/lib/shoko/application/pending_jump_handler.rb +55 -71
- data/lib/shoko/application/services/pagination/page_info_calculator.rb +262 -0
- data/lib/shoko/application/services/pagination/pagination_cache_preloader.rb +232 -0
- data/lib/shoko/application/services/pagination/pagination_coordinator.rb +279 -0
- data/lib/shoko/application/services/pagination/pagination_orchestrator.rb +399 -0
- data/lib/shoko/application/services/popup_position_service.rb +35 -0
- data/lib/shoko/application/services/reader/annotation_state_service.rb +53 -0
- data/lib/shoko/application/services/reader/bookmark_service.rb +318 -0
- data/lib/shoko/application/services/reader/navigation/absolute_change_applier.rb +98 -0
- data/lib/shoko/application/services/reader/navigation/absolute_layout.rb +128 -0
- data/lib/shoko/application/services/reader/navigation/absolute_strategy.rb +181 -0
- data/lib/shoko/application/services/reader/navigation/context_builder.rb +77 -0
- data/lib/shoko/application/services/reader/navigation/context_helpers.rb +77 -0
- data/lib/shoko/application/services/reader/navigation/dynamic_change_applier.rb +49 -0
- data/lib/shoko/application/services/reader/navigation/dynamic_strategy.rb +53 -0
- data/lib/shoko/application/services/reader/navigation/image_offset_snapper.rb +183 -0
- data/lib/shoko/application/services/reader/navigation/nav_context.rb +29 -0
- data/lib/shoko/application/services/reader/navigation/state_updater.rb +26 -0
- data/lib/shoko/application/services/reader/navigation/strategy_factory.rb +22 -0
- data/lib/shoko/application/services/reader/navigation_service.rb +169 -0
- data/lib/shoko/application/unified_application.rb +134 -18
- data/lib/shoko/application/use_cases/catalog_service.rb +52 -38
- data/lib/shoko/application/use_cases/command_bus.rb +170 -0
- data/lib/shoko/application/use_cases/commands/base_command.rb +125 -135
- data/lib/shoko/application/use_cases/commands/bookmark_commands.rb +70 -84
- data/lib/shoko/application/use_cases/commands/input_command_payload.rb +13 -0
- data/lib/shoko/application/use_cases/commands/menu_intent_command.rb +51 -0
- data/lib/shoko/application/use_cases/commands/navigation_commands.rb +151 -134
- data/lib/shoko/application/use_cases/commands/reader_intent_command.rb +51 -0
- data/lib/shoko/application/use_cases/commands/shared_intent_command.rb +55 -0
- data/lib/shoko/application/use_cases/intents/menu_intent_handler.rb +47 -0
- data/lib/shoko/application/use_cases/intents/reader_intent_handler.rb +47 -0
- data/lib/shoko/application/use_cases/settings_service.rb +173 -55
- data/lib/shoko/application/workflows/cli/folder_import_workflow.rb +164 -0
- data/lib/shoko/application/workflows/menu/annotation_workflow.rb +132 -0
- data/lib/shoko/application/workflows/menu/dictionary_workflow.rb +203 -0
- data/lib/shoko/application/workflows/menu/download_workflow.rb +181 -0
- data/lib/shoko/application/workflows/menu/menu_progress_presenter.rb +85 -0
- data/lib/shoko/application/workflows/menu/null_progress_presenter.rb +24 -0
- data/lib/shoko/application/workflows/menu/reader_launch/contracts.rb +70 -0
- data/lib/shoko/application/workflows/menu/reader_launch/document_preparation.rb +137 -0
- data/lib/shoko/application/workflows/menu/reader_launch/path_resolution.rb +76 -0
- data/lib/shoko/application/workflows/menu/reader_launch/progress_orchestration.rb +203 -0
- data/lib/shoko/application/workflows/menu/reader_launch/runtime_execution.rb +106 -0
- data/lib/shoko/application/workflows/menu/reader_launch_service.rb +161 -0
- data/lib/shoko/bootstrap/container_factory/controller_composition/menu_builder.rb +163 -0
- data/lib/shoko/bootstrap/container_factory/controller_composition/menu_state_controller_composer.rb +174 -0
- data/lib/shoko/bootstrap/container_factory/controller_composition/reader_builder.rb +400 -0
- data/lib/shoko/bootstrap/container_factory/controller_composition/reader_runtime_assembler.rb +267 -0
- data/lib/shoko/bootstrap/container_factory/controller_composition.rb +19 -0
- data/lib/shoko/bootstrap/container_factory/domain_application_registration.rb +340 -0
- data/lib/shoko/bootstrap/container_factory/infrastructure_registration.rb +123 -0
- data/lib/shoko/bootstrap/container_factory/port_and_repository_registration.rb +241 -0
- data/lib/shoko/bootstrap/container_factory/test_container_registration.rb +198 -0
- data/lib/shoko/bootstrap/container_factory.rb +174 -0
- data/lib/shoko/bootstrap/dependency_container.rb +142 -0
- data/lib/shoko/bootstrap/format_registry_bootstrap.rb +137 -0
- data/lib/shoko/bootstrap/runtime_bootstrap.rb +86 -0
- data/lib/shoko/core/book_formats/epub/html_processor.rb +146 -0
- data/lib/shoko/core/book_formats/epub/metadata_extractor.rb +65 -0
- data/lib/shoko/core/book_formats/epub/opf/entry_reader.rb +120 -0
- data/lib/shoko/core/book_formats/epub/opf/metadata_extractor.rb +71 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_context.rb +90 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_document_index.rb +79 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_document_scanner.rb +51 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_extractor.rb +50 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_label_resolver.rb +91 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_list_item.rb +59 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_result.rb +12 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_selector.rb +104 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_source_locator.rb +97 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_traversal.rb +108 -0
- data/lib/shoko/core/book_formats/epub/opf/navigation_walker.rb +60 -0
- data/lib/shoko/core/book_formats/epub/opf_processor.rb +115 -0
- data/lib/shoko/core/book_formats/epub/rexml_safe_parser.rb +22 -0
- data/lib/shoko/core/book_formats/epub/xhtml_content_parser.rb +803 -0
- data/lib/shoko/core/book_formats/epub/xml_text_normalizer.rb +45 -0
- data/lib/shoko/core/book_formats/fb2/fb2_content_parser.rb +324 -0
- data/lib/shoko/core/book_formats/fb2/fb2_inline_parser.rb +117 -0
- data/lib/shoko/core/book_formats/fb2/fb2_metadata_extractor.rb +68 -0
- data/lib/shoko/core/book_formats/fb2/fb2_section_flattener.rb +133 -0
- data/lib/shoko/core/book_formats/fb2/metadata_parser.rb +96 -0
- data/lib/shoko/core/book_formats/format_registry.rb +157 -0
- data/lib/shoko/core/book_formats/kindle/exth_parser.rb +169 -0
- data/lib/shoko/core/book_formats/kindle/kindle_content_parser.rb +31 -0
- data/lib/shoko/core/book_formats/kindle/kindle_metadata_extractor.rb +79 -0
- data/lib/shoko/core/book_formats/kindle/metadata_parser.rb +61 -0
- data/lib/shoko/core/book_formats/kindle/mobi_header_parser.rb +224 -0
- data/lib/shoko/core/book_formats/kindle/palmdoc_decompressor.rb +142 -0
- data/lib/shoko/core/book_formats/kindle/pdb_header_parser.rb +103 -0
- data/lib/shoko/core/book_formats/pdf/metadata_parser.rb +57 -0
- data/lib/shoko/core/book_formats/pdf/pdf_content_parser.rb +687 -0
- data/lib/shoko/core/book_formats/pdf/pdf_metadata_extractor.rb +64 -0
- data/lib/shoko/core/book_formats/pdf/pdf_reader.rb +485 -0
- data/lib/shoko/core/book_formats/pdf/pdf_text_extractor.rb +629 -0
- data/lib/shoko/core/book_formats/rtf/metadata_parser.rb +121 -0
- data/lib/shoko/core/book_formats/rtf/rtf_content_parser.rb +29 -0
- data/lib/shoko/core/book_formats/rtf/rtf_metadata_extractor.rb +73 -0
- data/lib/shoko/core/book_formats/rtf/rtf_parser.rb +767 -0
- data/lib/shoko/core/errors/dictionary_failure.rb +30 -0
- data/lib/shoko/core/events/base_domain_event.rb +30 -10
- data/lib/shoko/core/events/domain_event_bus.rb +15 -21
- data/lib/shoko/core/events/event_factory.rb +23 -0
- data/lib/shoko/core/models/annotation_selection.rb +59 -0
- data/lib/shoko/core/models/block_type.rb +51 -0
- data/lib/shoko/core/models/book_data.rb +29 -0
- data/lib/shoko/core/models/chapter.rb +5 -1
- data/lib/shoko/core/models/dictionary_catalog_entry.rb +52 -0
- data/lib/shoko/core/models/dictionary_entry.rb +163 -0
- data/lib/shoko/core/models/menu_book.rb +36 -0
- data/lib/shoko/core/models/pending_jump_payload.rb +58 -0
- data/lib/shoko/core/models/reader_settings.rb +8 -8
- data/lib/shoko/core/models/reading_progress.rb +30 -0
- data/lib/shoko/core/models/selection_anchor.rb +58 -53
- data/lib/shoko/core/ports/inbound/command_bus.rb +39 -0
- data/lib/shoko/core/ports/inbound/input_command_payload.rb +55 -0
- data/lib/shoko/core/ports/inbound/intent_dispatch_context.rb +24 -0
- data/lib/shoko/core/ports/inbound/menu_intent_handler.rb +82 -0
- data/lib/shoko/core/ports/inbound/reader_bookmark_command_context.rb +16 -0
- data/lib/shoko/core/ports/inbound/reader_intent_handler.rb +70 -0
- data/lib/shoko/core/ports/inbound/reader_navigation_command_context.rb +20 -0
- data/lib/shoko/core/ports/outbound/annotation_editor_launcher.rb +16 -0
- data/lib/shoko/core/ports/outbound/annotation_repository.rb +96 -0
- data/lib/shoko/core/ports/outbound/annotation_selection_reader.rb +17 -0
- data/lib/shoko/core/ports/outbound/annotation_view_refresher.rb +16 -0
- data/lib/shoko/core/ports/outbound/app_mode_runner.rb +20 -0
- data/lib/shoko/core/ports/outbound/async_executor.rb +26 -0
- data/lib/shoko/core/ports/outbound/background_worker_builder.rb +19 -0
- data/lib/shoko/core/ports/outbound/book_cache_pipeline_factory.rb +16 -0
- data/lib/shoko/core/ports/outbound/bookmark_repository.rb +79 -0
- data/lib/shoko/core/ports/outbound/cache_availability.rb +20 -0
- data/lib/shoko/core/ports/outbound/cache_manager.rb +28 -0
- data/lib/shoko/core/ports/outbound/cache_pointer_resolver.rb +29 -0
- data/lib/shoko/core/ports/outbound/chapter_formatter.rb +38 -0
- data/lib/shoko/core/ports/outbound/clock.rb +16 -0
- data/lib/shoko/core/ports/outbound/config_reader.rb +60 -0
- data/lib/shoko/core/ports/outbound/config_storage.rb +71 -0
- data/lib/shoko/core/ports/outbound/data_cleanup.rb +34 -0
- data/lib/shoko/core/ports/outbound/dictionary_availability.rb +21 -0
- data/lib/shoko/core/ports/outbound/dictionary_repository.rb +78 -0
- data/lib/shoko/core/ports/outbound/dictionary_storage.rb +47 -0
- data/lib/shoko/core/ports/outbound/display_capabilities.rb +20 -0
- data/lib/shoko/core/ports/outbound/document_loader.rb +20 -0
- data/lib/shoko/core/ports/outbound/event_publisher.rb +18 -0
- data/lib/shoko/core/ports/outbound/file_probe.rb +24 -0
- data/lib/shoko/core/ports/outbound/folder_importer.rb +17 -0
- data/lib/shoko/core/ports/outbound/folder_scanner.rb +18 -0
- data/lib/shoko/core/ports/outbound/id_generator.rb +16 -0
- data/lib/shoko/core/ports/outbound/instrumentation.rb +33 -0
- data/lib/shoko/core/ports/outbound/layout_metrics.rb +80 -0
- data/lib/shoko/core/ports/outbound/library_scanner.rb +48 -0
- data/lib/shoko/core/ports/outbound/line_wrapper.rb +36 -0
- data/lib/shoko/core/ports/outbound/logging.rb +67 -0
- data/lib/shoko/core/ports/outbound/menu_book_selection.rb +22 -0
- data/lib/shoko/core/ports/outbound/menu_intent_executor.rb +16 -0
- data/lib/shoko/core/ports/outbound/menu_launch_state.rb +24 -0
- data/lib/shoko/core/ports/outbound/menu_mode_switcher.rb +16 -0
- data/lib/shoko/core/ports/outbound/menu_progress_presenters.rb +16 -0
- data/lib/shoko/core/ports/outbound/menu_reader_runtime.rb +24 -0
- data/lib/shoko/core/ports/outbound/menu_workflow_runtime.rb +20 -0
- data/lib/shoko/core/ports/outbound/menu_workflow_state_reader.rb +36 -0
- data/lib/shoko/core/ports/outbound/menu_workflow_state_writer.rb +28 -0
- data/lib/shoko/core/ports/outbound/metadata_reader.rb +22 -0
- data/lib/shoko/core/ports/outbound/notification_writer.rb +20 -0
- data/lib/shoko/core/ports/outbound/observer_registry.rb +32 -0
- data/lib/shoko/core/ports/outbound/pagination_state_writer.rb +24 -0
- data/lib/shoko/core/ports/outbound/path_ops.rb +28 -0
- data/lib/shoko/core/ports/outbound/process_control.rb +16 -0
- data/lib/shoko/core/ports/outbound/progress_repository.rb +57 -0
- data/lib/shoko/core/ports/outbound/reader_chapter.rb +24 -0
- data/lib/shoko/core/ports/outbound/reader_document.rb +32 -0
- data/lib/shoko/core/ports/outbound/reader_intent_executor.rb +16 -0
- data/lib/shoko/core/ports/outbound/reader_launch_state.rb +36 -0
- data/lib/shoko/core/ports/outbound/reader_navigation_reader.rb +56 -0
- data/lib/shoko/core/ports/outbound/reader_render_requester.rb +18 -0
- data/lib/shoko/core/ports/outbound/reader_runner.rb +16 -0
- data/lib/shoko/core/ports/outbound/reader_state_writer.rb +48 -0
- data/lib/shoko/core/ports/outbound/recent_files_repository.rb +27 -0
- data/lib/shoko/core/ports/outbound/render_state_writer.rb +22 -0
- data/lib/shoko/core/ports/outbound/rendered_content_reader.rb +34 -0
- data/lib/shoko/core/ports/outbound/runtime_config.rb +113 -0
- data/lib/shoko/core/ports/outbound/sidebar_state_reader.rb +48 -0
- data/lib/shoko/core/ports/outbound/terminal_capabilities.rb +35 -0
- data/lib/shoko/core/ports/outbound/terminal_session.rb +24 -0
- data/lib/shoko/core/ports/outbound/text_metrics.rb +21 -0
- data/lib/shoko/core/ports/outbound/text_sanitizer.rb +24 -0
- data/lib/shoko/core/ports/outbound/ui_loading_writer.rb +16 -0
- data/lib/shoko/core/ports/outbound/ui_state_reader.rb +32 -0
- data/lib/shoko/core/ports/outbound/wall_clock.rb +16 -0
- data/lib/shoko/core/ports/outbound/wrapped_lines_provider.rb +25 -0
- data/lib/shoko/core/services/annotation_service.rb +39 -52
- data/lib/shoko/core/services/base_service.rb +7 -46
- data/lib/shoko/core/services/coordinate_service.rb +7 -34
- data/lib/shoko/core/services/default_display_capabilities.rb +18 -0
- data/lib/shoko/core/services/default_layout_metrics.rb +65 -0
- data/lib/shoko/core/services/default_terminal_capabilities.rb +23 -0
- data/lib/shoko/core/services/default_text_metrics.rb +44 -0
- data/lib/shoko/core/services/dictionary_service.rb +232 -0
- data/lib/shoko/core/services/document_path_resolver.rb +62 -0
- data/lib/shoko/core/services/in_book_search_service.rb +188 -0
- data/lib/shoko/core/services/inline_executor.rb +24 -0
- data/lib/shoko/core/services/layout_service.rb +34 -9
- data/lib/shoko/core/services/null_instrumentation.rb +24 -0
- data/lib/shoko/core/services/null_logger.rb +39 -0
- data/lib/shoko/core/services/page_calculator_service.rb +330 -106
- data/lib/shoko/core/services/pagination/internal/absolute_page_map_builder.rb +53 -21
- data/lib/shoko/core/services/pagination/internal/chapter_cache.rb +56 -45
- data/lib/shoko/core/services/pagination/internal/dynamic_page_map_builder.rb +165 -110
- data/lib/shoko/core/services/pagination/internal/layout_metrics_calculator.rb +51 -58
- data/lib/shoko/core/services/pagination/internal/page_hydrator.rb +115 -120
- data/lib/shoko/core/services/pagination/internal/pagination_workflow.rb +141 -128
- data/lib/shoko/core/services/progress_helper.rb +10 -10
- data/lib/shoko/core/services/selection_service.rb +62 -53
- data/lib/shoko/core/services/toc_tree_service.rb +196 -0
- data/lib/shoko/shared/contracts/session_outcome.rb +18 -0
- data/lib/shoko/shared/errors.rb +101 -3
- data/lib/shoko/{adapters/input → shared}/key_definitions.rb +18 -22
- data/lib/shoko/shared/menu_definitions.rb +76 -0
- data/lib/shoko/shared/optional_dependency.rb +70 -0
- data/lib/shoko/shared/runtime/null_runtime_config.rb +44 -0
- data/lib/shoko/{adapters/book_sources → shared}/source_fingerprint.rb +5 -5
- data/lib/shoko/shared/terminal/ansi.rb +73 -0
- data/lib/shoko/shared/terminal/kitty_unicode_placeholders.rb +137 -0
- data/lib/shoko/shared/terminal/text_metrics.rb +490 -0
- data/lib/shoko/shared/terminal/text_sanitizer.rb +12 -0
- data/lib/shoko/shared/text_sanitizer.rb +239 -0
- data/lib/shoko/shared/ui_constraints.rb +11 -0
- data/lib/shoko/shared/unicode_display_width/display_width.marshal.gz +0 -0
- data/lib/shoko/shared/unicode_display_width.rb +147 -0
- data/lib/shoko/shared/version.rb +1 -1
- data/lib/shoko/test_support/terminal_double.rb +1 -1
- data/lib/shoko/test_support/test_mode.rb +5 -19
- data/lib/shoko.rb +4 -275
- data/script/architecture/fallback_report.rb +105 -0
- data/script/bench/sidebar_toggle_layout_benchmark.rb +194 -0
- data/script/bench/snappiness_benchmark.rb +443 -0
- data/script/bench/startup_menu_benchmark.rb +114 -0
- data/tmp/rspec-results/fixtures.json +1 -0
- data/tmp/rspec-results/full-seed-10101.log +10 -0
- data/tmp/rspec-results/full-seed-1559.log +10 -0
- data/tmp/rspec-results/full-seed-20202.log +10 -0
- data/tmp/rspec-results/full-seed-30303.log +10 -0
- data/tmp/rspec-results/full-seed-49446.log +10 -0
- data/tmp/rspec-results/full-seed-52407.log +10 -0
- data/tmp/rspec-results/full-seed-5517.log +10 -0
- data/tmp/rspec-results/full-seed-56072.log +10 -0
- data/tmp/rspec-results/full-seed-61968.log +10 -0
- data/tmp/rspec-results/full-seed-63851.log +10 -0
- data/tmp/rspec-results/full-seed-65033.log +10 -0
- data/tmp/rspec-results/full-seed-87095.log +10 -0
- data/tmp/rspec-results/full-seed-97342.log +10 -0
- data/tmp/rspec-results/guardrails.json +1 -0
- data/tmp/rspec-results/required-seed-10101.json +1 -0
- data/tmp/rspec-results/required-seed-20202.json +1 -0
- data/tmp/rspec-results/required-seed-30303.json +1 -0
- data/tmp/rubocop-metrics.json +1 -0
- metadata +507 -227
- data/lib/shoko/adapters/book_sources/epub/parsers/html_processor.rb +0 -151
- data/lib/shoko/adapters/book_sources/epub/parsers/metadata_extractor.rb +0 -53
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/entry_reader.rb +0 -77
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/metadata_extractor.rb +0 -67
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_context.rb +0 -86
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_document_index.rb +0 -75
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_document_scanner.rb +0 -47
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_extractor.rb +0 -46
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_label_resolver.rb +0 -83
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_list_item.rb +0 -55
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_result.rb +0 -8
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_selector.rb +0 -100
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_source_locator.rb +0 -93
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_traversal.rb +0 -103
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_walker.rb +0 -56
- data/lib/shoko/adapters/book_sources/epub/parsers/opf_processor.rb +0 -102
- data/lib/shoko/adapters/book_sources/epub/parsers/xhtml_content_parser.rb +0 -661
- data/lib/shoko/adapters/book_sources/epub/parsers/xml_text_normalizer.rb +0 -41
- data/lib/shoko/adapters/book_sources/epub_document.rb +0 -253
- data/lib/shoko/adapters/book_sources/epub_finder/directory_scanner.rb +0 -134
- data/lib/shoko/adapters/book_sources/epub_finder/scanner_context.rb +0 -28
- data/lib/shoko/adapters/book_sources/epub_importer.rb +0 -268
- data/lib/shoko/adapters/input/command_bridge.rb +0 -148
- data/lib/shoko/adapters/input/input_controller.rb +0 -250
- data/lib/shoko/adapters/monitoring/logger.rb +0 -150
- data/lib/shoko/adapters/output/render_registry.rb +0 -45
- data/lib/shoko/adapters/output/rendering/models/rendering_context.rb +0 -58
- data/lib/shoko/adapters/output/ui/builders/page_setup_builder.rb +0 -47
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay/footer_renderer.rb +0 -80
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay/geometry.rb +0 -61
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay/note_renderer.rb +0 -86
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay_component.rb +0 -234
- data/lib/shoko/adapters/output/ui/components/annotations_overlay/list_renderer.rb +0 -142
- data/lib/shoko/adapters/output/ui/components/annotations_overlay_component.rb +0 -185
- data/lib/shoko/adapters/output/ui/components/base_component.rb +0 -110
- data/lib/shoko/adapters/output/ui/components/component_interface.rb +0 -80
- data/lib/shoko/adapters/output/ui/components/content_component.rb +0 -61
- data/lib/shoko/adapters/output/ui/components/enhanced_popup_menu.rb +0 -191
- data/lib/shoko/adapters/output/ui/components/footer_component.rb +0 -120
- data/lib/shoko/adapters/output/ui/components/header_component.rb +0 -46
- data/lib/shoko/adapters/output/ui/components/layouts/horizontal.rb +0 -63
- data/lib/shoko/adapters/output/ui/components/layouts/vertical.rb +0 -73
- data/lib/shoko/adapters/output/ui/components/main_menu_component.rb +0 -103
- data/lib/shoko/adapters/output/ui/components/reading/base_view_renderer.rb +0 -199
- data/lib/shoko/adapters/output/ui/components/reading/config_helpers.rb +0 -42
- data/lib/shoko/adapters/output/ui/components/reading/help_renderer.rb +0 -62
- data/lib/shoko/adapters/output/ui/components/reading/inline_segment_highlighter.rb +0 -144
- data/lib/shoko/adapters/output/ui/components/reading/kitty_image_line_renderer.rb +0 -262
- data/lib/shoko/adapters/output/ui/components/reading/line_content_composer.rb +0 -114
- data/lib/shoko/adapters/output/ui/components/reading/line_drawer.rb +0 -87
- data/lib/shoko/adapters/output/ui/components/reading/line_geometry_builder.rb +0 -41
- data/lib/shoko/adapters/output/ui/components/reading/rendered_lines_recorder.rb +0 -64
- data/lib/shoko/adapters/output/ui/components/reading/single_view_renderer.rb +0 -156
- data/lib/shoko/adapters/output/ui/components/reading/split_view_renderer.rb +0 -221
- data/lib/shoko/adapters/output/ui/components/reading/view_renderer_factory.rb +0 -20
- data/lib/shoko/adapters/output/ui/components/reading/wrapped_lines_fetcher.rb +0 -139
- data/lib/shoko/adapters/output/ui/components/rect.rb +0 -15
- data/lib/shoko/adapters/output/ui/components/render_style.rb +0 -84
- data/lib/shoko/adapters/output/ui/components/screen_component.rb +0 -24
- data/lib/shoko/adapters/output/ui/components/screens/annotation_detail_screen_component.rb +0 -175
- data/lib/shoko/adapters/output/ui/components/screens/annotation_edit_screen_component.rb +0 -221
- data/lib/shoko/adapters/output/ui/components/screens/annotation_editor_screen_component.rb +0 -205
- data/lib/shoko/adapters/output/ui/components/screens/annotation_rendering_helpers.rb +0 -190
- data/lib/shoko/adapters/output/ui/components/screens/annotations_screen_component.rb +0 -266
- data/lib/shoko/adapters/output/ui/components/screens/base_screen_component.rb +0 -49
- data/lib/shoko/adapters/output/ui/components/screens/browse_screen_component.rb +0 -319
- data/lib/shoko/adapters/output/ui/components/screens/download_books_screen_component.rb +0 -340
- data/lib/shoko/adapters/output/ui/components/screens/library_screen_component.rb +0 -205
- data/lib/shoko/adapters/output/ui/components/screens/loading_overlay_component.rb +0 -49
- data/lib/shoko/adapters/output/ui/components/screens/menu_screen_component.rb +0 -107
- data/lib/shoko/adapters/output/ui/components/screens/settings_screen_component.rb +0 -238
- data/lib/shoko/adapters/output/ui/components/sidebar/annotations_tab_renderer.rb +0 -159
- data/lib/shoko/adapters/output/ui/components/sidebar/bookmarks_tab_renderer.rb +0 -139
- data/lib/shoko/adapters/output/ui/components/sidebar/tab_header_component.rb +0 -157
- data/lib/shoko/adapters/output/ui/components/sidebar/toc_tab_renderer.rb +0 -111
- data/lib/shoko/adapters/output/ui/components/sidebar/toc_tab_support.rb +0 -1606
- data/lib/shoko/adapters/output/ui/components/sidebar_panel_component.rb +0 -217
- data/lib/shoko/adapters/output/ui/components/surface.rb +0 -88
- data/lib/shoko/adapters/output/ui/components/tooltip_overlay_component.rb +0 -224
- data/lib/shoko/adapters/output/ui/components/ui/box_drawer.rb +0 -32
- data/lib/shoko/adapters/output/ui/components/ui/list_helpers.rb +0 -33
- data/lib/shoko/adapters/output/ui/components/ui/overlay_layout.rb +0 -79
- data/lib/shoko/adapters/output/ui/components/ui/text_utils.rb +0 -46
- data/lib/shoko/adapters/output/ui/constants/highlighting.rb +0 -21
- data/lib/shoko/adapters/output/ui/constants/messages.rb +0 -12
- data/lib/shoko/adapters/output/ui/constants/themes.rb +0 -79
- data/lib/shoko/adapters/output/ui/constants/ui_constants.rb +0 -85
- data/lib/shoko/adapters/output/ui/rendering/frame_coordinator.rb +0 -42
- data/lib/shoko/adapters/output/ui/rendering/reader_render_coordinator.rb +0 -169
- data/lib/shoko/adapters/output/ui/rendering/render_pipeline.rb +0 -55
- data/lib/shoko/adapters/storage/repositories/config_repository.rb +0 -262
- data/lib/shoko/application/annotation_editor_overlay_session.rb +0 -138
- data/lib/shoko/application/cli.rb +0 -134
- data/lib/shoko/application/controllers/menu/input_controller.rb +0 -189
- data/lib/shoko/application/controllers/menu/state_controller.rb +0 -642
- data/lib/shoko/application/controllers/menu_controller.rb +0 -469
- data/lib/shoko/application/controllers/mouseable_reader.rb +0 -421
- data/lib/shoko/application/controllers/reader_controller.rb +0 -449
- data/lib/shoko/application/controllers/state_controller.rb +0 -410
- data/lib/shoko/application/controllers/ui_controller.rb +0 -782
- data/lib/shoko/application/dependency_container.rb +0 -301
- data/lib/shoko/application/infrastructure/event_bus.rb +0 -80
- data/lib/shoko/application/infrastructure/observer_state_store.rb +0 -136
- data/lib/shoko/application/infrastructure/state_store.rb +0 -413
- data/lib/shoko/application/main_menu/menu_progress_presenter.rb +0 -83
- data/lib/shoko/application/reader_lifecycle.rb +0 -65
- data/lib/shoko/application/reader_startup_orchestrator.rb +0 -113
- data/lib/shoko/application/selectors/config_selectors.rb +0 -62
- data/lib/shoko/application/selectors/menu_selectors.rb +0 -62
- data/lib/shoko/application/selectors/reader_selectors.rb +0 -190
- data/lib/shoko/application/state/actions/base_action.rb +0 -24
- data/lib/shoko/application/state/actions/quit_to_menu_action.rb +0 -16
- data/lib/shoko/application/state/actions/switch_reader_mode_action.rb +0 -22
- data/lib/shoko/application/state/actions/toggle_view_mode_action.rb +0 -31
- data/lib/shoko/application/state/actions/update_annotation_editor_overlay_action.rb +0 -27
- data/lib/shoko/application/state/actions/update_annotations_action.rb +0 -20
- data/lib/shoko/application/state/actions/update_annotations_overlay_action.rb +0 -27
- data/lib/shoko/application/state/actions/update_bookmarks_action.rb +0 -20
- data/lib/shoko/application/state/actions/update_chapter_action.rb +0 -24
- data/lib/shoko/application/state/actions/update_config_action.rb +0 -22
- data/lib/shoko/application/state/actions/update_field_helpers.rb +0 -26
- data/lib/shoko/application/state/actions/update_menu_action.rb +0 -21
- data/lib/shoko/application/state/actions/update_message_action.rb +0 -35
- data/lib/shoko/application/state/actions/update_page_action.rb +0 -21
- data/lib/shoko/application/state/actions/update_pagination_state_action.rb +0 -21
- data/lib/shoko/application/state/actions/update_popup_menu_action.rb +0 -27
- data/lib/shoko/application/state/actions/update_reader_meta_action.rb +0 -21
- data/lib/shoko/application/state/actions/update_reader_mode_action.rb +0 -20
- data/lib/shoko/application/state/actions/update_rendered_lines_action.rb +0 -40
- data/lib/shoko/application/state/actions/update_selection_action.rb +0 -27
- data/lib/shoko/application/state/actions/update_selections_action.rb +0 -21
- data/lib/shoko/application/state/actions/update_sidebar_action.rb +0 -34
- data/lib/shoko/application/state/actions/update_ui_loading_action.rb +0 -23
- data/lib/shoko/application/ui/reader_view_model_builder.rb +0 -74
- data/lib/shoko/application/ui/view_models/reader_view_model.rb +0 -177
- data/lib/shoko/application/use_cases/commands/annotation_editor_commands.rb +0 -105
- data/lib/shoko/application/use_cases/commands/application_commands.rb +0 -208
- data/lib/shoko/application/use_cases/commands/conditional_navigation_commands.rb +0 -57
- data/lib/shoko/application/use_cases/commands/menu_commands.rb +0 -170
- data/lib/shoko/application/use_cases/commands/reader_commands.rb +0 -46
- data/lib/shoko/application/use_cases/commands/sidebar_commands.rb +0 -55
- data/lib/shoko/core/ports/annotation_repository.rb +0 -0
- data/lib/shoko/core/ports/book_repository.rb +0 -0
- data/lib/shoko/core/ports/book_source.rb +0 -0
- data/lib/shoko/core/ports/bookmark_repository.rb +0 -0
- data/lib/shoko/core/ports/cache.rb +0 -0
- data/lib/shoko/core/ports/input_handler.rb +0 -0
- data/lib/shoko/core/ports/renderer.rb +0 -0
- data/lib/shoko/core/ports/storage.rb +0 -0
- data/lib/shoko/core/services/bookmark_service.rb +0 -267
- data/lib/shoko/core/services/navigation/absolute_change_applier.rb +0 -96
- data/lib/shoko/core/services/navigation/absolute_layout.rb +0 -101
- data/lib/shoko/core/services/navigation/absolute_strategy.rb +0 -179
- data/lib/shoko/core/services/navigation/context_builder.rb +0 -52
- data/lib/shoko/core/services/navigation/context_helpers.rb +0 -63
- data/lib/shoko/core/services/navigation/dynamic_change_applier.rb +0 -50
- data/lib/shoko/core/services/navigation/dynamic_strategy.rb +0 -51
- data/lib/shoko/core/services/navigation/image_offset_snapper.rb +0 -150
- data/lib/shoko/core/services/navigation/nav_context.rb +0 -27
- data/lib/shoko/core/services/navigation/state_updater.rb +0 -29
- data/lib/shoko/core/services/navigation/strategy_factory.rb +0 -20
- data/lib/shoko/core/services/navigation_service.rb +0 -150
- data/lib/shoko/core/services/pagination/page_info_calculator.rb +0 -247
- data/lib/shoko/core/services/pagination/pagination_cache_preloader.rb +0 -173
- data/lib/shoko/core/services/pagination/pagination_coordinator.rb +0 -202
- data/lib/shoko/core/services/pagination/pagination_orchestrator.rb +0 -291
- data/zip.rb +0 -5
- /data/lib/shoko/{adapters/output/kitty → shared/terminal}/kitty_unicode_placeholders_diacritic_codepoints.txt +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a52dba22d1ec1059543f62821ab8e1bf7236def9a0cb8ef2376b13434faf2f03
|
|
4
|
+
data.tar.gz: 2da5e4f6c6b7a31702f7b9c9fe1786b02895f1588415a215ab0130068eebfb33
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: acbbf2c9f160186d0cf41a3a8ed41efeb60be2f261398f80d2e9318eb0573f9c1ef47bb6f01851c9cdec6a42f8409b99b4b789d36e9d0af36491c3000cfbaa88
|
|
7
|
+
data.tar.gz: 6756ad75a6ffcfe850b99958f30440f35800a602d910115b1e79a59bfdb0afc3d06d4558c5f8f114eac15a3281acccfd8948b10a508c22b1aee952c66c41d4c8
|
data/.bundle/config
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
plugins:
|
|
2
2
|
- rubocop-performance
|
|
3
|
-
- rubocop-rails
|
|
4
3
|
|
|
5
4
|
AllCops:
|
|
6
5
|
TargetRubyVersion: 3.3
|
|
@@ -36,24 +35,45 @@ Metrics/MethodLength:
|
|
|
36
35
|
CountComments: false
|
|
37
36
|
AllowedMethods:
|
|
38
37
|
- 'initialize'
|
|
38
|
+
# Data schema definition - just a hash literal
|
|
39
|
+
- 'build_initial_state'
|
|
40
|
+
# Character-by-character algorithms where splitting obscures logic
|
|
41
|
+
- 'sanitize'
|
|
42
|
+
- 'wrap_cells'
|
|
43
|
+
- 'truncate_to'
|
|
39
44
|
Exclude:
|
|
40
45
|
- 'spec/**/*'
|
|
41
46
|
- 'test/**/*'
|
|
42
47
|
|
|
43
48
|
Metrics/AbcSize:
|
|
44
49
|
Max: 20
|
|
50
|
+
AllowedMethods:
|
|
51
|
+
# Character-by-character algorithms
|
|
52
|
+
- 'wrap_cells'
|
|
53
|
+
- 'sanitize'
|
|
54
|
+
- 'truncate_to'
|
|
45
55
|
Exclude:
|
|
46
56
|
- 'spec/**/*'
|
|
47
57
|
- 'test/**/*'
|
|
48
58
|
|
|
49
59
|
Metrics/CyclomaticComplexity:
|
|
50
60
|
Max: 8
|
|
61
|
+
AllowedMethods:
|
|
62
|
+
# Character-by-character algorithms - inherent complexity
|
|
63
|
+
- 'sanitize'
|
|
64
|
+
- 'truncate_to'
|
|
65
|
+
- 'wrap_cells'
|
|
51
66
|
Exclude:
|
|
52
67
|
- 'spec/**/*'
|
|
53
68
|
- 'test/**/*'
|
|
54
69
|
|
|
55
70
|
Metrics/PerceivedComplexity:
|
|
56
71
|
Max: 9
|
|
72
|
+
AllowedMethods:
|
|
73
|
+
# Character-by-character algorithms - inherent complexity
|
|
74
|
+
- 'sanitize'
|
|
75
|
+
- 'truncate_to'
|
|
76
|
+
- 'wrap_cells'
|
|
57
77
|
Exclude:
|
|
58
78
|
- 'spec/**/*'
|
|
59
79
|
- 'test/**/*'
|
|
@@ -71,6 +91,20 @@ Metrics/BlockLength:
|
|
|
71
91
|
- 'spec/**/*'
|
|
72
92
|
- 'test/**/*'
|
|
73
93
|
|
|
94
|
+
# Naming
|
|
95
|
+
Naming/PredicateMethod:
|
|
96
|
+
# Allow handler methods that return boolean for control flow
|
|
97
|
+
AllowedMethods:
|
|
98
|
+
- handle_overlay_click
|
|
99
|
+
- handle_sidebar_interaction
|
|
100
|
+
- handle_sidebar_tab_click
|
|
101
|
+
- handle_sidebar_toc_click
|
|
102
|
+
- handle_sidebar_wheel
|
|
103
|
+
- handle_sidebar_scroll_drag
|
|
104
|
+
- start_sidebar_scroll_drag
|
|
105
|
+
- cancel_via_ui
|
|
106
|
+
- dispatch_to_mode
|
|
107
|
+
|
|
74
108
|
# Style
|
|
75
109
|
Style/Documentation:
|
|
76
110
|
Enabled: true
|
|
@@ -119,6 +153,3 @@ Lint/UselessAssignment:
|
|
|
119
153
|
|
|
120
154
|
Lint/DuplicateMethods:
|
|
121
155
|
Enabled: true
|
|
122
|
-
|
|
123
|
-
Rails:
|
|
124
|
-
Enabled: false
|
data/Gemfile
CHANGED
|
@@ -6,6 +6,7 @@ gemspec
|
|
|
6
6
|
|
|
7
7
|
group :development do
|
|
8
8
|
gem 'reek'
|
|
9
|
+
gem 'rake'
|
|
9
10
|
gem 'rubocop', require: false
|
|
10
11
|
gem 'rubocop-performance', require: false
|
|
11
12
|
gem 'rubocop-rails', require: false
|
|
@@ -16,4 +17,5 @@ group :test do
|
|
|
16
17
|
gem 'fakefs', require: 'fakefs/spec_helpers'
|
|
17
18
|
gem 'rspec'
|
|
18
19
|
gem 'simplecov', require: false
|
|
20
|
+
gem 'webmock', require: false
|
|
19
21
|
end
|
data/README.md
CHANGED
|
@@ -15,10 +15,42 @@ Terminal ebook reader for EPUB files.
|
|
|
15
15
|
## How it works
|
|
16
16
|
|
|
17
17
|
- `bin/start` runs the CLI and enters menu mode or opens a file directly.
|
|
18
|
+
- `bootstrap` is the only runtime wiring boundary (`Bootstrap::ContainerFactory`).
|
|
18
19
|
- State lives in a single store; actions update state and selectors read it.
|
|
19
20
|
- Rendering is component-based and drawn through a terminal buffer with diff updates.
|
|
20
21
|
- Selection/highlighting uses recorded line geometry from the render pass.
|
|
21
22
|
|
|
23
|
+
## Architecture boundaries
|
|
24
|
+
|
|
25
|
+
- Hexagonal layering is enforced.
|
|
26
|
+
- `core` contains domain models/services and the single ports root.
|
|
27
|
+
- Ports are split by direction only:
|
|
28
|
+
- `Core::Ports::Inbound::*` (driving boundary into application use cases).
|
|
29
|
+
- `Core::Ports::Outbound::*` (driven dependencies implemented by adapters).
|
|
30
|
+
- `application` contains use-case/workflow/service orchestration only.
|
|
31
|
+
- `adapters` contains all input, UI, output, runtime, monitoring, and storage implementations.
|
|
32
|
+
- `bootstrap` is the only composition root and the only layer that mutates/resolves the container.
|
|
33
|
+
- Reader runtime controller graph composition is bootstrap-only (`ContainerFactory::ControllerComposition::ReaderBuilder`).
|
|
34
|
+
|
|
35
|
+
Canonical runtime layout:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
lib/shoko/
|
|
39
|
+
core/ports/{inbound,outbound}
|
|
40
|
+
application/{use_cases,services,workflows}
|
|
41
|
+
adapters/{input,ui,output,runtime,storage,monitoring}
|
|
42
|
+
bootstrap/{container_factory,dependencies}
|
|
43
|
+
shared/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Inbound command boundary:
|
|
47
|
+
|
|
48
|
+
- `Core::Ports::Inbound::CommandBus`
|
|
49
|
+
- `Core::Ports::Inbound::ReaderIntentHandler`
|
|
50
|
+
- `Core::Ports::Inbound::MenuIntentHandler`
|
|
51
|
+
- Implemented by `Application::UseCases::CommandBus`
|
|
52
|
+
- Input symbols are dispatched through `ReaderIntentCommand`, `MenuIntentCommand`, and `SharedIntentCommand`
|
|
53
|
+
|
|
22
54
|
## Usage
|
|
23
55
|
|
|
24
56
|
From source:
|
|
@@ -34,12 +66,27 @@ Open a file directly:
|
|
|
34
66
|
bin/start /path/to/book.epub
|
|
35
67
|
```
|
|
36
68
|
|
|
69
|
+
Import a folder of ebooks from CLI:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
bin/start /path/to/books-directory
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This scans the directory recursively (skipping hidden files/folders), shows counts by format, and lets you:
|
|
76
|
+
|
|
77
|
+
- import all discovered files
|
|
78
|
+
- import only one file type
|
|
79
|
+
- exit without importing
|
|
80
|
+
|
|
81
|
+
After import, Shoko opens menu mode by default.
|
|
82
|
+
|
|
37
83
|
Options:
|
|
38
84
|
|
|
39
85
|
- `-d`, `--debug` Enable debug logging.
|
|
40
86
|
- `--log PATH` Write JSON logs to PATH.
|
|
41
87
|
- `--log-level LEVEL` Set log level (`debug`, `info`, `warn`, `error`, `fatal`).
|
|
42
88
|
- `--profile PATH` Write a concise performance profile to PATH.
|
|
89
|
+
- `-v`, `--version` Show version.
|
|
43
90
|
- `-h`, `--help` Show help.
|
|
44
91
|
|
|
45
92
|
## Controls (basics)
|
|
@@ -69,7 +116,6 @@ Reader:
|
|
|
69
116
|
- `config.json`
|
|
70
117
|
- `annotations.json`, `bookmarks.json`, `progress.json`, `recent.json`
|
|
71
118
|
- `downloads/` (Gutendex downloads)
|
|
72
|
-
- `epub_cache.json` (scan cache)
|
|
73
119
|
- Cache: `~/.cache/shoko/`
|
|
74
120
|
|
|
75
121
|
## Logging and profiling
|
|
@@ -80,3 +126,56 @@ You can also configure logging with environment variables:
|
|
|
80
126
|
- `SHOKO_LOG_PATH=/path/to/log` Write JSON logs to a file.
|
|
81
127
|
- `SHOKO_LOG_LEVEL=info` Set log level.
|
|
82
128
|
- `SHOKO_PROFILE_PATH=/path/to/profile` Write a performance profile.
|
|
129
|
+
|
|
130
|
+
## Testing
|
|
131
|
+
|
|
132
|
+
Required guardrails lane:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
bundle exec rake test:guardrails
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Required non-fixture lane (runs 3 fixed seeds):
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
bundle exec rake test:required
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Real-book fixture lane:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
SHOKO_BOOK_FIXTURES=1 SHOKO_FIXTURES_DIR=/path/to/book-fixtures bundle exec rake test:fixtures
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Full suite sanity:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
bundle exec rspec
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Benchmarking
|
|
157
|
+
|
|
158
|
+
Run the built-in snappiness benchmark:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
bundle exec ruby script/bench/snappiness_benchmark.rb
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The benchmark prints baseline vs optimized timings for:
|
|
165
|
+
|
|
166
|
+
- `TextMetrics.visible_length` cache impact
|
|
167
|
+
- `TextMetrics.visible_length` ASCII fast-path impact
|
|
168
|
+
- `TextMetrics.truncate_to` ASCII fast-path impact
|
|
169
|
+
- `TextMetrics.wrap_plain_text` cache impact
|
|
170
|
+
- `TextMetrics.wrap_plain_text` result-cache impact
|
|
171
|
+
- `LineAssembler.build` cache impact
|
|
172
|
+
- `LineAssembler::Tokenizer.tokenize` cache impact
|
|
173
|
+
- `LineAssembler.build` tokenize-cache impact
|
|
174
|
+
- `LineAssembler.build` token-width-hints impact
|
|
175
|
+
- `LineAssembler.build` token-pipeline combined impact
|
|
176
|
+
- `WrappingService.wrap_window` prefetch-range reuse impact
|
|
177
|
+
- `LineGeometryBuilder.build` repeated-line cell cache impact
|
|
178
|
+
- `TerminalBuffer::Frame.write` ASCII fast-path impact
|
|
179
|
+
- `LineContentComposer.compose` repeated-line cache impact
|
|
180
|
+
- `ManifestShaFinder.sha` large-manifest lookup impact
|
|
181
|
+
- `JsonCacheStore.manifest_rows` repeated-read cache impact
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'bundler/gem_tasks'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'English'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
require 'shellwords'
|
|
4
8
|
require 'rspec/core/rake_task'
|
|
5
9
|
require 'rubocop/rake_task'
|
|
6
10
|
|
|
@@ -13,9 +17,84 @@ task quality: %i[spec rubocop]
|
|
|
13
17
|
task default: :quality
|
|
14
18
|
|
|
15
19
|
namespace :test do
|
|
20
|
+
module RSpecLane
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
RESULT_DIR = File.expand_path('tmp/rspec-results', __dir__)
|
|
24
|
+
|
|
25
|
+
def run!(name:, args:, env: {})
|
|
26
|
+
FileUtils.mkdir_p(RESULT_DIR)
|
|
27
|
+
output_path = File.join(RESULT_DIR, "#{name}.json")
|
|
28
|
+
command = ['bundle', 'exec', 'rspec', *args, '--format', 'json', '--out', output_path]
|
|
29
|
+
|
|
30
|
+
puts "==> #{name}: #{Shellwords.join(command)}"
|
|
31
|
+
success = system(env, *command)
|
|
32
|
+
pending = pending_count(output_path)
|
|
33
|
+
|
|
34
|
+
raise "Pending examples detected in #{name}: #{pending}" if pending.positive?
|
|
35
|
+
raise "RSpec failed in #{name} (exit #{$CHILD_STATUS.exitstatus})" unless success
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def pending_count(path)
|
|
39
|
+
return 0 unless File.exist?(path)
|
|
40
|
+
|
|
41
|
+
payload = JSON.parse(File.read(path))
|
|
42
|
+
payload.dig('summary', 'pending_count').to_i
|
|
43
|
+
rescue JSON::ParserError => e
|
|
44
|
+
raise "Unable to parse RSpec JSON report at #{path}: #{e.message}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
desc 'Run architecture and wiring guardrail specs only'
|
|
49
|
+
task :guardrails do
|
|
50
|
+
FileUtils.mkdir_p(RSpecLane::RESULT_DIR)
|
|
51
|
+
fallback_report_path = File.join(RSpecLane::RESULT_DIR, 'fallback-report.json')
|
|
52
|
+
fallback_command = ['ruby', File.expand_path('script/architecture/fallback_report.rb', __dir__)]
|
|
53
|
+
puts "==> fallback-report: #{Shellwords.join(fallback_command)}"
|
|
54
|
+
fallback_payload = IO.popen(fallback_command, &:read)
|
|
55
|
+
File.write(fallback_report_path, fallback_payload)
|
|
56
|
+
raise 'Fallback report detected guardrail offenders' unless $CHILD_STATUS.success?
|
|
57
|
+
|
|
58
|
+
guardrail_targets = [
|
|
59
|
+
'spec/core/architecture',
|
|
60
|
+
'spec/adapters/input/command_bus_only_bindings_spec.rb',
|
|
61
|
+
'spec/adapters/input/command_binding_completeness_spec.rb',
|
|
62
|
+
'spec/bootstrap/dependencies/bundle_guardrails_spec.rb',
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
RSpecLane.run!(
|
|
66
|
+
name: 'guardrails',
|
|
67
|
+
args: [*guardrail_targets, '--seed', '10101']
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
desc 'Run required non-fixture specs across fixed deterministic seeds'
|
|
72
|
+
task :required do
|
|
73
|
+
%w[10101 20202 30303].each do |seed|
|
|
74
|
+
RSpecLane.run!(
|
|
75
|
+
name: "required-seed-#{seed}",
|
|
76
|
+
args: ['--tag', '~requires_book_fixtures', '--seed', seed]
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
desc 'Run fixture-dependent specs only'
|
|
82
|
+
task :fixtures do
|
|
83
|
+
env = {
|
|
84
|
+
'SHOKO_BOOK_FIXTURES' => '1',
|
|
85
|
+
}
|
|
86
|
+
env['SHOKO_FIXTURES_DIR'] = ENV['SHOKO_FIXTURES_DIR'] if ENV.key?('SHOKO_FIXTURES_DIR')
|
|
87
|
+
|
|
88
|
+
RSpecLane.run!(
|
|
89
|
+
name: 'fixtures',
|
|
90
|
+
env: env,
|
|
91
|
+
args: ['--tag', 'requires_book_fixtures', '--seed', '30303']
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
16
95
|
desc 'Run tests with coverage'
|
|
17
96
|
task :coverage do
|
|
18
|
-
ENV['COVERAGE'] = '
|
|
97
|
+
ENV['COVERAGE'] = '1'
|
|
19
98
|
Rake::Task['spec'].invoke
|
|
20
99
|
end
|
|
21
100
|
end
|
data/Shoko.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/shoko/shared/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'shoko'
|
|
7
|
+
spec.version = Shoko::VERSION
|
|
8
|
+
spec.authors = ['Shoko']
|
|
9
|
+
spec.email = ['ruby.computer770@passinbox.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Terminal EBook Reader'
|
|
12
|
+
spec.description = 'Terminal EBook Reader'
|
|
13
|
+
spec.homepage = 'https://sr.ht/~shayan/Shoko/'
|
|
14
|
+
spec.license = 'MIT'
|
|
15
|
+
spec.required_ruby_version = '>= 4.0.0'
|
|
16
|
+
|
|
17
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
18
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
|
19
|
+
|
|
20
|
+
# Specify which files should be added to the gem
|
|
21
|
+
spec.files = Dir.chdir(__dir__) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
23
|
+
f.end_with?('.gem') ||
|
|
24
|
+
(f == __FILE__) ||
|
|
25
|
+
f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
|
|
26
|
+
end.select { |f| File.file?(f) }
|
|
27
|
+
end
|
|
28
|
+
spec.bindir = 'bin'
|
|
29
|
+
spec.executables = %w[shoko start]
|
|
30
|
+
spec.require_paths = ['lib']
|
|
31
|
+
|
|
32
|
+
# Development dependencies are managed in the Gemfile
|
|
33
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
34
|
+
end
|
data/bin/shoko
CHANGED
|
@@ -6,14 +6,20 @@ lib_dir = File.join(app_root, 'lib')
|
|
|
6
6
|
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
|
-
|
|
10
|
-
if
|
|
11
|
-
require 'bundler/setup'
|
|
12
|
-
end
|
|
9
|
+
# Only activate Bundler when explicitly running under it (e.g. bundle exec).
|
|
10
|
+
require 'bundler/setup' if ENV['BUNDLE_GEMFILE'] || ENV['BUNDLE_BIN_PATH']
|
|
13
11
|
rescue LoadError
|
|
14
12
|
# Running without Bundler (e.g., installed gem).
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
require 'shoko'
|
|
18
16
|
|
|
19
|
-
Shoko::CLI.run
|
|
17
|
+
Shoko::Adapters::Input::CLI.run(
|
|
18
|
+
ARGV,
|
|
19
|
+
app_factory: lambda do |epub_path:, log_config:|
|
|
20
|
+
Shoko::Bootstrap::ContainerFactory.build_unified_application(epub_path: epub_path, log_config: log_config)
|
|
21
|
+
end,
|
|
22
|
+
folder_import_factory: lambda do |log_config:|
|
|
23
|
+
Shoko::Bootstrap::ContainerFactory.build_cli_folder_import_context(log_config: log_config)
|
|
24
|
+
end
|
|
25
|
+
)
|
data/bin/start
CHANGED
|
@@ -6,14 +6,20 @@ lib_dir = File.join(app_root, 'lib')
|
|
|
6
6
|
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
|
-
|
|
10
|
-
if
|
|
11
|
-
require 'bundler/setup'
|
|
12
|
-
end
|
|
9
|
+
# Only activate Bundler when explicitly running under it (e.g. bundle exec).
|
|
10
|
+
require 'bundler/setup' if ENV['BUNDLE_GEMFILE'] || ENV['BUNDLE_BIN_PATH']
|
|
13
11
|
rescue LoadError
|
|
14
12
|
# Running without Bundler (e.g., installed gem).
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
require 'shoko'
|
|
18
16
|
|
|
19
|
-
Shoko::CLI.run
|
|
17
|
+
Shoko::Adapters::Input::CLI.run(
|
|
18
|
+
ARGV,
|
|
19
|
+
app_factory: lambda do |epub_path:, log_config:|
|
|
20
|
+
Shoko::Bootstrap::ContainerFactory.build_unified_application(epub_path: epub_path, log_config: log_config)
|
|
21
|
+
end,
|
|
22
|
+
folder_import_factory: lambda do |log_config:|
|
|
23
|
+
Shoko::Bootstrap::ContainerFactory.build_cli_folder_import_context(log_config: log_config)
|
|
24
|
+
end
|
|
25
|
+
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Hexagonal Architecture Adherence Checklist (Zero-Fallback Cutover)
|
|
2
|
+
|
|
3
|
+
Date: 2026-03-03
|
|
4
|
+
Scope: `lib/shoko/**` runtime + architecture guardrails/spec gates
|
|
5
|
+
|
|
6
|
+
## Completed
|
|
7
|
+
|
|
8
|
+
- [x] Removed optional DI resolution usage:
|
|
9
|
+
- zero `resolve_optional(` occurrences in `lib/shoko`.
|
|
10
|
+
- `DependencyContainer` exposes mandatory `resolve` only.
|
|
11
|
+
- [x] Removed two-phase reader runtime wiring from public API:
|
|
12
|
+
- no `defer_runtime_setup`.
|
|
13
|
+
- no `attach_runtime_components!`.
|
|
14
|
+
- reader runtime graph is single-phase via constructor-time runtime factory.
|
|
15
|
+
- [x] Completed inbound boundary ownership migration:
|
|
16
|
+
- adapters no longer include inbound intent handler ports.
|
|
17
|
+
- adapter-owned intent handler classes removed.
|
|
18
|
+
- application intent handlers added under `application/use_cases/intents`.
|
|
19
|
+
- [x] Removed reflection-style probing/dispatch globally in runtime code:
|
|
20
|
+
- zero `respond_to?(` occurrences.
|
|
21
|
+
- zero `public_send` occurrences.
|
|
22
|
+
- zero dynamic `send(` occurrences.
|
|
23
|
+
- [x] Removed collaborator-probing rescues:
|
|
24
|
+
- zero `rescue NoMethodError` collaborator probing occurrences.
|
|
25
|
+
- [x] Removed known swallow/fallback runtime behaviors in strict paths:
|
|
26
|
+
- reader quit/save progress now fails fast.
|
|
27
|
+
- event bus subscriber failures are logged then re-raised.
|
|
28
|
+
- render state writer failures are logged then re-raised.
|
|
29
|
+
- document path resolver no longer masks resolver failures.
|
|
30
|
+
- kitty image line renderer no longer suppresses renderer exceptions.
|
|
31
|
+
- [x] Removed known mechanical migration violations:
|
|
32
|
+
- bare `rescue =>` patterns removed (runtime code).
|
|
33
|
+
- inline `... rescue ...` expressions removed from runtime code.
|
|
34
|
+
- [x] Boundary translation hardened:
|
|
35
|
+
- document load failures are translated to `Shoko::BookParseError`.
|
|
36
|
+
- dictionary catalog boundary uses typed `CatalogError < Shoko::Error`.
|
|
37
|
+
- cache import boundary propagates typed malformed-book failures (`BookParseError` / `MalformedBookInputError`) with no adapter shim fallback.
|
|
38
|
+
- [x] Completed inbound handler decoupling from adapter controllers:
|
|
39
|
+
- application intent handlers now depend on typed executors (`ReaderIntentExecutor` / `MenuIntentExecutor`).
|
|
40
|
+
- adapter controller dispatch moved to adapter bridges.
|
|
41
|
+
- no `@reader_controller.` / `@menu_controller.` loopback remains in app intent handlers.
|
|
42
|
+
- [x] Replaced bootstrap session contexts with launch-state ports/adapters:
|
|
43
|
+
- added `Core::Ports::Outbound::ReaderLaunchState` and `MenuLaunchState`.
|
|
44
|
+
- runtime adapters added in `adapters/runtime/session_state`.
|
|
45
|
+
- `ReaderSessionContext` / `MenuSessionContext` removed from bootstrap.
|
|
46
|
+
- application workflows and unified app now use launch-state ports.
|
|
47
|
+
- [x] Enforced symbol-only input command execution contract:
|
|
48
|
+
- `Adapters::Input::Commands.execute` now rejects non-symbol commands.
|
|
49
|
+
- legacy proc/object/array execution paths removed.
|
|
50
|
+
- [x] Optional dependency hard-error path introduced for sqlite execution:
|
|
51
|
+
- added `Shared::OptionalDependency.require_gem!`.
|
|
52
|
+
- added `DependencyUnavailableError` and used it in sqlite runtime load path.
|
|
53
|
+
- dictionary repository now remains wired in auto mode; missing sqlite fails explicitly on invocation.
|
|
54
|
+
- [x] Fixed reader relaunch crash after closing/opening another book:
|
|
55
|
+
- reader launch state now clears background worker on reader exit (`RuntimeExecution#run_reader` ensure block), preventing reuse of stopped workers.
|
|
56
|
+
- [x] Added canonical zero-fallback architecture guardrails:
|
|
57
|
+
- `spec/core/architecture/no_rescue_literal_default_spec.rb`
|
|
58
|
+
- `spec/core/architecture/no_overlapping_rescue_chains_spec.rb`
|
|
59
|
+
- `spec/core/architecture/no_stale_optional_resolution_spec.rb`
|
|
60
|
+
- `spec/core/architecture/no_standard_error_rescue_spec.rb`
|
|
61
|
+
- [x] Removed duplicate/overlapping rescue chains that created unreachable branches.
|
|
62
|
+
- importer translation chains fixed (`fb2`, `kindle`, `pdf`, `rtf`).
|
|
63
|
+
- cache/string translation chain fixed (`lazy_file_string`).
|
|
64
|
+
- CLI contract coercion rescue overlaps fixed.
|
|
65
|
+
- bootstrap background worker fallback contract rescue overlap fixed.
|
|
66
|
+
- [x] Removed stale optional-resolution scaffolding in reader composition.
|
|
67
|
+
- `ReaderBuilder#resolve_many` now has a single deterministic resolve path.
|
|
68
|
+
- [x] Eliminated explicit `rescue StandardError` usage in `lib/shoko/**`.
|
|
69
|
+
- fail-fast boundaries now use explicit/translated rescue flows without `rescue StandardError`.
|
|
70
|
+
- [x] Completed hard-cutover removal of legacy callable factories.
|
|
71
|
+
- removed DI keys/usages of `:document_service_factory` and `:background_worker_factory`.
|
|
72
|
+
- replaced with typed outbound ports `DocumentLoader` and `BackgroundWorkerBuilder`.
|
|
73
|
+
- [x] Added typed progress boundary and removed adapter-to-adapter coupling in the progress path.
|
|
74
|
+
- new port `Core::Ports::Outbound::ProgressRepository`.
|
|
75
|
+
- new core value `Core::Models::ReadingProgress`.
|
|
76
|
+
- input adapter progress actions now consume typed core progress data only.
|
|
77
|
+
- [x] Removed Proc-type migration fallbacks from runtime paths.
|
|
78
|
+
- zero `is_a?(Proc)` checks remain in `lib/shoko`.
|
|
79
|
+
- [x] Removed implicit `NullRuntimeConfig` fallback expressions from runtime code.
|
|
80
|
+
- runtime config is now explicit at composition boundaries and test builders.
|
|
81
|
+
- [x] Removed `rescue Exception` and bare string raises from `lib/shoko`.
|
|
82
|
+
- `rescue Exception`: `0`
|
|
83
|
+
- `raise '...'` / `raise "..."`: `0`
|
|
84
|
+
- [x] Added permanent guardrails for zero-fallback constraints.
|
|
85
|
+
- `spec/core/architecture/no_rescue_exception_spec.rb`
|
|
86
|
+
- `spec/core/architecture/no_bare_string_raise_spec.rb`
|
|
87
|
+
- `spec/core/architecture/no_implicit_null_runtime_config_spec.rb`
|
|
88
|
+
- `spec/core/architecture/no_legacy_factory_keys_spec.rb`
|
|
89
|
+
- `spec/core/architecture/no_proc_type_fallbacks_spec.rb`
|
|
90
|
+
- [x] Fixed post-cutover runtime regressions in browse/menu flow.
|
|
91
|
+
- directory scanner recursion now works (books populate in Browse).
|
|
92
|
+
- scanner roots narrowed to explicit book directories by default, with opt-in overrides via `SHOKO_BOOK_SCAN_DIRS`.
|
|
93
|
+
- metadata extraction wiring includes required `path_ops` / `file_probe`.
|
|
94
|
+
- terminal and menu styling normalize binary-encoded text safely for UTF-8 rendering.
|
|
95
|
+
- annotation editor session/controller event handling now enforces hash payloads; non-event return values (e.g. cursor timestamp floats) are ignored safely.
|
|
96
|
+
- [x] Completed fatal external-input hard-break semantics across runtime boundaries.
|
|
97
|
+
- added `FatalExternalInputError` hierarchy with typed subclasses (`MalformedBookInputError`, `MalformedMetadataInputError`, `MalformedDictionaryInputError`).
|
|
98
|
+
- top boundaries now terminate with exit code `2` on fatal external input (`CLI`, menu lifecycle, reader lifecycle).
|
|
99
|
+
- fatal logs use stable event IDs (`fatal.external_input.book|metadata|dictionary`).
|
|
100
|
+
- [x] Removed rescue-fallback defaults and hardened guardrails to enforce zero fallback.
|
|
101
|
+
- AST-based analyzer now detects literal defaults (`[]`, `{}`, `''`, `""`, booleans, symbols, numeric literals) and variable passthrough.
|
|
102
|
+
- added guardrails:
|
|
103
|
+
- `no_rescue_numeric_default_spec.rb`
|
|
104
|
+
- `no_swallowing_rescue_spec.rb`
|
|
105
|
+
- `no_noop_reraise_rescue_spec.rb`
|
|
106
|
+
- `no_mixed_symbol_string_key_reads_in_application_spec.rb`
|
|
107
|
+
- `no_cross_adapter_runtime_coupling_spec.rb`
|
|
108
|
+
- added deterministic report: `script/architecture/fallback_report.rb` (wired into `test:guardrails`).
|
|
109
|
+
- [x] Completed typed boundary migration for key menu/runtime flows.
|
|
110
|
+
- introduced typed models used across workflow boundaries:
|
|
111
|
+
- `MenuBook`
|
|
112
|
+
- `AnnotationSelection`
|
|
113
|
+
- `PendingJumpPayload`
|
|
114
|
+
- `DictionaryCatalogEntry`
|
|
115
|
+
- removed mixed symbol/string dual-key normalization from `application/**` (`x[:k] || x['k']`).
|
|
116
|
+
- [x] Removed cross-adapter runtime coupling in flagged paths.
|
|
117
|
+
- `DocumentLoaderAdapter` now depends on outbound `BookCachePipelineFactory` port.
|
|
118
|
+
- output terminal runtime config no longer depends on runtime-adapter null type directly.
|
|
119
|
+
- [x] Hard-deleted legacy command/fallback APIs.
|
|
120
|
+
- removed unused bookmark command factory methods (`remove_bookmark`, `toggle_bookmark`, `jump_to_bookmark`).
|
|
121
|
+
- removed cache-import compatibility wrapper error type (`CacheImportAdapter::ImportError`).
|
|
122
|
+
|
|
123
|
+
## Open Items
|
|
124
|
+
|
|
125
|
+
- [ ] Persist benchmark baselines and enforce CI threshold checks.
|
|
126
|
+
- [ ] Fixture lane is blocked locally by missing required books (see verification snapshot).
|
|
127
|
+
- [ ] Extend optional dependency hard-error semantics to remaining optional capability execution paths (not only sqlite).
|
|
128
|
+
|
|
129
|
+
## Verification Checklist
|
|
130
|
+
|
|
131
|
+
- [x] `bundle exec rspec spec/core/architecture spec/bootstrap/dependencies`
|
|
132
|
+
- [x] `bundle exec rake test:guardrails`
|
|
133
|
+
- [x] `bundle exec rake test:required`
|
|
134
|
+
- [x] `bundle exec rspec` (fixtures excluded by default tag filter)
|
|
135
|
+
- [ ] `bundle exec rake test:fixtures` (blocked locally)
|
|
136
|
+
|
|
137
|
+
## Verification Snapshot
|
|
138
|
+
|
|
139
|
+
- `bundle exec rspec spec/core/architecture spec/bootstrap/dependencies`:
|
|
140
|
+
- 101 examples, 0 failures.
|
|
141
|
+
- `bundle exec rake test:guardrails`:
|
|
142
|
+
- pass (`fallback_report` summary all zero).
|
|
143
|
+
- `bundle exec rake test:required`:
|
|
144
|
+
- pass for seeds `10101`, `20202`, `30303` (973 examples/seed, 0 failures).
|
|
145
|
+
- `bundle exec rspec`:
|
|
146
|
+
- 973 examples, 0 failures (with `requires_book_fixtures` excluded by default).
|
|
147
|
+
- `bundle exec rake test:fixtures`:
|
|
148
|
+
- blocked by missing files:
|
|
149
|
+
- `Persuasion (Jane Austen).mobi`
|
|
150
|
+
- `Pride Prejudice (Jane Austen).azw`
|
|
151
|
+
- `Emma (Jane Austen).azw3`
|
|
152
|
+
- `Pride And Prejudice (Austen Jane).rtf`
|
|
153
|
+
- Artifact sweeps (`lib/shoko`):
|
|
154
|
+
- `resolve_optional(`: `0`
|
|
155
|
+
- `rescue StandardError`: `0`
|
|
156
|
+
- `rescue Exception`: `0`
|
|
157
|
+
- bare `rescue =>`: `0`
|
|
158
|
+
- bare string raise (`raise '...'` / `raise "..."`): `0`
|
|
159
|
+
- duplicate `rescue ArgumentError, ArgumentError`: `0`
|
|
160
|
+
- duplicate/overlapping same-class rescue chains with unreachable fallback branches: `0`
|
|
161
|
+
- stale optional resolution ternary (`optional ? resolve : resolve`): `0`
|
|
162
|
+
- inline `... rescue ...` expressions: `0`
|
|
163
|
+
- `rescue NoMethodError` probing: `0`
|
|
164
|
+
- `respond_to?` / `public_send` / dynamic `send(`: `0`
|
|
165
|
+
- `fallback_report` zero-fallback summary:
|
|
166
|
+
- `fallback_literal_defaults`: `0`
|
|
167
|
+
- `numeric_rescue_defaults`: `0`
|
|
168
|
+
- `no_op_reraise_rescues`: `0`
|
|
169
|
+
- `fatal_input_swallow_rescues`: `0`
|
|
170
|
+
- `mixed_key_reads_application`: `0`
|
|
171
|
+
- legacy factory keys/usages (`document_service_factory|background_worker_factory`): `0`
|
|
172
|
+
- proc-type fallbacks (`is_a?(Proc)`): `0`
|
|
173
|
+
- implicit null runtime fallback expression (`|| ...NullRuntimeConfig.instance`): `0`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Adapters
|
|
5
|
+
# Base class for adapters in the hexagonal architecture.
|
|
6
|
+
# Adapters connect ports to external infrastructure (UI, databases, etc.)
|
|
7
|
+
# and should NOT extend Core's BaseService.
|
|
8
|
+
#
|
|
9
|
+
# This class provides a simple dependency injection pattern via constructor kwargs
|
|
10
|
+
# without the `resolve()` semantics of BaseService.
|
|
11
|
+
class BaseAdapter
|
|
12
|
+
# @param logger [Object, nil] Optional logger for debugging
|
|
13
|
+
def initialize(logger: nil)
|
|
14
|
+
@logger = logger
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
protected
|
|
18
|
+
|
|
19
|
+
attr_reader :logger
|
|
20
|
+
|
|
21
|
+
def log_debug(message, **context)
|
|
22
|
+
logger&.debug(message, **context)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def log_error(message, **context)
|
|
26
|
+
logger&.error(message, **context)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|