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,355 @@
1
+ """Terminal view functions and supporting definitions."""
2
+ from meltygui.core.services.terminal_runtime import TerminalRuntime
3
+ from meltygui.model.terminal_model import Terminal
4
+ from meltygui.core.core_render import render_func
5
+ from meltygui.state.terminal_state import TerminalScreenState
6
+ from meltygui.core.runtime.toggles import Toggles
7
+ import meltygui_imgui as imgui
8
+ import re
9
+ from meltygui.hdr_color import pack_color
10
+ from meltygui.core.styling.fonts import Font
11
+ from meltygui.state.terminal_state import _norm
12
+
13
+
14
+ _COL_ERR = (1.0, 0.45, 0.40)
15
+
16
+
17
+ _PALETTE = {
18
+ 'black': (0.0, 0.0, 0.0), 'red': (0.86, 0.30, 0.30), 'green': (0.34, 0.78, 0.40),
19
+ 'brown': (0.80, 0.66, 0.28), 'blue': (0.38, 0.56, 0.94), 'magenta': (0.83, 0.46, 0.83),
20
+ 'cyan': (0.33, 0.80, 0.86), 'white': (0.85, 0.85, 0.85),
21
+ 'brightblack': (0.46, 0.48, 0.52), 'brightred': (1.0, 0.46, 0.43),
22
+ 'brightgreen': (0.52, 0.92, 0.54), 'brightbrown': (0.96, 0.86, 0.42),
23
+ 'brightblue': (0.56, 0.70, 1.0), 'brightmagenta': (0.96, 0.62, 0.96),
24
+ 'brightcyan': (0.56, 0.93, 0.96), 'brightwhite': (1.0, 1.0, 1.0),
25
+ }
26
+
27
+
28
+ _DEFAULT_FG = (0.85, 0.85, 0.85)
29
+
30
+
31
+ _DEFAULT_BG = None # None == transparent, let the window background show through
32
+
33
+
34
+ _SEL_COLOR = pack_color(51 / 255, 102 / 255, 204 / 255, 102 / 255) # pale blue wash
35
+
36
+
37
+ def _pack(rgb, alpha=255):
38
+ return pack_color(rgb[0], rgb[1], rgb[2], alpha / 255.0)
39
+
40
+
41
+ def _resolve(name, default, bold=False):
42
+ if name in (None, 'default'):
43
+ rgb = default
44
+ elif name in _PALETTE:
45
+ rgb = _PALETTE[name]
46
+ elif isinstance(name, str) and len(name) == 6:
47
+ try:
48
+ rgb = (int(name[0:2], 16) / 255, int(name[2:4], 16) / 255, int(name[4:6], 16) / 255)
49
+ except ValueError:
50
+ rgb = default
51
+ else:
52
+ rgb = default
53
+ if bold and rgb is not None:
54
+ rgb = tuple(min(1.0, c * 1.25 + 0.08) for c in rgb)
55
+ return rgb
56
+
57
+
58
+ def _wheel_lines(visible_px, line_px):
59
+ """Lines to scroll per wheel tick, from the global Toggles scroll settings — the
60
+ same pixel model core_render uses (`scroll_speed` px, capped to a fraction of the
61
+ visible height so small views don't overshoot), converted to lines."""
62
+ px = min(Toggles.ScrollSettings.scroll_speed,
63
+ Toggles.ScrollSettings.max_increment_fraction
64
+ * max(1.0, visible_px))
65
+ return max(1, int(round(px / max(1.0, line_px))))
66
+
67
+
68
+ def _row_blank(line, ncols):
69
+ return all(line[x].data in (' ', '', '\x00') for x in range(ncols))
70
+
71
+
72
+ _LINK_RE = re.compile(
73
+ r'File "(?P<p1>[^"\n]+)", line (?P<l1>\d+)'
74
+ r'|(?<![\w./~-])(?P<p2>(?:/|~/|\./|\.\./)[^\s:"\'\)\],]+\.[A-Za-z0-9_]+):(?P<l2>\d+)')
75
+
76
+
77
+ _LINK_COLOR = pack_color(110 / 255, 180 / 255, 1.0, 200 / 255) # underline (cyan-blue)
78
+
79
+
80
+ _LINK_HOVER_COLOR = pack_color(170 / 255, 235 / 255, 1.0, 1.0) # brighter on hover
81
+
82
+
83
+ def _find_links(grid, scols):
84
+ """Scan the visible grid for file:line references, joining wrapped rows so a path
85
+ split across the terminal width still matches. Returns [(path, line, segments)]
86
+ where segments is [(row, col_start, col_end)] (a link can span wrapped rows)."""
87
+ if not grid:
88
+ return []
89
+ # Flatten visible rows into one string + a char ->-(row,col) origin map, NOT
90
+ # inserting a newline where a row wrapped (pyte fills the next row when it wraps).
91
+ parts, origins = [], []
92
+ for r, row in enumerate(grid):
93
+ text = "".join((c[0] or ' ') for c in row)
94
+ end = len(text.rstrip())
95
+ for c in range(end):
96
+ parts.append(text[c])
97
+ origins.append((r, c))
98
+ wrapped = scols > 0 and row[scols - 1][0] not in (' ', '', '\x00')
99
+ if not wrapped:
100
+ parts.append('\n')
101
+ origins.append((r, end))
102
+ text = "".join(parts)
103
+
104
+ links = []
105
+ for m in _LINK_RE.finditer(text):
106
+ if m.group('p1') is not None:
107
+ path, line = m.group('p1'), int(m.group('l1'))
108
+ else:
109
+ path, line = m.group('p2'), int(m.group('l2'))
110
+ by_row = {}
111
+ for (r, c) in origins[m.start():m.end()]:
112
+ lo, hi = by_row.get(r, (c, c))
113
+ by_row[r] = (min(lo, c), max(hi, c))
114
+ segments = [(r, lo, hi + 1) for r, (lo, hi) in sorted(by_row.items())]
115
+ links.append((path, line, segments))
116
+ return links
117
+
118
+
119
+
120
+ @render_func(is_default_for=(Terminal), show_bg=False, show_header=False, show_name=False, is_tree=False,
121
+ selectable=False, disable_scroll=True, initial={"closed": False})
122
+ def draw_terminal_screen(input_value: Terminal, draw_state, view_state: TerminalScreenState,
123
+ left_mouse_down=False, left_mouse_drag=False, left_mouse_held=False,
124
+ left_mouse_clicked=False, cursor_moved=None,
125
+ cursor_hover_exit=None, scroll_y_changed=None,
126
+ terminal_runtime: TerminalRuntime = None, font_manager=None):
127
+ from meltygui.core.services.terminal_core import _ALT_SCREEN_MODES
128
+ from meltygui.core.services.terminal_core import _MOUSE_MODES
129
+ from meltygui.core.services.terminal_core import _TMUX_WHEEL_LINES
130
+ from meltygui.core.services.terminal_core import _mouse_seq
131
+
132
+ term, ds, vs = input_value, draw_state, view_state
133
+ left, top, right, bottom = ds.abs_left, ds.abs_top, ds.abs_left + ds.width, ds.abs_top+ ds.height
134
+ pad = 4.0
135
+
136
+ font = font_manager.get(Font.JETBRAINS_MONO_19) if font_manager else None
137
+ pushed = font is not None
138
+ if pushed:
139
+ imgui.push_font(font)
140
+ try:
141
+ char_w, line_px = max(1.0, imgui.calc_text_size("0").x), imgui.get_text_line_height() * 1.25
142
+ x0, y0 = left + pad, top + pad
143
+ # Logical terminal size is the available body, but never SMALLER than the
144
+ # configured minimum (Toggles.TerminalSettings, in px). Below that floor the PTY
145
+ # grid stays frozen at the minimum - line wrapping stops re-flowing - and the
146
+ # clip is pushed before the draw call crops any overflow instead of rewrapping
147
+ # to an unusably narrow grid.
148
+ avail_w = max(right - left - 2 * pad,
149
+ Toggles.TerminalSettings.min_width)
150
+ avail_h = max(bottom - top - 2 * pad,
151
+ Toggles.TerminalSettings.min_height)
152
+ cols = max(2, int(avail_w / char_w))
153
+ rows = max(2, int(avail_h / line_px))
154
+
155
+ terminal_runtime.prepare(term, cols, rows)
156
+ if term.error:
157
+ imgui.set_cursor_screen_pos((x0, y0))
158
+ imgui.text_colored(term.error, _COL_ERR[0], _COL_ERR[1], _COL_ERR[2], 1.0)
159
+ return False, term
160
+ # start() now spawns the PTY on a bg thread, so screen is None until it's wired.
161
+ # Show a placeholder and bail (the reader invalidates this tile when ready).
162
+ if term.screen is None:
163
+ imgui.set_cursor_screen_pos((x0, y0))
164
+ imgui.text_colored("starting…", 0.55, 0.55, 0.55, 1.0)
165
+ return False, term
166
+ is_focused = terminal_runtime.focused
167
+ for event in (cursor_moved, scroll_y_changed, left_mouse_down,
168
+ left_mouse_drag, left_mouse_held, left_mouse_clicked):
169
+ if event:
170
+ vs.pointer = (event.x, event.y)
171
+ if cursor_hover_exit:
172
+ vs.pointer = None
173
+ mouse_x, mouse_y = vs.pointer if vs.pointer is not None else (-1e9, -1e9)
174
+ wheel = scroll_y_changed.value if scroll_y_changed else 0
175
+
176
+ srows, scols, cursor, modes, hist, buf_rows = term.snapshot()
177
+ cur_x, cur_y, cur_hidden = cursor
178
+
179
+ # When the grid is taller than the window body (window dragged below min_height,
180
+ # so `rows` are frozen), crop from the TOP rather than the BOTTOM: shift the
181
+ # origin up so the last grid rows - the live prompt + cursor - stay pinned to the
182
+ # window's bottom edge, and the blank rows above slide out of the clip. No
183
+ # overflow -> the min() keeps the normal top-anchored origin.
184
+ y0 = min(top + pad, (bottom - pad) - srows * line_px)
185
+
186
+ # Compose history-above + the live screen. We read history.top directly rather
187
+ # than driving pyte's pop_page/next_page, which rewrites the live screen and
188
+ # corrupts both scrollback and the program (the "mangled off-screen text").
189
+ all_lines = hist + buf_rows
190
+ total = len(all_lines)
191
+
192
+ # Growing the window makes pyte pad blank rows at the BOTTOM of the buffer,
193
+ # leaving the prompt floating above a big empty block. Outside the alternate
194
+ # screen, anchor the view's bottom to the last content row and pull scrollback
195
+ # up to fill it, so the prompt stays pinned to the bottom like a real terminal.
196
+ # In the alternate screen (vim, Claude) the program owns the grid - leave it.
197
+ trailing = 0
198
+ if not (_ALT_SCREEN_MODES & modes):
199
+ for line in reversed(buf_rows):
200
+ if _row_blank(line, scols):
201
+ trailing += 1
202
+ else:
203
+ break
204
+ content_bottom = total - 1 - trailing
205
+ max_scroll = max(0, content_bottom - srows + 1)
206
+
207
+ # Hold the viewport steady when output grows while the user is scrolled up.
208
+ if vs.last_total is not None and total > vs.last_total and vs.scroll > 0:
209
+ vs.scroll += total - vs.last_total
210
+ vs.last_total = total
211
+ over = left <= mouse_x <= right and top <= mouse_y <= bottom
212
+ if over and wheel:
213
+ lines = _wheel_lines(bottom - top, line_px) # speed = Toggles.ScrollSettings
214
+ if (_MOUSE_MODES & modes) and (_ALT_SCREEN_MODES & modes):
215
+ # Forward the wheel to the program ONLY when it's an ALT-SCREEN program
216
+ # that owns the grid (vim/Claude/emacs) - it has its own scrollback and
217
+ # our pyte history is unused there. Crucially NOT for a plain shell under
218
+ # tmux `mouse on`: forwarding a wheel-up there makes tmux enter copy-mode
219
+ # (`[0/0]` when there's no content selection) and swallow keystrokes on copy-mode
220
+ # nav - "can't copy" when you press q. A plain shell falls to the else
221
+ # branch and scrolls OUR pyte history instead (clipped, so a no-log
222
+ # terminal simply doesn't scroll). Button 64 = wheel up, 65 = wheel down;
223
+ # tmux scrolls _TMUX_WHEEL_LINES per escape, so send enough to hit `lines`.
224
+ col = max(0, min(int((mouse_x - x0) / char_w), scols - 1))
225
+ row = max(0, min(int((mouse_y - y0) / line_px), srows - 1))
226
+ btn = 64 if wheel > 0 else 65
227
+ ticks = abs(int(round(wheel))) or 1
228
+ for _ in range(ticks * max(1, round(lines / _TMUX_WHEEL_LINES))):
229
+ term.write(_mouse_seq(modes, btn, col, row))
230
+ else:
231
+ vs.scroll += int(round(wheel * lines))
232
+ vs.scroll = max(0, min(vs.scroll, max_scroll))
233
+ at_bottom = vs.scroll == 0
234
+
235
+ start = max(0, content_bottom - vs.scroll - srows + 1)
236
+ visible = all_lines[start:start + srows]
237
+ cursor_vy = (len(hist) + cur_y) - start # cursor's row within the visible window
238
+ grid = [[(line[x].data, line[x].fg, line[x].bg, line[x].bold, line[x].reverse)
239
+ for x in range(scols)] for line in visible]
240
+
241
+ # Clickable file:line links in the visible text (underlined, click to jump).
242
+ links = _find_links(grid, scols)
243
+ hovered_link = None
244
+ if over:
245
+ hc = int((mouse_x - x0) / char_w)
246
+ hr = int((mouse_y - y0) / line_px)
247
+ for i, (_p, _l, segs) in enumerate(links):
248
+ if any(r == hr and lo_c <= hc < hi_c for (r, lo_c, hi_c) in segs):
249
+ hovered_link = i
250
+ break
251
+
252
+
253
+ # Per-row printed width (columns up to the last non-blank cell) and the last
254
+ # row with any content. Selection clamps to these so a drag can't run off
255
+ # the prompt into the empty area below, or past the text on a line.
256
+ row_len = [next((i + 1 for i in range(len(row) - 1, -1, -1)
257
+ if row[i][0] not in (' ', '', '\x00')), 0)
258
+ for row in grid]
259
+ last_row = max((y for y in range(len(grid)) if row_len[y] > 0), default=0)
260
+
261
+ def xy_to_rc(px, py):
262
+ r = max(0, min(int((py - y0) / line_px), last_row))
263
+ c = max(0, min(int((px - x0) / char_w), row_len[r] if r < len(row_len) else 0))
264
+ return (r, c)
265
+
266
+ # --- mouse: focus + drag select (selection is ours, not sent to the program) ---
267
+ if left_mouse_down:
268
+ terminal_runtime.focus()
269
+ is_focused = True
270
+ vs.sel_anchor = vs.sel_active = xy_to_rc(mouse_x, mouse_y)
271
+ if (left_mouse_drag or left_mouse_held) and vs.sel_anchor is not None:
272
+ mx = left_mouse_drag.x if left_mouse_drag else mouse_x
273
+ my = left_mouse_drag.y if left_mouse_drag else mouse_y
274
+ vs.sel_active = xy_to_rc(mx, my)
275
+
276
+ # A plain click (no drag) on a link -> jump to it in the IDE, off-thread like
277
+ # draw_text's jump button. `left_mouse_clicked` fires only on click, not drag,
278
+ # so this never fights with selection.
279
+ if left_mouse_clicked:
280
+ cc = int((mouse_x - x0) / char_w)
281
+ cr = int((mouse_y - y0) / line_px)
282
+ for path, line, segments in links:
283
+ if any(r == cr and lo <= cc < hi for (r, lo, hi) in segments):
284
+ terminal_runtime.open_link(path, line)
285
+ break
286
+
287
+ terminal_runtime.forward_keys(term, vs)
288
+
289
+ # --- render: per-row style runs, selection highlight, block cursor ---
290
+ # Clip to the body rect: when the grid is frozen at the min-size (window dragged
291
+ # below min_width/min_height) the PTY is larger than the window, so the grid can
292
+ # overrun the shrinking window - the clip keeps it from painting over neighbouring
293
+ # windows.
294
+ lo, hi = _norm(vs.sel_anchor, vs.sel_active)
295
+ dl = imgui.get_window_draw_list()
296
+ dl.push_clip_rect(left, top, right, bottom, True)
297
+ for y, row in enumerate(grid):
298
+ ry = y0 + y * line_px
299
+ # selection highlight, clamped to this row's printed width so trailing
300
+ # blanks (and empty rows) don't get washed.
301
+ if lo is not None and lo != hi and lo[0] <= y <= hi[0]:
302
+ cs = lo[1] if y == lo[0] else 0
303
+ ce = hi[1] if y == hi[0] else row_len[y]
304
+ ce = min(ce, row_len[y])
305
+ if ce > cs:
306
+ dl.add_rect_filled(x0 + cs * char_w, ry, x0 + ce * char_w, ry + line_px, _SEL_COLOR)
307
+ x = 0
308
+ while x < len(row):
309
+ style = row[x][1:]
310
+ j = x + 1
311
+ while j < len(row) and row[j][1:] == style:
312
+ j += 1
313
+ data, fg, bg, bold, rev = row[x]
314
+ if rev:
315
+ fg, bg = bg, fg
316
+ bgc = _resolve(bg, _DEFAULT_BG)
317
+ if bgc is not None:
318
+ dl.add_rect_filled(x0 + x * char_w, ry, x0 + j * char_w, ry + line_px, _pack(bgc))
319
+ seg = "".join(c[0] for c in row[x:j])
320
+ if seg.strip():
321
+ dl.add_text(x0 + x * char_w, ry, _pack(_resolve(fg, _DEFAULT_FG, bold)), seg)
322
+ x = j
323
+
324
+ # Underline clickable file:line links so they read as actionable; the link
325
+ # under the mouse gets a brighter, thicker underline.
326
+ for i, (_p, _l, segments) in enumerate(links):
327
+ hot = i == hovered_link
328
+ lc, th = (_LINK_HOVER_COLOR, 2.0) if hot else (_LINK_COLOR, 1.0)
329
+ for (r, lo_c, hi_c) in segments:
330
+ uy = y0 + r * line_px + line_px - 1.0
331
+ dl.add_line(x0 + lo_c * char_w, uy, x0 + hi_c * char_w, uy, lc, th)
332
+
333
+ if is_focused and at_bottom and not cur_hidden and 0 <= cursor_vy < srows:
334
+ cx, cy = x0 + cur_x * char_w, y0 + cursor_vy * line_px
335
+ dl.add_rect_filled(cx, cy, cx + char_w, cy + line_px, 0x88FFFFFF)
336
+ dl.pop_clip_rect()
337
+ finally:
338
+ if pushed:
339
+ imgui.pop_font()
340
+
341
+ return False, term
342
+
343
+
344
+ @render_func(is_default_for=Terminal)
345
+ def draw_terminal(input_value: Terminal, draw_state):
346
+ from meltygui.core.services.terminal_core import _draw_terminal_window
347
+
348
+ return _draw_terminal_window(input_value, draw_state, "terminal_screen")
349
+
350
+
351
+ @render_func
352
+ def draw_session_terminal(input_value: Terminal, draw_state, max_bg_value=0.064):
353
+ from meltygui.core.services.terminal_core import _draw_terminal_window
354
+
355
+ return _draw_terminal_window(input_value, draw_state, "session_screen")