railmux 0.3.6.dev3__tar.gz → 0.3.6.dev4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. {railmux-0.3.6.dev3/src/railmux.egg-info → railmux-0.3.6.dev4}/PKG-INFO +1 -1
  2. railmux-0.3.6.dev4/src/railmux/__init__.py +1 -0
  3. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/fast_display_server.py +33 -16
  4. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4/src/railmux.egg-info}/PKG-INFO +1 -1
  5. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_fast_full_window.py +48 -18
  6. railmux-0.3.6.dev3/src/railmux/__init__.py +0 -1
  7. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/LICENSE +0 -0
  8. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/MANIFEST.in +0 -0
  9. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/README.md +0 -0
  10. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/pyproject.toml +0 -0
  11. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/setup.cfg +0 -0
  12. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/__main__.py +0 -0
  13. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/atomic_file.py +0 -0
  14. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/background_index.py +0 -0
  15. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/cli.py +0 -0
  16. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/codex_index.py +0 -0
  17. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/config.py +0 -0
  18. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/config_cli.py +0 -0
  19. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/diagnostics.py +0 -0
  20. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/discovery.py +0 -0
  21. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/display_transport.py +0 -0
  22. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/fast_display_client.py +0 -0
  23. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/fast_display_history.py +0 -0
  24. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/fast_display_input.py +0 -0
  25. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/fast_display_protocol.py +0 -0
  26. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/favorites.py +0 -0
  27. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/fuzzy.py +0 -0
  28. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/help_workspace.py +0 -0
  29. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/launcher.py +0 -0
  30. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/legacy_sessions.py +0 -0
  31. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/local_clipboard.py +0 -0
  32. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/local_open.py +0 -0
  33. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/models.py +0 -0
  34. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/modes.py +0 -0
  35. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/mouse_manager.py +0 -0
  36. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/orphan_marker.py +0 -0
  37. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/pane_surface.py +0 -0
  38. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/path_codec.py +0 -0
  39. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/remote_config.py +0 -0
  40. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/renames.py +0 -0
  41. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/restart_state.py +0 -0
  42. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/runtime_config.py +0 -0
  43. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/scroll_agent.py +0 -0
  44. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/scroll_manager.py +0 -0
  45. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/selection_isolation.py +0 -0
  46. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/self_update.py +0 -0
  47. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/session_cache.py +0 -0
  48. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/session_index.py +0 -0
  49. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/session_lease.py +0 -0
  50. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/setting_contracts.py +0 -0
  51. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/settings.py +0 -0
  52. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ssh_args.py +0 -0
  53. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ssh_compat.py +0 -0
  54. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ssh_display_diagnostics.py +0 -0
  55. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ssh_doctor.py +0 -0
  56. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/system_deps.py +0 -0
  57. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/terminal_status.py +0 -0
  58. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/tmux_binding_manager.py +0 -0
  59. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/tmux_ctl.py +0 -0
  60. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/tmux_health.py +0 -0
  61. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/tmux_server.py +0 -0
  62. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/tool_panes.py +0 -0
  63. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/transcript.py +0 -0
  64. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/__init__.py +0 -0
  65. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/_widgets.py +0 -0
  66. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/app.py +0 -0
  67. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/keymap.py +0 -0
  68. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/modals.py +0 -0
  69. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/projects_pane.py +0 -0
  70. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/running_pane.py +0 -0
  71. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/sessions_pane.py +0 -0
  72. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/sidebar.py +0 -0
  73. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/statusbar.py +0 -0
  74. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux/ui/workspace.py +0 -0
  75. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux.egg-info/SOURCES.txt +0 -0
  76. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux.egg-info/dependency_links.txt +0 -0
  77. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux.egg-info/entry_points.txt +0 -0
  78. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux.egg-info/requires.txt +0 -0
  79. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/src/railmux.egg-info/top_level.txt +0 -0
  80. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_agent_workspace.py +0 -0
  81. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_atomic_file.py +0 -0
  82. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_background_index.py +0 -0
  83. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_cli.py +0 -0
  84. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_codex_delete.py +0 -0
  85. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_codex_index.py +0 -0
  86. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_codex_lineage.py +0 -0
  87. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_codex_transcript.py +0 -0
  88. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_config.py +0 -0
  89. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_config_cli.py +0 -0
  90. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_denested_transport_benchmark.py +0 -0
  91. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_diagnostics.py +0 -0
  92. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_discovery.py +0 -0
  93. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_display_transport.py +0 -0
  94. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_focus_highlight.py +0 -0
  95. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_fullscreen_binding.py +0 -0
  96. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_fuzzy.py +0 -0
  97. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_help_agent.py +0 -0
  98. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_help_workspace.py +0 -0
  99. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_history_cleanup.py +0 -0
  100. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_keymap.py +0 -0
  101. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_launcher.py +0 -0
  102. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_layout_profile.py +0 -0
  103. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_legacy_sessions.py +0 -0
  104. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_local_clipboard.py +0 -0
  105. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_local_open.py +0 -0
  106. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_modals.py +0 -0
  107. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_mode_selection.py +0 -0
  108. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_modes.py +0 -0
  109. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_mouse_manager.py +0 -0
  110. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_new_project.py +0 -0
  111. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_options.py +0 -0
  112. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_orphan_recovery.py +0 -0
  113. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_pane_surface.py +0 -0
  114. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_path_codec.py +0 -0
  115. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_projects_pane.py +0 -0
  116. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_release_notes.py +0 -0
  117. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_release_workflow.py +0 -0
  118. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_remote_config.py +0 -0
  119. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_renames.py +0 -0
  120. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_restart_state.py +0 -0
  121. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_running_pane.py +0 -0
  122. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_running_sort.py +0 -0
  123. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_runtime_config.py +0 -0
  124. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_scroll_agent.py +0 -0
  125. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_scroll_manager.py +0 -0
  126. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_selection_isolation.py +0 -0
  127. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_self_update.py +0 -0
  128. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_session_cache.py +0 -0
  129. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_session_index.py +0 -0
  130. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_session_lease.py +0 -0
  131. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_sessions_pane.py +0 -0
  132. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_setting_contracts.py +0 -0
  133. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_settings.py +0 -0
  134. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_sidebar.py +0 -0
  135. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_soft_quit.py +0 -0
  136. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_ssh_args.py +0 -0
  137. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_ssh_compat.py +0 -0
  138. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_ssh_display_benchmark.py +0 -0
  139. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_ssh_display_diagnostics.py +0 -0
  140. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_ssh_doctor.py +0 -0
  141. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_status.py +0 -0
  142. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_statusbar.py +0 -0
  143. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_system_deps.py +0 -0
  144. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_terminal_size.py +0 -0
  145. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_terminal_status.py +0 -0
  146. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_termux_local_touch.py +0 -0
  147. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tmux_binding_manager.py +0 -0
  148. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tmux_ctl.py +0 -0
  149. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tmux_health.py +0 -0
  150. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tmux_integration.py +0 -0
  151. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tmux_server.py +0 -0
  152. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tmux_status.py +0 -0
  153. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_tool_panes.py +0 -0
  154. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_transcript.py +0 -0
  155. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_utf8_state.py +0 -0
  156. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_web_demo_recorder.py +0 -0
  157. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_wheel_smoke.py +0 -0
  158. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_widgets.py +0 -0
  159. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tests/test_yolo_prompt.py +0 -0
  160. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tools/denested_transport_benchmark.py +0 -0
  161. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tools/release_notes.py +0 -0
  162. {railmux-0.3.6.dev3 → railmux-0.3.6.dev4}/tools/wheel_smoke.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: railmux
