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,481 @@
|
|
|
1
|
+
"""Built-in FIM context sources + the editor-side helpers that build an
|
|
2
|
+
`EditorView`. Every source is a `@fim_context_source` function
|
|
3
|
+
`(view: EditorView) -> Iterable[ContextItem]`; the fitter in `fim.py`
|
|
4
|
+
dedupes, budgets and orders them. Adding a source ("tests that call this
|
|
5
|
+
function", "git blame for these lines") is one decorated function.
|
|
6
|
+
|
|
7
|
+
All file text is PENDING truth (`PendingSave.current_file_text` through the
|
|
8
|
+
roster's `file_text`), never disk.
|
|
9
|
+
|
|
10
|
+
Tiers (see fim.py): stable items don't change while typing inside one
|
|
11
|
+
function (definitions from other files, the enclosing class outline, this
|
|
12
|
+
file's imports, observed runtime types); run items change per RUN (live
|
|
13
|
+
values); volatile items ride next to the buffer (definitions of symbols
|
|
14
|
+
on the caret line).
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from meltygui.completion.fim import ContextItem
|
|
23
|
+
from meltygui.completion.fim import EditorView
|
|
24
|
+
from meltygui.completion.fim import fim_context_source
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_DEF_LINE_RE = re.compile(r"^\s*(?:async\s+)?(?:def|class)\s+([A-Za-z_]\w*)")
|
|
28
|
+
_SKIP_CHAINS = frozenset({"self", "cls", "True", "False", "None", "import", "from", "def",
|
|
29
|
+
"class", "return", "if", "else", "elif", "for", "in", "not", "and",
|
|
30
|
+
"or", "is", "while", "try", "except", "finally", "with", "as",
|
|
31
|
+
"pass", "break", "continue", "lambda", "yield", "raise", "del",
|
|
32
|
+
"global", "nonlocal", "assert", "async", "await"})
|
|
33
|
+
_IMPORT_RE = re.compile(r"^(?:import\s+\S|from\s+\S+\s+import\s)")
|
|
34
|
+
_ASSIGN_TARGET_RE_T = r"(?:^|[\s,(\[])%s\s*(?::[^=\n]*)?=(?!=)|\bfor\s+%s\b|\bas\s+%s\b|\b%s\s*:=|\bdef\s+\w+\([^)]*\b%s\b"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
38
|
+
# Editor-side helpers
|
|
39
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
def enclosing_def_line(text: str, cursor: int) -> int:
|
|
42
|
+
"""0-based buffer line of the nearest `def`/`class` at or above the
|
|
43
|
+
caret (-1 if none) — the stable-tier membership key's scope part."""
|
|
44
|
+
line = text.count("\n", 0, cursor)
|
|
45
|
+
lines = text.split("\n")
|
|
46
|
+
for i in range(min(line, len(lines) - 1), -1, -1):
|
|
47
|
+
if _DEF_LINE_RE.match(lines[i]):
|
|
48
|
+
return i
|
|
49
|
+
return -1
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def file_head_tail(text: str, address):
|
|
53
|
+
"""(head, tail): the PENDING file text before and after the editor
|
|
54
|
+
buffer `text` for the span at `address` (same splice convention as
|
|
55
|
+
libcst_conversion._full_file_context, so head + text + tail is the file
|
|
56
|
+
as a save would land it). ("", "") when there is no file context."""
|
|
57
|
+
try:
|
|
58
|
+
if (address is None or getattr(address, "path", None) is None
|
|
59
|
+
or getattr(address, "start", None) is None):
|
|
60
|
+
return "", ""
|
|
61
|
+
from meltygui.editor.pending_save import PendingSave
|
|
62
|
+
file_text = PendingSave.current_file_text(address.path)
|
|
63
|
+
if file_text is None:
|
|
64
|
+
return "", ""
|
|
65
|
+
lines = file_text.split("\n")
|
|
66
|
+
start = address.start
|
|
67
|
+
if not (0 <= start <= len(lines)):
|
|
68
|
+
return "", ""
|
|
69
|
+
end = address.end if address.end is not None else start
|
|
70
|
+
end = max(start, min(end, len(lines)))
|
|
71
|
+
buf = text[:-1] if text.endswith("\n") else text
|
|
72
|
+
head = "\n".join(lines[:start]) + ("\n" if start > 0 else "")
|
|
73
|
+
spliced = head + buf + (("\n" + "\n".join(lines[end:])) if lines[end:] else "")
|
|
74
|
+
return head, spliced[len(head) + len(text):]
|
|
75
|
+
except Exception:
|
|
76
|
+
return "", ""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def span_function(path, span_start: int):
|
|
80
|
+
"""The live function object whose def starts the span (the live-value
|
|
81
|
+
store owner), via the same resolver the markers use."""
|
|
82
|
+
if path is None:
|
|
83
|
+
return None
|
|
84
|
+
try:
|
|
85
|
+
from meltygui.code.chain_converters import _enclosing_function
|
|
86
|
+
return _enclosing_function(str(path), span_start + 1)
|
|
87
|
+
except Exception:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def language_of(path) -> str:
|
|
92
|
+
ext = os.path.splitext(str(path or ""))[1].lower()
|
|
93
|
+
return {".py": "python", ".js": "javascript", ".ts": "typescript", ".glsl": "glsl",
|
|
94
|
+
".frag": "glsl", ".vert": "glsl", ".cu": "cuda", ".md": "markdown",
|
|
95
|
+
".json": "json", ".toml": "toml", ".ini": "ini", ".sh": "bash"}.get(ext, "text")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def editor_view(text: str, cursor: int, address, fn=None) -> EditorView:
|
|
99
|
+
"""Build the EditorView for an editor buffer + its span address (cheap:
|
|
100
|
+
the whole-file split and the function resolve are lazy)."""
|
|
101
|
+
path = str(address.path) if address is not None and getattr(address, "path", None) else None
|
|
102
|
+
version = None
|
|
103
|
+
if path is not None:
|
|
104
|
+
try:
|
|
105
|
+
from meltygui.editor.text_editor import _pending_gen_of
|
|
106
|
+
version = _pending_gen_of(path)
|
|
107
|
+
except Exception:
|
|
108
|
+
version = None
|
|
109
|
+
return EditorView(path=path, text=text, cursor=cursor, address=address,
|
|
110
|
+
fn=fn, language=language_of(path), version=version)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
114
|
+
# Value summaries (live values) - strings only, the value is never stored
|
|
115
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
def _shorten(s: str, n: int) -> str:
|
|
118
|
+
s = s.replace("\n", "\\n")
|
|
119
|
+
return s if len(s) <= n else s[:n - 1] + "…"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def summarize_value(v, stats: bool = False, maxlen: int = 80) -> str:
|
|
123
|
+
"""One-line, cheap summary of a runtime value for the model. Tensors/
|
|
124
|
+
arrays report shape·dtype·device (stats — a GPU reduce — only when
|
|
125
|
+
asked); scalars/strings verbatim (truncated); containers by length and
|
|
126
|
+
a few members; anything else by type."""
|
|
127
|
+
try:
|
|
128
|
+
if v is None or isinstance(v, (bool, int, float, complex)):
|
|
129
|
+
return repr(v)
|
|
130
|
+
if isinstance(v, (str, bytes)):
|
|
131
|
+
return _shorten(repr(v), maxlen)
|
|
132
|
+
shape = getattr(v, "shape", None)
|
|
133
|
+
dtype = getattr(v, "dtype", None)
|
|
134
|
+
if shape is not None and dtype is not None:
|
|
135
|
+
try:
|
|
136
|
+
shp = ", ".join(str(int(d)) for d in tuple(shape))
|
|
137
|
+
except Exception:
|
|
138
|
+
shp = str(shape)
|
|
139
|
+
dt = str(dtype).replace("torch.", "")
|
|
140
|
+
dev = getattr(v, "device", None)
|
|
141
|
+
dev_s = f" {dev}" if dev is not None and str(dev) != "cpu" else ""
|
|
142
|
+
out = f"{type(v).__name__}[{shp}] {dt}{dev_s}"
|
|
143
|
+
if stats:
|
|
144
|
+
try:
|
|
145
|
+
numel = int(getattr(v, "numel", lambda: 0)() or getattr(v, "size", 0))
|
|
146
|
+
if 0 < numel <= 50_000_000 and "bool" not in dt:
|
|
147
|
+
f = v.float() if hasattr(v, "float") else v
|
|
148
|
+
out += f" min={float(f.min()):.3g} mean={float(f.mean()):.3g} max={float(f.max()):.3g}"
|
|
149
|
+
except Exception:
|
|
150
|
+
pass
|
|
151
|
+
return out
|
|
152
|
+
if isinstance(v, dict):
|
|
153
|
+
keys = list(v.keys())[:4]
|
|
154
|
+
ks = ", ".join(_shorten(repr(k), 16) for k in keys)
|
|
155
|
+
return f"dict[{len(v)}]" + (f" {{{ks}{', …' if len(v) > 4 else ''}}}" if keys else "")
|
|
156
|
+
if isinstance(v, (list, tuple, set, frozenset)):
|
|
157
|
+
items = list(v)[:3]
|
|
158
|
+
inner = ", ".join(_shorten(summarize_value(x, False, 24), 24) for x in items)
|
|
159
|
+
return f"{type(v).__name__}[{len(v)}]" + (f" [{inner}{', …' if len(v) > 3 else ''}]" if items else "")
|
|
160
|
+
return type(v).__name__
|
|
161
|
+
except Exception:
|
|
162
|
+
return type(v).__name__
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
166
|
+
# Sources
|
|
167
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
def _whole_file(view: EditorView) -> str:
|
|
170
|
+
return view.file_head + view.text + view.file_tail
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _word_set(text: str) -> set:
|
|
174
|
+
return set(re.findall(r"[A-Za-z_]\w*", text))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@fim_context_source("outline", tier="stable", order=10)
|
|
178
|
+
def outline_source(view: EditorView):
|
|
179
|
+
"""This file's imports (col-0 import/from lines, parenthesised
|
|
180
|
+
continuations included) — the names the model may use unqualified."""
|
|
181
|
+
if view.path is None:
|
|
182
|
+
return
|
|
183
|
+
lines = _whole_file(view).split("\n")
|
|
184
|
+
out = []
|
|
185
|
+
i = 0
|
|
186
|
+
while i < len(lines):
|
|
187
|
+
ln = lines[i]
|
|
188
|
+
if _IMPORT_RE.match(ln):
|
|
189
|
+
block = [ln]
|
|
190
|
+
if "(" in ln and ")" not in ln:
|
|
191
|
+
while i + 1 < len(lines) and ")" not in lines[i]:
|
|
192
|
+
i += 1
|
|
193
|
+
block.append(lines[i])
|
|
194
|
+
out.append("\n".join(block))
|
|
195
|
+
i += 1
|
|
196
|
+
if out:
|
|
197
|
+
yield ContextItem("outline", ("outline", view.path), "\n".join(out),
|
|
198
|
+
tier="stable", score=0.5, path=view.path, line=1,
|
|
199
|
+
version=view.version)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _table(view: EditorView):
|
|
203
|
+
"""(roster, FileTable) for the file: the roster's cached PENDING-text
|
|
204
|
+
table (content-free key, so repeated assemblies are free). The buffer's
|
|
205
|
+
last few unsaved keystrokes aren't in the table yet — fine, the chain
|
|
206
|
+
SCAN runs over the live buffer and resolves against it. Never the
|
|
207
|
+
roster's `live_text=` overlay: that re-parses the span alone and a
|
|
208
|
+
method loses its class parent. Falls back to a one-off parse of the
|
|
209
|
+
spliced file when the roster has no table for the path."""
|
|
210
|
+
import meltygui.code.symbol_roster as roster
|
|
211
|
+
tbl = getattr(view, "_table", None)
|
|
212
|
+
if tbl is None:
|
|
213
|
+
try:
|
|
214
|
+
tbl = roster.table_for(view.path)
|
|
215
|
+
except Exception:
|
|
216
|
+
tbl = None
|
|
217
|
+
if tbl is None:
|
|
218
|
+
tbl = roster.extract_table(view.path, _whole_file(view), with_tints=False)
|
|
219
|
+
view._table = tbl
|
|
220
|
+
return roster, tbl
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _window(view: EditorView, lines: int):
|
|
224
|
+
"""(start_char, end_char, start_line) of the ±`lines` window around the
|
|
225
|
+
caret — the only part of a huge buffer the per-request scans look at.
|
|
226
|
+
Found by newline walks, no full split."""
|
|
227
|
+
text = view.text
|
|
228
|
+
cur = view.cursor
|
|
229
|
+
ls = text.rfind("\n", 0, cur) + 1
|
|
230
|
+
start_line = view.caret_line
|
|
231
|
+
s = ls
|
|
232
|
+
for _ in range(lines):
|
|
233
|
+
if s <= 0:
|
|
234
|
+
break
|
|
235
|
+
s = text.rfind("\n", 0, s - 1) + 1
|
|
236
|
+
start_line -= 1
|
|
237
|
+
e = text.find("\n", cur)
|
|
238
|
+
e = len(text) if e < 0 else e + 1
|
|
239
|
+
for _ in range(lines):
|
|
240
|
+
if e >= len(text):
|
|
241
|
+
break
|
|
242
|
+
nxt = text.find("\n", e)
|
|
243
|
+
e = len(text) if nxt < 0 else nxt + 1
|
|
244
|
+
return s, e, max(0, start_line)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@fim_context_source("enclosing", tier="stable", order=20)
|
|
248
|
+
def enclosing_source(view: EditorView):
|
|
249
|
+
"""Skeleton of the class enclosing the span's first def — class vars and
|
|
250
|
+
sibling method signatures — so `self.` completions see the surface."""
|
|
251
|
+
if view.path is None:
|
|
252
|
+
return
|
|
253
|
+
try:
|
|
254
|
+
roster, tbl = _table(view)
|
|
255
|
+
except Exception:
|
|
256
|
+
return
|
|
257
|
+
if tbl is None:
|
|
258
|
+
return
|
|
259
|
+
first = view.span_start + 1
|
|
260
|
+
scope = tbl.scope_at(first + 1) or tbl.scope_at(first)
|
|
261
|
+
cls_q = tbl.enclosing_class(scope) if scope is not None else None
|
|
262
|
+
if cls_q is None:
|
|
263
|
+
return
|
|
264
|
+
cls = tbl.by_qualname.get(cls_q)
|
|
265
|
+
if cls is None:
|
|
266
|
+
return
|
|
267
|
+
src = roster.file_text(view.path).split("\n")
|
|
268
|
+
rows = [src[cls.line - 1].rstrip() if 0 < cls.line <= len(src) else f"class {cls.name}:"]
|
|
269
|
+
own_q = scope.qualname if scope is not None else None
|
|
270
|
+
for e in tbl.entries:
|
|
271
|
+
if e.parent != cls_q or e.qualname == own_q:
|
|
272
|
+
continue
|
|
273
|
+
if e.kind == "var":
|
|
274
|
+
if 0 < e.line <= len(src):
|
|
275
|
+
rows.append(" " + src[e.line - 1].strip())
|
|
276
|
+
else:
|
|
277
|
+
sig = e.sig or (src[e.line - 1].strip() if 0 < e.line <= len(src) else f"def {e.name}(...)")
|
|
278
|
+
rows.append(" " + sig.strip().rstrip(":") + ": ...")
|
|
279
|
+
if len(rows) > 1:
|
|
280
|
+
yield ContextItem("enclosing", ("enclosing", view.path, cls_q), "\n".join(rows),
|
|
281
|
+
tier="stable", score=2.0, path=view.path, line=cls.line,
|
|
282
|
+
end=cls.end, version=view.version)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@fim_context_source("definition", tier="stable", order=30)
|
|
286
|
+
def definition_source(view: EditorView):
|
|
287
|
+
"""Source of every definition the span references, resolved textually
|
|
288
|
+
through the roster (pending truth, closures/self./imports honoured).
|
|
289
|
+
Definitions referenced on the caret line go to the volatile tier; the
|
|
290
|
+
rest are stable. `data` carries the signature line for budget
|
|
291
|
+
degradation."""
|
|
292
|
+
if view.path is None:
|
|
293
|
+
return
|
|
294
|
+
try:
|
|
295
|
+
roster, tbl = _table(view)
|
|
296
|
+
except Exception:
|
|
297
|
+
return
|
|
298
|
+
if tbl is None:
|
|
299
|
+
return
|
|
300
|
+
from meltygui.core.runtime.toggles import Toggles
|
|
301
|
+
text = view.text
|
|
302
|
+
caret_line = view.caret_line
|
|
303
|
+
own_lo = view.span_start + 1
|
|
304
|
+
own_hi = view.span_start + text.count("\n") + 1
|
|
305
|
+
# Scan only a window around the caret (a whole-file buffer has
|
|
306
|
+
# thousands of chains; each resolve is a roster walk), and resolve each
|
|
307
|
+
# unique (chain, scope) once - a window sees the same names a lot.
|
|
308
|
+
ws, we, wline = _window(view, Toggles.Fim.scan_lines)
|
|
309
|
+
occurrences = {} # (chain, scope qualname) -> [scope, count, best_prox, on_caret]
|
|
310
|
+
ln = wline
|
|
311
|
+
pos = ws
|
|
312
|
+
for s, e, chain in roster.iter_chains(text, ws, we):
|
|
313
|
+
ln += text.count("\n", pos, s)
|
|
314
|
+
pos = s
|
|
315
|
+
if chain in _SKIP_CHAINS:
|
|
316
|
+
continue
|
|
317
|
+
sc = tbl.scope_at(ln + 1 + view.span_start)
|
|
318
|
+
k = (chain, sc.qualname if sc is not None else None)
|
|
319
|
+
prox = abs(ln - caret_line)
|
|
320
|
+
o = occurrences.get(k)
|
|
321
|
+
if o is None:
|
|
322
|
+
occurrences[k] = [sc, 1, prox, ln == caret_line]
|
|
323
|
+
else:
|
|
324
|
+
o[1] += 1
|
|
325
|
+
o[2] = min(o[2], prox)
|
|
326
|
+
o[3] = o[3] or ln == caret_line
|
|
327
|
+
hits = {} # ident -> [entry, count, best_prox, on_caret_line]
|
|
328
|
+
for (chain, _sq), (sc, count, prox, on_caret) in occurrences.items():
|
|
329
|
+
try:
|
|
330
|
+
res = roster.resolve_prefixes(view.path, chain, tbl, scope=sc)
|
|
331
|
+
except Exception:
|
|
332
|
+
continue
|
|
333
|
+
if not res:
|
|
334
|
+
continue
|
|
335
|
+
ent, _n = res[-1]
|
|
336
|
+
if ent.path == view.path and own_lo <= ent.line <= own_hi:
|
|
337
|
+
continue # defined inside the span itself
|
|
338
|
+
h = hits.get(ent.ident)
|
|
339
|
+
if h is None:
|
|
340
|
+
hits[ent.ident] = [ent, count, prox, on_caret]
|
|
341
|
+
else:
|
|
342
|
+
h[1] += count
|
|
343
|
+
h[2] = min(h[2], prox)
|
|
344
|
+
h[3] = h[3] or on_caret
|
|
345
|
+
max_lines = Toggles.Fim.definition_max_lines
|
|
346
|
+
for ident, (ent, count, prox, on_caret) in hits.items():
|
|
347
|
+
try:
|
|
348
|
+
src = roster.file_text(ent.path).split("\n")
|
|
349
|
+
except Exception:
|
|
350
|
+
continue
|
|
351
|
+
lo, hi = ent.line - 1, max(ent.line, ent.end)
|
|
352
|
+
if not (0 <= lo < len(src)):
|
|
353
|
+
continue
|
|
354
|
+
block = src[lo:hi]
|
|
355
|
+
sig = (ent.sig or block[0]).strip()
|
|
356
|
+
if len(block) > max_lines:
|
|
357
|
+
block = block[:max_lines] + [" ..."]
|
|
358
|
+
score = count * (4.0 if on_caret else 2.0 if prox <= 3 else 1.0)
|
|
359
|
+
score *= {"class": 1.2, "def": 1.0, "var": 0.6}.get(ent.kind, 1.0)
|
|
360
|
+
yield ContextItem("definition", ("definition", ent.path, ent.qualname),
|
|
361
|
+
"\n".join(block), tier="volatile" if on_caret else "stable",
|
|
362
|
+
score=score, path=ent.path, line=ent.line, end=hi,
|
|
363
|
+
version=view.version, data=sig)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@fim_context_source("runtime_types", tier="stable", order=40)
|
|
367
|
+
def runtime_types_source(view: EditorView):
|
|
368
|
+
"""Observed runtime types of the span's names (FuncsMetadata) — tells
|
|
369
|
+
the model what un-annotated params are."""
|
|
370
|
+
if view.fn is None:
|
|
371
|
+
return
|
|
372
|
+
try:
|
|
373
|
+
from meltygui.core.rendering.func_metadata import FuncsMetadata
|
|
374
|
+
from meltygui.core.rendering.func_metadata import _meta_key
|
|
375
|
+
slot = FuncsMetadata.metadata.get(_meta_key(view.fn))
|
|
376
|
+
except Exception:
|
|
377
|
+
return
|
|
378
|
+
if not slot:
|
|
379
|
+
return
|
|
380
|
+
from meltygui.core.runtime.toggles import Toggles
|
|
381
|
+
ws, we, _ = _window(view, Toggles.Fim.scan_lines)
|
|
382
|
+
words = _word_set(view.text[ws:we])
|
|
383
|
+
rows = []
|
|
384
|
+
for name in sorted(slot):
|
|
385
|
+
if name not in words or name.startswith("__"):
|
|
386
|
+
continue
|
|
387
|
+
meta = slot[name]
|
|
388
|
+
t = getattr(meta, "type", None)
|
|
389
|
+
if t is None:
|
|
390
|
+
continue
|
|
391
|
+
mod = getattr(t, "__module__", "") or ""
|
|
392
|
+
tn = t.__name__ if mod in ("builtins", "") else f"{mod.rsplit('.', 1)[-1]}.{t.__name__}"
|
|
393
|
+
rows.append(f"{name}: {tn}")
|
|
394
|
+
if rows:
|
|
395
|
+
q = getattr(view.fn, "__qualname__", "?")
|
|
396
|
+
yield ContextItem("runtime_types", ("runtime_types", view.path, q),
|
|
397
|
+
"# observed at runtime:\n# " + ", ".join(rows),
|
|
398
|
+
tier="stable", score=3.0, path=view.path, version=view.version)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _parse_live_key(key_path):
|
|
402
|
+
"""(line, name) from a store key whose tail is `line:N#name`."""
|
|
403
|
+
tail = key_path[-1] if isinstance(key_path, tuple) and key_path else key_path
|
|
404
|
+
if not isinstance(tail, str) or not tail.startswith("line:"):
|
|
405
|
+
return None, None
|
|
406
|
+
body = tail[5:]
|
|
407
|
+
num, _, name = body.partition("#")
|
|
408
|
+
try:
|
|
409
|
+
return int(num), (name or None)
|
|
410
|
+
except ValueError:
|
|
411
|
+
return None, None
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def _binding_line(lines, name, guess, radius=25):
|
|
415
|
+
"""Nearest buffer line to `guess` that binds `name` (assignment / for /
|
|
416
|
+
with-as / walrus / def param), or None."""
|
|
417
|
+
if not name:
|
|
418
|
+
return None
|
|
419
|
+
pat = re.compile(_ASSIGN_TARGET_RE_T % ((re.escape(name),) * 5))
|
|
420
|
+
best = None
|
|
421
|
+
for d in range(radius + 1):
|
|
422
|
+
for cand in (guess - d, guess + d) if d else (guess,):
|
|
423
|
+
if 0 <= cand < len(lines) and pat.search(lines[cand]):
|
|
424
|
+
return cand
|
|
425
|
+
return best
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
@fim_context_source("live_values", tier="run", order=50)
|
|
429
|
+
def live_values_source(view: EditorView):
|
|
430
|
+
"""Values from the LAST RUN of the span's function (`__live_values__`,
|
|
431
|
+
`line:N#name` keys), summarized and anchored to the buffer line that
|
|
432
|
+
binds the name. `data` = {buffer line: summary} for inline
|
|
433
|
+
annotation; `text` = the same as a block for providers that can't
|
|
434
|
+
inline. Values are summarized on the spot and never retained."""
|
|
435
|
+
if view.fn is None:
|
|
436
|
+
return
|
|
437
|
+
from meltygui.core.runtime.toggles import Toggles
|
|
438
|
+
try:
|
|
439
|
+
from meltygui.code.live_view import live_values_for
|
|
440
|
+
store = live_values_for(view.fn)
|
|
441
|
+
except Exception:
|
|
442
|
+
return
|
|
443
|
+
if not store:
|
|
444
|
+
return
|
|
445
|
+
try:
|
|
446
|
+
import inspect as _inspect
|
|
447
|
+
labels = getattr(_inspect.unwrap(view.fn), "__live_labels__", None) or {}
|
|
448
|
+
except Exception:
|
|
449
|
+
labels = {}
|
|
450
|
+
lines = view.text.split("\n")
|
|
451
|
+
delta = 0
|
|
452
|
+
try:
|
|
453
|
+
from meltygui.editor.text_editor import _pending_line_delta
|
|
454
|
+
delta = _pending_line_delta(view.path, view.span_start) if view.path else 0
|
|
455
|
+
except Exception:
|
|
456
|
+
delta = 0
|
|
457
|
+
found = {}
|
|
458
|
+
for key_path, value in store.items():
|
|
459
|
+
disk_line, name = _parse_live_key(key_path)
|
|
460
|
+
if disk_line is None:
|
|
461
|
+
continue
|
|
462
|
+
name = labels.get(key_path, name) or name
|
|
463
|
+
guess = disk_line - 1 + delta - view.span_start
|
|
464
|
+
bl = _binding_line(lines, name, guess)
|
|
465
|
+
if bl is None:
|
|
466
|
+
continue
|
|
467
|
+
summary = summarize_value(value, stats=Toggles.Fim.live_value_stats)
|
|
468
|
+
prev = found.get(bl)
|
|
469
|
+
entry = f"{name} = {summary}" if name else summary
|
|
470
|
+
found[bl] = entry if prev is None else f"{prev}; {entry}"
|
|
471
|
+
del store
|
|
472
|
+
if not found:
|
|
473
|
+
return
|
|
474
|
+
caret = view.caret_line
|
|
475
|
+
keep = sorted(found, key=lambda bl: abs(bl - caret))[:Toggles.Fim.live_values_max]
|
|
476
|
+
data = {bl: found[bl] for bl in sorted(keep)}
|
|
477
|
+
text = "# values from the last run:\n" + "\n".join(
|
|
478
|
+
f"# L{bl + 1}: {s}" for bl, s in data.items())
|
|
479
|
+
q = getattr(view.fn, "__qualname__", "?")
|
|
480
|
+
yield ContextItem("live_values", ("live_values", view.path, q), text,
|
|
481
|
+
tier="run", score=3.0, path=view.path, data=data)
|
|
File without changes
|