meltygui 0.1.0__py3-none-any.whl

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 (372) hide show
  1. meltygui/__init__.py +107 -0
  2. meltygui/accounts/__init__.py +0 -0
  3. meltygui/accounts/internet_accounts.py +1355 -0
  4. meltygui/chat/__init__.py +91 -0
  5. meltygui/chat/activity.py +75 -0
  6. meltygui/chat/backends.py +36 -0
  7. meltygui/chat/chat_interface.py +732 -0
  8. meltygui/chat/chat_proxy.py +352 -0
  9. meltygui/chat/codex_proxy.py +592 -0
  10. meltygui/chat/codex_settings.py +100 -0
  11. meltygui/chat/codex_transport.py +60 -0
  12. meltygui/chat/command_parser.py +204 -0
  13. meltygui/chat/images.py +227 -0
  14. meltygui/chat/messages.py +417 -0
  15. meltygui/chat/metadata.py +139 -0
  16. meltygui/chat/writer_locks.py +64 -0
  17. meltygui/code/__init__.py +0 -0
  18. meltygui/code/basic_converters.py +533 -0
  19. meltygui/code/chain_converters.py +2111 -0
  20. meltygui/code/code_checks.py +2209 -0
  21. meltygui/code/core_syntax.py +1430 -0
  22. meltygui/code/file_converters.py +1933 -0
  23. meltygui/code/fileref.py +702 -0
  24. meltygui/code/hotswap_guard.py +144 -0
  25. meltygui/code/libcst_conversion.py +9724 -0
  26. meltygui/code/live_instrument.py +392 -0
  27. meltygui/code/live_view.py +2490 -0
  28. meltygui/code/melty_scan.py +2684 -0
  29. meltygui/code/new_codecs.py +1255 -0
  30. meltygui/code/new_converters.py +3017 -0
  31. meltygui/code/project_code.py +278 -0
  32. meltygui/code/source_context.py +63 -0
  33. meltygui/code/symbol_roster.py +1588 -0
  34. meltygui/code/syntax_check.py +34 -0
  35. meltygui/code/syntax_check_worker.py +114 -0
  36. meltygui/completion/__init__.py +0 -0
  37. meltygui/completion/fim.py +1232 -0
  38. meltygui/completion/fim_context.py +481 -0
  39. meltygui/completion/providers/__init__.py +0 -0
  40. meltygui/completion/providers/anthropic_oauth.py +446 -0
  41. meltygui/completion/providers/anthropic_requests.py +69 -0
  42. meltygui/completion/providers/claude.py +203 -0
  43. meltygui/completion/providers/claude_usage.py +499 -0
  44. meltygui/completion/providers/codex_accounts.py +180 -0
  45. meltygui/completion/providers/copilot.py +617 -0
  46. meltygui/completion/providers/oauth_popup.py +220 -0
  47. meltygui/completion/providers/ollama.py +320 -0
  48. meltygui/completion/providers/profiles.py +23 -0
  49. meltygui/core/README.md +88 -0
  50. meltygui/core/__init__.py +1 -0
  51. meltygui/core/automation/__init__.py +1 -0
  52. meltygui/core/automation/action_core.py +153 -0
  53. meltygui/core/automation/collection_action.py +45 -0
  54. meltygui/core/automation/mcp_eval.py +167 -0
  55. meltygui/core/automation/mcp_hotswap.py +107 -0
  56. meltygui/core/automation/mcp_query.py +552 -0
  57. meltygui/core/automation/mcp_server.py +657 -0
  58. meltygui/core/automation/orchestration_core.py +2636 -0
  59. meltygui/core/automation/query_core.py +124 -0
  60. meltygui/core/automation/search_core.py +26 -0
  61. meltygui/core/automation/selector_core.py +340 -0
  62. meltygui/core/automation/value_core.py +1752 -0
  63. meltygui/core/cache/__init__.py +1 -0
  64. meltygui/core/cache/cache_diagnostics.py +0 -0
  65. meltygui/core/cache/invalidation_decoration.py +153 -0
  66. meltygui/core/cache/invalidation_tracker.py +43 -0
  67. meltygui/core/cache/tile_cache.py +5968 -0
  68. meltygui/core/conversion/__init__.py +1 -0
  69. meltygui/core/conversion/bubbling.py +599 -0
  70. meltygui/core/conversion/cache_tree.py +188 -0
  71. meltygui/core/conversion/chain.py +113 -0
  72. meltygui/core/conversion/converter_register.py +145 -0
  73. meltygui/core/conversion/data_decoration.py +67 -0
  74. meltygui/core/conversion/dict_conversion.py +1815 -0
  75. meltygui/core/conversion/dict_conversion_util.py +177 -0
  76. meltygui/core/conversion/dynamic_obj.py +89 -0
  77. meltygui/core/conversion/graph_compare.py +183 -0
  78. meltygui/core/conversion/load_save_v2.py +1032 -0
  79. meltygui/core/conversion/missing_saved_class.py +39 -0
  80. meltygui/core/conversion/path_finder.py +606 -0
  81. meltygui/core/conversion/render_host.py +1083 -0
  82. meltygui/core/core_render.py +6537 -0
  83. meltygui/core/definition_hotswap.py +231 -0
  84. meltygui/core/diagnostics/__init__.py +1 -0
  85. meltygui/core/diagnostics/attribute_churn.py +38 -0
  86. meltygui/core/diagnostics/fps_counter.py +39 -0
  87. meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
  88. meltygui/core/diagnostics/inspection_core.py +169 -0
  89. meltygui/core/diagnostics/monitor_core.py +105 -0
  90. meltygui/core/diagnostics/notifications.py +706 -0
  91. meltygui/core/diagnostics/perf_trace.py +281 -0
  92. meltygui/core/diagnostics/profile_decoration.py +88 -0
  93. meltygui/core/diagnostics/resize_trace.py +62 -0
  94. meltygui/core/diagnostics/screenshot_core.py +247 -0
  95. meltygui/core/diagnostics/session_status.py +98 -0
  96. meltygui/core/diagnostics/trace_core.py +445 -0
  97. meltygui/core/files/__init__.py +1 -0
  98. meltygui/core/files/file_core.py +208 -0
  99. meltygui/core/files/file_explorer_core.py +104 -0
  100. meltygui/core/files/file_tree_core.py +198 -0
  101. meltygui/core/files/file_watch_core.py +43 -0
  102. meltygui/core/files/import_graph_core.py +43 -0
  103. meltygui/core/files/metadata_core.py +51 -0
  104. meltygui/core/graphics/__init__.py +1 -0
  105. meltygui/core/graphics/cuda_context_core.py +166 -0
  106. meltygui/core/graphics/cuda_interop_core.py +136 -0
  107. meltygui/core/graphics/cuda_kernel_core.py +91 -0
  108. meltygui/core/graphics/framebuffer_recorder.py +337 -0
  109. meltygui/core/graphics/gl_state.py +658 -0
  110. meltygui/core/graphics/lut_core.py +52 -0
  111. meltygui/core/graphics/overlay_renderer.py +984 -0
  112. meltygui/core/graphics/scene_target.py +180 -0
  113. meltygui/core/graphics/screenshot.py +439 -0
  114. meltygui/core/graphics/shader_func.py +478 -0
  115. meltygui/core/graphics/tensor_core.py +45 -0
  116. meltygui/core/graphics/text_texture.py +329 -0
  117. meltygui/core/graphics/wayland_color.py +635 -0
  118. meltygui/core/input/__init__.py +1 -0
  119. meltygui/core/input/collision.py +165 -0
  120. meltygui/core/input/drag_drop_core.py +1525 -0
  121. meltygui/core/input/hypr_left_drag.py +323 -0
  122. meltygui/core/input/input_core.py +245 -0
  123. meltygui/core/input/input_handler.py +1101 -0
  124. meltygui/core/input/mouse_cursor.py +355 -0
  125. meltygui/core/input/pynput_backend.py +1054 -0
  126. meltygui/core/input/space_mouse.py +338 -0
  127. meltygui/core/input/touchpad_backend.py +393 -0
  128. meltygui/core/input/view_selection.py +177 -0
  129. meltygui/core/layout/__init__.py +1 -0
  130. meltygui/core/layout/column_core.py +2153 -0
  131. meltygui/core/layout/cursor_core.py +161 -0
  132. meltygui/core/layout/dropdown_core.py +278 -0
  133. meltygui/core/layout/edge_constraints.py +155 -0
  134. meltygui/core/layout/grid_core.py +117 -0
  135. meltygui/core/layout/header_core.py +23 -0
  136. meltygui/core/layout/header_runtime.py +67 -0
  137. meltygui/core/layout/layout_core.py +87 -0
  138. meltygui/core/layout/tile_manager_core.py +591 -0
  139. meltygui/core/melty.py +6726 -0
  140. meltygui/core/module_map.json +896 -0
  141. meltygui/core/module_names.py +19 -0
  142. meltygui/core/rendering/__init__.py +1 -0
  143. meltygui/core/rendering/core_decoration.py +431 -0
  144. meltygui/core/rendering/core_render_helpers.py +328 -0
  145. meltygui/core/rendering/func_metadata.py +398 -0
  146. meltygui/core/rendering/mode.py +818 -0
  147. meltygui/core/rendering/mode_defaults.py +41 -0
  148. meltygui/core/rendering/modes.py +136 -0
  149. meltygui/core/rendering/parameter_core.py +1665 -0
  150. meltygui/core/rendering/render_dispatch.py +1891 -0
  151. meltygui/core/rendering/render_funcs.py +273 -0
  152. meltygui/core/rendering/shaped.py +312 -0
  153. meltygui/core/rendering/window_decoration.py +25 -0
  154. meltygui/core/runtime/__init__.py +1 -0
  155. meltygui/core/runtime/app.py +735 -0
  156. meltygui/core/runtime/app_session.py +140 -0
  157. meltygui/core/runtime/background.py +564 -0
  158. meltygui/core/runtime/extensions.py +53 -0
  159. meltygui/core/runtime/gc_manager.py +1163 -0
  160. meltygui/core/runtime/lifecycle.py +21 -0
  161. meltygui/core/runtime/paths.py +27 -0
  162. meltygui/core/runtime/settings.py +14 -0
  163. meltygui/core/runtime/singleton.py +16 -0
  164. meltygui/core/runtime/thread_safe_bool.py +24 -0
  165. meltygui/core/runtime/thread_signal.py +30 -0
  166. meltygui/core/runtime/toggles.py +3115 -0
  167. meltygui/core/services/__init__.py +1 -0
  168. meltygui/core/services/account_core.py +10 -0
  169. meltygui/core/services/chat_core.py +19 -0
  170. meltygui/core/services/claude_terminal_core.py +346 -0
  171. meltygui/core/services/terminal_core.py +458 -0
  172. meltygui/core/services/terminal_runtime.py +78 -0
  173. meltygui/core/styling/__init__.py +1 -0
  174. meltygui/core/styling/color_core.py +46 -0
  175. meltygui/core/styling/fonts.py +639 -0
  176. meltygui/core/styling/global_style.py +338 -0
  177. meltygui/core/styling/style.py +198 -0
  178. meltygui/core/styling/style_core.py +522 -0
  179. meltygui/core/styling/warm_start.py +149 -0
  180. meltygui/core/windowing/__init__.py +1 -0
  181. meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
  182. meltygui/core/windowing/backends/__init__.py +1 -0
  183. meltygui/core/windowing/backends/imgui_renderer.py +138 -0
  184. meltygui/core/windowing/backends/native_wayland.py +850 -0
  185. meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
  186. meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
  187. meltygui/core/windowing/backends/wayland_protocol.py +101 -0
  188. meltygui/core/windowing/dock_core.py +182 -0
  189. meltygui/core/windowing/frame_geometry.py +42 -0
  190. meltygui/core/windowing/geometry_feed.py +864 -0
  191. meltygui/core/windowing/glfw_utils.py +1343 -0
  192. meltygui/core/windowing/os_frame.py +1552 -0
  193. meltygui/core/windowing/surface.py +643 -0
  194. meltygui/core/windowing/titlebar.py +1560 -0
  195. meltygui/core/windowing/titlebar_buttons.py +281 -0
  196. meltygui/core/windowing/wayland_move.py +932 -0
  197. meltygui/core/windowing/window_api.py +62 -0
  198. meltygui/core/windowing/window_constants.py +339 -0
  199. meltygui/core/windowing/window_visibility.py +162 -0
  200. meltygui/debug/__init__.py +0 -0
  201. meltygui/debug/app_view_utils.py +9 -0
  202. meltygui/editor/__init__.py +0 -0
  203. meltygui/editor/bash_syntax.py +30 -0
  204. meltygui/editor/code_line_fast.py +152 -0
  205. meltygui/editor/diff.py +139 -0
  206. meltygui/editor/external_changes.py +159 -0
  207. meltygui/editor/file_header.py +41 -0
  208. meltygui/editor/live_usage.py +169 -0
  209. meltygui/editor/live_view_views.py +1803 -0
  210. meltygui/editor/pending_save.py +1351 -0
  211. meltygui/editor/roster_tints.py +547 -0
  212. meltygui/editor/source_preview.py +16 -0
  213. meltygui/editor/source_tools.py +10 -0
  214. meltygui/editor/source_ui.py +70 -0
  215. meltygui/editor/spell_check.py +77 -0
  216. meltygui/editor/text_editor.py +9076 -0
  217. meltygui/editor/usage_picker.py +538 -0
  218. meltygui/events/__init__.py +0 -0
  219. meltygui/events/example.py +118 -0
  220. meltygui/examples/__init__.py +0 -0
  221. meltygui/examples/columns_demo.py +33 -0
  222. meltygui/examples/columns_window_demo.py +60 -0
  223. meltygui/examples/context_menu_demo.py +24 -0
  224. meltygui/examples/context_menu_window_demo.py +49 -0
  225. meltygui/examples/gui_playground.py +127 -0
  226. meltygui/examples/live_view_playground.py +256 -0
  227. meltygui/examples/lora.py +43 -0
  228. meltygui/examples/lora_data.py +59 -0
  229. meltygui/examples/lora_policies.py +67 -0
  230. meltygui/examples/mode_demo.py +49 -0
  231. meltygui/examples/modifies_demo.py +119 -0
  232. meltygui/examples/scalar_policies.py +60 -0
  233. meltygui/examples/style_layouts.py +149 -0
  234. meltygui/examples/tile_manager_demo.py +74 -0
  235. meltygui/examples/tint_demo.py +160 -0
  236. meltygui/examples/tint_functions.py +56 -0
  237. meltygui/examples/trace_demo.py +88 -0
  238. meltygui/examples/two_windows.py +36 -0
  239. meltygui/files/__init__.py +0 -0
  240. meltygui/files/fast_file_explorer.py +439 -0
  241. meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
  242. meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
  243. meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
  244. meltygui/graphics/__init__.py +6 -0
  245. meltygui/graphics/base.py +85 -0
  246. meltygui/graphics/examples.py +507 -0
  247. meltygui/graphics/executor.py +520 -0
  248. meltygui/graphics/filter.py +667 -0
  249. meltygui/graphics/filter.pyi +856 -0
  250. meltygui/graphics/generate_stubs.py +22 -0
  251. meltygui/graphics/registry.py +203 -0
  252. meltygui/graphics/shader_compiler.py +155 -0
  253. meltygui/graphics/shaders.py +1302 -0
  254. meltygui/graphics/stub_generator.py +250 -0
  255. meltygui/graphics/texture_manager.py +170 -0
  256. meltygui/graphics/texture_min_max.py +295 -0
  257. meltygui/hdr_color.py +757 -0
  258. meltygui/image_load.py +308 -0
  259. meltygui/model/__init__.py +1 -0
  260. meltygui/model/account_model.py +142 -0
  261. meltygui/model/camera_model.py +159 -0
  262. meltygui/model/chat_model.py +86 -0
  263. meltygui/model/code_model.py +62 -0
  264. meltygui/model/code_proxy_model.py +876 -0
  265. meltygui/model/collection_model.py +41 -0
  266. meltygui/model/color_model.py +127 -0
  267. meltygui/model/cuda_tensor_model.py +36 -0
  268. meltygui/model/cuda_texture_model.py +149 -0
  269. meltygui/model/dropdown_model.py +137 -0
  270. meltygui/model/file_metadata_model.py +73 -0
  271. meltygui/model/file_model.py +289 -0
  272. meltygui/model/format_model.py +390 -0
  273. meltygui/model/graph_model.py +98 -0
  274. meltygui/model/icon_model.py +1024 -0
  275. meltygui/model/import_graph_model.py +468 -0
  276. meltygui/model/layout_model.py +15 -0
  277. meltygui/model/lut_model.py +266 -0
  278. meltygui/model/search_model.py +173 -0
  279. meltygui/model/tensor_model.py +402 -0
  280. meltygui/model/terminal_model.py +329 -0
  281. meltygui/model/texture_model.py +146 -0
  282. meltygui/model/tile_model.py +24 -0
  283. meltygui/model/trace_model.py +198 -0
  284. meltygui/model/trace_report_model.py +146 -0
  285. meltygui/models/__init__.py +0 -0
  286. meltygui/models/file_meta.py +613 -0
  287. meltygui/models/function_console.py +184 -0
  288. meltygui/models/orchestration.py +48 -0
  289. meltygui/pbr.py +1576 -0
  290. meltygui/png_unfilter.c +49 -0
  291. meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
  292. meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
  293. meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
  294. meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
  295. meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
  296. meltygui/resources/dejavu/LICENSE.txt +78 -0
  297. meltygui/resources/fontawesome-LICENSE.txt +121 -0
  298. meltygui/resources/fontawesome-webfont.ttf +0 -0
  299. meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
  300. meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
  301. meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
  302. meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
  303. meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
  304. meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
  305. meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
  306. meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
  307. meltygui/resources/jetbrains-weights/OFL.txt +93 -0
  308. meltygui/resources/jetbrains-weights/README.md +2 -0
  309. meltygui/state/__init__.py +0 -0
  310. meltygui/state/account_state.py +22 -0
  311. meltygui/state/animation_state.py +97 -0
  312. meltygui/state/annotation_state.py +22 -0
  313. meltygui/state/chat_state.py +36 -0
  314. meltygui/state/code_state.py +10 -0
  315. meltygui/state/core_enums.py +59 -0
  316. meltygui/state/core_markers.py +115 -0
  317. meltygui/state/core_undo.py +1075 -0
  318. meltygui/state/file_state.py +75 -0
  319. meltygui/state/graph_state.py +26 -0
  320. meltygui/state/inspection_state.py +47 -0
  321. meltygui/state/menu_state.py +10 -0
  322. meltygui/state/model_enums.py +11 -0
  323. meltygui/state/new_core_model.py +2394 -0
  324. meltygui/state/orchestration_state.py +14 -0
  325. meltygui/state/query_state.py +24 -0
  326. meltygui/state/tensor_state.py +10 -0
  327. meltygui/state/terminal_state.py +23 -0
  328. meltygui/state/trace_state.py +32 -0
  329. meltygui/state/voxel_state.py +12 -0
  330. meltygui/text_index.py +816 -0
  331. meltygui/utils/__init__.py +0 -0
  332. meltygui/utils/jump_to_code.py +344 -0
  333. meltygui/utils/pkl_inspect.py +90 -0
  334. meltygui/utils/render_utils.py +1419 -0
  335. meltygui/view/__init__.py +1 -0
  336. meltygui/view/account_view.py +524 -0
  337. meltygui/view/action_view.py +73 -0
  338. meltygui/view/chat_decoration_view.py +112 -0
  339. meltygui/view/chat_view.py +1703 -0
  340. meltygui/view/code_view.py +2677 -0
  341. meltygui/view/collection_view.py +1185 -0
  342. meltygui/view/color_view.py +824 -0
  343. meltygui/view/control_view.py +559 -0
  344. meltygui/view/decoration_view.py +439 -0
  345. meltygui/view/diagnostic_view.py +177 -0
  346. meltygui/view/dropdown_view.py +1082 -0
  347. meltygui/view/file_view.py +1599 -0
  348. meltygui/view/graph_cuda_view.py +105 -0
  349. meltygui/view/graph_view.py +882 -0
  350. meltygui/view/header_view.py +848 -0
  351. meltygui/view/input_view.py +238 -0
  352. meltygui/view/inspection_view.py +1783 -0
  353. meltygui/view/layout_view.py +596 -0
  354. meltygui/view/lut_view.py +45 -0
  355. meltygui/view/menu_view.py +212 -0
  356. meltygui/view/orchestration_view.py +658 -0
  357. meltygui/view/query_view.py +118 -0
  358. meltygui/view/search_view.py +342 -0
  359. meltygui/view/tab_view.py +258 -0
  360. meltygui/view/tensor_view.py +430 -0
  361. meltygui/view/terminal_view.py +355 -0
  362. meltygui/view/text_view.py +8031 -0
  363. meltygui/view/texture_view.py +480 -0
  364. meltygui/view/tile_view.py +38 -0
  365. meltygui/view/trace_view.py +923 -0
  366. meltygui/view/voxel_cuda_view.py +824 -0
  367. meltygui/view/voxel_view.py +1860 -0
  368. meltygui/view/window_view.py +111 -0
  369. meltygui-0.1.0.dist-info/METADATA +143 -0
  370. meltygui-0.1.0.dist-info/RECORD +372 -0
  371. meltygui-0.1.0.dist-info/WHEEL +4 -0
  372. meltygui-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,198 @@