3
- Version: 0.3.6.dev3
3
+ Version: 0.3.6.dev4
4
4
  Summary: Terminal UI to navigate, resume, and start Claude Code and Codex sessions
5
5
  Author-email: Rightglow <zhang.taian@foxmail.com>
6
6
  License-Expression: MIT
@@ -0,0 +1 @@
1
+ __version__ = "0.3.6.dev4"
@@ -1171,12 +1171,35 @@ def apply_path_open_request(
1171
1171
  )
1172
1172
 
1173
1173
 
1174
- def _render_history_line(pyte: object, line: bytes, width: int) -> bytes:
1175
- """Parse one physical tmux line and emit only allowlisted SGR styling."""
1174
+ def _render_history_lines(
1175
+ pyte: object,
1176
+ lines: Sequence[bytes],
1177
+ width: int,
1178
+ ) -> tuple[bytes, ...]:
1179
+ """Render physical tmux rows while retaining cross-row terminal style.
1180
+
1181
+ ``tmux capture-pane -e`` is a terminal stream, not a collection of
1182
+ independently styled strings. In particular, tmux omits an SGR prefix
1183
+ when a row inherits the previous row's foreground, background, or text
1184
+ attributes. Keep one decoder alive for the ordered capture, but clear its
1185
+ one-row cell buffer between rows. :func:`render_rows` then makes every
1186
+ result independently paintable for the local history overlay.
1187
+ """
1176
1188
  screen = pyte.Screen(width, 1)
