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.
- meltygui/__init__.py +107 -0
- meltygui/accounts/__init__.py +0 -0
- meltygui/accounts/internet_accounts.py +1355 -0
- meltygui/chat/__init__.py +91 -0
- meltygui/chat/activity.py +75 -0
- meltygui/chat/backends.py +36 -0
- meltygui/chat/chat_interface.py +732 -0
- meltygui/chat/chat_proxy.py +352 -0
- meltygui/chat/codex_proxy.py +592 -0
- meltygui/chat/codex_settings.py +100 -0
- meltygui/chat/codex_transport.py +60 -0
- meltygui/chat/command_parser.py +204 -0
- meltygui/chat/images.py +227 -0
- meltygui/chat/messages.py +417 -0
- meltygui/chat/metadata.py +139 -0
- meltygui/chat/writer_locks.py +64 -0
- meltygui/code/__init__.py +0 -0
- meltygui/code/basic_converters.py +533 -0
- meltygui/code/chain_converters.py +2111 -0
- meltygui/code/code_checks.py +2209 -0
- meltygui/code/core_syntax.py +1430 -0
- meltygui/code/file_converters.py +1933 -0
- meltygui/code/fileref.py +702 -0
- meltygui/code/hotswap_guard.py +144 -0
- meltygui/code/libcst_conversion.py +9724 -0
- meltygui/code/live_instrument.py +392 -0
- meltygui/code/live_view.py +2490 -0
- meltygui/code/melty_scan.py +2684 -0
- meltygui/code/new_codecs.py +1255 -0
- meltygui/code/new_converters.py +3017 -0
- meltygui/code/project_code.py +278 -0
- meltygui/code/source_context.py +63 -0
- meltygui/code/symbol_roster.py +1588 -0
- meltygui/code/syntax_check.py +34 -0
- meltygui/code/syntax_check_worker.py +114 -0
- meltygui/completion/__init__.py +0 -0
- meltygui/completion/fim.py +1232 -0
- meltygui/completion/fim_context.py +481 -0
- meltygui/completion/providers/__init__.py +0 -0
- meltygui/completion/providers/anthropic_oauth.py +446 -0
- meltygui/completion/providers/anthropic_requests.py +69 -0
- meltygui/completion/providers/claude.py +203 -0
- meltygui/completion/providers/claude_usage.py +499 -0
- meltygui/completion/providers/codex_accounts.py +180 -0
- meltygui/completion/providers/copilot.py +617 -0
- meltygui/completion/providers/oauth_popup.py +220 -0
- meltygui/completion/providers/ollama.py +320 -0
- meltygui/completion/providers/profiles.py +23 -0
- meltygui/core/README.md +88 -0
- meltygui/core/__init__.py +1 -0
- meltygui/core/automation/__init__.py +1 -0
- meltygui/core/automation/action_core.py +153 -0
- meltygui/core/automation/collection_action.py +45 -0
- meltygui/core/automation/mcp_eval.py +167 -0
- meltygui/core/automation/mcp_hotswap.py +107 -0
- meltygui/core/automation/mcp_query.py +552 -0
- meltygui/core/automation/mcp_server.py +657 -0
- meltygui/core/automation/orchestration_core.py +2636 -0
- meltygui/core/automation/query_core.py +124 -0
- meltygui/core/automation/search_core.py +26 -0
- meltygui/core/automation/selector_core.py +340 -0
- meltygui/core/automation/value_core.py +1752 -0
- meltygui/core/cache/__init__.py +1 -0
- meltygui/core/cache/cache_diagnostics.py +0 -0
- meltygui/core/cache/invalidation_decoration.py +153 -0
- meltygui/core/cache/invalidation_tracker.py +43 -0
- meltygui/core/cache/tile_cache.py +5968 -0
- meltygui/core/conversion/__init__.py +1 -0
- meltygui/core/conversion/bubbling.py +599 -0
- meltygui/core/conversion/cache_tree.py +188 -0
- meltygui/core/conversion/chain.py +113 -0
- meltygui/core/conversion/converter_register.py +145 -0
- meltygui/core/conversion/data_decoration.py +67 -0
- meltygui/core/conversion/dict_conversion.py +1815 -0
- meltygui/core/conversion/dict_conversion_util.py +177 -0
- meltygui/core/conversion/dynamic_obj.py +89 -0
- meltygui/core/conversion/graph_compare.py +183 -0
- meltygui/core/conversion/load_save_v2.py +1032 -0
- meltygui/core/conversion/missing_saved_class.py +39 -0
- meltygui/core/conversion/path_finder.py +606 -0
- meltygui/core/conversion/render_host.py +1083 -0
- meltygui/core/core_render.py +6537 -0
- meltygui/core/definition_hotswap.py +231 -0
- meltygui/core/diagnostics/__init__.py +1 -0
- meltygui/core/diagnostics/attribute_churn.py +38 -0
- meltygui/core/diagnostics/fps_counter.py +39 -0
- meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
- meltygui/core/diagnostics/inspection_core.py +169 -0
- meltygui/core/diagnostics/monitor_core.py +105 -0
- meltygui/core/diagnostics/notifications.py +706 -0
- meltygui/core/diagnostics/perf_trace.py +281 -0
- meltygui/core/diagnostics/profile_decoration.py +88 -0
- meltygui/core/diagnostics/resize_trace.py +62 -0
- meltygui/core/diagnostics/screenshot_core.py +247 -0
- meltygui/core/diagnostics/session_status.py +98 -0
- meltygui/core/diagnostics/trace_core.py +445 -0
- meltygui/core/files/__init__.py +1 -0
- meltygui/core/files/file_core.py +208 -0
- meltygui/core/files/file_explorer_core.py +104 -0
- meltygui/core/files/file_tree_core.py +198 -0
- meltygui/core/files/file_watch_core.py +43 -0
- meltygui/core/files/import_graph_core.py +43 -0
- meltygui/core/files/metadata_core.py +51 -0
- meltygui/core/graphics/__init__.py +1 -0
- meltygui/core/graphics/cuda_context_core.py +166 -0
- meltygui/core/graphics/cuda_interop_core.py +136 -0
- meltygui/core/graphics/cuda_kernel_core.py +91 -0
- meltygui/core/graphics/framebuffer_recorder.py +337 -0
- meltygui/core/graphics/gl_state.py +658 -0
- meltygui/core/graphics/lut_core.py +52 -0
- meltygui/core/graphics/overlay_renderer.py +984 -0
- meltygui/core/graphics/scene_target.py +180 -0
- meltygui/core/graphics/screenshot.py +439 -0
- meltygui/core/graphics/shader_func.py +478 -0
- meltygui/core/graphics/tensor_core.py +45 -0
- meltygui/core/graphics/text_texture.py +329 -0
- meltygui/core/graphics/wayland_color.py +635 -0
- meltygui/core/input/__init__.py +1 -0
- meltygui/core/input/collision.py +165 -0
- meltygui/core/input/drag_drop_core.py +1525 -0
- meltygui/core/input/hypr_left_drag.py +323 -0
- meltygui/core/input/input_core.py +245 -0
- meltygui/core/input/input_handler.py +1101 -0
- meltygui/core/input/mouse_cursor.py +355 -0
- meltygui/core/input/pynput_backend.py +1054 -0
- meltygui/core/input/space_mouse.py +338 -0
- meltygui/core/input/touchpad_backend.py +393 -0
- meltygui/core/input/view_selection.py +177 -0
- meltygui/core/layout/__init__.py +1 -0
- meltygui/core/layout/column_core.py +2153 -0
- meltygui/core/layout/cursor_core.py +161 -0
- meltygui/core/layout/dropdown_core.py +278 -0
- meltygui/core/layout/edge_constraints.py +155 -0
- meltygui/core/layout/grid_core.py +117 -0
- meltygui/core/layout/header_core.py +23 -0
- meltygui/core/layout/header_runtime.py +67 -0
- meltygui/core/layout/layout_core.py +87 -0
- meltygui/core/layout/tile_manager_core.py +591 -0
- meltygui/core/melty.py +6726 -0
- meltygui/core/module_map.json +896 -0
- meltygui/core/module_names.py +19 -0
- meltygui/core/rendering/__init__.py +1 -0
- meltygui/core/rendering/core_decoration.py +431 -0
- meltygui/core/rendering/core_render_helpers.py +328 -0
- meltygui/core/rendering/func_metadata.py +398 -0
- meltygui/core/rendering/mode.py +818 -0
- meltygui/core/rendering/mode_defaults.py +41 -0
- meltygui/core/rendering/modes.py +136 -0
- meltygui/core/rendering/parameter_core.py +1665 -0
- meltygui/core/rendering/render_dispatch.py +1891 -0
- meltygui/core/rendering/render_funcs.py +273 -0
- meltygui/core/rendering/shaped.py +312 -0
- meltygui/core/rendering/window_decoration.py +25 -0
- meltygui/core/runtime/__init__.py +1 -0
- meltygui/core/runtime/app.py +735 -0
- meltygui/core/runtime/app_session.py +140 -0
- meltygui/core/runtime/background.py +564 -0
- meltygui/core/runtime/extensions.py +53 -0
- meltygui/core/runtime/gc_manager.py +1163 -0
- meltygui/core/runtime/lifecycle.py +21 -0
- meltygui/core/runtime/paths.py +27 -0
- meltygui/core/runtime/settings.py +14 -0
- meltygui/core/runtime/singleton.py +16 -0
- meltygui/core/runtime/thread_safe_bool.py +24 -0
- meltygui/core/runtime/thread_signal.py +30 -0
- meltygui/core/runtime/toggles.py +3115 -0
- meltygui/core/services/__init__.py +1 -0
- meltygui/core/services/account_core.py +10 -0
- meltygui/core/services/chat_core.py +19 -0
- meltygui/core/services/claude_terminal_core.py +346 -0
- meltygui/core/services/terminal_core.py +458 -0
- meltygui/core/services/terminal_runtime.py +78 -0
- meltygui/core/styling/__init__.py +1 -0
- meltygui/core/styling/color_core.py +46 -0
- meltygui/core/styling/fonts.py +639 -0
- meltygui/core/styling/global_style.py +338 -0
- meltygui/core/styling/style.py +198 -0
- meltygui/core/styling/style_core.py +522 -0
- meltygui/core/styling/warm_start.py +149 -0
- meltygui/core/windowing/__init__.py +1 -0
- meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
- meltygui/core/windowing/backends/__init__.py +1 -0
- meltygui/core/windowing/backends/imgui_renderer.py +138 -0
- meltygui/core/windowing/backends/native_wayland.py +850 -0
- meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
- meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
- meltygui/core/windowing/backends/wayland_protocol.py +101 -0
- meltygui/core/windowing/dock_core.py +182 -0
- meltygui/core/windowing/frame_geometry.py +42 -0
- meltygui/core/windowing/geometry_feed.py +864 -0
- meltygui/core/windowing/glfw_utils.py +1343 -0
- meltygui/core/windowing/os_frame.py +1552 -0
- meltygui/core/windowing/surface.py +643 -0
- meltygui/core/windowing/titlebar.py +1560 -0
- meltygui/core/windowing/titlebar_buttons.py +281 -0
- meltygui/core/windowing/wayland_move.py +932 -0
- meltygui/core/windowing/window_api.py +62 -0
- meltygui/core/windowing/window_constants.py +339 -0
- meltygui/core/windowing/window_visibility.py +162 -0
- meltygui/debug/__init__.py +0 -0
- meltygui/debug/app_view_utils.py +9 -0
- meltygui/editor/__init__.py +0 -0
- meltygui/editor/bash_syntax.py +30 -0
- meltygui/editor/code_line_fast.py +152 -0
- meltygui/editor/diff.py +139 -0
- meltygui/editor/external_changes.py +159 -0
- meltygui/editor/file_header.py +41 -0
- meltygui/editor/live_usage.py +169 -0
- meltygui/editor/live_view_views.py +1803 -0
- meltygui/editor/pending_save.py +1351 -0
- meltygui/editor/roster_tints.py +547 -0
- meltygui/editor/source_preview.py +16 -0
- meltygui/editor/source_tools.py +10 -0
- meltygui/editor/source_ui.py +70 -0
- meltygui/editor/spell_check.py +77 -0
- meltygui/editor/text_editor.py +9076 -0
- meltygui/editor/usage_picker.py +538 -0
- meltygui/events/__init__.py +0 -0
- meltygui/events/example.py +118 -0
- meltygui/examples/__init__.py +0 -0
- meltygui/examples/columns_demo.py +33 -0
- meltygui/examples/columns_window_demo.py +60 -0
- meltygui/examples/context_menu_demo.py +24 -0
- meltygui/examples/context_menu_window_demo.py +49 -0
- meltygui/examples/gui_playground.py +127 -0
- meltygui/examples/live_view_playground.py +256 -0
- meltygui/examples/lora.py +43 -0
- meltygui/examples/lora_data.py +59 -0
- meltygui/examples/lora_policies.py +67 -0
- meltygui/examples/mode_demo.py +49 -0
- meltygui/examples/modifies_demo.py +119 -0
- meltygui/examples/scalar_policies.py +60 -0
- meltygui/examples/style_layouts.py +149 -0
- meltygui/examples/tile_manager_demo.py +74 -0
- meltygui/examples/tint_demo.py +160 -0
- meltygui/examples/tint_functions.py +56 -0
- meltygui/examples/trace_demo.py +88 -0
- meltygui/examples/two_windows.py +36 -0
- meltygui/files/__init__.py +0 -0
- meltygui/files/fast_file_explorer.py +439 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
- meltygui/graphics/__init__.py +6 -0
- meltygui/graphics/base.py +85 -0
- meltygui/graphics/examples.py +507 -0
- meltygui/graphics/executor.py +520 -0
- meltygui/graphics/filter.py +667 -0
- meltygui/graphics/filter.pyi +856 -0
- meltygui/graphics/generate_stubs.py +22 -0
- meltygui/graphics/registry.py +203 -0
- meltygui/graphics/shader_compiler.py +155 -0
- meltygui/graphics/shaders.py +1302 -0
- meltygui/graphics/stub_generator.py +250 -0
- meltygui/graphics/texture_manager.py +170 -0
- meltygui/graphics/texture_min_max.py +295 -0
- meltygui/hdr_color.py +757 -0
- meltygui/image_load.py +308 -0
- meltygui/model/__init__.py +1 -0
- meltygui/model/account_model.py +142 -0
- meltygui/model/camera_model.py +159 -0
- meltygui/model/chat_model.py +86 -0
- meltygui/model/code_model.py +62 -0
- meltygui/model/code_proxy_model.py +876 -0
- meltygui/model/collection_model.py +41 -0
- meltygui/model/color_model.py +127 -0
- meltygui/model/cuda_tensor_model.py +36 -0
- meltygui/model/cuda_texture_model.py +149 -0
- meltygui/model/dropdown_model.py +137 -0
- meltygui/model/file_metadata_model.py +73 -0
- meltygui/model/file_model.py +289 -0
- meltygui/model/format_model.py +390 -0
- meltygui/model/graph_model.py +98 -0
- meltygui/model/icon_model.py +1024 -0
- meltygui/model/import_graph_model.py +468 -0
- meltygui/model/layout_model.py +15 -0
- meltygui/model/lut_model.py +266 -0
- meltygui/model/search_model.py +173 -0
- meltygui/model/tensor_model.py +402 -0
- meltygui/model/terminal_model.py +329 -0
- meltygui/model/texture_model.py +146 -0
- meltygui/model/tile_model.py +24 -0
- meltygui/model/trace_model.py +198 -0
- meltygui/model/trace_report_model.py +146 -0
- meltygui/models/__init__.py +0 -0
- meltygui/models/file_meta.py +613 -0
- meltygui/models/function_console.py +184 -0
- meltygui/models/orchestration.py +48 -0
- meltygui/pbr.py +1576 -0
- meltygui/png_unfilter.c +49 -0
- meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
- meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
- meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
- meltygui/resources/dejavu/LICENSE.txt +78 -0
- meltygui/resources/fontawesome-LICENSE.txt +121 -0
- meltygui/resources/fontawesome-webfont.ttf +0 -0
- meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
- meltygui/resources/jetbrains-weights/OFL.txt +93 -0
- meltygui/resources/jetbrains-weights/README.md +2 -0
- meltygui/state/__init__.py +0 -0
- meltygui/state/account_state.py +22 -0
- meltygui/state/animation_state.py +97 -0
- meltygui/state/annotation_state.py +22 -0
- meltygui/state/chat_state.py +36 -0
- meltygui/state/code_state.py +10 -0
- meltygui/state/core_enums.py +59 -0
- meltygui/state/core_markers.py +115 -0
- meltygui/state/core_undo.py +1075 -0
- meltygui/state/file_state.py +75 -0
- meltygui/state/graph_state.py +26 -0
- meltygui/state/inspection_state.py +47 -0
- meltygui/state/menu_state.py +10 -0
- meltygui/state/model_enums.py +11 -0
- meltygui/state/new_core_model.py +2394 -0
- meltygui/state/orchestration_state.py +14 -0
- meltygui/state/query_state.py +24 -0
- meltygui/state/tensor_state.py +10 -0
- meltygui/state/terminal_state.py +23 -0
- meltygui/state/trace_state.py +32 -0
- meltygui/state/voxel_state.py +12 -0
- meltygui/text_index.py +816 -0
- meltygui/utils/__init__.py +0 -0
- meltygui/utils/jump_to_code.py +344 -0
- meltygui/utils/pkl_inspect.py +90 -0
- meltygui/utils/render_utils.py +1419 -0
- meltygui/view/__init__.py +1 -0
- meltygui/view/account_view.py +524 -0
- meltygui/view/action_view.py +73 -0
- meltygui/view/chat_decoration_view.py +112 -0
- meltygui/view/chat_view.py +1703 -0
- meltygui/view/code_view.py +2677 -0
- meltygui/view/collection_view.py +1185 -0
- meltygui/view/color_view.py +824 -0
- meltygui/view/control_view.py +559 -0
- meltygui/view/decoration_view.py +439 -0
- meltygui/view/diagnostic_view.py +177 -0
- meltygui/view/dropdown_view.py +1082 -0
- meltygui/view/file_view.py +1599 -0
- meltygui/view/graph_cuda_view.py +105 -0
- meltygui/view/graph_view.py +882 -0
- meltygui/view/header_view.py +848 -0
- meltygui/view/input_view.py +238 -0
- meltygui/view/inspection_view.py +1783 -0
- meltygui/view/layout_view.py +596 -0
- meltygui/view/lut_view.py +45 -0
- meltygui/view/menu_view.py +212 -0
- meltygui/view/orchestration_view.py +658 -0
- meltygui/view/query_view.py +118 -0
- meltygui/view/search_view.py +342 -0
- meltygui/view/tab_view.py +258 -0
- meltygui/view/tensor_view.py +430 -0
- meltygui/view/terminal_view.py +355 -0
- meltygui/view/text_view.py +8031 -0
- meltygui/view/texture_view.py +480 -0
- meltygui/view/tile_view.py +38 -0
- meltygui/view/trace_view.py +923 -0
- meltygui/view/voxel_cuda_view.py +824 -0
- meltygui/view/voxel_view.py +1860 -0
- meltygui/view/window_view.py +111 -0
- meltygui-0.1.0.dist-info/METADATA +143 -0
- meltygui-0.1.0.dist-info/RECORD +372 -0
- meltygui-0.1.0.dist-info/WHEEL +4 -0
- 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
|