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