shoko 0.1.4 → 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/Gemfile +1 -0
- data/README.md +100 -1
- data/Rakefile +80 -1
- data/bin/shoko +10 -4
- data/bin/start +10 -4
- data/docs/architecture/hexagonal-adherence-checklist.md +173 -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 -44
- 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 +132 -185
- data/lib/shoko/adapters/book_sources/download_service.rb +72 -67
- data/lib/shoko/adapters/book_sources/epub/epub_importer.rb +266 -0
- data/lib/shoko/adapters/book_sources/epub/epub_resource_loader.rb +138 -128
- 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 +136 -125
- data/lib/shoko/adapters/book_sources/kindle/kindle_importer.rb +422 -0
- data/lib/shoko/adapters/book_sources/library_scanner.rb +137 -101
- data/lib/shoko/adapters/book_sources/metadata_reader_adapter.rb +63 -12
- 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 +266 -286
- data/lib/shoko/adapters/input/commands.rb +74 -46
- 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 +21 -16
- data/lib/shoko/adapters/input/key_classifier_adapter.rb +44 -46
- data/lib/shoko/adapters/input/reader_input_controller.rb +342 -0
- data/lib/shoko/adapters/input/validators/file_path_validator.rb +69 -62
- data/lib/shoko/adapters/input/validators/terminal_size_validator.rb +64 -59
- data/lib/shoko/adapters/monitoring/logger_adapter.rb +50 -8
- data/lib/shoko/adapters/monitoring/perf_tracer.rb +145 -138
- data/lib/shoko/adapters/monitoring/performance_monitor.rb +98 -96
- data/lib/shoko/adapters/output/clipboard/clipboard_service.rb +3 -3
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/image_builder.rb +135 -135
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/table_renderer.rb +304 -300
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/text_wrapper.rb +172 -108
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/tokenizer.rb +210 -71
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler.rb +270 -215
- data/lib/shoko/adapters/output/formatting/formatting_service/plain_lines_builder.rb +49 -41
- data/lib/shoko/adapters/output/formatting/formatting_service.rb +276 -253
- data/lib/shoko/adapters/output/formatting/wrapped_lines_provider_adapter.rb +43 -0
- data/lib/shoko/adapters/output/formatting/wrapping_service.rb +75 -34
- data/lib/shoko/adapters/output/instrumentation_service.rb +66 -49
- data/lib/shoko/adapters/output/kitty/display_capabilities.rb +2 -2
- 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 -231
- 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 +41 -54
- data/lib/shoko/adapters/output/terminal/buffer.rb +348 -259
- 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 +364 -362
- data/lib/shoko/adapters/output/terminal/input.rb +195 -190
- data/lib/shoko/adapters/output/terminal/null_runtime_config.rb +23 -0
- data/lib/shoko/adapters/output/terminal/output.rb +42 -97
- data/lib/shoko/adapters/output/terminal/terminal.rb +199 -183
- data/lib/shoko/adapters/output/terminal/terminal_sanitizer.rb +7 -232
- data/lib/shoko/adapters/output/terminal/terminal_service.rb +144 -143
- data/lib/shoko/adapters/output/terminal/terminal_session_adapter.rb +32 -0
- data/lib/shoko/adapters/output/terminal/text_metrics.rb +4 -262
- data/lib/shoko/adapters/output/terminal/text_metrics_port_adapter.rb +41 -0
- data/lib/shoko/adapters/output/terminal/text_sanitizer_adapter.rb +13 -9
- data/lib/shoko/adapters/output/terminal_capabilities_adapter.rb +2 -2
- 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 -46
- 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 +119 -601
- 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 +52 -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 +18 -13
- data/lib/shoko/adapters/storage/cache_manager_adapter.rb +17 -15
- 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 +15 -5
- data/lib/shoko/adapters/storage/config_paths.rb +22 -20
- data/lib/shoko/adapters/storage/config_storage_adapter.rb +14 -8
- data/lib/shoko/adapters/storage/data_cleanup_adapter.rb +83 -0
- data/lib/shoko/adapters/storage/dictionary_availability_adapter.rb +13 -23
- data/lib/shoko/adapters/storage/dictionary_catalog_service.rb +13 -5
- data/lib/shoko/adapters/storage/dictionary_storage_adapter.rb +84 -0
- data/lib/shoko/adapters/storage/epub_cache.rb +133 -150
- data/lib/shoko/adapters/storage/file_probe_adapter.rb +26 -0
- data/lib/shoko/adapters/storage/file_writer_service.rb +27 -27
- data/lib/shoko/adapters/storage/json_cache_store/chapters.rb +104 -102
- data/lib/shoko/adapters/storage/json_cache_store/layouts.rb +52 -50
- 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 -137
- data/lib/shoko/adapters/storage/lazy_file_string.rb +39 -50
- data/lib/shoko/adapters/storage/pagination_cache.rb +107 -96
- data/lib/shoko/adapters/storage/path_ops_adapter.rb +30 -0
- data/lib/shoko/adapters/storage/recent_files.rb +98 -62
- data/lib/shoko/adapters/storage/recent_files_repository.rb +2 -2
- data/lib/shoko/adapters/storage/repositories/annotation_repository.rb +149 -162
- data/lib/shoko/adapters/storage/repositories/base_repository.rb +70 -58
- data/lib/shoko/adapters/storage/repositories/bookmark_repository.rb +113 -109
- data/lib/shoko/adapters/storage/repositories/cached_library_repository.rb +116 -114
- data/lib/shoko/adapters/storage/repositories/progress_repository.rb +139 -152
- data/lib/shoko/adapters/storage/repositories/storage/annotation_file_store.rb +80 -83
- data/lib/shoko/adapters/storage/repositories/storage/base_file_store.rb +24 -18
- data/lib/shoko/adapters/storage/repositories/storage/bookmark_file_store.rb +75 -67
- data/lib/shoko/adapters/storage/repositories/storage/file_store_utils.rb +13 -9
- data/lib/shoko/adapters/storage/repositories/storage/progress_file_store.rb +31 -25
- data/lib/shoko/adapters/storage/sqlite_dictionary_adapter.rb +29 -35
- 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 +1 -1
- 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/{output → ui}/rendering/models/rendering_context.rb +12 -8
- 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 +45 -63
- data/lib/shoko/{core → application}/services/pagination/page_info_calculator.rb +36 -19
- data/lib/shoko/{core → application}/services/pagination/pagination_cache_preloader.rb +64 -36
- data/lib/shoko/{core → application}/services/pagination/pagination_coordinator.rb +89 -41
- data/lib/shoko/{core → application}/services/pagination/pagination_orchestrator.rb +112 -45
- 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 +77 -37
- data/lib/shoko/application/use_cases/catalog_service.rb +101 -81
- data/lib/shoko/application/use_cases/command_bus.rb +170 -0
- data/lib/shoko/application/use_cases/commands/base_command.rb +125 -130
- data/lib/shoko/application/use_cases/commands/bookmark_commands.rb +70 -82
- 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 +154 -124
- 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 +203 -267
- 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 +22 -5
- data/lib/shoko/core/events/domain_event_bus.rb +10 -13
- 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/menu_book.rb +36 -0
- data/lib/shoko/core/models/pending_jump_payload.rb +58 -0
- data/lib/shoko/core/models/reading_progress.rb +30 -0
- data/lib/shoko/core/models/selection_anchor.rb +1 -1
- 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 +31 -43
- data/lib/shoko/core/services/coordinate_service.rb +2 -27
- data/lib/shoko/core/services/default_display_capabilities.rb +2 -2
- data/lib/shoko/core/services/default_layout_metrics.rb +2 -2
- data/lib/shoko/core/services/default_terminal_capabilities.rb +2 -2
- data/lib/shoko/core/services/default_text_metrics.rb +2 -2
- data/lib/shoko/core/services/dictionary_service.rb +31 -19
- 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 +2 -2
- data/lib/shoko/core/services/layout_service.rb +36 -4
- data/lib/shoko/core/services/null_instrumentation.rb +2 -2
- data/lib/shoko/core/services/null_logger.rb +2 -2
- data/lib/shoko/core/services/page_calculator_service.rb +274 -57
- data/lib/shoko/core/services/pagination/internal/absolute_page_map_builder.rb +26 -2
- data/lib/shoko/core/services/pagination/internal/chapter_cache.rb +1 -1
- data/lib/shoko/core/services/pagination/internal/dynamic_page_map_builder.rb +14 -12
- data/lib/shoko/core/services/pagination/internal/layout_metrics_calculator.rb +19 -28
- data/lib/shoko/core/services/pagination/internal/page_hydrator.rb +38 -32
- data/lib/shoko/core/services/pagination/internal/pagination_workflow.rb +47 -31
- data/lib/shoko/core/services/selection_service.rb +3 -16
- 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 +48 -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 +25 -5
- 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/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 -270
- 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 +473 -229
- data/lib/shoko/adapters/book_sources/epub/parsers/html_processor.rb +0 -146
- data/lib/shoko/adapters/book_sources/epub/parsers/metadata_extractor.rb +0 -54
- 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 -104
- 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 -111
- data/lib/shoko/adapters/book_sources/epub/parsers/rexml_safe_parser.rb +0 -50
- data/lib/shoko/adapters/book_sources/epub/parsers/xhtml_content_parser.rb +0 -784
- data/lib/shoko/adapters/book_sources/epub/parsers/xml_text_normalizer.rb +0 -41
- data/lib/shoko/adapters/book_sources/epub_document.rb +0 -266
- data/lib/shoko/adapters/book_sources/epub_finder/directory_scanner.rb +0 -135
- data/lib/shoko/adapters/book_sources/epub_finder/scanner_context.rb +0 -28
- data/lib/shoko/adapters/book_sources/epub_importer.rb +0 -278
- data/lib/shoko/adapters/input/command_bridge.rb +0 -81
- data/lib/shoko/adapters/input/input_controller.rb +0 -330
- data/lib/shoko/adapters/monitoring/logger.rb +0 -150
- data/lib/shoko/adapters/output/render_registry.rb +0 -40
- data/lib/shoko/adapters/output/ui/builders/page_setup_builder.rb +0 -47
- data/lib/shoko/adapters/output/ui/component_factory.rb +0 -84
- 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 -87
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay_component.rb +0 -407
- data/lib/shoko/adapters/output/ui/components/annotations_overlay/list_renderer.rb +0 -144
- data/lib/shoko/adapters/output/ui/components/annotations_overlay_component.rb +0 -195
- data/lib/shoko/adapters/output/ui/components/base_component.rb +0 -114
- data/lib/shoko/adapters/output/ui/components/content_component.rb +0 -69
- data/lib/shoko/adapters/output/ui/components/dictionary/entry_formatter.rb +0 -228
- data/lib/shoko/adapters/output/ui/components/dictionary_panel_component.rb +0 -266
- data/lib/shoko/adapters/output/ui/components/dictionary_popup_component.rb +0 -251
- data/lib/shoko/adapters/output/ui/components/enhanced_popup_menu.rb +0 -203
- data/lib/shoko/adapters/output/ui/components/footer_component.rb +0 -122
- 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/horizontal_three.rb +0 -90
- data/lib/shoko/adapters/output/ui/components/layouts/vertical.rb +0 -73
- data/lib/shoko/adapters/output/ui/components/main_menu_component.rb +0 -106
- data/lib/shoko/adapters/output/ui/components/reading/base_view_renderer.rb +0 -250
- data/lib/shoko/adapters/output/ui/components/reading/config_helpers.rb +0 -50
- 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 -165
- data/lib/shoko/adapters/output/ui/components/reading/kitty_image_line_renderer.rb +0 -274
- 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 -95
- 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 -219
- data/lib/shoko/adapters/output/ui/components/reading/view_renderer_factory.rb +0 -29
- 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 -103
- data/lib/shoko/adapters/output/ui/components/screens/annotation_edit_screen_component.rb +0 -179
- data/lib/shoko/adapters/output/ui/components/screens/annotation_editor_screen_component.rb +0 -239
- data/lib/shoko/adapters/output/ui/components/screens/annotation_rendering_helpers.rb +0 -466
- data/lib/shoko/adapters/output/ui/components/screens/annotations_screen_component.rb +0 -201
- 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 -332
- data/lib/shoko/adapters/output/ui/components/screens/dictionary_settings_screen_component.rb +0 -457
- data/lib/shoko/adapters/output/ui/components/screens/download_books_screen_component.rb +0 -357
- data/lib/shoko/adapters/output/ui/components/screens/library_screen_component.rb +0 -233
- data/lib/shoko/adapters/output/ui/components/screens/loading_overlay_component.rb +0 -58
- data/lib/shoko/adapters/output/ui/components/screens/menu_screen_component.rb +0 -115
- data/lib/shoko/adapters/output/ui/components/screens/settings_screen_component.rb +0 -321
- data/lib/shoko/adapters/output/ui/components/sidebar/annotations_tab_renderer.rb +0 -169
- data/lib/shoko/adapters/output/ui/components/sidebar/bookmarks_tab_renderer.rb +0 -156
- data/lib/shoko/adapters/output/ui/components/sidebar/tab_header_component.rb +0 -167
- data/lib/shoko/adapters/output/ui/components/sidebar/toc_tab_renderer.rb +0 -122
- data/lib/shoko/adapters/output/ui/components/sidebar/toc_tab_support.rb +0 -1603
- data/lib/shoko/adapters/output/ui/components/sidebar_panel_component.rb +0 -220
- data/lib/shoko/adapters/output/ui/components/surface.rb +0 -88
- data/lib/shoko/adapters/output/ui/components/tooltip_overlay_component.rb +0 -250
- data/lib/shoko/adapters/output/ui/components/ui/annotation_list_input.rb +0 -98
- data/lib/shoko/adapters/output/ui/components/ui/annotation_markup.rb +0 -452
- data/lib/shoko/adapters/output/ui/components/ui/box_drawer.rb +0 -33
- data/lib/shoko/adapters/output/ui/components/ui/cursor_blink.rb +0 -46
- 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 -88
- 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 -104
- data/lib/shoko/adapters/output/ui/rendering/frame_coordinator.rb +0 -44
- data/lib/shoko/adapters/output/ui/rendering/reader_render_coordinator.rb +0 -255
- data/lib/shoko/adapters/output/ui/rendering/render_pipeline.rb +0 -87
- data/lib/shoko/adapters/output/ui/rendering_factory_adapter.rb +0 -34
- data/lib/shoko/adapters/storage/repositories/config_repository.rb +0 -266
- data/lib/shoko/application/adapters/command_port_adapter.rb +0 -133
- data/lib/shoko/application/adapters/config_reader_adapter.rb +0 -80
- data/lib/shoko/application/adapters/layout_metrics_adapter.rb +0 -66
- data/lib/shoko/application/adapters/menu_state_reader_adapter.rb +0 -204
- data/lib/shoko/application/adapters/menu_state_writer_adapter.rb +0 -134
- data/lib/shoko/application/adapters/notification_writer_adapter.rb +0 -37
- data/lib/shoko/application/adapters/progress_state_reader_adapter.rb +0 -35
- data/lib/shoko/application/adapters/reader_state_reader_adapter.rb +0 -150
- data/lib/shoko/application/adapters/render_state_writer_adapter.rb +0 -51
- data/lib/shoko/application/adapters/rendered_content_reader_adapter.rb +0 -27
- data/lib/shoko/application/adapters/sidebar_state_reader_adapter.rb +0 -65
- data/lib/shoko/application/adapters/state_writer_adapter.rb +0 -98
- data/lib/shoko/application/adapters/ui_state_reader_adapter.rb +0 -39
- data/lib/shoko/application/adapters/wrapped_lines_provider_adapter.rb +0 -35
- data/lib/shoko/application/annotation_editor_overlay_session.rb +0 -158
- data/lib/shoko/application/cli.rb +0 -134
- data/lib/shoko/application/cli_progress_renderer.rb +0 -151
- data/lib/shoko/application/controllers/annotation_overlay_controller.rb +0 -259
- data/lib/shoko/application/controllers/dictionary_controller.rb +0 -437
- data/lib/shoko/application/controllers/document_path_resolver.rb +0 -69
- data/lib/shoko/application/controllers/menu/input_controller.rb +0 -218
- data/lib/shoko/application/controllers/menu/state_controller.rb +0 -777
- data/lib/shoko/application/controllers/menu_controller.rb +0 -668
- data/lib/shoko/application/controllers/mouseable_reader.rb +0 -221
- data/lib/shoko/application/controllers/reader_controller.rb +0 -584
- data/lib/shoko/application/controllers/selection_mouse_handler.rb +0 -172
- data/lib/shoko/application/controllers/sidebar_controller.rb +0 -491
- data/lib/shoko/application/controllers/sidebar_mouse_handler.rb +0 -184
- data/lib/shoko/application/controllers/state_controller.rb +0 -444
- data/lib/shoko/application/controllers/ui_controller.rb +0 -443
- data/lib/shoko/application/dependency_container.rb +0 -943
- data/lib/shoko/application/infrastructure/event_bus.rb +0 -82
- data/lib/shoko/application/infrastructure/observer_state_store.rb +0 -139
- data/lib/shoko/application/infrastructure/state_store.rb +0 -584
- data/lib/shoko/application/main_menu/menu_progress_presenter.rb +0 -83
- data/lib/shoko/application/reader_lifecycle.rb +0 -58
- data/lib/shoko/application/reader_startup_orchestrator.rb +0 -74
- data/lib/shoko/application/selectors/config_selectors.rb +0 -78
- data/lib/shoko/application/selectors/menu_selectors.rb +0 -82
- data/lib/shoko/application/selectors/reader_selectors.rb +0 -183
- 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_config_action.rb +0 -26
- data/lib/shoko/application/state/actions/update_field_helpers.rb +0 -26
- data/lib/shoko/application/state/actions/update_menu_action.rb +0 -17
- data/lib/shoko/application/state/actions/update_message_action.rb +0 -22
- data/lib/shoko/application/state/actions/update_page_action.rb +0 -14
- data/lib/shoko/application/state/actions/update_pagination_state_action.rb +0 -19
- data/lib/shoko/application/state/actions/update_reader_meta_action.rb +0 -19
- data/lib/shoko/application/state/actions/update_rendered_lines_action.rb +0 -30
- data/lib/shoko/application/state/actions/update_selection_action.rb +0 -24
- data/lib/shoko/application/state/actions/update_selections_action.rb +0 -14
- data/lib/shoko/application/state/actions/update_sidebar_action.rb +0 -38
- data/lib/shoko/application/state/actions/update_state_action.rb +0 -72
- data/lib/shoko/application/state/actions/update_ui_loading_action.rb +0 -19
- 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 -165
- data/lib/shoko/application/use_cases/commands/application_commands.rb +0 -181
- data/lib/shoko/application/use_cases/commands/conditional_navigation_commands.rb +0 -69
- data/lib/shoko/application/use_cases/commands/menu_commands.rb +0 -266
- data/lib/shoko/application/use_cases/commands/reader_commands.rb +0 -39
- data/lib/shoko/application/use_cases/commands/sidebar_commands.rb +0 -56
- data/lib/shoko/core/ports/annotation_repository.rb +0 -94
- data/lib/shoko/core/ports/async_executor.rb +0 -24
- data/lib/shoko/core/ports/bookmark_repository.rb +0 -77
- data/lib/shoko/core/ports/cache_availability.rb +0 -18
- data/lib/shoko/core/ports/cache_manager.rb +0 -26
- data/lib/shoko/core/ports/cache_pointer_resolver.rb +0 -27
- data/lib/shoko/core/ports/command_port.rb +0 -55
- data/lib/shoko/core/ports/config_reader.rb +0 -109
- data/lib/shoko/core/ports/config_storage.rb +0 -61
- data/lib/shoko/core/ports/dictionary_availability.rb +0 -41
- data/lib/shoko/core/ports/dictionary_repository.rb +0 -69
- data/lib/shoko/core/ports/display_capabilities.rb +0 -18
- data/lib/shoko/core/ports/input_system_factory.rb +0 -36
- data/lib/shoko/core/ports/instrumentation.rb +0 -31
- data/lib/shoko/core/ports/key_classifier.rb +0 -107
- data/lib/shoko/core/ports/layout_metrics.rb +0 -78
- data/lib/shoko/core/ports/logging.rb +0 -65
- data/lib/shoko/core/ports/menu_state_reader.rb +0 -291
- data/lib/shoko/core/ports/menu_state_writer.rb +0 -136
- data/lib/shoko/core/ports/metadata_reader.rb +0 -20
- data/lib/shoko/core/ports/notification_writer.rb +0 -40
- data/lib/shoko/core/ports/progress_state_reader.rb +0 -47
- data/lib/shoko/core/ports/reader_state_reader.rb +0 -207
- data/lib/shoko/core/ports/recent_files_repository.rb +0 -25
- data/lib/shoko/core/ports/render_state_writer.rb +0 -31
- data/lib/shoko/core/ports/rendered_content_reader.rb +0 -32
- data/lib/shoko/core/ports/rendering_factory.rb +0 -38
- data/lib/shoko/core/ports/sidebar_state_reader.rb +0 -88
- data/lib/shoko/core/ports/state_writer.rb +0 -152
- data/lib/shoko/core/ports/terminal_capabilities.rb +0 -33
- data/lib/shoko/core/ports/text_metrics.rb +0 -19
- data/lib/shoko/core/ports/text_sanitizer.rb +0 -22
- data/lib/shoko/core/ports/ui_component_factory.rb +0 -61
- data/lib/shoko/core/ports/ui_state_reader.rb +0 -53
- data/lib/shoko/core/ports/wrapped_lines_provider.rb +0 -23
- data/lib/shoko/core/services/bookmark_service.rb +0 -292
- data/lib/shoko/core/services/config_bridge.rb +0 -27
- data/lib/shoko/core/services/navigation/absolute_change_applier.rb +0 -96
- data/lib/shoko/core/services/navigation/absolute_layout.rb +0 -131
- data/lib/shoko/core/services/navigation/absolute_strategy.rb +0 -179
- data/lib/shoko/core/services/navigation/context_builder.rb +0 -77
- data/lib/shoko/core/services/navigation/context_helpers.rb +0 -78
- data/lib/shoko/core/services/navigation/dynamic_change_applier.rb +0 -47
- data/lib/shoko/core/services/navigation/dynamic_strategy.rb +0 -51
- data/lib/shoko/core/services/navigation/image_offset_snapper.rb +0 -169
- data/lib/shoko/core/services/navigation/nav_context.rb +0 -27
- data/lib/shoko/core/services/navigation/state_updater.rb +0 -32
- data/lib/shoko/core/services/navigation/strategy_factory.rb +0 -20
- data/lib/shoko/core/services/navigation_service.rb +0 -161
- 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/Gemfile
CHANGED
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/bin/shoko
CHANGED
|
@@ -7,13 +7,19 @@ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
9
|
# Only activate Bundler when explicitly running under it (e.g. bundle exec).
|
|
10
|
-
if ENV['BUNDLE_GEMFILE'] || ENV['BUNDLE_BIN_PATH']
|
|
11
|
-
require 'bundler/setup'
|
|
12
|
-
end
|
|
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
|
@@ -7,13 +7,19 @@ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
|
7
7
|
|
|
8
8
|
begin
|
|
9
9
|
# Only activate Bundler when explicitly running under it (e.g. bundle exec).
|
|
10
|
-
if ENV['BUNDLE_GEMFILE'] || ENV['BUNDLE_BIN_PATH']
|
|
11
|
-
require 'bundler/setup'
|
|
12
|
-
end
|
|
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`
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
# Public API:
|
|
7
7
|
# Zip::File.open(path) { |zip| ... }
|
|
8
|
+
# zip.entries -> Array<Zip::Entry>
|
|
8
9
|
# zip.read(entry_path) -> String (binary)
|
|
9
10
|
# zip.find_entry(entry_path) -> entry or nil
|
|
10
11
|
# zip.close ; zip.closed?
|
|
@@ -269,21 +270,9 @@ module Zip
|
|
|
269
270
|
attr_reader :max_entry_compressed, :max_entry_uncompressed, :max_total_uncompressed
|
|
270
271
|
|
|
271
272
|
def initialize(max_entry_uncompressed:, max_entry_compressed:, max_total_uncompressed:)
|
|
272
|
-
@max_entry_uncompressed = LimitResolver.resolve(
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
default: Limits::MAX_ENTRY_UNCOMPRESSED
|
|
276
|
-
)
|
|
277
|
-
@max_entry_compressed = LimitResolver.resolve(
|
|
278
|
-
max_entry_compressed,
|
|
279
|
-
env: 'SHOKO_ZIP_MAX_ENTRY_COMPRESSED_BYTES',
|
|
280
|
-
default: Limits::MAX_ENTRY_COMPRESSED
|
|
281
|
-
)
|
|
282
|
-
@max_total_uncompressed = LimitResolver.resolve(
|
|
283
|
-
max_total_uncompressed,
|
|
284
|
-
env: 'SHOKO_ZIP_MAX_TOTAL_BYTES',
|
|
285
|
-
default: Limits::MAX_TOTAL_UNCOMPRESSED
|
|
286
|
-
)
|
|
273
|
+
@max_entry_uncompressed = LimitResolver.resolve(max_entry_uncompressed, default: Limits::MAX_ENTRY_UNCOMPRESSED)
|
|
274
|
+
@max_entry_compressed = LimitResolver.resolve(max_entry_compressed, default: Limits::MAX_ENTRY_COMPRESSED)
|
|
275
|
+
@max_total_uncompressed = LimitResolver.resolve(max_total_uncompressed, default: Limits::MAX_TOTAL_UNCOMPRESSED)
|
|
287
276
|
@total_uncompressed_bytes = 0
|
|
288
277
|
end
|
|
289
278
|
|
|
@@ -351,34 +340,28 @@ module Zip
|
|
|
351
340
|
end
|
|
352
341
|
end
|
|
353
342
|
|
|
354
|
-
# Resolves limit values from arguments
|
|
343
|
+
# Resolves limit values from explicit arguments or defaults.
|
|
355
344
|
class LimitResolver
|
|
356
|
-
def self.resolve(value,
|
|
357
|
-
new(value,
|
|
345
|
+
def self.resolve(value, default:)
|
|
346
|
+
new(value, default).resolve
|
|
358
347
|
end
|
|
359
348
|
|
|
360
|
-
def initialize(value,
|
|
349
|
+
def initialize(value, default)
|
|
361
350
|
@value = value
|
|
362
|
-
@env = env
|
|
363
351
|
@default = default
|
|
364
352
|
end
|
|
365
353
|
|
|
366
354
|
def resolve
|
|
367
|
-
|
|
368
|
-
parsed = parse_integer(candidate)
|
|
355
|
+
parsed = parse_integer(@value)
|
|
369
356
|
valid_positive_or_default(parsed)
|
|
370
357
|
end
|
|
371
358
|
|
|
372
359
|
private
|
|
373
360
|
|
|
374
|
-
def value_or_env
|
|
375
|
-
@value || ENV.fetch(@env, nil)
|
|
376
|
-
end
|
|
377
|
-
|
|
378
361
|
def parse_integer(candidate)
|
|
362
|
+
return nil if candidate.nil?
|
|
363
|
+
|
|
379
364
|
Integer(candidate)
|
|
380
|
-
rescue StandardError
|
|
381
|
-
nil
|
|
382
365
|
end
|
|
383
366
|
|
|
384
367
|
def valid_positive_or_default(parsed)
|
|
@@ -479,8 +462,8 @@ module Zip
|
|
|
479
462
|
|
|
480
463
|
def close_inflater(inflater)
|
|
481
464
|
inflater&.close
|
|
482
|
-
rescue
|
|
483
|
-
|
|
465
|
+
rescue Shoko::Error
|
|
466
|
+
raise
|
|
484
467
|
end
|
|
485
468
|
|
|
486
469
|
def decompress_all(inflater, entry, remaining_bytes)
|
|
@@ -657,7 +640,7 @@ module Zip
|
|
|
657
640
|
|
|
658
641
|
def self.close_safely(zip_file)
|
|
659
642
|
zip_file.close
|
|
660
|
-
rescue
|
|
643
|
+
rescue Shoko::Error
|
|
661
644
|
# ignore close errors
|
|
662
645
|
end
|
|
663
646
|
|
|
@@ -674,7 +657,7 @@ module Zip
|
|
|
674
657
|
@io = @state.io
|
|
675
658
|
@entries = @state.entries
|
|
676
659
|
build_index!
|
|
677
|
-
rescue
|
|
660
|
+
rescue Shoko::Error
|
|
678
661
|
close
|
|
679
662
|
raise
|
|
680
663
|
end
|
|
@@ -692,6 +675,10 @@ module Zip
|
|
|
692
675
|
@entries[normalized_path]
|
|
693
676
|
end
|
|
694
677
|
|
|
678
|
+
def entries
|
|
679
|
+
@entries.values
|
|
680
|
+
end
|
|
681
|
+
|
|
695
682
|
def read(path)
|
|
696
683
|
entry = find_entry_or_raise(path)
|
|
697
684
|
validate_entry_readable(entry)
|
|
@@ -730,3 +717,30 @@ module Zip
|
|
|
730
717
|
end
|
|
731
718
|
end
|
|
732
719
|
end
|
|
720
|
+
|
|
721
|
+
module Shoko
|
|
722
|
+
module Adapters
|
|
723
|
+
module BookSources
|
|
724
|
+
module Archive
|
|
725
|
+
# Adapter-owned archive facade used by book-source importers/loaders.
|
|
726
|
+
module ZipReader
|
|
727
|
+
module_function
|
|
728
|
+
|
|
729
|
+
def open(path, runtime_config: nil, &block)
|
|
730
|
+
Zip::File.open(path, **zip_limit_kwargs(runtime_config), &block)
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
def zip_limit_kwargs(runtime_config)
|
|
734
|
+
return {} unless runtime_config
|
|
735
|
+
|
|
736
|
+
{
|
|
737
|
+
max_entry_uncompressed_bytes: runtime_config.zip_max_entry_uncompressed_bytes,
|
|
738
|
+
max_entry_compressed_bytes: runtime_config.zip_max_entry_compressed_bytes,
|
|
739
|
+
max_total_uncompressed_bytes: runtime_config.zip_max_total_uncompressed_bytes
|
|
740
|
+
}
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
end
|