1
+ """Trace model functions and supporting definitions."""
2
+ from pathlib import Path
3
+ import json
4
+ import os
5
+
6
+
7
+ class SavedTrace:
8
+ """EXTERNAL frames for draw_stack_trace — a trace captured or saved
9
+ elsewhere (a crash report file, a queued capture) rather than a live
10
+ exception: `frames` = [(path, lineno, function_name[, scope]), ...]
11
+ outermost first, `scope` a {name: value} dict the view shows as the
12
+ frame's live values (None = none), `error` the raising line's message
13
+ for draw_text's error marker ("" = no marker). draw_stack_trace is the
14
+ default view for it, so `draw_any(SavedTrace(...))` works. Keep ONE
15
+ object per trace: the view rebuilds its panes whenever the input's
16
+ identity changes."""
17
+ __slots__ = ("frames", "error", "seen_height")
18
+
19
+ def __init__(self, frames, error=""):
20
+ self.frames = list(frames or ())
21
+ self.error = error or ""
22
+ # The view's height last measured while IN VIEW (a scrolling host
23
+ # stamps it - see crash_reports): the honest height to lay out even
24
+ # while the view sits off-screen, where the wrapper's group measure
25
+ # runs to the clip edge.
26
+ self.seen_height = None
27
+
28
+ def __repr__(self):
29
+ return f"SavedTrace({len(self.frames)} frames, {self.error!r})"
30
+
31
+
32
+ class CrashReportStore(dict):
33
+ """path (str) → {"name", "time", "thread", "error", "commit", "mtime", "size"},
34
+ newest first. The trace bodies load lazily (`text`) and are cached by
35
+ the file's (mtime, size) so a rewritten file re-reads."""
36
+ # save_crash_report's header: `key: value` lines up to the first blank
37
+ # line - time / thread / error, and `frames` (JSON) when the trace saved
38
+ # frames. Parsed by _read_header; nothing here counts lines.
39
+ HEADER_KEYS = ("time", "thread", "error", "commit", "frames", "locals")
40
+
41
+ def __init__(self):
42
+ super().__init__()
43
+ self.loaded = False
44
+ self.error = ""
45
+ self._seen_generation = -1
46
+ self._dir_mtime = None
47
+ self._texts = {} # path → (signature, lines, SavedTrace)
48
+
49
+ def directory(self) -> Path:
50
+ from meltygui.core.windowing.glfw_utils import crash_reports_dir
51
+
52
+ return crash_reports_dir()
53
+
54
+ def refresh_if_stale(self):
55
+ """Reload the listing when a report was saved (`reports_changed`)
56
+ or the directory's mtime moved (a file deleted or added by hand).
57
+ One stat per call — content-free, so it is fine per frame."""
58
+ from meltygui.model.trace_report_model import _generation
59
+
60
+ directory = self.directory()
61
+ try:
62
+ dir_mtime = os.stat(directory).st_mtime_ns
63
+ except OSError:
64
+ dir_mtime = None
65
+ if (self.loaded and self._seen_generation == _generation
66
+ and dir_mtime == self._dir_mtime):
67
+ return
68
+ self._seen_generation = _generation
69
+ self._dir_mtime = dir_mtime
70
+ self.load()
71
+
72
+ def load(self):
73
+ self.clear()
74
+ self.error = ""
75
+ directory = self.directory()
76
+ try:
77
+ files = sorted(directory.glob("*.txt"), reverse=True) # names sort by time
78
+ except OSError as exc:
79
+ files = []
80
+ self.error = str(exc)
81
+ for path in files:
82
+ try:
83
+ stat = path.stat()
84
+ except OSError:
85
+ continue
86
+ entry = {"name": path.stem, "time": "", "thread": "", "error": "", "commit": "",
87
+ "mtime": stat.st_mtime, "size": stat.st_size}
88
+ try:
89
+ with open(path, "r", encoding="utf-8", errors="replace") as handle:
90
+ header, _ = self._read_header(handle)
91
+ except OSError:
92
+ header = {}
93
+ for key in ("time", "thread", "error", "commit"):
94
+ entry[key] = header.get(key, "")
95
+ self[str(path)] = entry
96
+ self.loaded = True
97
+ live = set(self.keys())
98
+ for stale in [key for key in self._texts if key not in live]:
99
+ del self._texts[stale]
100
+
101
+ @classmethod
102
+ def _read_header(cls, handle):
103
+ """(header dict, rest of the file) from an open report: `key: value`
104
+ lines up to the first blank line; an unknown first line means an
105
+ older file with no header (everything is body)."""
106
+ header = {}
107
+ first = handle.readline()
108
+ key, _, value = first.rstrip("\n").partition(": ")
109
+ if key not in cls.HEADER_KEYS:
110
+ return header, first + handle.read()
111
+ header[key] = value
112
+ while True:
113
+ line = handle.readline()
114
+ if not line or not line.strip():
115
+ break
116
+ key, _, value = line.rstrip("\n").partition(": ")
117
+ if key in cls.HEADER_KEYS:
118
+ header[key] = value
119
+ return header, handle.read()
120
+
121
+ def _load_body(self, path):
122
+ """(trace lines, SavedTrace) of one report, cached per file version.
123
+ The trace's frames are the header's JSON list as (path, lineno,
124
+ name, scope) tuples; `scope` is the frame's saved locals as
125
+ {name: value}, display strings restored to plain literals where
126
+ they parse (`_restore_value`), None when the report saved none;
127
+ its `error` the header's error line. ONE SavedTrace object per
128
+ file version, which draw_stack_trace needs: it rebuilds its panes
129
+ whenever the input's identity changes."""
130
+ from meltygui.model.trace_model import SavedTrace
131
+ from meltygui.model.trace_report_model import _frames_from_text
132
+ from meltygui.model.trace_report_model import _restore_scope
133
+
134
+ entry = self.get(path)
135
+ signature = (entry["mtime"], entry["size"]) if entry else None
136
+ cached = self._texts.get(path)
137
+ if cached is not None and cached[0] == signature:
138
+ return cached[1], cached[2]
139
+ frames = None
140
+ header = {}
141
+ try:
142
+ with open(path, "r", encoding="utf-8", errors="replace") as handle:
143
+ header, body_text = self._read_header(handle)
144
+ if header.get("frames"):
145
+ rows = json.loads(header["frames"])
146
+ scopes = json.loads(header["locals"]) if header.get("locals") else []
147
+ scopes = list(scopes) + [None] * (len(rows) - len(scopes))
148
+ frames = [(str(row[0]), int(row[1]), str(row[2]), _restore_scope(scope))
149
+ for row, scope in zip(rows, scopes)]
150
+ except (OSError, ValueError, TypeError, IndexError) as exc:
151
+ header, body_text = {}, f"<could not read {path}: {exc}>"
152
+ lines = body_text.split("\n")
153
+ while lines and not lines[0].strip():
154
+ lines = lines[1:]
155
+ while lines and not lines[-1].strip():
156
+ lines = lines[:-1]
157
+ if frames is None:
158
+ frames = _frames_from_text(lines)
159
+ trace = SavedTrace(frames, header.get("error") or (entry["error"] if entry else ""))
160
+ self._texts[path] = (signature, lines, trace)
161
+ return lines, trace
162
+
163
+ def text(self, path):
164
+ """The report's printed trace lines (header stripped)."""
165
+ return self._load_body(path)[0]
166
+
167
+ def trace(self, path):
168
+ """The report as a SavedTrace (draw_stack_trace's external-frames
169
+ input): the header's frames, else the ones its printed text names
170
+ (an older report) — empty when the text has none either."""
171
+ return self._load_body(path)[1]
172
+
173
+ def frames(self, path):
174
+ """The report's (path, lineno, name, scope) frames."""
175
+ return self.trace(path).frames
176
+
177
+ def remove(self, path):
178
+ from meltygui.model.trace_report_model import reports_changed
179
+
180
+ try:
181
+ os.unlink(path)
182
+ except OSError as exc:
183
+ self.error = str(exc)
184
+ self.pop(path, None)
185
+ self._texts.pop(path, None)
186
+ reports_changed()
187
+
188
+ def remove_all(self):
189
+ from meltygui.model.trace_report_model import reports_changed
190
+
191
+ for path in list(self.keys()):
192
+ try:
193
+ os.unlink(path)
194
+ except OSError as exc:
195
+ self.error = str(exc)
196
+ self.clear()
197
+ self._texts.clear()
198
+ reports_changed()
@@ -0,0 +1,146 @@
1
+ """Crash Reports — the traces print_stack_trace saved under
2
+ `Toggles.CrashReports.directory` (~/.lsd/crash_reports by default), one file
3
+ per trace (glfw_utils.save_crash_report), listed newest first.
4
+
5
+ Modelled on fast_dock: rows are plain draw-list rects/text with manual
6
+ hit-testing; hover boosts and clicks resolve inside the body while the view
7
+ is hovered (the wrapper repaints every frame then), and the idle tile is a
8
+ cached blit that a new report repaints via `reports_changed()` (called by
9
+ save_crash_report from whatever thread printed the trace).
10
+
11
+ Model: `reports` (CrashReportStore, a dict path → entry dict with the
12
+ report's header fields: time / thread / error). Clicking a row expands it
13
+ and draws it through draw_stack_trace (the code behind each frame, from
14
+ the report's saved (path, lineno, function) frames — an older report
15
+ without a frames header has them parsed out of its printed text); the
16
+ trash button on a hovered row deletes that file, the toolbar's Clear all
17
+ deletes every file.
18
+ Which rows are expanded persists in CrashReportsPanelState.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import ast
23
+ import json
24
+ import os
25
+ import re
26
+ import threading
27
+ import time
28
+ from pathlib import Path
29
+
30
+ import meltygui_imgui as imgui
31
+ from meltygui.hdr_color import pack_color
32
+
33
+ from meltygui.core.melty import Melty
34
+ from meltygui.core.conversion.dict_conversion import DictConversion
35
+ from meltygui.core.runtime.toggles import Toggles
36
+ from meltygui.core.windowing.glfw_utils import crash_reports_dir
37
+ from meltygui.core.windowing.glfw_utils import request_render
38
+ from meltygui.core.cache.tile_cache import add_shadow
39
+ from meltygui.core.core_render import render_func
40
+ from meltygui.core.rendering.window_decoration import window
41
+ from meltygui.core.layout.header_runtime import _brightness_clamp_fn
42
+ from meltygui.editor.source_ui import _tab_text_color
43
+ from meltygui.editor.text_editor import COLORS
44
+ from meltygui.editor.source_ui import _file_meta_tint
45
+
46
+ # Bumped by reports_changed(); the store refreshes when it sees a new value.
47
+ _generation = 0
48
+ _generation_lock = threading.Lock()
49
+
50
+
51
+ def reports_changed():
52
+ """A report file was written or removed outside the window (any
53
+ thread): mark the store stale and repaint the window's cached tile."""
54
+ global _generation
55
+ with _generation_lock:
56
+ _generation += 1
57
+ try:
58
+ Melty.cache.invalidate_up_by_obj(reports, force=True)
59
+ request_render()
60
+ except Exception:
61
+ pass # no studio (tests, launcher): nothing to repaint
62
+
63
+
64
+ # ──────────────────────────────────────────────────────────────────────────
65
+ # Store
66
+ # ──────────────────────────────────────────────────────────────────────────
67
+
68
+ from meltygui.model.trace_model import CrashReportStore
69
+
70
+
71
+ # `File "path", line num, in func` - the printed trace's frame line, the
72
+ # fallback source of frames for a report file without a frames header.
73
+ _FRAME_LINE = re.compile(r'File "([^"]+)", line (\d+), in (\S+)')
74
+
75
+
76
+ def _frames_from_text(lines):
77
+ return [(match.group(1), int(match.group(2)), match.group(3), None)
78
+ for line in lines for match in [_FRAME_LINE.search(line)] if match]
79
+
80
+
81
+ def _restore_value(text):
82
+ """A saved local back to a plain value where its display string is a
83
+ literal (numbers, strings, None, small containers) so the marker shows
84
+ `5`, not `'5'`; anything else (`<Tensor (3, 4) float32>`, an object
85
+ repr) stays the string it was saved as."""
86
+ try:
87
+ return ast.literal_eval(text)
88
+ except (ValueError, SyntaxError, TypeError, MemoryError, RecursionError):
89
+ return text
90
+
91
+
92
+ def _restore_scope(scope):
93
+ if not isinstance(scope, dict):
94
+ return None
95
+ return {str(name): _restore_value(value) for name, value in scope.items()}
96
+
97
+
98
+ reports = CrashReportStore()
99
+
100
+
101
+ from meltygui.state.trace_state import CrashReportsPanelState
102
+
103
+
104
+ def date_bucket(epoch, now=None):
105
+ """The section a report files under by its day, local time: "Today",
106
+ "Yesterday", else the date ("Mon Sep 2, 2026")."""
107
+ when = time.localtime(epoch)
108
+ today = time.localtime(time.time() if now is None else now)
109
+ day = (when.tm_year, when.tm_yday)
110
+ if day == (today.tm_year, today.tm_yday):
111
+ return "Today"
112
+ yesterday = time.localtime(time.mktime(today) - 86400)
113
+ if day == (yesterday.tm_year, yesterday.tm_yday):
114
+ return "Yesterday"
115
+ return time.strftime("%a %b ", when) + f"{when.tm_mday}, {when.tm_year}"
116
+
117
+
118
+ def _mix(style_manager, tint, value, factor, saturation):
119
+ return style_manager.make_color_rgb(tint[0], tint[1], tint[2], value=value,
120
+ factor=factor, saturation_scale=saturation)
121
+
122
+
123
+ def _color_u32(color, alpha=1.0):
124
+ return pack_color(color[0], color[1], color[2], alpha)
125
+
126
+
127
+ def _ellipsize(text, max_width):
128
+ if max_width <= 0:
129
+ return ""
130
+ if imgui.calc_text_size(text)[0] <= max_width:
131
+ return text
132
+ ellipsis = "…"
133
+ low, high = 0, len(text)
134
+ while low < high:
135
+ mid = (low + high + 1) // 2
136
+ if imgui.calc_text_size(text[:mid] + ellipsis)[0] <= max_width:
137
+ low = mid
138
+ else:
139
+ high = mid - 1
140
+ return text[:low] + ellipsis if low else ellipsis
141
+
142
+
143
+ # disable_scroll=False: the @window draw path defaults it to True (most
144
+ # windows lay out their own scrolling); this one is a scrolling list.
145
+ from meltygui.view.trace_view import draw_crash_reports
146
+ draw_crash_reports = window(input_value=reports, tint=(0.25, 0.23, 0.23), icon=f'\uf188', display_name='Crash Reports', initial={'width': 720, 'height': 480}, disable_scroll=False)(draw_crash_reports)
File without changes