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,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