1177
1189
  stream = pyte.ByteStream(screen)
1178
- stream.feed(line)
1179
- return render_rows(screen)[0]
1190
+ rendered: list[bytes] = []
1191
+ for line in lines:
1192
+ screen.buffer[0].clear()
1193
+ screen.cursor.x = 0
1194
+ screen.cursor.y = 0
1195
+ stream.feed(line)
1196
+ rendered.append(render_rows(screen)[0])
1197
+ return tuple(rendered)
1198
+
1199
+
1200
+ def _render_history_line(pyte: object, line: bytes, width: int) -> bytes:
1201
+ """Render one self-contained physical row with allowlisted SGR styling."""
1202
+ return _render_history_lines(pyte, (line,), width)[0]
1180
1203
 
1181
1204
 
1182
1205
  def _read_transcript_tail(fd: int) -> tuple[str, bool]:
@@ -1352,7 +1375,8 @@ def _capture_pane_history(
1352
1375
  # Retain the newest suffix when the styled representation reaches its byte
1353
1376
  # budget. Iterate backwards so an oversized response never sacrifices the
1354
1377
  # pane's current viewport merely to retain older scrollback.
1355
- current_raw = raw_lines[-pane.height :]
1378
+ rendered_raw = _render_history_lines(pyte, raw_lines, pane.width)
1379
+ current_raw = rendered_raw[-pane.height :]
1356
1380
  transcript_entry = None
1357
1381
  # ``None`` is retained only for old/test geometry that predates the
1358
1382
  # provider field; every validated live marker carries an explicit value.
@@ -1383,21 +1407,14 @@ def _capture_pane_history(
1383
1407
  transcript_lines = transcript_entry.rows
1384
1408
  history_count = max(0, max_lines - pane.height)
1385
1409
  source_lines = (
1386
- tuple((line, True) for line in transcript_lines[-history_count:])
1387
- if history_count
1388
- else ()
1389
- ) + tuple((line, False) for line in current_raw)
1410
+ transcript_lines[-history_count:] if history_count else ()
1411
+ ) + current_raw
1390
1412
  else:
1391
- source_lines = tuple((line, False) for line in raw_lines)
1413
+ source_lines = rendered_raw
1392
1414
  newest_first: list[bytes] = []
1393
1415
  packed_size = 2 # history line-count prefix
1394
1416
  budget_truncated = False
1395
- for raw_line, rendered_already in reversed(source_lines[-max_lines:]):
1396
- rendered = (
1397
- raw_line
1398
- if rendered_already
1399
- else _render_history_line(pyte, raw_line, pane.width)
1400
- )
1417
+ for rendered in reversed(source_lines[-max_lines:]):
1401
1418
  line_size = 4 + len(rendered)
1402
1419
  if packed_size + line_size > _HISTORY_SNAPSHOT_RAW_BUDGET:
1403
1420
  budget_truncated = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: railmux
3
- Version: 0.3.6.dev3
3
+ Version: 0.3.6.dev4
4
4
  Summary: Terminal UI to navigate, resume, and start Claude Code and Codex sessions
5
5
  Author-email: Rightglow <zhang.taian@foxmail.com>
6
6
  License-Expression: MIT
@@ -6977,8 +6977,8 @@ def test_server_history_capture_honours_limits_above_the_old_4096_cap(
6977
6977
  )
6978
6978
  monkeypatch.setattr(
6979
6979
  fast_display_server,
6980
- "_render_history_line",
6981
- lambda _pyte, line, _width: line,
6980
+ "_render_history_lines",
6981
+ lambda _pyte, lines, _width: tuple(lines),
6982
6982
  )
6983
6983
 
6984
6984
  snapshot = fast_display_server._capture_pane_history(object(), pane, 7, 5000)
@@ -7019,16 +7019,31 @@ def test_server_raw_styled_hot_and_deep_history_keep_codex_foreground(
7019
7019
  b"\033[38;2;205;214;244mvalue = 1\033[39m"
7020
7020
  )
7021
7021
  monochrome = (
7022
- b"\033[48;5;22m 3 \033[0m\033[38;5;2m\033[48;5;22m"
7022
+ # tmux omits the leading background because this physical row inherits
7023
+ # it from ``highlighted``. History parsing must keep that stream state
7024
+ # while still returning an independently paintable row.
7025
+ b" 3 \033[0m\033[38;5;2m\033[48;5;22m"
7023
7026
  b"+#!/bin/bash\033[39m"
7024
7027
  )
7028
+ removed = (
7029
+ b"\033[48;5;52m 4 \033[0m\033[38;5;1m\033[48;5;52m"
7030
+ b"-removed = True\033[39m"
7031
+ )
7032
+ removed_inherited = (
7033
+ b" 5 \033[0m\033[38;5;1m\033[48;5;52m"
7034
+ b"-removed = False\033[39m"
7035
+ )
7036
+ ordinary = b"\033[0m ordinary output"
7025
7037
  raw = b"\n".join((
7026
7038
  *(f"old-{index}".encode() for index in range(99)),
7027
7039
  wrap_head,
7028
7040
  wrap_continuation,
7029
- *(f"line-{index}".encode() for index in range(297)),
7041
+ *(f"line-{index}".encode() for index in range(294)),
7030
7042
  highlighted,
7031
7043
  monochrome,
7044
+ removed,
7045
+ removed_inherited,
7046
+ ordinary,
7032
7047
  )) + b"\n"
7033
7048
  monkeypatch.setattr(
7034
7049
  subprocess, "check_output", lambda *_args, **_kwargs: raw)
@@ -7054,19 +7069,32 @@ def test_server_raw_styled_hot_and_deep_history_keep_codex_foreground(
7054
7069
  terminal.ByteStream(screen).feed(row)
7055
7070
  return screen
7056
7071
 
7057
- highlighted_screen = styled_row(deep.lines[-2])
7058
- monochrome_screen = styled_row(deep.lines[-1])
7072
+ highlighted_screen = styled_row(deep.lines[-5])
7073
+ monochrome_screen = styled_row(deep.lines[-4])
7074
+ removed_screen = styled_row(deep.lines[-3])
7075
+ removed_inherited_screen = styled_row(deep.lines[-2])
7076
+ ordinary_screen = styled_row(deep.lines[-1])
7059
7077
  highlighted_start = highlighted_screen.display[0].index("value")
7060
7078
  monochrome_start = monochrome_screen.display[0].index("#!/bin/bash")
7061
7079
  assert highlighted_screen.buffer[0][highlighted_start].fg == "cdd6f4"
7062
7080
  assert monochrome_screen.buffer[0][monochrome_start].fg == "00cd00"
7081
+ assert highlighted_screen.buffer[0][0].bg == "005f00"
7082
+ assert monochrome_screen.buffer[0][0].bg == "005f00"
7083
+ assert removed_screen.buffer[0][0].bg == "5f0000"
7084
+ assert removed_inherited_screen.buffer[0][0].bg == "5f0000"
7085
+ assert ordinary_screen.buffer[0][0].bg == "default"
7063
7086
  coloured_backgrounds = {
7064
7087
  char.bg
7065
- for screen in (highlighted_screen, monochrome_screen)
7088
+ for screen in (
7089
+ highlighted_screen,
7090
+ monochrome_screen,
7091
+ removed_screen,
7092
+ removed_inherited_screen,
7093
+ )
7066
7094
  for char in screen.buffer[0].values()
7067
7095
  if char.bg != "default"
7068
7096
  }
7069
- assert coloured_backgrounds == {"005f00"}
7097
+ assert coloured_backgrounds == {"005f00", "5f0000"}
7070
7098
 
7071
7099
 
7072
7100
  def test_server_claude_history_uses_stable_transcript_suffix(monkeypatch):
@@ -7097,8 +7125,8 @@ def test_server_claude_history_uses_stable_transcript_suffix(monkeypatch):
7097
7125
  )
7098
7126
  monkeypatch.setattr(
7099
7127
  fast_display_server,
7100
- "_render_history_line",
7101
- lambda _pyte, line, _width: line,
7128
+ "_render_history_lines",
7129
+ lambda _pyte, lines, _width: tuple(lines),
7102
7130
  )
7103
7131
 
7104
7132
  hot = fast_display_server._capture_pane_history(object(), pane, 1, 300)
@@ -7140,8 +7168,8 @@ def test_server_waits_for_local_choice_before_rendering_claude_transcript(
7140
7168
  )
7141
7169
  monkeypatch.setattr(
7142
7170
  fast_display_server,
7143
- "_render_history_line",
7144
- lambda _pyte, line, _width: line,
7171
+ "_render_history_lines",
7172
+ lambda _pyte, lines, _width: tuple(lines),
7145
7173
  )
7146
7174
 
7147
7175
  snapshot = fast_display_server._capture_pane_history(object(), pane, 1, 300)
@@ -7188,8 +7216,8 @@ def test_server_codex_history_uses_canonical_transcript_after_rewind(
7188
7216
  )
7189
7217
  monkeypatch.setattr(
7190
7218
  fast_display_server,
7191
- "_render_history_line",
7192
- lambda _pyte, line, _width: line,
7219
+ "_render_history_lines",
7220
+ lambda _pyte, lines, _width: tuple(lines),
7193
7221
  )
7194
7222
 
7195
7223
  snapshot = fast_display_server._capture_pane_history(
@@ -7230,8 +7258,8 @@ def test_server_unreadable_claude_transcript_preserves_native_wheel_fallback(
7230
7258
  )
7231
7259
  monkeypatch.setattr(
7232
7260
  fast_display_server,
7233
- "_render_history_line",
7234
- lambda _pyte, line, _width: line,
7261
+ "_render_history_lines",
7262
+ lambda _pyte, lines, _width: tuple(lines),
7235
7263
  )
7236
7264
 
7237
7265
  snapshot = fast_display_server._capture_pane_history(object(), pane, 1, 300)
@@ -7314,8 +7342,10 @@ def test_server_history_capture_truncates_to_newest_styled_byte_budget(
7314
7342
  line_bytes = fast_display_server._HISTORY_SNAPSHOT_RAW_BUDGET // 3 + 100
7315
7343
  monkeypatch.setattr(
7316
7344
  fast_display_server,
7317
- "_render_history_line",
7318
- lambda _pyte, line, _width: line + b"x" * line_bytes,
7345
+ "_render_history_lines",
7346
+ lambda _pyte, lines, _width: tuple(
7347
+ line + b"x" * line_bytes for line in lines
7348
+ ),
7319
7349
  )
7320
7350
 
7321
7351
  snapshot = fast_display_server._capture_pane_history(object(), pane, 7, 20000)
@@ -1 +0,0 @@
1
- __version__ = "0.3.6.dev3"
File without changes
File without changes
File without changes
File without changes