Full Code of marlocarlo/psmux for AI

master 9ed1f48e8250 cached
576 files
7.9 MB
2.1M tokens
3943 symbols
1 requests
Download .txt
Showing preview only (8,619K chars total). Download the full file or copy to clipboard to get everything.
Repository: marlocarlo/psmux
Branch: master
Commit: 9ed1f48e8250
Files: 576
Total size: 7.9 MB

Directory structure:
gitextract_ld4ke3i2/

├── .cargo/
│   └── config.toml
├── .github/
│   ├── ASSETS.md
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── choco-pkg/
│   ├── psmux.nuspec
│   └── tools/
│       ├── chocolateyinstall.ps1
│       └── chocolateyuninstall.ps1
├── crates/
│   ├── portable-pty-psmux/
│   │   ├── .cargo-ok
│   │   ├── .cargo_vcs_info.json
│   │   ├── Cargo.toml
│   │   ├── Cargo.toml.orig
│   │   ├── LICENSE.md
│   │   ├── README.md
│   │   ├── examples/
│   │   │   ├── bash.rs
│   │   │   ├── narrow.rs
│   │   │   ├── whoami.rs
│   │   │   └── whoami_async.rs
│   │   └── src/
│   │       ├── cmdbuilder.rs
│   │       ├── lib.rs
│   │       ├── serial.rs
│   │       ├── unix.rs
│   │       └── win/
│   │           ├── conpty.rs
│   │           ├── mod.rs
│   │           ├── procthreadattr.rs
│   │           └── psuedocon.rs
│   └── vt100-psmux/
│       ├── .cargo-ok
│       ├── .cargo_vcs_info.json
│       ├── CHANGELOG.md
│       ├── Cargo.toml
│       ├── Cargo.toml.orig
│       ├── LICENSE
│       ├── README.md
│       └── src/
│           ├── attrs.rs
│           ├── callbacks.rs
│           ├── cell.rs
│           ├── grid.rs
│           ├── lib.rs
│           ├── parser.rs
│           ├── perform.rs
│           ├── row.rs
│           ├── screen.rs
│           └── term.rs
├── docker/
│   ├── Dockerfile
│   ├── Profile/
│   │   └── Microsoft.PowerShell_profile.ps1
│   ├── README.md
│   ├── Run-PsmuxDev.ps1
│   └── Tools/
│       ├── ImportVsDevEnv.ps1
│       ├── InstallAll.ps1
│       ├── InstallGit.ps1
│       ├── InstallOpenSSH.ps1
│       ├── InstallRust.ps1
│       ├── InstallVsBuildTools.ps1
│       └── StartContainer.ps1
├── docs/
│   ├── claude-code.md
│   ├── compatibility.md
│   ├── configuration.md
│   ├── control-mode.md
│   ├── faq.md
│   ├── features.md
│   ├── integration.md
│   ├── iterm2-control-mode.md
│   ├── keybindings.md
│   ├── mouse-ssh.md
│   ├── multi-shell.md
│   ├── pane-titles.md
│   ├── performance.md
│   ├── plugins.md
│   ├── preview.md
│   ├── scripting.md
│   ├── tmux_args_reference.md
│   └── warm-sessions.md
├── examples/
│   ├── crossterm_sgr_diag.rs
│   ├── enter_diag.rs
│   ├── key_diag.rs
│   ├── key_test.rs
│   ├── latency_harness.rs
│   ├── pipeline_diag.rs
│   ├── pty_diag.rs
│   ├── pty_sgr_diag.rs
│   ├── ratatui_render_diag.rs
│   └── test_cursor_debug.rs
├── installer/
│   └── psmux.nsi
├── packages/
│   └── chocolatey/
│       ├── psmux.nuspec
│       └── tools/
│           ├── chocolateyinstall.ps1
│           └── chocolateyuninstall.ps1
├── psmux.json
├── rust-toolchain.toml
├── scoop/
│   └── psmux.json
├── scripts/
│   ├── build.ps1
│   ├── install.ps1
│   ├── pmux-title.ps1
│   ├── pmux-title.sh
│   ├── publish-choco.ps1
│   └── uninstall.ps1
├── src/
│   ├── cli.rs
│   ├── client.rs
│   ├── clipboard.rs
│   ├── commands.rs
│   ├── config.rs
│   ├── control.rs
│   ├── copy_mode.rs
│   ├── cross_session.rs
│   ├── cross_session_server.rs
│   ├── debug_log.rs
│   ├── format.rs
│   ├── help.rs
│   ├── input.rs
│   ├── layout.rs
│   ├── main.rs
│   ├── pane.rs
│   ├── platform.rs
│   ├── popup.rs
│   ├── preview.rs
│   ├── proxy_pane.rs
│   ├── rendering.rs
│   ├── server/
│   │   ├── connection.rs
│   │   ├── helpers.rs
│   │   ├── mod.rs
│   │   ├── option_catalog.rs
│   │   └── options.rs
│   ├── session.rs
│   ├── ssh_input.rs
│   ├── style.rs
│   ├── tree.rs
│   ├── types.rs
│   ├── util.rs
│   ├── warm_pane_sync.rs
│   └── window_ops.rs
├── tests/
│   ├── _batch_runner.ps1
│   ├── _full_run.ps1
│   ├── _launch_debug.bat
│   ├── _run_batch3.ps1
│   ├── alt_emit.ps1
│   ├── alt_emit_inner.ps1
│   ├── alt_emit_simple.ps1
│   ├── battle_test.ps1
│   ├── battle_test.py
│   ├── bench_squelch_cwd.ps1
│   ├── bench_startup_exit.ps1
│   ├── burst_bench2.cs
│   ├── burst_benchmark.cs
│   ├── cursor_bench.cs
│   ├── debug_paste_trace.ps1
│   ├── destructive_test.ps1
│   ├── diag_cursor_claude.ps1
│   ├── diag_cursor_raw.ps1
│   ├── diag_enter_selfcontained.ps1
│   ├── diag_key_events.ps1
│   ├── diag_scroll_inject.ps1
│   ├── disable_processed_input.ps1
│   ├── injector.cs
│   ├── injector_batch.cs
│   ├── inspect_issue263_dump.ps1
│   ├── inspect_issue263_runs.ps1
│   ├── investigate_274_attach_kill.ps1
│   ├── investigate_274_clean_recovery.ps1
│   ├── investigate_274_long.ps1
│   ├── investigate_274_node_daemon.ps1
│   ├── investigate_274_unresponsive_proc.ps1
│   ├── investigate_274_wedge.ps1
│   ├── issue246_emitter.py
│   ├── mouse_diag.ps1
│   ├── mouse_injector.cs
│   ├── repro_enter_bugs.ps1
│   ├── repro_issue303.ps1
│   ├── repro_issue303b.ps1
│   ├── repro_issue303c.ps1
│   ├── repro_preview_compare.ps1
│   ├── repro_preview_layout.ps1
│   ├── repro_pstop_preview.ps1
│   ├── repro_seven_panes.ps1
│   ├── run_all_tests.ps1
│   ├── run_batch_fast.ps1
│   ├── run_fmt_test.ps1
│   ├── test_advanced.ps1
│   ├── test_agent_teams_e2e.ps1
│   ├── test_all.ps1
│   ├── test_all.sh
│   ├── test_alt_key.ps1
│   ├── test_bell_activity_silence.ps1
│   ├── test_bind_key.ps1
│   ├── test_bind_pipe_key.ps1
│   ├── test_bug_detection.ps1
│   ├── test_bugfixes.ps1
│   ├── test_burst_typing_benchmark.ps1
│   ├── test_capture_pane.ps1
│   ├── test_cc_iterm2_compat.ps1
│   ├── test_choose_tree_preview.ps1
│   ├── test_cjk_paste_split.ps1
│   ├── test_claude_agent_teams.ps1
│   ├── test_claude_compat_fixes.ps1
│   ├── test_claude_cursor_diag.ps1
│   ├── test_claude_mouse.ps1
│   ├── test_cli_flag_parity.ps1
│   ├── test_cli_handlers.ps1
│   ├── test_cli_mega_suite.ps1
│   ├── test_combined_flags.ps1
│   ├── test_config.ps1
│   ├── test_config_exhaustive_cli.ps1
│   ├── test_config_exhaustive_tcp.ps1
│   ├── test_config_exhaustive_tui.ps1
│   ├── test_config_plugin_loading.ps1
│   ├── test_conpty_mouse.ps1
│   ├── test_control_mode.ps1
│   ├── test_copy_mode_advanced.ps1
│   ├── test_copy_mode_bracket_paragraph.ps1
│   ├── test_copy_mode_full.ps1
│   ├── test_cross_session_join_pane.ps1
│   ├── test_cross_shell_backslash.ps1
│   ├── test_cursor_fallback.ps1
│   ├── test_cursor_style.ps1
│   ├── test_debug_focus.ps1
│   ├── test_default_command_format.ps1
│   ├── test_default_shell_cmd.ps1
│   ├── test_default_shell_wsl.ps1
│   ├── test_display_message_duration.ps1
│   ├── test_e2e_latency.ps1
│   ├── test_env_shim.ps1
│   ├── test_extreme_perf.ps1
│   ├── test_f_flag_config.ps1
│   ├── test_features.ps1
│   ├── test_features2.ps1
│   ├── test_features3.ps1
│   ├── test_features4.ps1
│   ├── test_features5.ps1
│   ├── test_format_engine.ps1
│   ├── test_format_vars.ps1
│   ├── test_full_feature.ps1
│   ├── test_github_issues.ps1
│   ├── test_github_issues_all.ps1
│   ├── test_hide_window_e2e.ps1
│   ├── test_install_speed.ps1
│   ├── test_issue100_key_names.ps1
│   ├── test_issue105_plugin_env_leak.ps1
│   ├── test_issue108_ctrl_tab.ps1
│   ├── test_issue110_popup_scroll.ps1
│   ├── test_issue111_format_cwd.ps1
│   ├── test_issue111_starship_compat.ps1
│   ├── test_issue112_113.ps1
│   ├── test_issue121_shift_enter.ps1
│   ├── test_issue125_per_window_zoom.ps1
│   ├── test_issue125_zoom_flag.ps1
│   ├── test_issue126_client_prefix.ps1
│   ├── test_issue133_hook_append.ps1
│   ├── test_issue133_hook_duplicates.ps1
│   ├── test_issue134_zoom_wrap_nav.ps1
│   ├── test_issue136_auth_failed.ps1
│   ├── test_issue137_default_terminal.ps1
│   ├── test_issue140_kill_pane_focus_loss.ps1
│   ├── test_issue146_list_commands.ps1
│   ├── test_issue146_popup_via_command_prompt.ps1
│   ├── test_issue151_strict_mode.ps1
│   ├── test_issue154_popup_fixes.ps1
│   ├── test_issue15_altgr.ps1
│   ├── test_issue165_prediction_view_style.ps1
│   ├── test_issue167_conpty_probe.ps1
│   ├── test_issue167_repro.ps1
│   ├── test_issue171_layout.ps1
│   ├── test_issue197_exact_text.ps1
│   ├── test_issue197_paste_tilde.ps1
│   ├── test_issue197_paste_validation.ps1
│   ├── test_issue197_win32_paste.ps1
│   ├── test_issue198_cv_unbind_persist.ps1
│   ├── test_issue198_cv_unbind_proof.ps1
│   ├── test_issue198_paste_detection.ps1
│   ├── test_issue198_paste_detection_proof.ps1
│   ├── test_issue19_config.ps1
│   ├── test_issue200_new_session.ps1
│   ├── test_issue200_proof.ps1
│   ├── test_issue200_sendkeys_proof.ps1
│   ├── test_issue201_rename_dialog.ps1
│   ├── test_issue201_win32_tui_proof.ps1
│   ├── test_issue202_cli_routing.ps1
│   ├── test_issue204_stale_port_files.ps1
│   ├── test_issue205_new_session_env.ps1
│   ├── test_issue206_tui_auth.ps1
│   ├── test_issue209_e2e_verify.ps1
│   ├── test_issue209_functional_proof.ps1
│   ├── test_issue209_tmux_parity_deep.ps1
│   ├── test_issue210_gastown_captures.ps1
│   ├── test_issue210_gastown_fixes.ps1
│   ├── test_issue211_pwsh_mouse_selection.ps1
│   ├── test_issue211_win32_mouse.ps1
│   ├── test_issue215_session_persistence.ps1
│   ├── test_issue217_pane_title_identify.ps1
│   ├── test_issue217_win32_tui_proof.ps1
│   ├── test_issue221_run_shell.ps1
│   ├── test_issue226_ctrl_slash.ps1
│   ├── test_issue226_full_proof.ps1
│   ├── test_issue227_remain_on_exit_hooks.ps1
│   ├── test_issue229_window_name_flash.ps1
│   ├── test_issue229_window_name_initial_command.ps1
│   ├── test_issue230_join_pane_and_ctrl_c.ps1
│   ├── test_issue230_join_pane_and_ctrl_c_proof.ps1
│   ├── test_issue230_send_keys_ctrl_c.ps1
│   ├── test_issue231_osc_title_propagation.ps1
│   ├── test_issue232_status_interval.ps1
│   ├── test_issue234_choose_buffer.ps1
│   ├── test_issue234_choose_buffer_proof.ps1
│   ├── test_issue235_display_panes_base_index.ps1
│   ├── test_issue237_final_proof.ps1
│   ├── test_issue237_typing_freeze.ps1
│   ├── test_issue237_typing_freeze_perf.ps1
│   ├── test_issue239_repro.ps1
│   ├── test_issue242_pageup_copy_mode.ps1
│   ├── test_issue244_capture_scrollback.ps1
│   ├── test_issue244_capture_scrollback_proof.ps1
│   ├── test_issue245_mouse_selection.ps1
│   ├── test_issue246_sparse_render.ps1
│   ├── test_issue247_session_picker_digit.ps1
│   ├── test_issue25.ps1
│   ├── test_issue250_root_cause.ps1
│   ├── test_issue253_repro.ps1
│   ├── test_issue253_repro2.ps1
│   ├── test_issue253_repro3.ps1
│   ├── test_issue257_preview.ps1
│   ├── test_issue259_picker_hjkl.ps1
│   ├── test_issue261_cc_verify.ps1
│   ├── test_issue261_proof.ps1
│   ├── test_issue263_box_drawing_color.ps1
│   ├── test_issue263_byte_proof.ps1
│   ├── test_issue263_definitive.ps1
│   ├── test_issue263_dump_state.ps1
│   ├── test_issue263_final.ps1
│   ├── test_issue263_irrefutable.ps1
│   ├── test_issue263_nested.ps1
│   ├── test_issue263_proof.ps1
│   ├── test_issue263_python_raw.ps1
│   ├── test_issue263_raw.ps1
│   ├── test_issue263_raw_bytes.ps1
│   ├── test_issue263_v2.ps1
│   ├── test_issue264_paste_buffer_proof.ps1
│   ├── test_issue264_paste_buffer_repro.ps1
│   ├── test_issue265_argv_backslash.ps1
│   ├── test_issue266_autorename_override.ps1
│   ├── test_issue266_autorename_override_proof.ps1
│   ├── test_issue266_explicit_name.ps1
│   ├── test_issue266_with_python.ps1
│   ├── test_issue268_dump_state.ps1
│   ├── test_issue269_byte_capture.ps1
│   ├── test_issue269_osc94_dropped.ps1
│   ├── test_issue269_osc94_dropped_proof.ps1
│   ├── test_issue271_runtime_set_propagation.ps1
│   ├── test_issue271_warm_pane_history.ps1
│   ├── test_issue271_warm_pane_history_proof.ps1
│   ├── test_issue272_status_format_perf.ps1
│   ├── test_issue273_send_prefix.ps1
│   ├── test_issue274_pane_isolation.ps1
│   ├── test_issue274_sustained_load.ps1
│   ├── test_issue274_tui_wedge_repro.ps1
│   ├── test_issue274_wezterm_repro.ps1
│   ├── test_issue275_detach_client.ps1
│   ├── test_issue275_detach_keystroke.ps1
│   ├── test_issue277_definitive.ps1
│   ├── test_issue277_scroll_controlled.ps1
│   ├── test_issue277_scroll_repro.ps1
│   ├── test_issue277_tcp_scroll.ps1
│   ├── test_issue284_pageup_wsl.ps1
│   ├── test_issue285_nvim_mouse.ps1
│   ├── test_issue286_ime_prefix.ps1
│   ├── test_issue287_german_keyboard.ps1
│   ├── test_issue288_pane_border_status.ps1
│   ├── test_issue295_scroll_regression.ps1
│   ├── test_issue296_nvim_hang.ps1
│   ├── test_issue33_remaining.ps1
│   ├── test_issue36.ps1
│   ├── test_issue41_btab.ps1
│   ├── test_issue42_version.ps1
│   ├── test_issue43_copy_pane_local.ps1
│   ├── test_issue43_prefix_o_l.ps1
│   ├── test_issue44_zoom_buffer.ps1
│   ├── test_issue45_unzoom_cursor.ps1
│   ├── test_issue46_zoom_nav_desync.ps1
│   ├── test_issue47_bare_run.ps1
│   ├── test_issue49_ctlseq.ps1
│   ├── test_issue50_chinese_chars.ps1
│   ├── test_issue52_claude.ps1
│   ├── test_issue52_cursor.ps1
│   ├── test_issue60_native_tui_mouse.ps1
│   ├── test_issue63_status_off.ps1
│   ├── test_issue70_mouse_mru_and_detached.ps1
│   ├── test_issue70_mru_navigation.ps1
│   ├── test_issue70_select_pane_mru.ps1
│   ├── test_issue71_kill_pane_focus.ps1
│   ├── test_issue74_paste.ps1
│   ├── test_issue82_zoom_split_borders.ps1
│   ├── test_issue88_alt_screen_proof.ps1
│   ├── test_issue88_alt_screen_v2.ps1
│   ├── test_issue88_clean_e2e.ps1
│   ├── test_issue88_codex_scrollback.ps1
│   ├── test_issue88_debug_b.ps1
│   ├── test_issue88_debug_v2.ps1
│   ├── test_issue88_fix_proof.ps1
│   ├── test_issue88_irrefutable_proof.ps1
│   ├── test_issue91_ime_paste.ps1
│   ├── test_issue94_split_percent.ps1
│   ├── test_issue95_commands.ps1
│   ├── test_issue98_bracketed_paste.ps1
│   ├── test_issue99_default_shell_bash.ps1
│   ├── test_issues_107_109_110.ps1
│   ├── test_keybinding_options.ps1
│   ├── test_keystroke_injection.ps1
│   ├── test_kill_pane_by_id.ps1
│   ├── test_kill_server.ps1
│   ├── test_kill_tree.ps1
│   ├── test_layout_engine.ps1
│   ├── test_load_buffer_w_clipboard.ps1
│   ├── test_long_paragraph_benchmark.ps1
│   ├── test_mouse_handling.ps1
│   ├── test_mouse_hover.ps1
│   ├── test_named_buffers.ps1
│   ├── test_named_session_parity.ps1
│   ├── test_new_features.ps1
│   ├── test_new_parity_features.ps1
│   ├── test_newsession_flags.ps1
│   ├── test_nsis_installer.ps1
│   ├── test_osc7_pane_path.ps1
│   ├── test_overlay_bugfixes.ps1
│   ├── test_overlay_rendering.ps1
│   ├── test_pane_mru.ps1
│   ├── test_pane_navigation.ps1
│   ├── test_pane_startup_perf.ps1
│   ├── test_parity.ps1
│   ├── test_perf.ps1
│   ├── test_perf_vs_wt.ps1
│   ├── test_picker_digit_jump_all.ps1
│   ├── test_plugins_themes.ps1
│   ├── test_pr118_bugs.ps1
│   ├── test_pr207_claims.ps1
│   ├── test_pr207_compat_bugs.ps1
│   ├── test_pr207_libtmux.py
│   ├── test_pr207_retest.ps1
│   ├── test_pr207_workaround_elimination.ps1
│   ├── test_pr222_223_run_shell_paths.ps1
│   ├── test_pr255_active_border.ps1
│   ├── test_pr255_visual_proof.ps1
│   ├── test_pr27.ps1
│   ├── test_preview_stuck_repro.ps1
│   ├── test_production_readiness.ps1
│   ├── test_pty_stability.ps1
│   ├── test_real_plugins.ps1
│   ├── test_realistic_typing.ps1
│   ├── test_round9.ps1
│   ├── test_run_shell.ps1
│   ├── test_scroll_memory.ps1
│   ├── test_scroll_viewport_proof.ps1
│   ├── test_scroll_viewport_tracking.ps1
│   ├── test_session.ps1
│   ├── test_session_mgmt.ps1
│   ├── test_showw_sendkeys_p.ps1
│   ├── test_spaces_in_paths.ps1
│   ├── test_split_limits.ps1
│   ├── test_split_window_target_focus.ps1
│   ├── test_squelch_visibility.ps1
│   ├── test_startup_exit_bench.ps1
│   ├── test_startup_perf.ps1
│   ├── test_stress.ps1
│   ├── test_stress_50.ps1
│   ├── test_stress_aggressive.ps1
│   ├── test_stress_attached.ps1
│   ├── test_sustained_fast_typing.ps1
│   ├── test_switch_client.ps1
│   ├── test_switch_client_live_proof.ps1
│   ├── test_tab_spacing.ps1
│   ├── test_target_focus_stability.ps1
│   ├── test_tcp_flag_parity.ps1
│   ├── test_tcp_mega_suite.ps1
│   ├── test_theme_rendering.ps1
│   ├── test_tmux_compat.ps1
│   ├── test_tui_exit_cleanup.ps1
│   ├── test_tui_win32_proof.ps1
│   ├── test_typing_benchmark.ps1
│   ├── test_typing_render_latency.ps1
│   ├── test_unbind_key_a.ps1
│   ├── test_vim_nav_keys.ps1
│   ├── test_vt_paste_missing_close.ps1
│   ├── test_vt_paste_ssh_real.ps1
│   ├── test_warm_off.ps1
│   ├── test_warm_pane.ps1
│   ├── test_warm_pane_sync_options.ps1
│   ├── test_warm_session_claim.ps1
│   ├── test_win32_tui_flag_parity.ps1
│   ├── test_win32_tui_mega_proof.ps1
│   ├── test_window_exit_statusbar.ps1
│   ├── test_window_index_prompt.ps1
│   ├── test_wsl_in_pwsh_latency.ps1
│   ├── test_wsl_in_pwsh_latency2.ps1
│   ├── test_wsl_latency.ps1
│   ├── test_wsl_pwsh_latency3.ps1
│   ├── test_wsl_pwsh_latency4.ps1
│   ├── test_wsl_pwsh_latency5.ps1
│   ├── test_zoom_resize.ps1
│   ├── timed_injector.cs
│   ├── tui_helper.ps1
│   ├── typing_bench.cs
│   └── typing_benchmark.cs
└── tests-rs/
    ├── test_client.rs
    ├── test_cmdbuilder.rs
    ├── test_commands.rs
    ├── test_commands_audit.rs
    ├── test_commands_new.rs
    ├── test_config_exhaustive.rs
    ├── test_config_plugin_paths.rs
    ├── test_cpr_responder.rs
    ├── test_flag_parity.rs
    ├── test_format.rs
    ├── test_gastown_scenarios.rs
    ├── test_h1_osc52_clipboard_capture.rs
    ├── test_h1_osc52_end_to_end.rs
    ├── test_hide_window.rs
    ├── test_input.rs
    ├── test_issue137_env_leak.rs
    ├── test_issue145_source_file.rs
    ├── test_issue151_strict_mode.rs
    ├── test_issue155_output_rendering.rs
    ├── test_issue155_rendering.rs
    ├── test_issue155_sgr_attrs.rs
    ├── test_issue157_bind_key_case.rs
    ├── test_issue165_prediction_view_style.rs
    ├── test_issue167_startup_log.rs
    ├── test_issue169_manual_rename.rs
    ├── test_issue171_layout_bugs.rs
    ├── test_issue179_bind_key_uppercase.rs
    ├── test_issue185_layout_directives.rs
    ├── test_issue192_command_chaining.rs
    ├── test_issue193_scroll_enter_copy_mode.rs
    ├── test_issue196_flag_equals.rs
    ├── test_issue198_cv_persist.rs
    ├── test_issue198_unbind_individual.rs
    ├── test_issue200_new_session.rs
    ├── test_issue201_rename_dialog.rs
    ├── test_issue202_switch_client.rs
    ├── test_issue209_tmux_compat.rs
    ├── test_issue210_gastown_captures.rs
    ├── test_issue210_gastown_fixes.rs
    ├── test_issue215_session_persistence.rs
    ├── test_issue226_ctrl_slash.rs
    ├── test_issue227_remain_on_exit_hooks.rs
    ├── test_issue235_display_panes_base_index.rs
    ├── test_issue244_capture_scrollback.rs
    ├── test_issue245_mouse_selection.rs
    ├── test_issue250_root_cause.rs
    ├── test_issue265_argv_backslash.rs
    ├── test_issue266_per_window_autorename.rs
    ├── test_issue268_set_titles.rs
    ├── test_issue269_osc94_dropped.rs
    ├── test_issue271_warm_pane_history.rs
    ├── test_issue272_format_shell_cache.rs
    ├── test_issue273_send_prefix.rs
    ├── test_issue275_detach_client.rs
    ├── test_issue278_toggle_bool_option.rs
    ├── test_issue284_pageup_wsl.rs
    ├── test_issue287_german_keyboard.rs
    ├── test_issue81_resize_direction.rs
    ├── test_issue88_alt_screen_toggle.rs
    ├── test_layout.rs
    ├── test_mega_unit_coverage.rs
    ├── test_named_buffers.rs
    ├── test_new_session_env.rs
    ├── test_pane_title.rs
    ├── test_parity.rs
    ├── test_pr207_compat_bugs.rs
    ├── test_pr255_active_border.rs
    ├── test_pr267_backpressure_proof.rs
    ├── test_run_shell_resolve.rs
    ├── test_server.rs
    ├── test_session.rs
    ├── test_ssh_vt_paste.rs
    ├── test_vt100_mouse.rs
    ├── test_vt100_screen.rs
    ├── test_warm_pane_sync.rs
    └── test_zoom_bleed.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config.toml
================================================
[alias]
lint = "clippy -- -D warnings"

# Statically link the C runtime so binaries don't need vcruntime140.dll
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

[target.i686-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

[target.aarch64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

================================================
FILE: .github/ASSETS.md
================================================
# Repository Assets

## Social Card Setup

To enable the social card on GitHub:

1. **Convert SVG to PNG** (if not already done):
   - Online: Upload `.github/social-card.svg` to https://cloudconvert.com/svg-to-png
   - Or install ImageMagick: `winget install ImageMagick.ImageMagick`
   - Then run: `magick .github/social-card.svg .github/social-card.png`

2. **Upload to GitHub**:
   - Go to: https://github.com/psmux/psmux/settings
   - Scroll to "Social preview"
   - Click "Edit" and upload `.github/social-card.png`
   - Dimensions: 1280x640px (optimal for social sharing)

## Repository Icon

The `icon.svg` can be used as:
- Project logo in documentation
- Favicon for project websites
- App icon if building a GUI wrapper

### Design Features

**Social Card (`1280x640px`):**
- Dark gradient background (#1a1a2e → #16213e)
- Terminal window with split pane visualization
- psmux branding with cyan accent (#00d9ff)
- Feature badges: tmux-compatible, Windows-native, Rust-powered, No WSL
- PS> prompts to emphasize PowerShell support

**Icon (`512x512px`):**
- Cyan gradient circular background
- Terminal window with 3-pane split layout
- Animated cursor (blinks when viewed as SVG)
- Compact design suitable for various sizes

Both designs emphasize:
- Terminal multiplexing (split panes)
- Windows/PowerShell focus (PS> prompts)
- Modern, professional aesthetic
- Brand color consistency (#00d9ff cyan)


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_dispatch:

permissions:
  contents: read

env:
  CARGO_TERM_COLOR: always

jobs:
  build:
    name: Build ${{ matrix.label }}
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-pc-windows-msvc
            label: Windows x64
          - target: i686-pc-windows-msvc
            label: Windows x86
          - target: aarch64-pc-windows-msvc
            label: Windows ARM64

    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Build
        run: cargo build --release --target ${{ matrix.target }}


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  workflow_dispatch:
    inputs:
      tag:
        description: 'Release tag to publish (e.g. v3.3.3) — tag must already exist in the repo'
        required: true
        type: string

permissions:
  contents: write

# Prevent duplicate runs from overwriting release assets / submitting duplicate PRs
concurrency:
  group: release-${{ inputs.tag }}
  cancel-in-progress: false

env:
  CARGO_TERM_COLOR: always

jobs:
  build:
    name: Build ${{ matrix.label }}
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-pc-windows-msvc
            label: Windows x64
            artifact: windows-x64
            nsis_arch: x64
          - target: i686-pc-windows-msvc
            label: Windows x86
            artifact: windows-x86
            nsis_arch: x86
          - target: aarch64-pc-windows-msvc
            label: Windows ARM64 (Snapdragon)
            artifact: windows-arm64
            nsis_arch: arm64

    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Build
        run: cargo build --release --target ${{ matrix.target }}

      - name: Create release package
        shell: pwsh
        run: |
          $ErrorActionPreference = "Stop"
          $version = "${{ inputs.tag }}"
          $zipName = "psmux-$version-${{ matrix.artifact }}"
          $releaseDir = "target/${{ matrix.target }}/release"
          New-Item -ItemType Directory -Path $zipName -Force

          # Verify all expected binaries exist before copying
          foreach ($exe in @("psmux.exe", "pmux.exe", "tmux.exe")) {
            $path = Join-Path $releaseDir $exe
            if (-not (Test-Path $path)) {
              Write-Error "FATAL: Expected binary '$path' not found! Build may have failed silently."
              Get-ChildItem $releaseDir -Filter "*.exe" | ForEach-Object { Write-Output "  Found: $($_.FullName) ($($_.Length) bytes)" }
              exit 1
            }
          }

          Copy-Item "$releaseDir/psmux.exe" "$zipName/psmux.exe" -ErrorAction Stop
          Copy-Item "$releaseDir/pmux.exe" "$zipName/pmux.exe" -ErrorAction Stop
          Copy-Item "$releaseDir/tmux.exe" "$zipName/tmux.exe" -ErrorAction Stop
          Copy-Item "README.md" "$zipName/" -ErrorAction Stop
          Copy-Item "LICENSE" "$zipName/" -ErrorAction Stop
          Compress-Archive -Path "$zipName/*" -DestinationPath "$zipName.zip"

          # Verify zip contents
          $entries = [System.IO.Compression.ZipFile]::OpenRead("$zipName.zip").Entries.Name
          foreach ($exe in @("psmux.exe", "pmux.exe", "tmux.exe")) {
            if ($exe -notin $entries) {
              Write-Error "FATAL: '$exe' missing from zip archive!"
              exit 1
            }
          }
          Write-Output "Zip contains: $($entries -join ', ')"

      - name: Install NSIS
        shell: pwsh
        run: |
          choco install nsis -y --no-progress
          # Install EnVar plugin for PATH manipulation
          $nsisDir = "C:\Program Files (x86)\NSIS"
          $pluginUrl = "https://nsis.sourceforge.io/mediawiki/images/7/7f/EnVar_plugin.zip"
          $pluginZip = "$env:TEMP\EnVar_plugin.zip"
          Invoke-WebRequest -Uri $pluginUrl -OutFile $pluginZip
          Expand-Archive -Path $pluginZip -DestinationPath "$env:TEMP\EnVar" -Force
          Copy-Item "$env:TEMP\EnVar\Plugins\x86-ansi\*" "$nsisDir\Plugins\x86-ansi\" -Force
          Copy-Item "$env:TEMP\EnVar\Plugins\x86-unicode\*" "$nsisDir\Plugins\x86-unicode\" -Force

      - name: Build NSIS installer
        shell: pwsh
        run: |
          $ErrorActionPreference = "Stop"
          $version = "${{ inputs.tag }}" -replace '^v', ''
          $releaseDir = Resolve-Path "target/${{ matrix.target }}/release"
          $repoDir = Resolve-Path "."
          New-Item -ItemType Directory -Path "target\installer" -Force | Out-Null

          & "C:\Program Files (x86)\NSIS\makensis.exe" /NOCD `
            /DVERSION=$version `
            /DARCH=${{ matrix.nsis_arch }} `
            "/DSOURCE_DIR=$releaseDir" `
            "/DREPO_DIR=$repoDir" `
            "installer\psmux.nsi"
          if ($LASTEXITCODE -ne 0) { Write-Error "NSIS build failed"; exit 1 }

          $setup = "target\installer\psmux-v${version}-${{ matrix.nsis_arch }}-setup.exe"
          if (-not (Test-Path $setup)) { Write-Error "Setup not found: $setup"; exit 1 }
          $sizeMB = [math]::Round((Get-Item $setup).Length / 1MB, 2)
          Write-Output "NSIS installer: $setup ($sizeMB MB)"

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: psmux-${{ matrix.artifact }}
          path: |
            psmux-*-${{ matrix.artifact }}.zip
            target/installer/*-${{ matrix.nsis_arch }}-setup.exe

  release:
    name: Create Release
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Generate changelog
        id: changelog
        run: |
          # Find the previous tag
          CURRENT_TAG="${{ inputs.tag }}"
          PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${CURRENT_TAG}$" | head -n 1)

          if [ -z "$PREV_TAG" ]; then
            echo "No previous tag found — generating changelog from all commits"
            LOG=$(git log --pretty=format:"- %s (%h)" --no-merges "$CURRENT_TAG")
          else
            echo "Generating changelog: $PREV_TAG → $CURRENT_TAG"
            LOG=$(git log --pretty=format:"- %s (%h)" --no-merges "${PREV_TAG}..${CURRENT_TAG}")
          fi

          # Write to file to preserve multiline content
          echo "$LOG" > /tmp/changelog.md
          echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT

      - name: Build release body
        id: body
        run: |
          CURRENT_TAG="${{ inputs.tag }}"
          PREV_TAG="${{ steps.changelog.outputs.prev_tag }}"

          {
            echo "## psmux ${CURRENT_TAG}"
            echo ""
            echo "Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal."
            echo ""
            if [ -n "$PREV_TAG" ]; then
              echo "### Changelog (${PREV_TAG} → ${CURRENT_TAG})"
            else
              echo "### Changelog"
            fi
            echo ""
            cat /tmp/changelog.md
            echo ""
            echo ""
            echo "### Downloads"
            echo ""
            echo "**Portable (zip):**"
            echo "| Platform | File |"
            echo "|----------|------|"
            echo "| Windows x64 (Intel/AMD 64-bit) | \`psmux-${CURRENT_TAG}-windows-x64.zip\` |"
            echo "| Windows x86 (Intel/AMD 32-bit) | \`psmux-${CURRENT_TAG}-windows-x86.zip\` |"
            echo "| Windows ARM64 (Snapdragon/Surface Pro X) | \`psmux-${CURRENT_TAG}-windows-arm64.zip\` |"
            echo ""
            echo "**Installer (NSIS setup — kills running instances, adds to PATH, warmup):**"
            echo "| Platform | File |"
            echo "|----------|------|"
            VERSION_NO_V="${CURRENT_TAG#v}"
            echo "| Windows x64 | \`psmux-v${VERSION_NO_V}-x64-setup.exe\` |"
            echo "| Windows x86 | \`psmux-v${VERSION_NO_V}-x86-setup.exe\` |"
            echo "| Windows ARM64 | \`psmux-v${VERSION_NO_V}-arm64-setup.exe\` |"
            echo ""
            echo "### Installation"
            echo ""
            echo "**Via Scoop (recommended):**"
            echo "\`\`\`powershell"
            echo "scoop bucket add psmux https://github.com/psmux/scoop-psmux"
            echo "scoop install psmux"
            echo "\`\`\`"
            echo ""
            echo "**Via Chocolatey:**"
            echo "\`\`\`powershell"
            echo "choco install psmux"
            echo "\`\`\`"
            echo ""
            echo "**Via WinGet:**"
            echo "\`\`\`powershell"
            echo "winget install marlocarlo.psmux"
            echo "\`\`\`"
            echo ""
            echo "**Via Cargo:**"
            echo "\`\`\`powershell"
            echo "cargo install psmux"
            echo "\`\`\`"
            echo ""
            echo "**Via PowerShell:**"
            echo "\`\`\`powershell"
            echo "irm https://raw.githubusercontent.com/psmux/psmux/master/scripts/install.ps1 | iex"
            echo "\`\`\`"
            echo ""
            echo "**Manual Installation:**"
            echo "1. Download the zip matching your architecture"
            echo "2. Extract to a folder in your PATH"
            echo "3. \`psmux\`, \`pmux\`, and \`tmux\` commands will all be available"
            echo ""
            echo "### What's Included"
            echo "- \`psmux.exe\` - Main executable"
            echo "- \`pmux.exe\` - Alias"
            echo "- \`tmux.exe\` - Alias for tmux compatibility"
          } > /tmp/release_body.md

      - name: Download all artifacts
        uses: actions/download-artifact@v4

      - name: List artifacts
        run: find . -type f \( -name "*.zip" -o -name "*-setup.exe" \)

      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ inputs.tag }}
          name: ${{ inputs.tag }}
          files: |
            psmux-windows-x64/*.zip
            psmux-windows-x86/*.zip
            psmux-windows-arm64/*.zip
            psmux-windows-x64/**/*-setup.exe
            psmux-windows-x86/**/*-setup.exe
            psmux-windows-arm64/**/*-setup.exe
          body_path: /tmp/release_body.md
          draft: false
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish-crates:
    name: Publish to crates.io
    needs: release
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Verify crate compiles with crates.io dependencies
        run: |
          cargo check 2>&1
          if ($LASTEXITCODE -ne 0) {
            Write-Error "Crate fails to compile with crates.io dependencies! Fix before publishing."
            exit 1
          }
        shell: pwsh

      - name: Publish sub-crates then main crate to crates.io
        shell: pwsh
        run: |
          # Sub-crates must be published first so crates.io can resolve path deps
          cargo publish --allow-dirty -p portable-pty-psmux 2>&1
          if ($LASTEXITCODE -ne 0) {
            Write-Warning "portable-pty-psmux publish failed (may already be published)"
          }
          Start-Sleep 15
          cargo publish --allow-dirty -p vt100-psmux 2>&1
          if ($LASTEXITCODE -ne 0) {
            Write-Warning "vt100-psmux publish failed (may already be published)"
          }
          Start-Sleep 15
          $out = cargo publish --allow-dirty 2>&1
          $out | Write-Output
          if ($LASTEXITCODE -ne 0) {
            # Treat "already exists" as a warning so re-runs don't break
            if ($out -match "already exists") {
              Write-Warning "psmux already published at this version -- skipping"
            } else {
              Write-Error "psmux publish failed!"
              exit 1
            }
          }
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  publish-chocolatey:
    name: Publish to Chocolatey
    needs: release
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - name: Wait for release assets to stabilize on GitHub CDN
        shell: pwsh
        run: |
          Write-Output "Waiting 60s for GitHub release CDN propagation..."
          Start-Sleep 60

      - name: Extract version from tag
        id: version
        shell: pwsh
        run: |
          $tag = "${{ inputs.tag }}"
          $ver = $tag -replace '^v', ''
          echo "VERSION=$ver" >> $env:GITHUB_OUTPUT
          echo "TAG=$tag" >> $env:GITHUB_OUTPUT
          Write-Output "Version: $ver  Tag: $tag"

      - name: Download x64 release zip from GitHub Release
        shell: pwsh
        run: |
          $tag = "${{ steps.version.outputs.TAG }}"
          $zipUrl = "https://github.com/${{ github.repository }}/releases/download/$tag/psmux-$tag-windows-x64.zip"
          Write-Output "Downloading $zipUrl"
          $ok = $false
          for ($i = 1; $i -le 5; $i++) {
            try {
              Invoke-WebRequest -Uri $zipUrl -OutFile "psmux-release.zip" -UseBasicParsing -ErrorAction Stop
              $ok = $true; break
            } catch {
              if ($i -eq 5) { throw }
              Write-Output "Retry $i..."
              Start-Sleep ($i * 10)
            }
          }

      - name: Compute SHA256 checksum
        id: checksum
        shell: pwsh
        run: |
          $hash = (Get-FileHash "psmux-release.zip" -Algorithm SHA256).Hash
          echo "SHA256=$hash" >> $env:GITHUB_OUTPUT
          Write-Output "SHA256: $hash"

      - name: Build and push Chocolatey package
        shell: pwsh
        run: |
          $ErrorActionPreference = 'Stop'
          $ver = "${{ steps.version.outputs.VERSION }}"
          $tag = "${{ steps.version.outputs.TAG }}"
          $hash = "${{ steps.checksum.outputs.SHA256 }}"
          $url = "https://github.com/${{ github.repository }}/releases/download/$tag/psmux-$tag-windows-x64.zip"
          $utf8 = New-Object System.Text.UTF8Encoding $false

          New-Item -ItemType Directory -Path "choco-pkg/tools" -Force | Out-Null

          # --- chocolateyinstall.ps1 ---
          $install = @(
            '$ErrorActionPreference = ''Stop'''
            ''
            '$toolsDir = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"'
            ('$url64 = ''{0}''' -f $url)
            ''
            '$packageArgs = @{'
            '  packageName    = $env:ChocolateyPackageName'
            '  unzipLocation  = $toolsDir'
            '  url64bit       = $url64'
            ('  checksum64     = ''{0}''' -f $hash)
            '  checksumType64 = ''sha256'''
            '}'
            ''
            'Install-ChocolateyZipPackage @packageArgs'
            ''
            '$psmuxPath = Join-Path $toolsDir "psmux.exe"'
            '$pmuxPath = Join-Path $toolsDir "pmux.exe"'
            '$tmuxPath = Join-Path $toolsDir "tmux.exe"'
            ''
            'Install-BinFile -Name "psmux" -Path $psmuxPath'
            'Install-BinFile -Name "pmux" -Path $pmuxPath'
            'Install-BinFile -Name "tmux" -Path $tmuxPath'
          ) -join "`n"
          [IO.File]::WriteAllText("$PWD/choco-pkg/tools/chocolateyinstall.ps1", $install, $utf8)

          # --- chocolateyuninstall.ps1 ---
          $uninstall = @(
            'Uninstall-BinFile -Name "psmux"'
            'Uninstall-BinFile -Name "pmux"'
            'Uninstall-BinFile -Name "tmux"'
          ) -join "`n"
          [IO.File]::WriteAllText("$PWD/choco-pkg/tools/chocolateyuninstall.ps1", $uninstall, $utf8)

          # --- nuspec ---
          $nuspec = @(
            '<?xml version="1.0" encoding="utf-8"?>'
            '<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">'
            '  <metadata>'
            '    <id>psmux</id>'
            ('    <version>{0}</version>' -f $ver)
            '    <title>psmux - Terminal Multiplexer for Windows</title>'
            '    <authors>Josh</authors>'
            '    <owners>Josh</owners>'
            '    <licenseUrl>https://github.com/psmux/psmux/blob/master/LICENSE</licenseUrl>'
            '    <projectUrl>https://github.com/psmux/psmux</projectUrl>'
            '    <requireLicenseAcceptance>false</requireLicenseAcceptance>'
            '    <description>Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal. Includes psmux, pmux, and tmux commands.</description>'
            '    <summary>Terminal multiplexer for Windows (tmux alternative)</summary>'
            '    <releaseNotes>https://github.com/psmux/psmux/releases</releaseNotes>'
            '    <tags>terminal multiplexer tmux powershell cli windows psmux pmux</tags>'
            '    <packageSourceUrl>https://github.com/psmux/psmux</packageSourceUrl>'
            '    <docsUrl>https://github.com/psmux/psmux#readme</docsUrl>'
            '    <bugTrackerUrl>https://github.com/psmux/psmux/issues</bugTrackerUrl>'
            '  </metadata>'
            '  <files>'
            '    <file src="tools\**" target="tools" />'
            '  </files>'
            '</package>'
          ) -join "`n"
          [IO.File]::WriteAllText("$PWD/choco-pkg/psmux.nuspec", $nuspec, $utf8)

          # --- Pack and push ---
          cd choco-pkg
          choco pack psmux.nuspec
          $nupkg = (Get-ChildItem *.nupkg)[0].Name
          Write-Output "Packed: $nupkg"
          choco push $nupkg --source https://push.chocolatey.org/ --api-key ${{ secrets.CHOCOLATEY_API_KEY }}
          Write-Output "Successfully pushed $nupkg to Chocolatey"

  publish-scoop:
    name: Publish to Scoop Bucket
    needs: release
    runs-on: ubuntu-latest
    steps:
      - name: Wait for release assets to stabilize on GitHub CDN
        run: |
          echo "Waiting 60s for GitHub release CDN propagation..."
          sleep 60

      - name: Extract version from tag
        id: version
        shell: bash
        run: |
          tag="${{ inputs.tag }}"
          ver="${tag#v}"
          echo "VERSION=$ver" >> $GITHUB_OUTPUT
          echo "TAG=$tag" >> $GITHUB_OUTPUT

      - name: Download release zips and compute SHA256
        id: hashes
        shell: bash
        run: |
          tag="${{ inputs.tag }}"
          repo="${{ github.repository }}"
          base="https://github.com/$repo/releases/download/$tag"

          for arch in x64 x86 arm64; do
            url="$base/psmux-$tag-windows-$arch.zip"
            echo "Downloading $url"
            for i in 1 2 3 4 5; do
              if curl -sL -o "installer-$arch.zip" "$url"; then break; fi
              echo "Retry $i..."
              sleep $((i * 10))
            done
            hash=$(sha256sum "installer-$arch.zip" | awk '{print $1}')
            upper_arch=$(echo "$arch" | tr '[:lower:]' '[:upper:]' | tr '-' '_')
            echo "SHA256_$upper_arch=$hash" >> $GITHUB_OUTPUT
            echo "  $arch: $hash"
          done

      - name: Clone scoop bucket repo
        shell: bash
        run: |
          git clone https://x-access-token:${{ secrets.WINGET_PAT }}@github.com/psmux/scoop-psmux.git scoop-bucket

      - name: Update scoop manifest
        shell: bash
        run: |
          ver="${{ steps.version.outputs.VERSION }}"
          tag="${{ steps.version.outputs.TAG }}"
          sha64="${{ steps.hashes.outputs.SHA256_X64 }}"
          sha86="${{ steps.hashes.outputs.SHA256_X86 }}"
          shaarm="${{ steps.hashes.outputs.SHA256_ARM64 }}"
          repo="${{ github.repository }}"
          base="https://github.com/$repo/releases/download/$tag"

          cat > scoop-bucket/bucket/psmux.json << MANIFEST
          {
              "version": "$ver",
              "description": "Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal",
              "homepage": "https://github.com/psmux/psmux",
              "license": "MIT",
              "architecture": {
                  "64bit": {
                      "url": "$base/psmux-$tag-windows-x64.zip",
                      "hash": "$sha64"
                  },
                  "32bit": {
                      "url": "$base/psmux-$tag-windows-x86.zip",
                      "hash": "$sha86"
                  },
                  "arm64": {
                      "url": "$base/psmux-$tag-windows-arm64.zip",
                      "hash": "$shaarm"
                  }
              },
              "bin": [
                  "psmux.exe",
                  "pmux.exe",
                  "tmux.exe"
              ],
              "checkver": {
                  "github": "https://github.com/psmux/psmux"
              },
              "autoupdate": {
                  "architecture": {
                      "64bit": {
                          "url": "https://github.com/psmux/psmux/releases/download/v\$version/psmux-v\$version-windows-x64.zip"
                      },
                      "32bit": {
                          "url": "https://github.com/psmux/psmux/releases/download/v\$version/psmux-v\$version-windows-x86.zip"
                      },
                      "arm64": {
                          "url": "https://github.com/psmux/psmux/releases/download/v\$version/psmux-v\$version-windows-arm64.zip"
                      }
                  }
              }
          }
          MANIFEST

          # Remove leading whitespace from heredoc indentation
          cd scoop-bucket
          python3 -c "
          import json
          with open('bucket/psmux.json') as f:
              data = json.load(f)
          with open('bucket/psmux.json', 'w', newline='\n') as f:
              json.dump(data, f, indent=4)
              f.write('\n')
          "

      - name: Push updated manifest to scoop bucket
        shell: bash
        run: |
          cd scoop-bucket
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add bucket/psmux.json
          git diff --cached --quiet && echo "No changes" && exit 0
          git commit -m "Update psmux to ${{ steps.version.outputs.VERSION }}"
          git push

  publish-winget:
    name: Publish to WinGet
    needs: release
    runs-on: windows-latest
    steps:
      - name: Wait for release assets to stabilize on GitHub CDN
        shell: pwsh
        run: |
          Write-Output "Waiting 90s for GitHub release CDN propagation..."
          Start-Sleep 90

      - name: Extract version from tag
        id: version
        shell: pwsh
        run: |
          $tag = "${{ inputs.tag }}"
          $ver = $tag -replace '^v', ''
          echo "VERSION=$ver" >> $env:GITHUB_OUTPUT
          echo "TAG=$tag" >> $env:GITHUB_OUTPUT
          Write-Output "Version: $ver  Tag: $tag"

      - name: Download release zips and compute SHA256
        id: hashes
        shell: pwsh
        run: |
          $tag  = "${{ steps.version.outputs.TAG }}"
          $repo = "${{ github.repository }}"
          $base = "https://github.com/$repo/releases/download/$tag"

          $archs = @(
            @{ label = "x64";   artifact = "windows-x64"  },
            @{ label = "x86";   artifact = "windows-x86"  },
            @{ label = "arm64"; artifact = "windows-arm64" }
          )

          foreach ($a in $archs) {
            $url  = "$base/psmux-$tag-$($a.artifact).zip"
            $file = "installer-$($a.label).zip"
            Write-Output "Downloading $url ..."
            $ok = $false
            for ($i = 1; $i -le 5; $i++) {
              try {
                Invoke-WebRequest -Uri $url -OutFile $file -UseBasicParsing -ErrorAction Stop
                $ok = $true; break
              } catch {
                if ($i -eq 5) { throw }
                Start-Sleep ($i * 10)
              }
            }
            $hash = (Get-FileHash $file -Algorithm SHA256).Hash
            Write-Output "  SHA256 ($($a.label)): $hash"
            echo "SHA256_$($a.label.ToUpper())=$hash" >> $env:GITHUB_OUTPUT
          }

      - name: Download wingetcreate
        shell: pwsh
        run: |
          $wgcPath = "$env:TEMP\wingetcreate.exe"
          Invoke-WebRequest -Uri https://aka.ms/wingetcreate/latest -OutFile $wgcPath -UseBasicParsing
          Write-Output "WGC_PATH=$wgcPath" >> $env:GITHUB_ENV
          Write-Output "Downloaded wingetcreate to $wgcPath"

      - name: Create WinGet manifests
        shell: pwsh
        run: |
          $ver  = "${{ steps.version.outputs.VERSION }}"
          $tag  = "${{ steps.version.outputs.TAG }}"
          $repo = "${{ github.repository }}"
          $base = "https://github.com/$repo/releases/download/$tag"

          $pkgId  = "marlocarlo.psmux"
          $outDir = "winget-manifests"
          New-Item -ItemType Directory -Force -Path $outDir | Out-Null

          $sha64   = "${{ steps.hashes.outputs.SHA256_X64 }}"
          $sha86   = "${{ steps.hashes.outputs.SHA256_X86 }}"
          $shaArm  = "${{ steps.hashes.outputs.SHA256_ARM64 }}"
          $url64   = "$base/psmux-$tag-windows-x64.zip"
          $url86   = "$base/psmux-$tag-windows-x86.zip"
          $urlArm  = "$base/psmux-$tag-windows-arm64.zip"

          # ---- Version manifest ----
          @"
          # yaml-language-server: `$schema=https://aka.ms/winget-manifest.version.1.9.0.schema.json
          PackageIdentifier: $pkgId
          PackageVersion: $ver
          DefaultLocale: en-US
          ManifestType: version
          ManifestVersion: 1.9.0
          "@ -replace '(?m)^\s{10}','' | Set-Content "$outDir/$pkgId.yaml" -Encoding utf8NoBOM

          # ---- Installer manifest ----
          @"
          # yaml-language-server: `$schema=https://aka.ms/winget-manifest.installer.1.9.0.schema.json
          PackageIdentifier: $pkgId
          PackageVersion: $ver
          Platform:
          - Windows.Desktop
          MinimumOSVersion: 10.0.0.0
          InstallerType: zip
          NestedInstallerType: portable
          NestedInstallerFiles:
          - RelativeFilePath: psmux.exe
            PortableCommandAlias: psmux
          - RelativeFilePath: pmux.exe
            PortableCommandAlias: pmux
          - RelativeFilePath: tmux.exe
            PortableCommandAlias: tmux
          Installers:
          - Architecture: x64
            InstallerUrl: $url64
            InstallerSha256: $sha64
          - Architecture: x86
            InstallerUrl: $url86
            InstallerSha256: $sha86
          - Architecture: arm64
            InstallerUrl: $urlArm
            InstallerSha256: $shaArm
          ManifestType: installer
          ManifestVersion: 1.9.0
          "@ -replace '(?m)^\s{10}','' | Set-Content "$outDir/$pkgId.installer.yaml" -Encoding utf8NoBOM

          # ---- Default locale manifest ----
          @"
          # yaml-language-server: `$schema=https://aka.ms/winget-manifest.defaultLocale.1.9.0.schema.json
          PackageIdentifier: $pkgId
          PackageVersion: $ver
          PackageLocale: en-US
          Publisher: Josh
          PublisherUrl: https://github.com/psmux
          PublisherSupportUrl: https://github.com/psmux/psmux/issues
          PackageName: psmux
          PackageUrl: https://github.com/psmux/psmux
          License: MIT
          LicenseUrl: https://github.com/psmux/psmux/blob/master/LICENSE
          Copyright: Copyright (c) Josh
          ShortDescription: Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal
          Description: |-
            psmux is a terminal multiplexer for Windows, bringing tmux-style split panes,
            multiple windows, sessions, copy mode, mouse support, and a familiar keybinding
            model to PowerShell and Windows Terminal. Ships with psmux, pmux, and tmux
            aliases for drop-in tmux compatibility. No WSL, no Cygwin — pure Windows.
          Moniker: psmux
          Tags:
          - terminal
          - multiplexer
          - tmux
          - powershell
          - windows
          - cli
          - pane
          - session
          - pmux
          ReleaseNotesUrl: https://github.com/psmux/psmux/releases/tag/$tag
          ManifestType: defaultLocale
          ManifestVersion: 1.9.0
          "@ -replace '(?m)^\s{10}','' | Set-Content "$outDir/$pkgId.locale.en-US.yaml" -Encoding utf8NoBOM

          Write-Output "Manifests created:"
          Get-ChildItem $outDir | ForEach-Object {
            Write-Output "  $($_.Name)"
            Get-Content $_.FullName | ForEach-Object { Write-Output "    $_" }
            Write-Output ""
          }

      - name: Submit manifests to WinGet (PR to microsoft/winget-pkgs)
        shell: pwsh
        run: |
          # submit validates manifests internally before creating the PR
          & $env:WGC_PATH submit "winget-manifests" --token "${{ secrets.WINGET_PAT }}" 2>&1
          if ($LASTEXITCODE -ne 0) {
            Write-Error "wingetcreate submit failed (exit $LASTEXITCODE)."
            exit 1
          }
          Write-Output "PR submitted to microsoft/winget-pkgs!"
          Write-Output "Track at: https://github.com/microsoft/winget-pkgs/pulls?q=is%3Apr+marlocarlo.psmux"


================================================
FILE: .gitignore
================================================
# Build artifacts
target/

# Backup and temp files
*.rs.bk
*.swp
*.tmp
~*

# IDE/editor
.vscode/
.idea/
*.code-workspace

# Trae workspace
.trae/

# Note: Cargo.lock is committed (recommended for binaries)

# OS files
.DS_Store
Thumbs.db
desktop.ini

# Binary and executable files
*.exe
*.dll
*.so
*.dylib
*.a
*.lib
*.o
*.obj
*.pdb

# Large media files
*.mp4
*.avi
*.mov
*.mkv
*.mp3
*.wav
*.flac
*.zip
*.tar
*.tar.gz
*.rar
*.7z
*.iso
*.dmg

# Log files
*.log

# Debug/temp output files
stderr.txt
stdout.txt
temp_cmd.txt

# Test/bugfix result logs (never commit these)
*bugfix*.txt
*bug_fix*.txt
*test_result*.txt
*test_bugfix*.txt
*fix_results*.txt
*_results.txt
*test_*.txt
*tmp_*.txt

# Database files
*.db
*.sqlite
*.sqlite3

# Environment and secrets
.env
.env.local
*.key
*.pem
psmux-windows-x86_64/
psmux-windows-x86_64.zip

# Release artifacts (generated by CI/CD, not source)
release/
*.nupkg


================================================
FILE: Cargo.toml
================================================
[package]
name = "psmux"
version = "3.3.4"
edition = "2021"
description = "Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal"
license = "MIT"
repository = "https://github.com/psmux/psmux"
readme = "README.md"
keywords = ["terminal", "multiplexer", "tmux", "windows", "powershell"]
categories = ["command-line-utilities"]

[workspace]
members = [".", "crates/portable-pty-psmux", "crates/vt100-psmux"]
exclude = [
    "target/",
    "release/",
    "tests/",
    "tests-rs/",
    "packages/",
    "psmux-windows-x86_64/",
    ".github/",
    "scripts/",
    "scoop/",
    "examples/",
    "*.txt",
]

# Disable auto-discovery of integration tests from tests/ directory
[[test]]
name = "test_vt100_mouse"
path = "tests-rs/test_vt100_mouse.rs"

[[test]]
name = "test_issue155_sgr_attrs"
path = "tests-rs/test_issue155_sgr_attrs.rs"

[[test]]
name = "test_issue155_rendering"
path = "tests-rs/test_issue155_rendering.rs"

[[test]]
name = "test_issue201_rename_dialog"
path = "tests-rs/test_issue201_rename_dialog.rs"

[[test]]
name = "test_issue269_osc94_dropped"
path = "tests-rs/test_issue269_osc94_dropped.rs"

[[test]]
name = "test_h1_osc52_clipboard_capture"
path = "tests-rs/test_h1_osc52_clipboard_capture.rs"

[[test]]
name = "test_h1_osc52_end_to_end"
path = "tests-rs/test_h1_osc52_end_to_end.rs"

# Windows only
[target.'cfg(not(windows))'.dependencies]
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61", features = [
    "Win32_Foundation",
    "Win32_System_Memory",
    "Win32_System_DataExchange",
] }

[[bin]]
name = "psmux"
path = "src/main.rs"

[[bin]]
name = "pmux"
path = "src/main.rs"

[[bin]]
name = "tmux"
path = "src/main.rs"

[dependencies]
ratatui = "0.30"
crossterm = "0.29"
portable-pty = { version = "0.9.3", path = "crates/portable-pty-psmux", package = "portable-pty-psmux" }
which = "8"
chrono = "0.4"
vt100 = { version = "0.16.6", path = "crates/vt100-psmux", package = "vt100-psmux" }
unicode-width = "0.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
regex = "1"
glob = "0.3"
anyhow = "1"
base64 = "0.22"

[profile.release]
opt-level = 3
lto = true
codegen-units = 1
strip = "symbols"


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2025 Josh

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
```
╔═══════════════════════════════════════════════════════════╗
║   ██████╗ ███████╗███╗   ███╗██╗   ██╗██╗  ██╗            ║
║   ██╔══██╗██╔════╝████╗ ████║██║   ██║╚██╗██╔╝            ║
║   ██████╔╝███████╗██╔████╔██║██║   ██║ ╚███╔╝             ║
║   ██╔═══╝ ╚════██║██║╚██╔╝██║██║   ██║ ██╔██╗             ║
║   ██║     ███████║██║ ╚═╝ ██║╚██████╔╝██╔╝ ██╗            ║
║   ╚═╝     ╚══════╝╚═╝     ╚═╝ ╚═════╝ ╚═╝  ╚═╝            ║
║     Born in PowerShell. Made in Rust. 🦀                 ║
║          Terminal Multiplexer for Windows                 ║
╚═══════════════════════════════════════════════════════════╝
```

<p align="center">
  <strong>The native Windows tmux. Born in PowerShell, made in Rust.</strong><br/>
  Full mouse support · tmux themes · tmux config · 83 commands · blazing fast
</p>

<p align="center">
  <a href="#installation">Install</a> ·
  <a href="#usage">Usage</a> ·
  <a href="docs/claude-code.md">Claude Code</a> ·
  <a href="docs/features.md">Features</a> ·
  <a href="docs/compatibility.md">Compatibility</a> ·
  <a href="docs/performance.md">Performance</a> ·
  <a href="docs/plugins.md">Plugins</a> ·
  <a href="docs/keybindings.md">Keys</a> ·
  <a href="docs/scripting.md">Scripting</a> ·
  <a href="docs/configuration.md">Config</a> ·
  <a href="docs/mouse-ssh.md">Mouse/SSH</a> ·
  <a href="docs/faq.md">FAQ</a> ·
  <a href="#related-projects">Related Projects</a>
</p>

---

# psmux

**The real tmux for Windows.** Not a port, not a wrapper, not a workaround.

psmux is a **native Windows terminal multiplexer** built from the ground up in Rust. It uses Windows ConPTY directly, speaks the tmux command language, reads your `.tmux.conf`, and supports tmux themes. All without WSL, Cygwin, or MSYS2.

> 💡 **Tip:** psmux ships with `tmux` and `pmux` aliases. Just type `tmux` and it works!

👀 On Windows 👇

![psmux in action](demo.gif)

## Installation

### Using WinGet

```powershell
winget install psmux
```

### Using Cargo

```powershell
cargo install psmux
```

This installs `psmux`, `pmux`, and `tmux` binaries to your Cargo bin directory.

### Using Scoop

```powershell
scoop bucket add psmux https://github.com/psmux/scoop-psmux
scoop install psmux
```

### Using Chocolatey

```powershell
choco install psmux
```

### From GitHub Releases

Download the latest `.zip` from [GitHub Releases](https://github.com/psmux/psmux/releases) and add to your PATH.

### From Source

```powershell
git clone https://github.com/psmux/psmux.git
cd psmux
cargo build --release
```

Built binaries:

```text
target\release\psmux.exe
target\release\pmux.exe
target\release\tmux.exe
```

### Docker (build environment)

A ready-made Windows container with Rust + MSVC + SSH for building psmux:

```powershell
cd docker
docker build -t psmux-dev .
docker run -d --name psmux-dev -p 127.0.0.1:2222:22 -e ADMIN_PASSWORD=YourPass123! psmux-dev
ssh ContainerAdministrator@localhost -p 2222
```

See [docker/README.md](docker/README.md) for full details.

### Requirements

- Windows 10 or Windows 11
- **PowerShell 7+** (recommended) or cmd.exe
  - Download PowerShell: `winget install --id Microsoft.PowerShell`
  - Or visit: https://aka.ms/powershell

## Why psmux?

If you've used tmux on Linux/macOS and wished you had something like it on Windows, **this is it**. Split panes, multiple windows, session persistence, full mouse support, tmux themes, 83 commands, 140+ format variables, 53 vim copy-mode keys. Your existing `.tmux.conf` works. Full details: **[docs/features.md](docs/features.md)** · **[docs/compatibility.md](docs/compatibility.md)**

## Usage

Use `psmux`, `pmux`, or `tmux` — they're identical:

```powershell
psmux                        # Start a new session
psmux new-session -s work    # Named session
psmux ls                     # List sessions
psmux attach -t work         # Attach to a session
psmux --help                 # Show help
```

## Claude Code Agent Teams

psmux has first-class support for Claude Code agent teams. When Claude Code runs inside a psmux session, teammate agents automatically spawn in separate tmux panes instead of running in-process.

```powershell
psmux new-session -s work    # Start a psmux session
claude                       # Run Claude Code — agent teams just work
```

No extra configuration needed. Full guide: **[docs/claude-code.md](docs/claude-code.md)**

## Documentation

| Topic | Description |
|-------|-------------|
| **[Features](docs/features.md)** | Full feature list — mouse, copy mode, layouts, format engine |
| **[Compatibility](docs/compatibility.md)** | tmux command/config compatibility matrix |
| **[Performance](docs/performance.md)** | Benchmarks and optimization details |
| **[Key Bindings](docs/keybindings.md)** | Default keys and customization |
| **[Scripting](docs/scripting.md)** | 83 commands, hooks, targets, pipe-pane |
| **[Configuration](docs/configuration.md)** | Config files, options, environment variables |
| **[Plugins & Themes](docs/plugins.md)** | Plugin ecosystem — Catppuccin, Dracula, Nord, and more |
| **[Mouse Over SSH](docs/mouse-ssh.md)** | SSH mouse support and Windows version requirements |
| **[Claude Code](docs/claude-code.md)** | Agent teams integration guide |
| **[FAQ](docs/faq.md)** | Common questions and answers |

## Related Projects

<table>
  <tr>
    <td align="center" width="50%">
      <a href="https://github.com/psmux/pstop">
        <img src="https://raw.githubusercontent.com/psmux/pstop/master/pstop-demo.gif" width="400" alt="pstop demo" /><br/>
        <b>pstop</b>
      </a><br/>
      <sub>htop for Windows — real-time system monitor with per-core CPU bars, tree view, 7 color schemes</sub><br/>
      <code>cargo install pstop</code>
    </td>
    <td align="center" width="50%">
      <a href="https://github.com/psmux/psnet">
        <img src="https://raw.githubusercontent.com/psmux/psnet/master/image.png" width="400" alt="psnet screenshot" /><br/>
        <b>psnet</b>
      </a><br/>
      <sub>Real-time TUI network monitor — live speed graphs, connections, traffic log, packet sniffer</sub><br/>
      <code>cargo install psnet</code>
    </td>
  </tr>
  <tr>
    <td align="center" width="50%">
      <a href="https://github.com/psmux/Tmux-Plugin-Panel">
        <img src="https://raw.githubusercontent.com/psmux/Tmux-Plugin-Panel/master/screenshot.png" width="400" alt="Tmux Plugin Panel screenshot" /><br/>
        <b>Tmux Plugin Panel</b>
      </a><br/>
      <sub>TUI plugin & theme manager for tmux and psmux — browse, install, update from your terminal</sub><br/>
      <code>cargo install tmuxpanel</code>
    </td>
    <td align="center" width="50%">
      <a href="https://github.com/psmux/omp-manager">
        <img src="https://raw.githubusercontent.com/psmux/omp-manager/master/screenshot.png" width="400" alt="OMP Manager screenshot" /><br/>
        <b>OMP Manager</b>
      </a><br/>
      <sub>Oh My Posh setup wizard — browse 100+ themes, install fonts, configure shells automatically</sub><br/>
      <code>cargo install omp-manager</code>
    </td>
  </tr>
</table>

## License

MIT

## Contributing

Contributions welcome — bug reports, PRs, docs, and test scripts via [GitHub Issues](https://github.com/psmux/psmux/issues).

If psmux helps your Windows workflow, consider giving it a ⭐ on GitHub!

## Star History

[![Star History Chart](https://api.star-history.com/image?repos=psmux/psmux&type=date&legend=top-left)](https://www.star-history.com/?repos=psmux%2Fpsmux&type=date&legend=top-left)

---

<p align="center">
  Made with ❤️ for PowerShell using Rust 🦀
</p>


================================================
FILE: choco-pkg/psmux.nuspec
================================================
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
  <metadata>
    <id>psmux</id>
    <version>3.3.3</version>
    <title>psmux - Terminal Multiplexer for Windows</title>
    <authors>Josh</authors>
    <owners>Josh</owners>
    <licenseUrl>https://github.com/psmux/psmux/blob/master/LICENSE</licenseUrl>
    <projectUrl>https://github.com/psmux/psmux</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal. Includes psmux, pmux, and tmux commands.</description>
    <summary>Terminal multiplexer for Windows (tmux alternative)</summary>
    <releaseNotes>https://github.com/psmux/psmux/releases</releaseNotes>
    <tags>terminal multiplexer tmux powershell cli windows psmux pmux</tags>
    <packageSourceUrl>https://github.com/psmux/psmux</packageSourceUrl>
    <docsUrl>https://github.com/psmux/psmux#readme</docsUrl>
    <bugTrackerUrl>https://github.com/psmux/psmux/issues</bugTrackerUrl>
  </metadata>
  <files>
    <file src="tools\**" target="tools" />
  </files>
</package>

================================================
FILE: choco-pkg/tools/chocolateyinstall.ps1
================================================
$ErrorActionPreference = 'Stop'

$toolsDir = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"
$url64 = 'https://github.com/psmux/psmux/releases/download/v3.3.3/psmux-v3.3.3-windows-x64.zip'

$packageArgs = @{
  packageName    = $env:ChocolateyPackageName
  unzipLocation  = $toolsDir
  url64bit       = $url64
  checksum64     = 'E6FE103A776ED453647F82254445CBD4BA851E1A14BCBB959FDF858DE16CE5DD'
  checksumType64 = 'sha256'
}

Install-ChocolateyZipPackage @packageArgs

$psmuxPath = Join-Path $toolsDir "psmux.exe"
$pmuxPath = Join-Path $toolsDir "pmux.exe"
$tmuxPath = Join-Path $toolsDir "tmux.exe"

Install-BinFile -Name "psmux" -Path $psmuxPath
Install-BinFile -Name "pmux" -Path $pmuxPath
Install-BinFile -Name "tmux" -Path $tmuxPath

================================================
FILE: choco-pkg/tools/chocolateyuninstall.ps1
================================================
Uninstall-BinFile -Name "psmux"
Uninstall-BinFile -Name "pmux"
Uninstall-BinFile -Name "tmux"

================================================
FILE: crates/portable-pty-psmux/.cargo-ok
================================================
{"v":1}

================================================
FILE: crates/portable-pty-psmux/.cargo_vcs_info.json
================================================
{
  "git": {
    "sha1": "d389cf717cdb7702c9a732d1d9bc0b6f08603b4a"
  },
  "path_in_vcs": ""
}

================================================
FILE: crates/portable-pty-psmux/Cargo.toml
================================================
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.

[package]
edition = "2018"
name = "portable-pty-psmux"
version = "0.9.3"
authors = ["Wez Furlong"]
build = false
include = [
    "src/**/*",
    "LICENSE.md",
    "README.md",
    "Cargo.toml",
    "examples/**/*",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Cross platform pty interface (psmux fork with ConPTY PASSTHROUGH_MODE + WIN32_INPUT_MODE + RESIZE_QUIRK patches)"
documentation = "https://docs.rs/portable-pty"
readme = false
license = "MIT"
repository = "https://github.com/psmux/portable-pty-patched"
resolver = "2"

[features]
default = []
serde_support = [
    "serde",
    "serde_derive",
]

[lib]
name = "portable_pty"
path = "src/lib.rs"

[[example]]
name = "bash"
path = "examples/bash.rs"

[[example]]
name = "narrow"
path = "examples/narrow.rs"

[[example]]
name = "whoami"
path = "examples/whoami.rs"

[[example]]
name = "whoami_async"
path = "examples/whoami_async.rs"

[dependencies.anyhow]
version = "1.0"

[dependencies.downcast-rs]
version = "2.0"

[dependencies.filedescriptor]
version = "0.8.3"

[dependencies.libc]
version = "0.2"

[dependencies.log]
version = "0.4"

[dependencies.nix]
version = "0.31"
features = [
    "term",
    "fs",
]

[dependencies.serde]
version = "1.0"
optional = true

[dependencies.serde_derive]
version = "1.0"
optional = true

[dependencies.serial2]
version = "0.2"

[dependencies.shell-words]
version = "1.1"

[dev-dependencies.futures]
version = "0.3"

[dev-dependencies.smol]
version = "2.0"

[target."cfg(windows)".dependencies.lazy_static]
version = "1.4"

[target."cfg(windows)".dependencies.shared_library]
version = "0.1"

[target."cfg(windows)".dependencies.winapi]
version = "0.3"
features = [
    "winuser",
    "consoleapi",
    "handleapi",
    "fileapi",
    "namedpipeapi",
    "synchapi",
    "libloaderapi",
    "winnt",
]

[target."cfg(windows)".dependencies.winreg]
version = "0.56"


================================================
FILE: crates/portable-pty-psmux/Cargo.toml.orig
================================================
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.

[package]
edition = "2018"
name = "portable-pty-psmux"
version = "0.9.1"
authors = ["Wez Furlong"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Cross platform pty interface (psmux fork with ConPTY PASSTHROUGH_MODE + WIN32_INPUT_MODE + RESIZE_QUIRK patches)"
documentation = "https://docs.rs/portable-pty"
readme = false
license = "MIT"
repository = "https://github.com/marlocarlo/portable-pty-patched"
include = ["src/**/*", "LICENSE.md", "README.md", "Cargo.toml", "examples/**/*"]
resolver = "2"

[lib]
name = "portable_pty"
path = "src/lib.rs"

[[example]]
name = "bash"
path = "examples/bash.rs"

[[example]]
name = "narrow"
path = "examples/narrow.rs"

[[example]]
name = "whoami"
path = "examples/whoami.rs"

[[example]]
name = "whoami_async"
path = "examples/whoami_async.rs"

[dependencies.anyhow]
version = "1.0"

[dependencies.downcast-rs]
version = "1.0"

[dependencies.filedescriptor]
version = "0.8.3"

[dependencies.libc]
version = "0.2"

[dependencies.log]
version = "0.4"

[dependencies.nix]
version = "0.28"
features = [
    "term",
    "fs",
]

[dependencies.serde]
version = "1.0"
optional = true

[dependencies.serde_derive]
version = "1.0"
optional = true

[dependencies.serial2]
version = "0.2"

[dependencies.shell-words]
version = "1.1"

[dev-dependencies.futures]
version = "0.3"

[dev-dependencies.smol]
version = "2.0"

[features]
default = []
serde_support = [
    "serde",
    "serde_derive",
]

[target."cfg(windows)".dependencies.bitflags]
version = "1.3"

[target."cfg(windows)".dependencies.lazy_static]
version = "1.4"

[target."cfg(windows)".dependencies.shared_library]
version = "0.1"

[target."cfg(windows)".dependencies.winapi]
version = "0.3"
features = [
    "winuser",
    "consoleapi",
    "handleapi",
    "fileapi",
    "namedpipeapi",
    "synchapi",
    "libloaderapi",
    "winnt",
]

[target."cfg(windows)".dependencies.winreg]
version = "0.10"


================================================
FILE: crates/portable-pty-psmux/LICENSE.md
================================================
MIT License

Copyright (c) 2018 Wez Furlong

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: crates/portable-pty-psmux/README.md
================================================
# portable-pty-patched

Patched version of [portable-pty](https://crates.io/crates/portable-pty) v0.9.0 (originally from [wez/wezterm](https://github.com/wez/wezterm)) with ConPTY flag support required by [psmux](https://github.com/psmux/psmux).

## Why this exists

`portable-pty` is not published as a standalone repo — it lives inside the wezterm monorepo, making a proper GitHub fork impractical (we'd be forking an entire terminal emulator project just for one file change).

The upstream crate does not pass modern ConPTY creation flags that psmux needs for correct terminal behavior on Windows 10/11.

## Patches (`src/win/psuedocon.rs`)

### New ConPTY flags
- **`PSEUDOCONSOLE_RESIZE_QUIRK`** (0x2) — fixes resize artifacts
- **`PSEUDOCONSOLE_WIN32_INPUT_MODE`** (0x4) — enables Win32 input mode for proper key handling
- **`PSEUDOCONSOLE_PASSTHROUGH_MODE`** (0x8) — relays VT sequences directly from child processes (Windows 11 22H2+ only), enabling cursor shape forwarding, DECSCUSR, etc.

### Build detection (`supports_passthrough_mode()`)
Uses `RtlGetVersion` to detect Windows build >= 22621 (Windows 11 22H2). On older builds, passthrough mode is skipped to avoid broken ConPTY output.

### Two-tier `PsuedoCon::new()`
1. Attempts `CreatePseudoConsole` with all flags including `PASSTHROUGH_MODE` on supported builds
2. Falls back to base flags (without passthrough) if the call fails or on older Windows

### Cargo.toml
Added `libloaderapi` and `winnt` features to `winapi` dependency for `GetModuleHandleW`/`GetProcAddress`/`RtlGetVersion`.

## Usage

In your `Cargo.toml`:
```toml
portable-pty = { git = "https://github.com/psmux/portable-pty-patched.git", branch = "main" }
```

## Keeping up to date

This is **not** a GitHub fork (upstream lives inside wezterm monorepo). To sync with a new upstream release:
1. Download the new version from [crates.io](https://crates.io/crates/portable-pty)
2. Re-apply the patches to `src/win/psuedocon.rs` and `Cargo.toml`


================================================
FILE: crates/portable-pty-psmux/examples/bash.rs
================================================
//! This example demonstrates how to spawn a Bash shell using the `portable_pty` crate.
//! based on pty/examples/whoami.rs

use portable_pty::{CommandBuilder, NativePtySystem, PtySize, PtySystem};
use std::io::{Read, Write};
use std::sync::mpsc::channel;
use std::thread;

fn main() {
    let pty_system = NativePtySystem::default();

    // Open the PTY with specified size.
    let pair = pty_system
        .openpty(PtySize {
            rows: 24,
            cols: 80,
            pixel_width: 0,
            pixel_height: 0,
        })
        .unwrap();

    // Set up the command to launch Bash.
    let cmd = CommandBuilder::new("bash");
    let mut child = pair.slave.spawn_command(cmd).unwrap();

    drop(pair.slave);

    // Set up channels for reading and writing.
    let (tx, rx) = channel::<String>();
    let mut reader = pair.master.try_clone_reader().unwrap();
    let master_writer = pair.master.take_writer().unwrap();

    // Thread to read from the PTY and send data to the main thread.
    thread::spawn(move || {
        let mut buffer = [0u8; 1024];
        loop {
            match reader.read(&mut buffer) {
                Ok(0) => break, // EOF
                Ok(n) => {
                    let output = String::from_utf8_lossy(&buffer[..n]);
                    println!("{}", output); // Print to stdout for visibility.
                }
                Err(e) => {
                    eprintln!("Error reading from PTY: {}", e);
                    break;
                }
            }
        }
    });

    // Thread to write input into the PTY.
    let tx_writer = thread::spawn(move || {
        handle_input_stream(rx, master_writer);
    });

    println!("You can now type commands for Bash (type 'exit' to quit):");

    // Main thread sends user input to the writer thread.
    loop {
        let mut input = String::new();
        std::io::stdin().read_line(&mut input).unwrap();

        if input.trim() == "exit" {
            break;
        }

        tx.send(input).unwrap();
    }

    drop(tx);
    tx_writer.join().unwrap();

    println!("Waiting for Bash to exit...");
    let status = child.wait().unwrap();
    println!("Bash exited with status: {:?}", status);
}

fn handle_input_stream(rx: std::sync::mpsc::Receiver<String>, mut writer: Box<dyn Write + Send>) {
    for input in rx.iter() {
        if writer.write_all(input.as_bytes()).is_err() {
            eprintln!("Error writing to PTY");
            break;
        }
    }
}


================================================
FILE: crates/portable-pty-psmux/examples/narrow.rs
================================================
//! Runs a command with a fixed terminal size.
//! This is used by wezterm's doc building automation to keep
//! the --help output within a reasonable width
use portable_pty::{CommandBuilder, NativePtySystem, PtySize, PtySystem};
use std::sync::mpsc::channel;

fn main() {
    let pty_system = NativePtySystem::default();

    let pair = pty_system
        .openpty(PtySize {
            rows: 24,
            cols: 80,
            pixel_width: 0,
            pixel_height: 0,
        })
        .unwrap();

    let mut args = std::env::args_os().skip(1);

    let mut cmd = CommandBuilder::new(args.next().unwrap());
    cmd.args(args);

    let mut child = pair.slave.spawn_command(cmd).unwrap();

    // Release any handles owned by the slave: we don't need it now
    // that we've spawned the child.
    drop(pair.slave);

    // Read the output in another thread.
    // This is important because it is easy to encounter a situation
    // where read/write buffers fill and block either your process
    // or the spawned process.
    let (tx, rx) = channel();
    let mut reader = pair.master.try_clone_reader().unwrap();
    std::thread::spawn(move || {
        // Consume the output from the child
        let mut s = String::new();
        reader.read_to_string(&mut s).unwrap();
        tx.send(s).unwrap();
    });

    {
        // Obtain the writer.
        // When the writer is dropped, EOF will be sent to
        // the program that was spawned.
        // It is important to take the writer even if you don't
        // send anything to its stdin so that EOF can be
        // generated, otherwise you risk deadlocking yourself.
        let mut writer = pair.master.take_writer().unwrap();

        if cfg!(target_os = "macos") {
            // macOS quirk: the child and reader must be started and
            // allowed a brief grace period to run before we allow
            // the writer to drop. Otherwise, the data we send to
            // the kernel to trigger EOF is interleaved with the
            // data read by the reader! WTF!?
            // This appears to be a race condition for very short
            // lived processes on macOS.
            // I'd love to find a more deterministic solution to
            // this than sleeping.
            std::thread::sleep(std::time::Duration::from_millis(20));
        }

        // This example doesn't need to write anything, but if you
        // want to send data to the child, you'd set `to_write` to
        // that data and do it like this:
        let to_write = "";
        if !to_write.is_empty() {
            // To avoid deadlock, wrt. reading and waiting, we send
            // data to the stdin of the child in a different thread.
            std::thread::spawn(move || {
                writer.write_all(to_write.as_bytes()).unwrap();
            });
        }
    }

    // Wait for the child to complete
    eprintln!("child status: {:?}", child.wait().unwrap());

    // Take care to drop the master after our processes are
    // done, as some platforms get unhappy if it is dropped
    // sooner than that.
    drop(pair.master);

    // Now wait for the output to be read by our reader thread
    let output = rx.recv().unwrap();

    let output = output.replace("\r\n", "\n");

    print!("{output}");
}


================================================
FILE: crates/portable-pty-psmux/examples/whoami.rs
================================================
//! This is a conceptually simple example that spawns the `whoami` program
//! to print your username.  It is made more complex because there are multiple
//! pipes involved and it is easy to get blocked/deadlocked if care and attention
//! is not paid to those pipes!
use portable_pty::{CommandBuilder, NativePtySystem, PtySize, PtySystem};
use std::sync::mpsc::channel;

fn main() {
    let pty_system = NativePtySystem::default();

    let pair = pty_system
        .openpty(PtySize {
            rows: 24,
            cols: 80,
            pixel_width: 0,
            pixel_height: 0,
        })
        .unwrap();

    let cmd = CommandBuilder::new("whoami");
    let mut child = pair.slave.spawn_command(cmd).unwrap();

    // Release any handles owned by the slave: we don't need it now
    // that we've spawned the child.
    drop(pair.slave);

    // Read the output in another thread.
    // This is important because it is easy to encounter a situation
    // where read/write buffers fill and block either your process
    // or the spawned process.
    let (tx, rx) = channel();
    let mut reader = pair.master.try_clone_reader().unwrap();
    std::thread::spawn(move || {
        // Consume the output from the child
        let mut s = String::new();
        reader.read_to_string(&mut s).unwrap();
        tx.send(s).unwrap();
    });

    {
        // Obtain the writer.
        // When the writer is dropped, EOF will be sent to
        // the program that was spawned.
        // It is important to take the writer even if you don't
        // send anything to its stdin so that EOF can be
        // generated, otherwise you risk deadlocking yourself.
        let mut writer = pair.master.take_writer().unwrap();

        if cfg!(target_os = "macos") {
            // macOS quirk: the child and reader must be started and
            // allowed a brief grace period to run before we allow
            // the writer to drop. Otherwise, the data we send to
            // the kernel to trigger EOF is interleaved with the
            // data read by the reader! WTF!?
            // This appears to be a race condition for very short
            // lived processes on macOS.
            // I'd love to find a more deterministic solution to
            // this than sleeping.
            std::thread::sleep(std::time::Duration::from_millis(20));
        }

        // This example doesn't need to write anything, but if you
        // want to send data to the child, you'd set `to_write` to
        // that data and do it like this:
        let to_write = "";
        if !to_write.is_empty() {
            // To avoid deadlock, wrt. reading and waiting, we send
            // data to the stdin of the child in a different thread.
            std::thread::spawn(move || {
                writer.write_all(to_write.as_bytes()).unwrap();
            });
        }
    }

    // Wait for the child to complete
    println!("child status: {:?}", child.wait().unwrap());

    // Take care to drop the master after our processes are
    // done, as some platforms get unhappy if it is dropped
    // sooner than that.
    drop(pair.master);

    // Now wait for the output to be read by our reader thread
    let output = rx.recv().unwrap();

    // We print with escapes escaped because the windows conpty
    // implementation synthesizes title change escape sequences
    // in the output stream and it can be confusing to see those
    // printed out raw in another terminal.
    print!("output: ");
    for c in output.escape_debug() {
        print!("{}", c);
    }
}


================================================
FILE: crates/portable-pty-psmux/examples/whoami_async.rs
================================================
use anyhow::anyhow;
use futures::prelude::*;
use portable_pty::{native_pty_system, CommandBuilder, PtySize};

// This example shows how to use the `smol` crate to use portable_pty
// in an asynchronous application.

fn main() -> anyhow::Result<()> {
    smol::block_on(async {
        let pty_system = native_pty_system();

        let pair = pty_system.openpty(PtySize {
            rows: 24,
            cols: 80,
            pixel_width: 0,
            pixel_height: 0,
        })?;

        let cmd = CommandBuilder::new("whoami");

        // Move the slave to another thread to block and spawn a
        // command.
        // Note that this implicitly drops slave and closes out
        // file handles which is important to avoid deadlock
        // when waiting for the child process!
        let slave = pair.slave;
        let mut child = smol::unblock(move || slave.spawn_command(cmd)).await?;

        {
            // Obtain the writer.
            // When the writer is dropped, EOF will be sent to
            // the program that was spawned.
            // It is important to take the writer even if you don't
            // send anything to its stdin so that EOF can be
            // generated, otherwise you risk deadlocking yourself.
            let writer = pair.master.take_writer()?;

            // Explicitly generate EOF
            drop(writer);
        }

        println!(
            "child status: {:?}",
            smol::unblock(move || child
                .wait()
                .map_err(|e| anyhow!("waiting for child: {}", e)))
            .await?
        );

        let reader = pair.master.try_clone_reader()?;

        // Take care to drop the master after our processes are
        // done, as some platforms get unhappy if it is dropped
        // sooner than that.
        drop(pair.master);

        let mut lines = smol::io::BufReader::new(smol::Unblock::new(reader)).lines();
        while let Some(line) = lines.next().await {
            let line = line.map_err(|e| anyhow!("problem reading line: {}", e))?;
            // We print with escapes escaped because the windows conpty
            // implementation synthesizes title change escape sequences
            // in the output stream and it can be confusing to see those
            // printed out raw in another terminal.
            print!("output: len={} ", line.len());
            for c in line.escape_debug() {
                print!("{}", c);
            }
            println!();
        }

        Ok(())
    })
}


================================================
FILE: crates/portable-pty-psmux/src/cmdbuilder.rs
================================================
#[cfg(unix)]
use anyhow::Context;
#[cfg(feature = "serde_support")]
use serde_derive::*;
use std::collections::BTreeMap;
use std::ffi::{OsStr, OsString};
#[cfg(windows)]
use std::os::windows::ffi::OsStrExt;
#[cfg(unix)]
use std::path::Component;
use std::path::Path;

/// Used to deal with Windows having case-insensitive environment variables.
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
struct EnvEntry {
    /// Whether or not this environment variable came from the base environment,
    /// as opposed to having been explicitly set by the caller.
    is_from_base_env: bool,

    /// For case-insensitive platforms, the environment variable key in its preferred casing.
    preferred_key: OsString,

    /// The environment variable value.
    value: OsString,
}

impl EnvEntry {
    fn map_key(k: OsString) -> OsString {
        if cfg!(windows) {
            // Best-effort lowercase transformation of an os string
            match k.to_str() {
                Some(s) => s.to_lowercase().into(),
                None => k,
            }
        } else {
            k
        }
    }
}

#[cfg(unix)]
fn get_shell() -> String {
    use nix::unistd::{access, AccessFlags};
    use std::ffi::CStr;
    use std::str;

    let ent = unsafe { libc::getpwuid(libc::getuid()) };
    if !ent.is_null() {
        let shell = unsafe { CStr::from_ptr((*ent).pw_shell) };
        match shell.to_str().map(str::to_owned) {
            Err(err) => {
                log::warn!(
                    "passwd database shell could not be \
                     represented as utf-8: {err:#}, \
                     falling back to /bin/sh"
                );
            }
            Ok(shell) => {
                if let Err(err) = access(Path::new(&shell), AccessFlags::X_OK) {
                    log::warn!(
                        "passwd database shell={shell:?} which is \
                         not executable ({err:#}), falling back to /bin/sh"
                    );
                } else {
                    return shell;
                }
            }
        }
    }
    "/bin/sh".into()
}

fn get_base_env() -> BTreeMap<OsString, EnvEntry> {
    let mut env: BTreeMap<OsString, EnvEntry> = std::env::vars_os()
        .map(|(key, value)| {
            (
                EnvEntry::map_key(key.clone()),
                EnvEntry {
                    is_from_base_env: true,
                    preferred_key: key,
                    value,
                },
            )
        })
        .collect();

    #[cfg(unix)]
    {
        let key = EnvEntry::map_key("SHELL".into());
        // Only set the value of SHELL if it isn't already set
        if !env.contains_key(&key) {
            env.insert(
                EnvEntry::map_key("SHELL".into()),
                EnvEntry {
                    is_from_base_env: true,
                    preferred_key: "SHELL".into(),
                    value: get_shell().into(),
                },
            );
        }
    }

    #[cfg(windows)]
    {
        use std::os::windows::ffi::OsStringExt;
        use winapi::um::processenv::ExpandEnvironmentStringsW;
        use winreg::enums::{RegType, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
        use winreg::types::FromRegValue;
        use winreg::{RegKey, RegValue};

        fn reg_value_to_string(value: &RegValue) -> anyhow::Result<OsString> {
            match value.vtype {
                RegType::REG_EXPAND_SZ => {
                    let src = unsafe {
                        std::slice::from_raw_parts(
                            value.bytes.as_ptr() as *const u16,
                            value.bytes.len() / 2,
                        )
                    };
                    let size =
                        unsafe { ExpandEnvironmentStringsW(src.as_ptr(), std::ptr::null_mut(), 0) };
                    let mut buf = vec![0u16; size as usize + 1];
                    unsafe {
                        ExpandEnvironmentStringsW(src.as_ptr(), buf.as_mut_ptr(), buf.len() as u32)
                    };

                    let mut buf = buf.as_slice();
                    while let Some(0) = buf.last() {
                        buf = &buf[0..buf.len() - 1];
                    }
                    Ok(OsString::from_wide(buf))
                }
                _ => Ok(OsString::from_reg_value(value)?),
            }
        }

        if let Ok(sys_env) = RegKey::predef(HKEY_LOCAL_MACHINE)
            .open_subkey("System\\CurrentControlSet\\Control\\Session Manager\\Environment")
        {
            for res in sys_env.enum_values() {
                if let Ok((name, value)) = res {
                    if name.eq_ignore_ascii_case("username") {
                        continue;
                    }
                    if let Ok(value) = reg_value_to_string(&value) {
                        log::trace!("adding SYS env: {:?} {:?}", name, value);
                        env.insert(
                            EnvEntry::map_key(name.clone().into()),
                            EnvEntry {
                                is_from_base_env: true,
                                preferred_key: name.into(),
                                value,
                            },
                        );
                    }
                }
            }
        }

        if let Ok(sys_env) = RegKey::predef(HKEY_CURRENT_USER).open_subkey("Environment") {
            for res in sys_env.enum_values() {
                if let Ok((name, value)) = res {
                    if let Ok(value) = reg_value_to_string(&value) {
                        // Merge the system and user paths together
                        let value = if name.eq_ignore_ascii_case("path") {
                            match env.get(&EnvEntry::map_key(name.clone().into())) {
                                Some(entry) => {
                                    let mut result = OsString::new();
                                    result.push(&entry.value);
                                    result.push(";");
                                    result.push(&value);
                                    result
                                }
                                None => value,
                            }
                        } else {
                            value
                        };

                        log::trace!("adding USER env: {:?} {:?}", name, value);
                        env.insert(
                            EnvEntry::map_key(name.clone().into()),
                            EnvEntry {
                                is_from_base_env: true,
                                preferred_key: name.into(),
                                value,
                            },
                        );
                    }
                }
            }
        }
    }

    env
}

/// `CommandBuilder` is used to prepare a command to be spawned into a pty.
/// The interface is intentionally similar to that of `std::process::Command`.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
pub struct CommandBuilder {
    args: Vec<OsString>,
    envs: BTreeMap<OsString, EnvEntry>,
    cwd: Option<OsString>,
    #[cfg(unix)]
    pub(crate) umask: Option<libc::mode_t>,
    controlling_tty: bool,
}

impl CommandBuilder {
    /// Create a new builder instance with argv\[0\] set to the specified
    /// program.
    pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
        Self {
            args: vec![program.as_ref().to_owned()],
            envs: get_base_env(),
            cwd: None,
            #[cfg(unix)]
            umask: None,
            controlling_tty: true,
        }
    }

    /// Create a new builder instance from a pre-built argument vector
    pub fn from_argv(args: Vec<OsString>) -> Self {
        Self {
            args,
            envs: get_base_env(),
            cwd: None,
            #[cfg(unix)]
            umask: None,
            controlling_tty: true,
        }
    }

    /// Set whether we should set the pty as the controlling terminal.
    /// The default is true, which is usually what you want, but you
    /// may need to set this to false if you are crossing container
    /// boundaries (eg: flatpak) to workaround issues like:
    /// <https://github.com/flatpak/flatpak/issues/3697>
    /// <https://github.com/flatpak/flatpak/issues/3285>
    pub fn set_controlling_tty(&mut self, controlling_tty: bool) {
        self.controlling_tty = controlling_tty;
    }

    pub fn get_controlling_tty(&self) -> bool {
        self.controlling_tty
    }

    /// Create a new builder instance that will run some idea of a default
    /// program.  Such a builder will panic if `arg` is called on it.
    pub fn new_default_prog() -> Self {
        Self {
            args: vec![],
            envs: get_base_env(),
            cwd: None,
            #[cfg(unix)]
            umask: None,
            controlling_tty: true,
        }
    }

    /// Returns true if this builder was created via `new_default_prog`
    pub fn is_default_prog(&self) -> bool {
        self.args.is_empty()
    }

    /// Append an argument to the current command line.
    /// Will panic if called on a builder created via `new_default_prog`.
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) {
        if self.is_default_prog() {
            panic!("attempted to add args to a default_prog builder");
        }
        self.args.push(arg.as_ref().to_owned());
    }

    /// Append a sequence of arguments to the current command line
    pub fn args<I, S>(&mut self, args: I)
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for arg in args {
            self.arg(arg);
        }
    }

    pub fn get_argv(&self) -> &Vec<OsString> {
        &self.args
    }

    pub fn get_argv_mut(&mut self) -> &mut Vec<OsString> {
        &mut self.args
    }

    /// Override the value of an environmental variable
    pub fn env<K, V>(&mut self, key: K, value: V)
    where
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        let key: OsString = key.as_ref().into();
        let value: OsString = value.as_ref().into();
        self.envs.insert(
            EnvEntry::map_key(key.clone()),
            EnvEntry {
                is_from_base_env: false,
                preferred_key: key,
                value: value,
            },
        );
    }

    pub fn env_remove<K>(&mut self, key: K)
    where
        K: AsRef<OsStr>,
    {
        let key = key.as_ref().into();
        self.envs.remove(&EnvEntry::map_key(key));
    }

    pub fn env_clear(&mut self) {
        self.envs.clear();
    }

    pub fn get_env<K>(&self, key: K) -> Option<&OsStr>
    where
        K: AsRef<OsStr>,
    {
        let key = key.as_ref().into();
        self.envs.get(&EnvEntry::map_key(key)).map(
            |EnvEntry {
                 is_from_base_env: _,
                 preferred_key: _,
                 value,
             }| value.as_os_str(),
        )
    }

    pub fn cwd<D>(&mut self, dir: D)
    where
        D: AsRef<OsStr>,
    {
        self.cwd = Some(dir.as_ref().to_owned());
    }

    pub fn clear_cwd(&mut self) {
        self.cwd.take();
    }

    pub fn get_cwd(&self) -> Option<&OsString> {
        self.cwd.as_ref()
    }

    /// Iterate over the configured environment. Only includes environment
    /// variables set by the caller via `env`, not variables set in the base
    /// environment.
    pub fn iter_extra_env_as_str(&self) -> impl Iterator<Item = (&str, &str)> {
        self.envs.values().filter_map(
            |EnvEntry {
                 is_from_base_env,
                 preferred_key,
                 value,
             }| {
                if *is_from_base_env {
                    None
                } else {
                    let key = preferred_key.to_str()?;
                    let value = value.to_str()?;
                    Some((key, value))
                }
            },
        )
    }

    pub fn iter_full_env_as_str(&self) -> impl Iterator<Item = (&str, &str)> {
        self.envs.values().filter_map(
            |EnvEntry {
                 preferred_key,
                 value,
                 ..
             }| {
                let key = preferred_key.to_str()?;
                let value = value.to_str()?;
                Some((key, value))
            },
        )
    }

    /// Return the configured command and arguments as a single string,
    /// quoted per the unix shell conventions.
    pub fn as_unix_command_line(&self) -> anyhow::Result<String> {
        let mut strs = vec![];
        for arg in &self.args {
            let s = arg
                .to_str()
                .ok_or_else(|| anyhow::anyhow!("argument cannot be represented as utf8"))?;
            strs.push(s);
        }
        Ok(shell_words::join(strs))
    }
}

#[cfg(unix)]
impl CommandBuilder {
    pub fn umask(&mut self, mask: Option<libc::mode_t>) {
        self.umask = mask;
    }

    fn resolve_path(&self) -> Option<&OsStr> {
        self.get_env("PATH")
    }

    fn search_path(&self, exe: &OsStr, cwd: &OsStr) -> anyhow::Result<OsString> {
        use nix::unistd::{access, AccessFlags};

        let exe_path: &Path = exe.as_ref();
        if exe_path.is_relative() {
            let cwd: &Path = cwd.as_ref();
            let mut errors = vec![];

            // If the requested executable is explicitly relative to cwd,
            // then check only there.
            if is_cwd_relative_path(exe_path) {
                let abs_path = cwd.join(exe_path);

                if abs_path.is_dir() {
                    anyhow::bail!(
                        "Unable to spawn {} because it is a directory",
                        abs_path.display()
                    );
                } else if access(&abs_path, AccessFlags::X_OK).is_ok() {
                    return Ok(abs_path.into_os_string());
                } else if access(&abs_path, AccessFlags::F_OK).is_ok() {
                    anyhow::bail!(
                        "Unable to spawn {} because it is not executable",
                        abs_path.display()
                    );
                }

                anyhow::bail!(
                    "Unable to spawn {} because it does not exist",
                    abs_path.display()
                );
            }

            if let Some(path) = self.resolve_path() {
                for path in std::env::split_paths(&path) {
                    let candidate = cwd.join(&path).join(&exe);

                    if candidate.is_dir() {
                        errors.push(format!("{} exists but is a directory", candidate.display()));
                    } else if access(&candidate, AccessFlags::X_OK).is_ok() {
                        return Ok(candidate.into_os_string());
                    } else if access(&candidate, AccessFlags::F_OK).is_ok() {
                        errors.push(format!(
                            "{} exists but is not executable",
                            candidate.display()
                        ));
                    }
                }
                errors.push(format!("No viable candidates found in PATH {path:?}"));
            } else {
                errors.push("Unable to resolve the PATH".to_string());
            }
            anyhow::bail!(
                "Unable to spawn {} because:\n{}",
                exe_path.display(),
                errors.join(".\n")
            );
        } else if exe_path.is_dir() {
            anyhow::bail!(
                "Unable to spawn {} because it is a directory",
                exe_path.display()
            );
        } else {
            if let Err(err) = access(exe_path, AccessFlags::X_OK) {
                if access(exe_path, AccessFlags::F_OK).is_ok() {
                    anyhow::bail!(
                        "Unable to spawn {} because it is not executable ({err:#})",
                        exe_path.display()
                    );
                } else {
                    anyhow::bail!(
                        "Unable to spawn {} because it doesn't exist on the filesystem ({err:#})",
                        exe_path.display()
                    );
                }
            }

            Ok(exe.to_owned())
        }
    }

    /// Convert the CommandBuilder to a `std::process::Command` instance.
    pub(crate) fn as_command(&self) -> anyhow::Result<std::process::Command> {
        use std::os::unix::process::CommandExt;

        let home = self.get_home_dir()?;
        let dir: &OsStr = self
            .cwd
            .as_ref()
            .map(|dir| dir.as_os_str())
            .filter(|dir| std::path::Path::new(dir).is_dir())
            .unwrap_or(home.as_ref());
        let shell = self.get_shell();

        let mut cmd = if self.is_default_prog() {
            let mut cmd = std::process::Command::new(&shell);

            // Run the shell as a login shell by prefixing the shell's
            // basename with `-` and setting that as argv0
            let basename = shell.rsplit('/').next().unwrap_or(&shell);
            cmd.arg0(&format!("-{}", basename));
            cmd
        } else {
            let resolved = self.search_path(&self.args[0], dir)?;
            let mut cmd = std::process::Command::new(&resolved);
            cmd.arg0(&self.args[0]);
            cmd.args(&self.args[1..]);
            cmd
        };

        cmd.current_dir(dir);

        cmd.env_clear();
        cmd.env("SHELL", shell);
        cmd.envs(self.envs.values().map(
            |EnvEntry {
                 is_from_base_env: _,
                 preferred_key,
                 value,
             }| (preferred_key.as_os_str(), value.as_os_str()),
        ));

        Ok(cmd)
    }

    /// Determine which shell to run.
    /// We take the contents of the $SHELL env var first, then
    /// fall back to looking it up from the password database.
    pub fn get_shell(&self) -> String {
        use nix::unistd::{access, AccessFlags};

        if let Some(shell) = self.get_env("SHELL").and_then(OsStr::to_str) {
            match access(shell, AccessFlags::X_OK) {
                Ok(()) => return shell.into(),
                Err(err) => log::warn!(
                    "$SHELL -> {shell:?} which is \
                     not executable ({err:#}), falling back to password db lookup"
                ),
            }
        }

        get_shell().into()
    }

    fn get_home_dir(&self) -> anyhow::Result<String> {
        if let Some(home_dir) = self.get_env("HOME").and_then(OsStr::to_str) {
            return Ok(home_dir.into());
        }

        let ent = unsafe { libc::getpwuid(libc::getuid()) };
        if ent.is_null() {
            Ok("/".into())
        } else {
            use std::ffi::CStr;
            use std::str;
            let home = unsafe { CStr::from_ptr((*ent).pw_dir) };
            home.to_str()
                .map(str::to_owned)
                .context("failed to resolve home dir")
        }
    }
}

#[cfg(windows)]
impl CommandBuilder {
    fn search_path(&self, exe: &OsStr) -> OsString {
        if let Some(path) = self.get_env("PATH") {
            let extensions = self.get_env("PATHEXT").unwrap_or(OsStr::new(".EXE"));
            for path in std::env::split_paths(&path) {
                // Check for exactly the user's string in this path dir
                let candidate = path.join(&exe);
                if candidate.exists() {
                    return candidate.into_os_string();
                }

                // otherwise try tacking on some extensions.
                // Note that this really replaces the extension in the
                // user specified path, so this is potentially wrong.
                for ext in std::env::split_paths(&extensions) {
                    // PATHEXT includes the leading `.`, but `with_extension`
                    // doesn't want that
                    let ext = ext.to_str().expect("PATHEXT entries must be utf8");
                    let path = path.join(&exe).with_extension(&ext[1..]);
                    if path.exists() {
                        return path.into_os_string();
                    }
                }
            }
        }

        exe.to_owned()
    }

    pub(crate) fn current_directory(&self) -> Option<Vec<u16>> {
        let home: Option<&OsStr> = self
            .get_env("USERPROFILE")
            .filter(|path| Path::new(path).is_dir());
        let cwd: Option<&OsStr> = self.cwd.as_deref().filter(|path| Path::new(path).is_dir());
        let dir: Option<&OsStr> = cwd.or(home);

        dir.map(|dir| {
            let mut wide = vec![];

            if Path::new(dir).is_relative() {
                if let Ok(ccwd) = std::env::current_dir() {
                    wide.extend(ccwd.join(dir).as_os_str().encode_wide());
                } else {
                    wide.extend(dir.encode_wide());
                }
            } else {
                wide.extend(dir.encode_wide());
            }

            wide.push(0);
            wide
        })
    }

    /// Constructs an environment block for this spawn attempt.
    /// Uses the current process environment as the base and then
    /// adds/replaces the environment that was specified via the
    /// `env` methods.
    pub(crate) fn environment_block(&self) -> Vec<u16> {
        // encode the environment as wide characters
        let mut block = vec![];

        for EnvEntry {
            is_from_base_env: _,
            preferred_key,
            value,
        } in self.envs.values()
        {
            block.extend(preferred_key.encode_wide());
            block.push(b'=' as u16);
            block.extend(value.encode_wide());
            block.push(0);
        }
        // and a final terminator for CreateProcessW
        block.push(0);

        block
    }

    pub fn get_shell(&self) -> String {
        let exe: OsString = self
            .get_env("ComSpec")
            .unwrap_or(OsStr::new("cmd.exe"))
            .into();
        exe.into_string()
            .unwrap_or_else(|_| "%CompSpec%".to_string())
    }

    pub(crate) fn cmdline(&self) -> anyhow::Result<(Vec<u16>, Vec<u16>)> {
        let mut cmdline = Vec::<u16>::new();

        let exe: OsString = if self.is_default_prog() {
            self.get_env("ComSpec")
                .unwrap_or(OsStr::new("cmd.exe"))
                .into()
        } else {
            self.search_path(&self.args[0])
        };

        Self::append_quoted(&exe, &mut cmdline);

        // Ensure that we nul terminate the module name, otherwise we'll
        // ask CreateProcessW to start something random!
        let mut exe: Vec<u16> = exe.encode_wide().collect();
        exe.push(0);

        for arg in self.args.iter().skip(1) {
            cmdline.push(' ' as u16);
            anyhow::ensure!(
                !arg.encode_wide().any(|c| c == 0),
                "invalid encoding for command line argument {:?}",
                arg
            );
            Self::append_quoted(arg, &mut cmdline);
        }
        // Ensure that the command line is nul terminated too!
        cmdline.push(0);
        Ok((exe, cmdline))
    }

    // Borrowed from https://github.com/hniksic/rust-subprocess/blob/873dfed165173e52907beb87118b2c0c05d8b8a1/src/popen.rs#L1117
    // which in turn was translated from ArgvQuote at http://tinyurl.com/zmgtnls
    fn append_quoted(arg: &OsStr, cmdline: &mut Vec<u16>) {
        if !arg.is_empty()
            && !arg.encode_wide().any(|c| {
                c == ' ' as u16
                    || c == '\t' as u16
                    || c == '\n' as u16
                    || c == '\x0b' as u16
                    || c == '\"' as u16
            })
        {
            cmdline.extend(arg.encode_wide());
            return;
        }
        cmdline.push('"' as u16);

        let arg: Vec<_> = arg.encode_wide().collect();
        let mut i = 0;
        while i < arg.len() {
            let mut num_backslashes = 0;
            while i < arg.len() && arg[i] == '\\' as u16 {
                i += 1;
                num_backslashes += 1;
            }

            if i == arg.len() {
                for _ in 0..num_backslashes * 2 {
                    cmdline.push('\\' as u16);
                }
                break;
            } else if arg[i] == b'"' as u16 {
                for _ in 0..num_backslashes * 2 + 1 {
                    cmdline.push('\\' as u16);
                }
                cmdline.push(arg[i]);
            } else {
                for _ in 0..num_backslashes {
                    cmdline.push('\\' as u16);
                }
                cmdline.push(arg[i]);
            }
            i += 1;
        }
        cmdline.push('"' as u16);
    }
}

#[cfg(unix)]
/// Returns true if the path begins with `./` or `../`
fn is_cwd_relative_path<P: AsRef<Path>>(p: P) -> bool {
    matches!(
        p.as_ref().components().next(),
        Some(Component::CurDir | Component::ParentDir)
    )
}

#[cfg(test)]
#[path = "../../../tests-rs/test_cmdbuilder.rs"]
mod tests;


================================================
FILE: crates/portable-pty-psmux/src/lib.rs
================================================
//! This crate provides a cross platform API for working with the
//! psuedo terminal (pty) interfaces provided by the system.
//! Unlike other crates in this space, this crate provides a set
//! of traits that allow selecting from different implementations
//! at runtime.
//! This crate is part of [wezterm](https://github.com/wezterm/wezterm).
//!
//! ```no_run
//! use portable_pty::{CommandBuilder, PtySize, native_pty_system, PtySystem};
//! use anyhow::Error;
//!
//! // Use the native pty implementation for the system
//! let pty_system = native_pty_system();
//!
//! // Create a new pty
//! let mut pair = pty_system.openpty(PtySize {
//!     rows: 24,
//!     cols: 80,
//!     // Not all systems support pixel_width, pixel_height,
//!     // but it is good practice to set it to something
//!     // that matches the size of the selected font.  That
//!     // is more complex than can be shown here in this
//!     // brief example though!
//!     pixel_width: 0,
//!     pixel_height: 0,
//! })?;
//!
//! // Spawn a shell into the pty
//! let cmd = CommandBuilder::new("bash");
//! let child = pair.slave.spawn_command(cmd)?;
//!
//! // Read and parse output from the pty with reader
//! let mut reader = pair.master.try_clone_reader()?;
//!
//! // Send data to the pty by writing to the master
//! writeln!(pair.master.take_writer()?, "ls -l\r\n")?;
//! # Ok::<(), Error>(())
//! ```
//!
use anyhow::Error;
use downcast_rs::{impl_downcast, Downcast};
#[cfg(unix)]
use libc;
#[cfg(feature = "serde_support")]
use serde_derive::*;
use std::io::Result as IoResult;
#[cfg(windows)]
use std::os::windows::prelude::{AsRawHandle, RawHandle};

pub mod cmdbuilder;
pub use cmdbuilder::CommandBuilder;

#[cfg(unix)]
pub mod unix;
#[cfg(windows)]
pub mod win;

pub mod serial;

/// Represents the size of the visible display area in the pty
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
pub struct PtySize {
    /// The number of lines of text
    pub rows: u16,
    /// The number of columns of text
    pub cols: u16,
    /// The width of a cell in pixels.  Note that some systems never
    /// fill this value and ignore it.
    pub pixel_width: u16,
    /// The height of a cell in pixels.  Note that some systems never
    /// fill this value and ignore it.
    pub pixel_height: u16,
}

impl Default for PtySize {
    fn default() -> Self {
        PtySize {
            rows: 24,
            cols: 80,
            pixel_width: 0,
            pixel_height: 0,
        }
    }
}

/// Represents the master/control end of the pty
pub trait MasterPty: Downcast + Send {
    /// Inform the kernel and thus the child process that the window resized.
    /// It will update the winsize information maintained by the kernel,
    /// and generate a signal for the child to notice and update its state.
    fn resize(&self, size: PtySize) -> Result<(), Error>;
    /// Retrieves the size of the pty as known by the kernel
    fn get_size(&self) -> Result<PtySize, Error>;
    /// Obtain a readable handle; output from the slave(s) is readable
    /// via this stream.
    fn try_clone_reader(&self) -> Result<Box<dyn std::io::Read + Send>, Error>;
    /// Obtain a writable handle; writing to it will send data to the
    /// slave end.
    /// Dropping the writer will send EOF to the slave end.
    /// It is invalid to take the writer more than once.
    fn take_writer(&self) -> Result<Box<dyn std::io::Write + Send>, Error>;

    /// If applicable to the type of the tty, return the local process id
    /// of the process group or session leader
    #[cfg(unix)]
    fn process_group_leader(&self) -> Option<libc::pid_t>;

    /// If get_termios() and process_group_leader() are both implemented and
    /// return Some, then as_raw_fd() should return the same underlying fd
    /// associated with the stream. This is to enable applications that
    /// "know things" to query similar information for themselves.
    #[cfg(unix)]
    fn as_raw_fd(&self) -> Option<unix::RawFd>;

    #[cfg(unix)]
    fn tty_name(&self) -> Option<std::path::PathBuf>;

    /// If applicable to the type of the tty, return the termios
    /// associated with the stream
    #[cfg(unix)]
    fn get_termios(&self) -> Option<nix::sys::termios::Termios> {
        None
    }
}
impl_downcast!(MasterPty);

/// Represents a child process spawned into the pty.
/// This handle can be used to wait for or terminate that child process.
pub trait Child: std::fmt::Debug + ChildKiller + Downcast + Send {
    /// Poll the child to see if it has completed.
    /// Does not block.
    /// Returns None if the child has not yet terminated,
    /// else returns its exit status.
    fn try_wait(&mut self) -> IoResult<Option<ExitStatus>>;
    /// Blocks execution until the child process has completed,
    /// yielding its exit status.
    fn wait(&mut self) -> IoResult<ExitStatus>;
    /// Returns the process identifier of the child process,
    /// if applicable
    fn process_id(&self) -> Option<u32>;
    /// Returns the process handle of the child process, if applicable.
    /// Only available on Windows.
    #[cfg(windows)]
    fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle>;
}
impl_downcast!(Child);

/// Represents the ability to signal a Child to terminate
pub trait ChildKiller: std::fmt::Debug + Downcast + Send {
    /// Terminate the child process
    fn kill(&mut self) -> IoResult<()>;

    /// Clone an object that can be split out from the Child in order
    /// to send it signals independently from a thread that may be
    /// blocked in `.wait`.
    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync>;
}
impl_downcast!(ChildKiller);

/// Represents the slave side of a pty.
/// Can be used to spawn processes into the pty.
pub trait SlavePty {
    /// Spawns the command specified by the provided CommandBuilder
    fn spawn_command(&self, cmd: CommandBuilder) -> Result<Box<dyn Child + Send + Sync>, Error>;
}

/// Represents the exit status of a child process.
#[derive(Debug, Clone)]
pub struct ExitStatus {
    code: u32,
    signal: Option<String>,
}

impl ExitStatus {
    /// Construct an ExitStatus from a process return code
    pub fn with_exit_code(code: u32) -> Self {
        Self { code, signal: None }
    }

    /// Construct an ExitStatus from a signal name
    pub fn with_signal(signal: &str) -> Self {
        Self {
            code: 1,
            signal: Some(signal.to_string()),
        }
    }

    /// Returns true if the status indicates successful completion
    pub fn success(&self) -> bool {
        match self.signal {
            None => self.code == 0,
            Some(_) => false,
        }
    }

    /// Returns the exit code that this ExitStatus was constructed with
    pub fn exit_code(&self) -> u32 {
        self.code
    }

    /// Returns the signal if present that this ExitStatus was constructed with
    pub fn signal(&self) -> Option<&str> {
        self.signal.as_deref()
    }
}

impl From<std::process::ExitStatus> for ExitStatus {
    fn from(status: std::process::ExitStatus) -> ExitStatus {
        #[cfg(unix)]
        {
            use std::os::unix::process::ExitStatusExt;

            if let Some(signal) = status.signal() {
                let signame = unsafe { libc::strsignal(signal) };
                let signal = if signame.is_null() {
                    format!("Signal {}", signal)
                } else {
                    let signame = unsafe { std::ffi::CStr::from_ptr(signame) };
                    signame.to_string_lossy().to_string()
                };

                return ExitStatus {
                    code: status.code().map(|c| c as u32).unwrap_or(1),
                    signal: Some(signal),
                };
            }
        }

        let code =
            status
                .code()
                .map(|c| c as u32)
                .unwrap_or_else(|| if status.success() { 0 } else { 1 });

        ExitStatus { code, signal: None }
    }
}

impl std::fmt::Display for ExitStatus {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.success() {
            write!(fmt, "Success")
        } else {
            match &self.signal {
                Some(sig) => write!(fmt, "Terminated by {}", sig),
                None => write!(fmt, "Exited with code {}", self.code),
            }
        }
    }
}

pub struct PtyPair {
    // slave is listed first so that it is dropped first.
    // The drop order is stable and specified by rust rfc 1857
    pub slave: Box<dyn SlavePty + Send>,
    pub master: Box<dyn MasterPty + Send>,
}

/// The `PtySystem` trait allows an application to work with multiple
/// possible Pty implementations at runtime.  This is important on
/// Windows systems which have a variety of implementations.
pub trait PtySystem: Downcast {
    /// Create a new Pty instance with the window size set to the specified
    /// dimensions.  Returns a (master, slave) Pty pair.  The master side
    /// is used to drive the slave side.
    fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair>;
}
impl_downcast!(PtySystem);

impl Child for std::process::Child {
    fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
        std::process::Child::try_wait(self).map(|s| match s {
            Some(s) => Some(s.into()),
            None => None,
        })
    }

    fn wait(&mut self) -> IoResult<ExitStatus> {
        std::process::Child::wait(self).map(Into::into)
    }

    fn process_id(&self) -> Option<u32> {
        Some(self.id())
    }

    #[cfg(windows)]
    fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
        Some(std::os::windows::io::AsRawHandle::as_raw_handle(self))
    }
}

#[derive(Debug)]
struct ProcessSignaller {
    pid: Option<u32>,

    #[cfg(windows)]
    handle: Option<filedescriptor::OwnedHandle>,
}

#[cfg(windows)]
impl ChildKiller for ProcessSignaller {
    fn kill(&mut self) -> IoResult<()> {
        if let Some(handle) = &self.handle {
            unsafe {
                if winapi::um::processthreadsapi::TerminateProcess(handle.as_raw_handle() as _, 127)
                    == 0
                {
                    return Err(std::io::Error::last_os_error());
                }
            }
        }
        Ok(())
    }
    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        Box::new(Self {
            pid: self.pid,
            handle: self.handle.as_ref().and_then(|h| h.try_clone().ok()),
        })
    }
}

#[cfg(unix)]
impl ChildKiller for ProcessSignaller {
    fn kill(&mut self) -> IoResult<()> {
        if let Some(pid) = self.pid {
            let result = unsafe { libc::kill(pid as i32, libc::SIGHUP) };
            if result != 0 {
                return Err(std::io::Error::last_os_error());
            }
        }
        Ok(())
    }

    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        Box::new(Self { pid: self.pid })
    }
}

impl ChildKiller for std::process::Child {
    fn kill(&mut self) -> IoResult<()> {
        #[cfg(unix)]
        {
            // On unix, we send the SIGHUP signal instead of trying to kill
            // the process. The default behavior of a process receiving this
            // signal is to be killed unless it configured a signal handler.
            let result = unsafe { libc::kill(self.id() as i32, libc::SIGHUP) };
            if result != 0 {
                return Err(std::io::Error::last_os_error());
            }

            // We successfully delivered SIGHUP, but the semantics of Child::kill
            // are that on success the process is dead or shortly about to
            // terminate.  Since SIGUP doesn't guarantee termination, we
            // give the process a bit of a grace period to shutdown or do whatever
            // it is doing in its signal handler befre we proceed with the
            // full on kill.
            for attempt in 0..5 {
                if attempt > 0 {
                    std::thread::sleep(std::time::Duration::from_millis(50));
                }

                if let Ok(Some(_)) = self.try_wait() {
                    // It completed, so report success!
                    return Ok(());
                }
            }

            // it's still alive after a grace period, so proceed with a kill
        }

        std::process::Child::kill(self)
    }

    #[cfg(windows)]
    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        struct RawDup(RawHandle);
        impl AsRawHandle for RawDup {
            fn as_raw_handle(&self) -> RawHandle {
                self.0
            }
        }

        Box::new(ProcessSignaller {
            pid: self.process_id(),
            handle: Child::as_raw_handle(self)
                .as_ref()
                .and_then(|h| filedescriptor::OwnedHandle::dup(&RawDup(*h)).ok()),
        })
    }

    #[cfg(unix)]
    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        Box::new(ProcessSignaller {
            pid: self.process_id(),
        })
    }
}

pub fn native_pty_system() -> Box<dyn PtySystem + Send> {
    Box::new(NativePtySystem::default())
}

#[cfg(unix)]
pub type NativePtySystem = unix::UnixPtySystem;
#[cfg(windows)]
pub type NativePtySystem = win::conpty::ConPtySystem;


================================================
FILE: crates/portable-pty-psmux/src/serial.rs
================================================
//! This module implements a serial port based tty.
//! This is a bit different from the other implementations in that
//! we cannot explicitly spawn a process into the serial connection,
//! so we can only use a `CommandBuilder::new_default_prog` with the
//! `openpty` method.
//! On most (all?) systems, attempting to open multiple instances of
//! the same serial port will fail.
use crate::{
    Child, ChildKiller, CommandBuilder, ExitStatus, MasterPty, PtyPair, PtySize, PtySystem,
    SlavePty,
};
use anyhow::{ensure, Context};
use filedescriptor::FileDescriptor;
use serial2::{CharSize, FlowControl, Parity, SerialPort, StopBits};
use std::cell::RefCell;
use std::ffi::{OsStr, OsString};
use std::io::{Read, Result as IoResult, Write};
#[cfg(unix)]
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;

type Handle = Arc<SerialPort>;

pub struct SerialTty {
    port: OsString,
    baud: u32,
    char_size: CharSize,
    parity: Parity,
    stop_bits: StopBits,
    flow_control: FlowControl,
}

impl SerialTty {
    pub fn new<T: AsRef<OsStr> + ?Sized>(port: &T) -> Self {
        Self {
            port: port.as_ref().to_owned(),
            baud: 9600,
            char_size: CharSize::Bits8,
            parity: Parity::None,
            stop_bits: StopBits::One,
            flow_control: FlowControl::XonXoff,
        }
    }

    pub fn set_baud_rate(&mut self, baud: u32) {
        self.baud = baud;
    }

    pub fn set_char_size(&mut self, char_size: CharSize) {
        self.char_size = char_size;
    }

    pub fn set_parity(&mut self, parity: Parity) {
        self.parity = parity;
    }

    pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
        self.stop_bits = stop_bits;
    }

    pub fn set_flow_control(&mut self, flow_control: FlowControl) {
        self.flow_control = flow_control;
    }
}

impl PtySystem for SerialTty {
    fn openpty(&self, _size: PtySize) -> anyhow::Result<PtyPair> {
        let mut port = SerialPort::open(&self.port, self.baud)
            .with_context(|| format!("openpty on serial port {:?}", self.port))?;

        let mut settings = port.get_configuration()?;
        settings.set_raw();
        settings.set_baud_rate(self.baud)?;
        settings.set_char_size(self.char_size);
        settings.set_flow_control(self.flow_control);
        settings.set_parity(self.parity);
        settings.set_stop_bits(self.stop_bits);
        log::debug!("serial settings: {:#?}", port.get_configuration());
        port.set_configuration(&settings)?;

        // The timeout needs to be rather short because, at least on Windows,
        // a read with a long timeout will block a concurrent write from
        // happening.  In wezterm we tend to have a thread looping on read
        // while writes happen occasionally from the gui thread, and if we
        // make this timeout too long we can block the gui thread.
        port.set_read_timeout(Duration::from_millis(50))?;
        port.set_write_timeout(Duration::from_millis(50))?;

        let port: Handle = Arc::new(port);

        Ok(PtyPair {
            slave: Box::new(Slave {
                port: Arc::clone(&port),
            }),
            master: Box::new(Master {
                port,
                took_writer: RefCell::new(false),
            }),
        })
    }
}

struct Slave {
    port: Handle,
}

impl SlavePty for Slave {
    fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child + Send + Sync>> {
        ensure!(
            cmd.is_default_prog(),
            "can only use default prog commands with serial tty implementations"
        );
        Ok(Box::new(SerialChild {
            port: Arc::clone(&self.port),
        }))
    }
}

/// There isn't really a child process on the end of the serial connection,
/// so all of the Child trait impls are NOP
struct SerialChild {
    port: Handle,
}

// An anemic impl of Debug to satisfy some indirect trait bounds
impl std::fmt::Debug for SerialChild {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        fmt.debug_struct("SerialChild").finish()
    }
}

impl Child for SerialChild {
    fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
        Ok(None)
    }

    fn wait(&mut self) -> IoResult<ExitStatus> {
        // There isn't really a child process to wait for,
        // as the serial connection never really "dies",
        // however, for something like a USB serial port,
        // if it is unplugged then it logically is terminated.
        // We read the CD (carrier detect) signal periodically
        // to see if the device has gone away: we actually discard
        // the CD value itself and just look for an error state.
        // We could potentially also decide to call CD==false the
        // same thing as the "child" completing.
        loop {
            std::thread::sleep(Duration::from_secs(5));

            let port = &self.port;
            if let Err(err) = port.read_cd() {
                log::error!("Error reading carrier detect: {:#}", err);
                return Ok(ExitStatus::with_exit_code(1));
            }
        }
    }

    fn process_id(&self) -> Option<u32> {
        None
    }

    #[cfg(windows)]
    fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
        None
    }
}

impl ChildKiller for SerialChild {
    fn kill(&mut self) -> IoResult<()> {
        Ok(())
    }

    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        Box::new(SerialChildKiller)
    }
}

#[derive(Debug)]
struct SerialChildKiller;

impl ChildKiller for SerialChildKiller {
    fn kill(&mut self) -> IoResult<()> {
        Ok(())
    }

    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        Box::new(SerialChildKiller)
    }
}

struct Master {
    port: Handle,
    took_writer: RefCell<bool>,
}

struct MasterWriter {
    port: Handle,
}

impl Write for MasterWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
        self.port.write(buf)
    }

    fn flush(&mut self) -> Result<(), std::io::Error> {
        self.port.flush()
    }
}

impl MasterPty for Master {
    fn resize(&self, _size: PtySize) -> anyhow::Result<()> {
        // Serial ports have no concept of size
        Ok(())
    }

    fn get_size(&self) -> anyhow::Result<PtySize> {
        // Serial ports have no concept of size
        Ok(PtySize::default())
    }

    fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Send>> {
        // We rely on the fact that SystemPort implements the traits
        // that expose the underlying file descriptor, and that direct
        // reads from that return the raw data that we want
        let fd = FileDescriptor::dup(&*self.port)?;
        Ok(Box::new(Reader { fd }))
    }

    fn take_writer(&self) -> anyhow::Result<Box<dyn std::io::Write + Send>> {
        if *self.took_writer.borrow() {
            anyhow::bail!("cannot take writer more than once");
        }
        *self.took_writer.borrow_mut() = true;
        let port = Arc::clone(&self.port);
        Ok(Box::new(MasterWriter { port }))
    }

    #[cfg(unix)]
    fn process_group_leader(&self) -> Option<libc::pid_t> {
        // N/A: there is no local process
        None
    }

    #[cfg(unix)]
    fn as_raw_fd(&self) -> Option<crate::unix::RawFd> {
        None
    }

    #[cfg(unix)]
    fn tty_name(&self) -> Option<PathBuf> {
        None
    }
}

struct Reader {
    fd: FileDescriptor,
}

impl Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
        // On windows, this self.fd.read will block for up to the time we set
        // as the timeout when we set up the port, but on unix it will
        // never block.
        loop {
            #[cfg(unix)]
            {
                use filedescriptor::{poll, pollfd, AsRawSocketDescriptor, POLLIN};
                // The serial crate puts the serial port in non-blocking mode,
                // so we must explicitly poll for ourselves here to avoid a
                // busy loop.
                let mut poll_array = [pollfd {
                    fd: self.fd.as_socket_descriptor(),
                    events: POLLIN,
                    revents: 0,
                }];
                let _ = poll(&mut poll_array, None);
            }

            match self.fd.read(buf) {
                Ok(0) => {
                    if cfg!(windows) {
                        // Read timeout with no data available yet;
                        // loop and try again.
                        continue;
                    }
                    return Err(std::io::Error::new(
                        std::io::ErrorKind::UnexpectedEof,
                        "EOF on serial port",
                    ));
                }
                Ok(size) => {
                    return Ok(size);
                }
                Err(e) => {
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        continue;
                    }
                    log::error!("serial read error: {}", e);
                    return Err(e);
                }
            }
        }
    }
}


================================================
FILE: crates/portable-pty-psmux/src/unix.rs
================================================
//! Working with pseudo-terminals

use crate::{Child, CommandBuilder, MasterPty, PtyPair, PtySize, PtySystem, SlavePty};
use anyhow::{bail, Error};
use filedescriptor::FileDescriptor;
use libc::{self, winsize};
use std::cell::RefCell;
use std::ffi::OsStr;
use std::io::{Read, Write};
use std::os::fd::AsFd;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::process::CommandExt;
use std::path::PathBuf;
use std::{io, mem, ptr};

pub use std::os::unix::io::RawFd;

#[derive(Default)]
pub struct UnixPtySystem {}

fn openpty(size: PtySize) -> anyhow::Result<(UnixMasterPty, UnixSlavePty)> {
    let mut master: RawFd = -1;
    let mut slave: RawFd = -1;

    let mut size = winsize {
        ws_row: size.rows,
        ws_col: size.cols,
        ws_xpixel: size.pixel_width,
        ws_ypixel: size.pixel_height,
    };

    let result = unsafe {
        // BSDish systems may require mut pointers to some args
        #[allow(clippy::unnecessary_mut_passed)]
        libc::openpty(
            &mut master,
            &mut slave,
            ptr::null_mut(),
            ptr::null_mut(),
            &mut size,
        )
    };

    if result != 0 {
        bail!("failed to openpty: {:?}", io::Error::last_os_error());
    }

    let tty_name = tty_name(slave);

    let master = UnixMasterPty {
        fd: PtyFd(unsafe { FileDescriptor::from_raw_fd(master) }),
        took_writer: RefCell::new(false),
        tty_name,
    };
    let slave = UnixSlavePty {
        fd: PtyFd(unsafe { FileDescriptor::from_raw_fd(slave) }),
    };

    // Ensure that these descriptors will get closed when we execute
    // the child process.  This is done after constructing the Pty
    // instances so that we ensure that the Ptys get drop()'d if
    // the cloexec() functions fail (unlikely!).
    cloexec(master.fd.as_raw_fd())?;
    cloexec(slave.fd.as_raw_fd())?;

    Ok((master, slave))
}

impl PtySystem for UnixPtySystem {
    fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
        let (master, slave) = openpty(size)?;
        Ok(PtyPair {
            master: Box::new(master),
            slave: Box::new(slave),
        })
    }
}

struct PtyFd(pub FileDescriptor);
impl std::ops::Deref for PtyFd {
    type Target = FileDescriptor;
    fn deref(&self) -> &FileDescriptor {
        &self.0
    }
}
impl std::ops::DerefMut for PtyFd {
    fn deref_mut(&mut self) -> &mut FileDescriptor {
        &mut self.0
    }
}

impl Read for PtyFd {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        match self.0.read(buf) {
            Err(ref e) if e.raw_os_error() == Some(libc::EIO) => {
                // EIO indicates that the slave pty has been closed.
                // Treat this as EOF so that std::io::Read::read_to_string
                // and similar functions gracefully terminate when they
                // encounter this condition
                Ok(0)
            }
            x => x,
        }
    }
}

fn tty_name(fd: RawFd) -> Option<PathBuf> {
    let mut buf = vec![0 as std::ffi::c_char; 128];

    loop {
        let res = unsafe { libc::ttyname_r(fd, buf.as_mut_ptr(), buf.len()) };

        if res == libc::ERANGE {
            if buf.len() > 64 * 1024 {
                // on macOS, if the buf is "too big", ttyname_r can
                // return ERANGE, even though that is supposed to
                // indicate buf is "too small".
                return None;
            }
            buf.resize(buf.len() * 2, 0 as std::ffi::c_char);
            continue;
        }

        return if res == 0 {
            let cstr = unsafe { std::ffi::CStr::from_ptr(buf.as_ptr()) };
            let osstr = OsStr::from_bytes(cstr.to_bytes());
            Some(PathBuf::from(osstr))
        } else {
            None
        };
    }
}

/// On Big Sur, Cocoa leaks various file descriptors to child processes,
/// so we need to make a pass through the open descriptors beyond just the
/// stdio descriptors and close them all out.
/// This is approximately equivalent to the darwin `posix_spawnattr_setflags`
/// option POSIX_SPAWN_CLOEXEC_DEFAULT which is used as a bit of a cheat
/// on macOS.
/// On Linux, gnome/mutter leak shell extension fds to wezterm too, so we
/// also need to make an effort to clean up the mess.
///
/// This function enumerates the open filedescriptors in the current process
/// and then will forcibly call close(2) on each open fd that is numbered
/// 3 or higher, effectively closing all descriptors except for the stdio
/// streams.
///
/// The implementation of this function relies on `/dev/fd` being available
/// to provide the list of open fds.  Any errors in enumerating or closing
/// the fds are silently ignored.
pub fn close_random_fds() {
    // FreeBSD, macOS and presumably other BSDish systems have /dev/fd as
    // a directory listing the current fd numbers for the process.
    //
    // On Linux, /dev/fd is a symlink to /proc/self/fd
    if let Ok(dir) = std::fs::read_dir("/dev/fd") {
        let mut fds = vec![];
        for entry in dir {
            if let Some(num) = entry
                .ok()
                .map(|e| e.file_name())
                .and_then(|s| s.into_string().ok())
                .and_then(|n| n.parse::<libc::c_int>().ok())
            {
                if num > 2 {
                    fds.push(num);
                }
            }
        }
        for fd in fds {
            unsafe {
                libc::close(fd);
            }
        }
    }
}

impl PtyFd {
    fn resize(&self, size: PtySize) -> Result<(), Error> {
        let ws_size = winsize {
            ws_row: size.rows,
            ws_col: size.cols,
            ws_xpixel: size.pixel_width,
            ws_ypixel: size.pixel_height,
        };

        if unsafe {
            libc::ioctl(
                self.0.as_raw_fd(),
                libc::TIOCSWINSZ as _,
                &ws_size as *const _,
            )
        } != 0
        {
            bail!(
                "failed to ioctl(TIOCSWINSZ): {:?}",
                io::Error::last_os_error()
            );
        }

        Ok(())
    }

    fn get_size(&self) -> Result<PtySize, Error> {
        let mut size: winsize = unsafe { mem::zeroed() };
        if unsafe {
            libc::ioctl(
                self.0.as_raw_fd(),
                libc::TIOCGWINSZ as _,
                &mut size as *mut _,
            )
        } != 0
        {
            bail!(
                "failed to ioctl(TIOCGWINSZ): {:?}",
                io::Error::last_os_error()
            );
        }
        Ok(PtySize {
            rows: size.ws_row,
            cols: size.ws_col,
            pixel_width: size.ws_xpixel,
            pixel_height: size.ws_ypixel,
        })
    }

    fn spawn_command(&self, builder: CommandBuilder) -> anyhow::Result<std::process::Child> {
        let configured_umask = builder.umask;

        let mut cmd = builder.as_command()?;
        let controlling_tty = builder.get_controlling_tty();

        unsafe {
            cmd.stdin(self.as_stdio()?)
                .stdout(self.as_stdio()?)
                .stderr(self.as_stdio()?)
                .pre_exec(move || {
                    // Clean up a few things before we exec the program
                    // Clear out any potentially problematic signal
                    // dispositions that we might have inherited
                    for signo in &[
                        libc::SIGCHLD,
                        libc::SIGHUP,
                        libc::SIGINT,
                        libc::SIGQUIT,
                        libc::SIGTERM,
                        libc::SIGALRM,
                    ] {
                        libc::signal(*signo, libc::SIG_DFL);
                    }

                    let empty_set: libc::sigset_t = std::mem::zeroed();
                    libc::sigprocmask(libc::SIG_SETMASK, &empty_set, std::ptr::null_mut());

                    // Establish ourselves as a session leader.
                    if libc::setsid() == -1 {
                        return Err(io::Error::last_os_error());
                    }

                    // Clippy wants us to explicitly cast TIOCSCTTY using
                    // type::from(), but the size and potentially signedness
                    // are system dependent, which is why we're using `as _`.
                    // Suppress this lint for this section of code.
                    #[allow(clippy::cast_lossless)]
                    if controlling_tty {
                        // Set the pty as the controlling terminal.
                        // Failure to do this means that delivery of
                        // SIGWINCH won't happen when we resize the
                        // terminal, among other undesirable effects.
                        if libc::ioctl(0, libc::TIOCSCTTY as _, 0) == -1 {
                            return Err(io::Error::last_os_error());
                        }
                    }

                    close_random_fds();

                    if let Some(mask) = configured_umask {
                        libc::umask(mask);
                    }

                    Ok(())
                })
        };

        let mut child = cmd.spawn()?;

        // Ensure that we close out the slave fds that Child retains;
        // they are not what we need (we need the master side to reference
        // them) and won't work in the usual way anyway.
        // In practice these are None, but it seems best to be move them
        // out in case the behavior of Command changes in the future.
        child.stdin.take();
        child.stdout.take();
        child.stderr.take();

        Ok(child)
    }
}

/// Represents the master end of a pty.
/// The file descriptor will be closed when the Pty is dropped.
struct UnixMasterPty {
    fd: PtyFd,
    took_writer: RefCell<bool>,
    tty_name: Option<PathBuf>,
}

/// Represents the slave end of a pty.
/// The file descriptor will be closed when the Pty is dropped.
struct UnixSlavePty {
    fd: PtyFd,
}

/// Helper function to set the close-on-exec flag for a raw descriptor
fn cloexec(fd: RawFd) -> Result<(), Error> {
    let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
    if flags == -1 {
        bail!(
            "fcntl to read flags failed: {:?}",
            io::Error::last_os_error()
        );
    }
    let result = unsafe { libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
    if result == -1 {
        bail!(
            "fcntl to set CLOEXEC failed: {:?}",
            io::Error::last_os_error()
        );
    }
    Ok(())
}

impl SlavePty for UnixSlavePty {
    fn spawn_command(
        &self,
        builder: CommandBuilder,
    ) -> Result<Box<dyn Child + Send + Sync>, Error> {
        Ok(Box::new(self.fd.spawn_command(builder)?))
    }
}

impl MasterPty for UnixMasterPty {
    fn resize(&self, size: PtySize) -> Result<(), Error> {
        self.fd.resize(size)
    }

    fn get_size(&self) -> Result<PtySize, Error> {
        self.fd.get_size()
    }

    fn try_clone_reader(&self) -> Result<Box<dyn Read + Send>, Error> {
        let fd = PtyFd(self.fd.try_clone()?);
        Ok(Box::new(fd))
    }

    fn take_writer(&self) -> Result<Box<dyn Write + Send>, Error> {
        if *self.took_writer.borrow() {
            anyhow::bail!("cannot take writer more than once");
        }
        *self.took_writer.borrow_mut() = true;
        let fd = PtyFd(self.fd.try_clone()?);
        Ok(Box::new(UnixMasterWriter { fd }))
    }

    fn as_raw_fd(&self) -> Option<RawFd> {
        Some(self.fd.0.as_raw_fd())
    }

    fn tty_name(&self) -> Option<PathBuf> {
        self.tty_name.clone()
    }

    fn process_group_leader(&self) -> Option<libc::pid_t> {
        match unsafe { libc::tcgetpgrp(self.fd.0.as_raw_fd()) } {
            pid if pid > 0 => Some(pid),
            _ => None,
        }
    }

    fn get_termios(&self) -> Option<nix::sys::termios::Termios> {
        nix::sys::termios::tcgetattr(self.fd.0.as_fd()).ok()
    }
}

/// Represents the master end of a pty.
/// EOT will be sent, and then the file descriptor will be closed when
/// the Pty is dropped.
struct UnixMasterWriter {
    fd: PtyFd,
}

impl Drop for UnixMasterWriter {
    fn drop(&mut self) {
        let mut t: libc::termios = unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
        if unsafe { libc::tcgetattr(self.fd.0.as_raw_fd(), &mut t) } == 0 {
            // EOF is only interpreted after a newline, so if it is set,
            // we send a newline followed by EOF.
            let eot = t.c_cc[libc::VEOF];
            if eot != 0 {
                let _ = self.fd.0.write_all(&[b'\n', eot]);
            }
        }
    }
}

impl Write for UnixMasterWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        self.fd.write(buf)
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.fd.flush()
    }
}


================================================
FILE: crates/portable-pty-psmux/src/win/conpty.rs
================================================
use crate::cmdbuilder::CommandBuilder;
use crate::win::psuedocon::PsuedoCon;
use crate::{Child, MasterPty, PtyPair, PtySize, PtySystem, SlavePty};
use anyhow::Error;
use filedescriptor::FileDescriptor;
use std::sync::{Arc, Mutex};
use winapi::um::wincon::COORD;

/// Create a pipe pair with an explicit buffer size.
///
/// Windows Terminal uses 128 KB pipe buffers for ConPTY I/O.  The default
/// `CreatePipe(..., 0)` typically gets 4 KB, which forces more frequent
/// kernel transitions during high-throughput output (e.g. `cat large_file`).
/// Using 64 KB matches Windows Terminal's approach and reduces syscall
/// overhead for both input (mouse/keyboard) and output.
fn create_pipe_with_buffer(size: u32) -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
    use std::os::windows::io::FromRawHandle;
    use std::ptr;
    use winapi::shared::minwindef::TRUE;
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::minwinbase::SECURITY_ATTRIBUTES;
    use winapi::um::namedpipeapi::CreatePipe;
    use winapi::um::winnt::HANDLE;

    let mut sa = SECURITY_ATTRIBUTES {
        nLength: std::mem::size_of::<SECURITY_ATTRIBUTES>() as u32,
        lpSecurityDescriptor: ptr::null_mut(),
        bInheritHandle: TRUE as _,
    };
    let mut read: HANDLE = INVALID_HANDLE_VALUE;
    let mut write: HANDLE = INVALID_HANDLE_VALUE;
    if unsafe { CreatePipe(&mut read, &mut write, &mut sa, size) } == 0 {
        return Err(std::io::Error::last_os_error().into());
    }
    Ok(unsafe {(
        FileDescriptor::from_raw_handle(read as _),
        FileDescriptor::from_raw_handle(write as _),
    )})
}

#[derive(Default)]
pub struct ConPtySystem {}

impl PtySystem for ConPtySystem {
    fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
        // Use 64KB pipe buffers (Windows Terminal uses 128KB).
        // Default CreatePipe(..., 0) = ~4KB, causing frequent kernel round-trips.
        const PIPE_BUF: u32 = 64 * 1024;
        let (stdin_read, stdin_write) = create_pipe_with_buffer(PIPE_BUF)?;
        let (stdout_read, stdout_write) = create_pipe_with_buffer(PIPE_BUF)?;

        let con = PsuedoCon::new(
            COORD {
                X: size.cols as i16,
                Y: size.rows as i16,
            },
            stdin_read,
            stdout_write,
        )?;

        let master = ConPtyMasterPty {
            inner: Arc::new(Mutex::new(Inner {
                con,
                readable: stdout_read,
                writable: Some(stdin_write),
                size,
            })),
        };

        let slave = ConPtySlavePty {
            inner: master.inner.clone(),
        };

        Ok(PtyPair {
            master: Box::new(master),
            slave: Box::new(slave),
        })
    }
}

struct Inner {
    con: PsuedoCon,
    readable: FileDescriptor,
    writable: Option<FileDescriptor>,
    size: PtySize,
}

impl Inner {
    pub fn resize(
        &mut self,
        num_rows: u16,
        num_cols: u16,
        pixel_width: u16,
        pixel_height: u16,
    ) -> Result<(), Error> {
        self.con.resize(COORD {
            X: num_cols as i16,
            Y: num_rows as i16,
        })?;
        self.size = PtySize {
            rows: num_rows,
            cols: num_cols,
            pixel_width,
            pixel_height,
        };
        Ok(())
    }
}

#[derive(Clone)]
pub struct ConPtyMasterPty {
    inner: Arc<Mutex<Inner>>,
}

pub struct ConPtySlavePty {
    inner: Arc<Mutex<Inner>>,
}

impl MasterPty for ConPtyMasterPty {
    fn resize(&self, size: PtySize) -> anyhow::Result<()> {
        let mut inner = self.inner.lock().unwrap();
        inner.resize(size.rows, size.cols, size.pixel_width, size.pixel_height)
    }

    fn get_size(&self) -> Result<PtySize, Error> {
        let inner = self.inner.lock().unwrap();
        Ok(inner.size.clone())
    }

    fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Send>> {
        Ok(Box::new(self.inner.lock().unwrap().readable.try_clone()?))
    }

    fn take_writer(&self) -> anyhow::Result<Box<dyn std::io::Write + Send>> {
        Ok(Box::new(
            self.inner
                .lock()
                .unwrap()
                .writable
                .take()
                .ok_or_else(|| anyhow::anyhow!("writer already taken"))?,
        ))
    }
}

impl SlavePty for ConPtySlavePty {
    fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child + Send + Sync>> {
        let mut inner = self.inner.lock().unwrap();
        match inner.con.spawn_command(cmd.clone()) {
            Ok(child) => Ok(Box::new(child)),
            Err(e) if inner.con.used_passthrough && is_invalid_parameter(&e) => {
                // CreateProcessW rejected the ConPTY handle that was created
                // with PSEUDOCONSOLE_PASSTHROUGH_MODE.  Some Windows 11 builds
                // (notably Insider/Canary builds like 26200) accept the flag
                // during CreatePseudoConsole but later fail in CreateProcessW
                // with ERROR_INVALID_PARAMETER (87).
                //
                // Recovery: recreate the ConPTY without passthrough mode and
                // create fresh pipe pairs for the new pseudo-console.
                log::warn!(
                    "CreateProcessW failed with ERROR_INVALID_PARAMETER while using \
                     ConPTY passthrough mode; retrying without passthrough"
                );
                const PIPE_BUF: u32 = 64 * 1024;
                let (stdin_read, stdin_write) = create_pipe_with_buffer(PIPE_BUF)?;
                let (stdout_read, stdout_write) = create_pipe_with_buffer(PIPE_BUF)?;

                let new_con = PsuedoCon::new_without_passthrough(
                    COORD {
                        X: inner.size.cols as i16,
                        Y: inner.size.rows as i16,
                    },
                    stdin_read,
                    stdout_write,
                )?;

                // Replace the ConPTY and pipe endpoints inside Inner.
                // At this point nobody has cloned the reader or taken the
                // writer yet (pane.rs acquires them after spawn_command),
                // so the old FileDescriptors are dropped cleanly.
                inner.con = new_con;
                inner.readable = stdout_read;
                inner.writable = Some(stdin_write);

                let child = inner.con.spawn_command(cmd)?;
                Ok(Box::new(child))
            }
            Err(e) => Err(e),
        }
    }
}

/// Check if an error chain contains Windows ERROR_INVALID_PARAMETER (87).
/// The OS error number is locale-independent; the textual message varies
/// (e.g. "Falscher Parameter" in German).
fn is_invalid_parameter(e: &anyhow::Error) -> bool {
    let msg = format!("{}", e);
    msg.contains("os error 87")
}


================================================
FILE: crates/portable-pty-psmux/src/win/mod.rs
================================================
use crate::{Child, ChildKiller, ExitStatus};
use anyhow::Context as _;
use std::io::{Error as IoError, Result as IoResult};
use std::os::windows::io::{AsRawHandle, RawHandle};
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use winapi::shared::minwindef::DWORD;
use winapi::um::minwinbase::STILL_ACTIVE;
use winapi::um::processthreadsapi::*;
use winapi::um::synchapi::WaitForSingleObject;
use winapi::um::winbase::INFINITE;

pub mod conpty;
mod procthreadattr;
mod psuedocon;

use filedescriptor::OwnedHandle;

#[derive(Debug)]
pub struct WinChild {
    proc: Mutex<OwnedHandle>,
}

impl WinChild {
    fn is_complete(&mut self) -> IoResult<Option<ExitStatus>> {
        let mut status: DWORD = 0;
        let proc = self.proc.lock().unwrap().try_clone().unwrap();
        let res = unsafe { GetExitCodeProcess(proc.as_raw_handle() as _, &mut status) };
        if res != 0 {
            if status == STILL_ACTIVE {
                Ok(None)
            } else {
                Ok(Some(ExitStatus::with_exit_code(status)))
            }
        } else {
            Ok(None)
        }
    }

    fn do_kill(&mut self) -> IoResult<()> {
        let proc = self.proc.lock().unwrap().try_clone().unwrap();
        let res = unsafe { TerminateProcess(proc.as_raw_handle() as _, 1) };
        let err = IoError::last_os_error();
        if res != 0 {
            Err(err)
        } else {
            Ok(())
        }
    }
}

impl ChildKiller for WinChild {
    fn kill(&mut self) -> IoResult<()> {
        self.do_kill().ok();
        Ok(())
    }

    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        let proc = self.proc.lock().unwrap().try_clone().unwrap();
        Box::new(WinChildKiller { proc })
    }
}

#[derive(Debug)]
pub struct WinChildKiller {
    proc: OwnedHandle,
}

impl ChildKiller for WinChildKiller {
    fn kill(&mut self) -> IoResult<()> {
        let res = unsafe { TerminateProcess(self.proc.as_raw_handle() as _, 1) };
        let err = IoError::last_os_error();
        if res != 0 {
            Err(err)
        } else {
            Ok(())
        }
    }

    fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
        let proc = self.proc.try_clone().unwrap();
        Box::new(WinChildKiller { proc })
    }
}

impl Child for WinChild {
    fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
        self.is_complete()
    }

    fn wait(&mut self) -> IoResult<ExitStatus> {
        if let Ok(Some(status)) = self.try_wait() {
            return Ok(status);
        }
        let proc = self.proc.lock().unwrap().try_clone().unwrap();
        unsafe {
            WaitForSingleObject(proc.as_raw_handle() as _, INFINITE);
        }
        let mut status: DWORD = 0;
        let res = unsafe { GetExitCodeProcess(proc.as_raw_handle() as _, &mut status) };
        if res != 0 {
            Ok(ExitStatus::with_exit_code(status))
        } else {
            Err(IoError::last_os_error())
        }
    }

    fn process_id(&self) -> Option<u32> {
        let res = unsafe { GetProcessId(self.proc.lock().unwrap().as_raw_handle() as _) };
        if res == 0 {
            None
        } else {
            Some(res)
        }
    }

    fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
        let proc = self.proc.lock().unwrap();
        Some(proc.as_raw_handle())
    }
}

impl std::future::Future for WinChild {
    type Output = anyhow::Result<ExitStatus>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<anyhow::Result<ExitStatus>> {
        match self.is_complete() {
            Ok(Some(status)) => Poll::Ready(Ok(status)),
            Err(err) => Poll::Ready(Err(err).context("Failed to retrieve process exit status")),
            Ok(None) => {
                struct PassRawHandleToWaiterThread(pub RawHandle);
                unsafe impl Send for PassRawHandleToWaiterThread {}

                let proc = self.proc.lock().unwrap().try_clone()?;
                let handle = PassRawHandleToWaiterThread(proc.as_raw_handle());

                let waker = cx.waker().clone();
                std::thread::spawn(move || {
                    unsafe {
                        WaitForSingleObject(handle.0 as _, INFINITE);
                    }
                    waker.wake();
                });
                Poll::Pending
            }
        }
    }
}


================================================
FILE: crates/portable-pty-psmux/src/win/procthreadattr.rs
================================================
use crate::win::psuedocon::HPCON;
use anyhow::{ensure, Error};
use std::io::Error as IoError;
use std::{mem, ptr};
use winapi::shared::minwindef::DWORD;
use winapi::um::processthreadsapi::*;

const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 0x00020016;

pub struct ProcThreadAttributeList {
    data: Vec<u8>,
}

impl ProcThreadAttributeList {
    pub fn with_capacity(num_attributes: DWORD) -> Result<Self, Error> {
        let mut bytes_required: usize = 0;
        unsafe {
            InitializeProcThreadAttributeList(
                ptr::null_mut(),
                num_attributes,
                0,
                &mut bytes_required,
            )
        };
        let mut data = Vec::with_capacity(bytes_required);
        // We have the right capacity, so force the vec to consider itself
        // that length.  The contents of those bytes will be maintained
        // by the win32 apis used in this impl.
        unsafe { data.set_len(bytes_required) };

        let attr_ptr = data.as_mut_slice().as_mut_ptr() as *mut _;
        let res = unsafe {
            InitializeProcThreadAttributeList(attr_ptr, num_attributes, 0, &mut bytes_required)
        };
        ensure!(
            res != 0,
            "InitializeProcThreadAttributeList failed: {}",
            IoError::last_os_error()
        );
        Ok(Self { data })
    }

    pub fn as_mut_ptr(&mut self) -> LPPROC_THREAD_ATTRIBUTE_LIST {
        self.data.as_mut_slice().as_mut_ptr() as *mut _
    }

    pub fn set_pty(&mut self, con: HPCON) -> Result<(), Error> {
        let res = unsafe {
            UpdateProcThreadAttribute(
                self.as_mut_ptr(),
                0,
                PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
                con,
                mem::size_of::<HPCON>(),
                ptr::null_mut(),
                ptr::null_mut(),
            )
        };
        ensure!(
            res != 0,
            "UpdateProcThreadAttribute failed: {}",
            IoError::last_os_error()
        );
        Ok(())
    }
}

impl Drop for ProcThreadAttributeList {
    fn drop(&mut self) {
        unsafe { DeleteProcThreadAttributeList(self.as_mut_ptr()) };
    }
}


================================================
FILE: crates/portable-pty-psmux/src/win/psuedocon.rs
================================================
use super::WinChild;
use crate::cmdbuilder::CommandBuilder;
use crate::win::procthreadattr::ProcThreadAttributeList;
use anyhow::{bail, ensure, Error};
use filedescriptor::{FileDescriptor, OwnedHandle};
use lazy_static::lazy_static;
use shared_library::shared_library;
use std::ffi::OsString;
use std::io::Error as IoError;
use std::os::windows::ffi::OsStringExt;
use std::os::windows::io::{AsRawHandle, FromRawHandle};
use std::path::Path;
use std::sync::Mutex;
use std::{mem, ptr};
use winapi::shared::minwindef::DWORD;
use winapi::shared::winerror::{HRESULT, S_OK};
use winapi::um::handleapi::*;
use winapi::um::processthreadsapi::*;
use winapi::um::winbase::{
    CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT, STARTUPINFOEXW,
};
use winapi::um::wincon::COORD;
use winapi::um::winnt::HANDLE;

pub type HPCON = HANDLE;

pub const PSUEDOCONSOLE_INHERIT_CURSOR: DWORD = 0x1;
pub const PSEUDOCONSOLE_RESIZE_QUIRK: DWORD = 0x2;
pub const PSEUDOCONSOLE_WIN32_INPUT_MODE: DWORD = 0x4;
pub const PSEUDOCONSOLE_PASSTHROUGH_MODE: DWORD = 0x8;

shared_library!(ConPtyFuncs,
    pub fn CreatePseudoConsole(
        size: COORD,
        hInput: HANDLE,
        hOutput: HANDLE,
        flags: DWORD,
        hpc: *mut HPCON
    ) -> HRESULT,
    pub fn ResizePseudoConsole(hpc: HPCON, size: COORD) -> HRESULT,
    pub fn ClosePseudoConsole(hpc: HPCON),
);

fn load_conpty() -> ConPtyFuncs {
    // Always use the system kernel32.dll ConPTY implementation.
    // Do NOT try to sideload conpty.dll — terminal emulators like WezTerm
    // bundle their own conpty.dll + OpenConsole.exe, and the DLL search order
    // can pick those up when psmux runs inside such a terminal.  Using a
    // foreign conpty.dll causes blank panes and broken I/O because the
    // bundled OpenConsole.exe may not be compatible with our ConPTY flags
    // (PASSTHROUGH_MODE, WIN32_INPUT_MODE, etc.).
    ConPtyFuncs::open(Path::new("kernel32.dll")).expect(
        "this system does not support conpty.  Windows 10 October 2018 or newer is required",
    )
}

lazy_static! {
    static ref CONPTY: ConPtyFuncs = load_conpty();
}

pub struct PsuedoCon {
    con: HPCON,
    /// Whether this ConPTY was created with PSEUDOCONSOLE_PASSTHROUGH_MODE.
    /// Used by the retry logic in ConPtySlavePty::spawn_command to decide
    /// whether a fallback without passthrough is worth attempting.
    pub used_passthrough: bool,
}

unsafe impl Send for PsuedoCon {}
unsafe impl Sync for PsuedoCon {}

impl Drop for PsuedoCon {
    fn drop(&mut self) {
        unsafe { (CONPTY.ClosePseudoConsole)(self.con) };
    }
}

/// Returns true if the current Windows build supports ConPTY passthrough mode.
/// PSEUDOCONSOLE_PASSTHROUGH_MODE requires Windows 11 22H2 (build 22621+).
/// On older Windows versions, the flag may be silently accepted but produce
/// broken ConPTY output (no Win32 Console API translation).
///
/// Respects `PSMUX_NO_PASSTHROUGH=1` environment variable to let users
/// force-disable passthrough mode on builds where it causes CreateProcessW
/// to fail with ERROR_INVALID_PARAMETER (87).
fn supports_passthrough_mode() -> bool {
    if std::env::var("PSMUX_NO_PASSTHROUGH")
        .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
        .unwrap_or(false)
    {
        log::info!("ConPTY passthrough mode disabled via PSMUX_NO_PASSTHROUGH");
        return false;
    }
    let ver = unsafe {
        let mut info: winapi::um::winnt::OSVERSIONINFOW = mem::zeroed();
        info.dwOSVersionInfoSize = mem::size_of::<winapi::um::winnt::OSVERSIONINFOW>() as u32;
        // RtlGetVersion is used because GetVersionEx lies on Windows 10+
        // unless the application has a compatibility manifest.
        type RtlGetVersionFn = unsafe extern "system" fn(*mut winapi::um::winnt::OSVERSIONINFOW) -> i32;
        let ntdll = winapi::um::libloaderapi::GetModuleHandleW(
            ['n' as u16, 't' as u16, 'd' as u16, 'l' as u16, 'l' as u16, '.' as u16,
             'd' as u16, 'l' as u16, 'l' as u16, 0].as_ptr()
        );
        if ntdll.is_null() {
            return false;
        }
        let func = winapi::um::libloaderapi::GetProcAddress(
            ntdll,
            b"RtlGetVersion\0".as_ptr() as *const i8,
        );
        if func.is_null() {
            return false;
        }
        let rtl_get_version: RtlGetVersionFn = mem::transmute(func);
        rtl_get_version(&mut info);
        info
    };
    // Windows 11 22H2 = build 22621
    ver.dwBuildNumber >= 22621
}

impl PsuedoCon {
    pub fn new(size: COORD, input: FileDescriptor, output: FileDescriptor) -> Result<Self, Error> {
        let mut con: HPCON = INVALID_HANDLE_VALUE;
        let base_flags = PSUEDOCONSOLE_INHERIT_CURSOR
            | PSEUDOCONSOLE_RESIZE_QUIRK
            | PSEUDOCONSOLE_WIN32_INPUT_MODE;

        // Use PSEUDOCONSOLE_PASSTHROUGH_MODE on Windows 11 22H2+ to relay
        // VT sequences (including DECSCUSR cursor shapes) from child processes
        // directly through the output pipe.  On older Windows, this flag is
        // silently accepted but breaks Win32 Console API translation, so we
        // only attempt it on known-good builds.
        if supports_passthrough_mode() {
            let result = unsafe {
                (CONPTY.CreatePseudoConsole)(
                    size,
                    input.as_raw_handle() as _,
                    output.as_raw_handle() as _,
                    base_flags | PSEUDOCONSOLE_PASSTHROUGH_MODE,
                    &mut con,
                )
            };

            if result == S_OK {
                return Ok(Self { con, used_passthrough: true });
            }
            // If the API call failed despite being on a supported build,
            // fall through to the standard path.
            con = INVALID_HANDLE_VALUE;
        }

        let result = unsafe {
            (CONPTY.CreatePseudoConsole)(
                size,
                input.as_raw_handle() as _,
                output.as_raw_handle() as _,
                base_flags,
                &mut con,
            )
        };
        ensure!(
            result == S_OK,
            "failed to create psuedo console: HRESULT {}",
            result
        );
        Ok(Self { con, used_passthrough: false })
    }

    /// Create a ConPTY explicitly without passthrough mode, regardless of
    /// Windows build version.  Used by the retry logic when CreateProcessW
    /// rejects the passthrough ConPTY handle.
    pub fn new_without_passthrough(size: COORD, input: FileDescriptor, output: FileDescriptor) -> Result<Self, Error> {
        let mut con: HPCON = INVALID_HANDLE_VALUE;
        let base_flags = PSUEDOCONSOLE_INHERIT_CURSOR
            | PSEUDOCONSOLE_RESIZE_QUIRK
            | PSEUDOCONSOLE_WIN32_INPUT_MODE;

        let result = unsafe {
            (CONPTY.CreatePseudoConsole)(
                size,
                input.as_raw_handle() as _,
                output.as_raw_handle() as _,
                base_flags,
                &mut con,
            )
        };
        ensure!(
            result == S_OK,
            "failed to create psuedo console (no passthrough): HRESULT {}",
            result
        );
        Ok(Self { con, used_passthrough: false })
    }

    pub fn resize(&self, size: COORD) -> Result<(), Error> {
        let result = unsafe { (CONPTY.ResizePseudoConsole)(self.con, size) };
        ensure!(
            result == S_OK,
            "failed to resize console to {}x{}: HRESULT: {}",
            size.X,
            size.Y,
            result
        );
        Ok(())
    }

    pub fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<WinChild> {
        let mut si: STARTUPINFOEXW = unsafe { mem::zeroed() };
        si.StartupInfo.cb = mem::size_of::<STARTUPINFOEXW>() as u32;
        // Note: we deliberately do NOT set STARTF_USESTDHANDLES with
        // INVALID_HANDLE_VALUE for stdio.  MSDN explicitly requires
        // STARTF_USESTDHANDLES to be paired with bInheritHandles=TRUE,
        // and we use bInheritHandles=FALSE below.  Most Windows builds
        // tolerate the combination silently (because INVALID_HANDLE_VALUE
        // is a sentinel rather than a real handle), but newer/restricted
        // configurations — Win 11 26200, Microsoft-account profiles with
        // tighter token policies, certain WDAC/AppLocker rule sets — now
        // enforce the contract strictly and reject the call with
        // ERROR_INVALID_PARAMETER (87).  See psmux issue #167.
        //
        // ConPTY routes stdio through the PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
        // attribute on the attribute list, so the child gets correct stdio
        // regardless of dwFlags.  bInheritHandles=FALSE prevents leaking
        // any other inheritable handles.

        let mut attrs = ProcThreadAttributeList::with_capacity(1)?;
        attrs.set_pty(self.con)?;
        si.lpAttributeList = attrs.as_mut_ptr();

        let mut pi: PROCESS_INFORMATION = unsafe { mem::zeroed() };

        let (mut exe, mut cmdline) = cmd.cmdline()?;
        let cmd_os = OsString::from_wide(&cmdline);

        let cwd = cmd.current_directory();

        let res = unsafe {
            CreateProcessW(
                exe.as_mut_slice().as_mut_ptr(),
                cmdline.as_mut_slice().as_mut_ptr(),
                ptr::null_mut(),
                ptr::null_mut(),
                0,
                EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT,
                cmd.environment_block().as_mut_slice().as_mut_ptr() as *mut _,
                cwd.as_ref()
                    .map(|c| c.as_slice().as_ptr())
                    .unwrap_or(ptr::null()),
                &mut si.StartupInfo,
                &mut pi,
            )
        };
        if res == 0 {
            let err = IoError::last_os_error();
            let msg = format!(
                "CreateProcessW `{:?}` in cwd `{:?}` failed: {}",
                cmd_os,
                cwd.as_ref().map(|c| OsString::from_wide(c)),
                err
            );
            log::error!("{}", msg);
            bail!("{}", msg);
        }

        // Make sure we close out the thread handle so we don't leak it;
        // we do this simply by making it owned
        let _main_thread = unsafe { OwnedHandle::from_raw_handle(pi.hThread as _) };
        let proc = unsafe { OwnedHandle::from_raw_handle(pi.hProcess as _) };

        Ok(WinChild {
            proc: Mutex::new(proc),
        })
    }
}


================================================
FILE: crates/vt100-psmux/.cargo-ok
================================================
{"v":1}

================================================
FILE: crates/vt100-psmux/.cargo_vcs_info.json
================================================
{
  "git": {
    "sha1": "e79e0d68ab3875f045bc3cc3120907a0e5b3bb0f"
  },
  "path_in_vcs": ""
}

================================================
FILE: crates/vt100-psmux/CHANGELOG.md
================================================
# Changelog

## [0.16.2] - 2025-07-11

### Fixed

* Fixed potential cursor out of bounds when using decrc after resizing. (#13)

## [0.16.1] - 2025-07-10

### Changed

* Reverted to the 2021 edition for now.

## [0.16.0] - 2025-07-08

### Added

* `Parser::process_cb`, which works the same as `Parser::process` except that
  it calls callbacks during parsing when it finds a terminal escape which is
  potentially useful but not something that affects the screen itself.
* Support for xterm window resize request escape codes, via the new callback
  mechanism.
* Support for dim formatting. (Daniel Faust, #9)
* Support for CNL/CPL escape codes. (Danny Weinberg, #10)
* Support for OSC 52 (clipboard manipulation).

### Removed

* These methods on `Screen` have been removed in favor of the new callback
  API described above:
  * `title_formatted`
  * `title_diff`
  * `title`
  * `icon_name`
  * `bells_diff`
  * `audible_bell_count`
  * `visual_bell_count`
  * `errors`
* Additionally, unhandled escape sequences no longer log to STDERR; they
  instead call various callback methods which can be defined to log if
  desired.
* `Cell` no longer implements `Default`.
* `Screen` no longer implements `vte::Perform`.

### Changed

* `Parser::set_size` and `Parser::set_scrollback` have been moved to methods
  on `Screen`, and `Parser::screen_mut` was added to get a mutable reference
  to the screen.
* `Cell::contents` now returns `&str` instead of `String`, eliminating an
  allocation in many cases. (Chris Olszewski, #14)

### Fixed

* Fixed some issues with calculating scrollback offsets correctly in
  `Grid::visible_rows`. (rezigned, #11)

## [0.15.2] - 2023-02-05

### Changed

* Bumped dependencies

## [0.15.1] - 2021-12-21

### Changed

* Removed a lot of unnecessary test data from the packaged crate, making
  downloads faster

## [0.15.0] - 2021-12-15

### Added

* `Screen::errors` to track the number of parsing errors seen so far

### Fixed

* No longer generate spurious diffs in some cases where the cursor is past the
  end of a row
* Fix restoring the cursor position when scrolled back

### Changed

* Various internal refactorings

## [0.14.0] - 2021-12-06

### Changed

* Unknown UTF-8 characters default to a width of 1, rather than 0 (except for
  control characters, as mentioned below)

### Fixed

* Ignore C1 control characters rather than adding them to the cell data, since
  they are non-printable

## [0.13.2] - 2021-12-05

### Changed

* Delay allocation of the alternate screen until it is used (saves a bit of
  memory in basic cases)

## [0.13.1] - 2021-12-04

### Fixed

* Fixed various line wrapping state issues
* Fixed cursor positioning after writing zero width characters at the end of
  the line
* Fixed `Screen::cursor_state_formatted` to draw the last character in a line
  with the appropriate drawing attributes if it needs to redraw it

## [0.13.0] - 2021-11-17

### Added

* `Screen::alternate_screen` to determine if the alternate screen is in use
* `Screen::row_wrapped` to determine whether the row at the given index should
  wrap its text
* `Screen::cursor_state_formatted` to set the cursor position and hidden state
  (including internal state like the one-past-the-end state which isn't visible
  in the return value of `cursor_position`)

### Fixed

* `Screen::rows_formatted` now outputs correct escape codes in some edge cases
  at the beginning of a row when the previous row was wrapped
* VPA escape sequence can no longer position the cursor off the screen

## [0.12.0] - 2021-03-09

### Added

* `Screen::state_formatted` and `Screen::state_diff` convenience wrappers

### Fixed

* `Screen::attributes_formatted` now correctly resets previously set attributes
  where necessary

### Removed

* Removed `Screen::attributes_diff`, since I can't actually think of any
  situation where it does a thing that makes sense.

## [0.11.1] - 2021-03-07

### Changed

* Drop dependency on `enumset`

## [0.11.0] - 2021-03-07

### Added

* `Screen::attributes_formatted` and `Screen::attributes_diff` to retrieve the
  current state of the drawing attributes as escape sequences
* `Screen::fgcolor`, `Screen::bgcolor`, `Screen::bold`, `Screen::italic`,
  `Screen::underline`, and `Screen::inverse` to retrieve the current state of
  the drawing attributes directly

## [0.10.0] - 2021-03-06

### Added

* Implementation of `std::io::Write` for `Parser`

## [0.9.0] - 2021-03-05

### Added

* `Screen::contents_between`, for returning the contents logically between two
  given cells (for things like clipboard selection)
* Support SGR subparameters (so `\e[38:2:255:0:0m` behaves the same way as
  `\e[38;2;255;0;0m`)

### Fixed

* Bump `enumset` to fix a dependency which fails to build

## [0.8.1] - 2020-02-09

### Changed

* Bumped `vte` dep to 0.6.

## [0.8.0] - 2019-12-07

### Removed

* Removed the unicode-normalization feature altogether - it turns out that it
  still has a couple edge cases where it causes incorrect behavior, and fixing
  those would be a lot more effort.

### Fixed

* Fix a couple more end-of-line/wrapping bugs, especially around cursor
  positioning.
* Fix applying combining characters to wide characters.
* Ensure cells can't have contents with width zero (to avoid ambiguity). If an
  empty cell gets a combining character applied to it, default that cell to a
  (normal-width) space first.

## [0.7.0] - 2019-11-23

### Added

* New (default-on) cargo feature `unicode-normalization` which can be disabled
  to disable normalizing cell contents to NFC - it's a pretty small edge case,
  and the data tables required to support it are quite large, which affects
  size-sensitive targets like wasm

## [0.6.3] - 2019-11-20

### Fixed

* Fix output of `contents_formatted` and `contents_diff` when the cursor
  position ends at one past the end of a row.
* If the cursor position is one past the end of a row, any char, even a
  combining char, needs to cause the cursor position to wrap.

## [0.6.2] - 2019-11-13

### Fixed

* Fix zero-width characters when the cursor is at the end of a row.

## [0.6.1] - 2019-11-13

### Added

* Add more debug logging for unhandled escape sequences.

### Changed

* Unhandled escape sequence warnings are now at the `debug` log level.

## [0.6.0] - 2019-11-13

### Added

* `Screen::input_mode_formatted` and `Screen::input_mode_diff` give escape
  codes to set the current terminal input modes.
* `Screen::title_formatted` and `Screen::title_diff` give escape codes to set
  the terminal window title.
* `Screen::bells_diff` gives escape codes to trigger any audible or visual
  bells which have been seen since the previous state.

### Changed

* `Screen::contents_diff` no longer includes audible or visual bells (see
  `Screen::bells_diff` instead).

## [0.5.1] - 2019-11-12

### Fixed

* `Screen::set_size` now actually resizes when requested (previously the
  underlying storage was not being resized, leading to panics when writing
  outside of the original screen).

## [0.5.0] - 2019-11-12

### Added

* Scrollback support.
* `Default` impl for `Parser` which creates an 80x24 terminal with no
  scrollback.

### Removed

* `Parser::screen_mut` (and the `pub` `&mut self` methods on `Screen`). The few
  things you can do to change the screen state directly are now exposed as
  methods on `Parser` itself.

### Changed

* `Cell::contents` now returns a `String` instead of a `&str`.
* `Screen::check_audible_bell` and `Screen::check_visual_bell` have been
  replaced with `Screen::audible_bell_count` and `Screen::visual_bell_count`.
  You should keep track of the "since the last method call" state yourself
  instead of having the screen track it for you.

### Fixed

* Lots of performance and output optimizations.
* Clearing a cell now sets all of that cell's attributes to the current
  attribute set, since different terminals render different things for an empty
  cell based on the attributes.
* `Screen::contents_diff` now includes audible and visual bells when
  appropriate.

## [0.4.0] - 2019-11-08

### Removed

* `Screen::fgcolor`, `Screen::bgcolor`, `Screen::bold`, `Screen::italic`,
  `Screen::underline`, `Screen::inverse`, and `Screen::alternate_screen`:
  these are just implementation details that people shouldn't need to care
  about.

### Fixed

* Fixed cursor movement when the cursor position is already outside of an
  active scroll region.

## [0.3.2] - 2019-11-08

### Fixed

* Clearing cells now correctly sets the cell background color.
* Fixed a couple bugs in wide character handling in `contents_formatted` and
  `contents_diff`.
* Fixed RI when the cursor is at the top of the screen (fixes scrolling up in
  `less`, for instance).
* Fixed VPA incorrectly being clamped to the scroll region.
* Stop treating soft hyphen specially (as far as i can tell, no other terminals
  do this, and i'm not sure why i thought it was necessary to begin with).
* `contents_formatted` now also resets attributes at the start, like
  `contents_diff` does.

## [0.3.1] - 2019-11-06

### Fixed

* Make `contents_formatted` explicitly show the cursor when necessary, in case
  the cursor was previously hidden.

## [0.3.0] - 2019-11-06

### Added

* `Screen::rows` which is like `Screen::contents` except that it returns the
  data by row instead of all at once, and also allows you to restrict the
  region returned to a subset of columns.
* `Screen::rows_formatted` which is like `Screen::rows`, but returns escape
  sequences sufficient to draw the requested subset of each row.
* `Screen::contents_diff` and `Screen::rows_diff` which return escape sequences
  sufficient to turn the visible state of one screen (or a subset of the screen
  in the case of `rows_diff`) into another.

### Changed

* The screen is now exposed separately from the parser, and is cloneable.
* `contents_formatted` now returns `Vec<u8>` instead of `String`.
* `contents` and `contents_formatted` now only allow getting the contents of
  the entire screen rather than a subset (but see the entry for `rows` and
  `rows_formatted` above).

### Removed

* `Cell::new`, since there's not really any reason that this is useful for
  someone to do from outside of the crate.

### Fixed

* `contents_formatted` now preserves the state of empty cells instead of
  filling them with spaces.
* We now clear the row wrapping state when the number of columns in the
  terminal is changed.
* `contents_formatted` now ensures that the cursor has the correct hidden state
  and location.
* `contents_formatted` now clears the screen before starting to draw.

## [0.2.0] - 2019-11-04

### Changed

* Reimplemented in pure safe rust, with a much more accurate parser
* A bunch of minor API tweaks, some backwards-incompatible

## [0.1.2] - 2016-06-04

### Fixed

* Fix returning uninit memory in get_string_formatted/get_string_plaintext
* Handle emoji and zero width unicode characters properly
* Fix cursor positioning with regards to scroll regions and wrapping
* Fix parsing of (ignored) character set escapes
* Explicitly suppress status report escapes

## [0.1.1] - 2016-04-28

### Fixed

* Fix builds

## [0.1.0] - 2016-04-28

### Added

* Initial release


================================================
FILE: crates/vt100-psmux/Cargo.toml
================================================
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.

[package]
edition = "2021"
rust-version = "1.70"
name = "vt100-psmux"
version = "0.16.6"
authors = ["Jesse Luehrs <doy@tozt.net>"]
build = false
include = [
    "src/**/*",
    "LICENSE",
    "README.md",
    "CHANGELOG.md",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Library for parsing terminal data (psmux fork with blink/hidden/strikethrough SGR + CSI cursor patches)"
homepage = "https://github.com/psmux/vt100-rust-patched"
readme = "README.md"
keywords = [
    "terminal",
    "vt100",
]
categories = [
    "command-line-interface",
    "encoding",
]
license = "MIT"
repository = "https://github.com/psmux/vt100-rust-patched"

[lib]
name = "vt100_psmux"
path = "src/lib.rs"

[dependencies.itoa]
version = "1.0.15"

[dependencies.unicode-width]
version = "0.2.1"

[dependencies.vte]
version = "0.15.0"

[dev-dependencies.nix]
version = "0.30.1"
features = ["term"]

[dev-dependencies.quickcheck]
version = "1.0"

[dev-dependencies.rand]
version = "0.10"

[dev-dependencies.serde]
version = "1.0.219"
features = ["derive"]

[dev-dependencies.serde_json]
version = "1.0.140"

[dev-dependencies.terminal_size]
version = "0.4.2"


================================================
FILE: crates/vt100-psmux/Cargo.toml.orig
================================================
[package]
name = "vt100-psmux"
version = "0.16.2"
authors = ["Jesse Luehrs <doy@tozt.net>"]
edition = "2021"
rust-version = "1.70"

description = "Library for parsing terminal data (psmux fork with blink/hidden/strikethrough SGR + CSI cursor patches)"
homepage = "https://github.com/marlocarlo/vt100-rust-patched"
repository = "https://github.com/marlocarlo/vt100-rust-patched"
readme = "README.md"
keywords = ["terminal", "vt100"]
categories = ["command-line-interface", "encoding"]
license = "MIT"
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]

[dependencies]
itoa = "1.0.15"
unicode-width = "0.2.1"
vte = "0.15.0"

[dev-dependencies]
nix = { version = "0.30.1", features = ["term"] }
quickcheck = "1.0"
rand = "0.9"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
terminal_size = "0.4.2"


================================================
FILE: crates/vt100-psmux/LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 Jesse Luehrs

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: crates/vt100-psmux/README.md
================================================
# vt100

This crate parses a terminal byte stream and provides an in-memory
representation of the rendered contents.

## Overview

This is essentially the terminal parser component of a graphical terminal
emulator pulled out into a separate crate. Although you can use this crate
to build a graphical terminal emulator, it also contains functionality
necessary for implementing terminal applications that want to run other
terminal applications - programs like `screen` or `tmux` for example.

## Synopsis

```rust
let mut parser = vt100::Parser::new(24, 80, 0);

let screen = parser.screen().clone();
parser.process(b"this text is \x1b[31mRED\x1b[m");
assert_eq!(
    parser.screen().cell(0, 13).unwrap().fgcolor(),
    vt100::Color::Idx(1),
);

let screen = parser.screen().clone();
parser.process(b"\x1b[3D\x1b[32mGREEN");
assert_eq!(
    parser.screen().contents_formatted(),
    &b"\x1b[?25h\x1b[m\x1b[H\x1b[Jthis text is \x1b[32mGREEN"[..],
);
assert_eq!(
    parser.screen().contents_diff(&screen),
    &b"\x1b[1;14H\x1b[32mGREEN"[..],
);
```


================================================
FILE: crates/vt100-psmux/src/attrs.rs
================================================
use crate::term::BufWrite as _;

/// Represents a foreground or background color for cells.
#[derive(Eq, PartialEq, Debug, Copy, Clone, Default)]
pub enum Color {
    /// The default terminal color.
    #[default]
    Default,

    /// An indexed terminal color.
    Idx(u8),

    /// An RGB terminal color. The parameters are (red, green, blue).
    Rgb(u8, u8, u8),
}

const TEXT_MODE_INTENSITY: u8 = 0b0000_0011;
const TEXT_MODE_BOLD: u8 = 0b0000_0001;
const TEXT_MODE_DIM: u8 = 0b0000_0010;
const TEXT_MODE_ITALIC: u8 = 0b0000_0100;
const TEXT_MODE_UNDERLINE: u8 = 0b0000_1000;
const TEXT_MODE_INVERSE: u8 = 0b0001_0000;
const TEXT_MODE_BLINK: u8 = 0b0010_0000;
const TEXT_MODE_HIDDEN: u8 = 0b0100_0000;
const TEXT_MODE_STRIKETHROUGH: u8 = 0b1000_0000;

#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
pub struct Attrs {
    pub fgcolor: Color,
    pub bgcolor: Color,
    pub mode: u8,
}

impl Attrs {
    pub fn bold(&self) -> bool {
        self.mode & TEXT_MODE_BOLD != 0
    }

    pub fn dim(&self) -> bool {
        self.mode & TEXT_MODE_DIM != 0
    }

    fn intensity(&self) -> u8 {
        self.mode & TEXT_MODE_INTENSITY
    }

    pub fn set_bold(&mut self) {
        self.mode &= !TEXT_MODE_INTENSITY;
        self.mode |= TEXT_MODE_BOLD;
    }

    pub fn set_dim(&mut self) {
        self.mode &= !TEXT_MODE_INTENSITY;
        self.mode |= TEXT_MODE_DIM;
    }

    pub fn set_normal_intensity(&mut self) {
        self.mode &= !TEXT_MODE_INTENSITY;
    }

    pub fn italic(&self) -> bool {
        self.mode & TEXT_MODE_ITALIC != 0
    }

    pub fn set_italic(&mut self, italic: bool) {
        if italic {
            self.mode |= TEXT_MODE_ITALIC;
        } else {
            self.mode &= !TEXT_MODE_ITALIC;
        }
    }

    pub fn underline(&self) -> bool {
        self.mode & TEXT_MODE_UNDERLINE != 0
    }

    pub fn set_underline(&mut self, underline: bool) {
        if underline {
            self.mode |= TEXT_MODE_UNDERLINE;
        } else {
            self.mode &= !TEXT_MODE_UNDERLINE;
        }
    }

    pub fn inverse(&self) -> bool {
        self.mode & TEXT_MODE_INVERSE != 0
    }

    pub fn set_inverse(&mut self, inverse: bool) {
        if inverse {
            self.mode |= TEXT_MODE_INVERSE;
        } else {
            self.mode &= !TEXT_MODE_INVERSE;
        }
    }

    pub fn blink(&self) -> bool {
        self.mode & TEXT_MODE_BLINK != 0
    }

    pub fn set_blink(&mut self, blink: bool) {
        if blink {
            self.mode |= TEXT_MODE_BLINK;
        } else {
            self.mode &= !TEXT_MODE_BLINK;
        }
    }

    pub fn hidden(&self) -> bool {
        self.mode & TEXT_MODE_HIDDEN != 0
    }

    pub fn set_hidden(&mut self, hidden: bool) {
        if hidden {
            self.mode |= TEXT_MODE_HIDDEN;
        } else {
            self.mode &= !TEXT_MODE_HIDDEN;
        }
    }

    pub fn strikethrough(&self) -> bool {
        self.mode & TEXT_MODE_STRIKETHROUGH != 0
    }

    pub fn set_strikethrough(&mut self, strikethrough: bool) {
        if strikethrough {
            self.mode |= TEXT_MODE_STRIKETHROUGH;
        } else {
            self.mode &= !TEXT_MODE_STRIKETHROUGH;
        }
    }

    pub fn write_escape_code_diff(
        &self,
        contents: &mut Vec<u8>,
        other: &Self,
    ) {
        if self != other && self == &Self::default() {
            crate::term::ClearAttrs.write_buf(contents);
            return;
        }

        let attrs = crate::term::Attrs::default();

        let attrs = if self.fgcolor == other.fgcolor {
            attrs
        } else {
            attrs.fgcolor(self.fgcolor)
        };
        let attrs = if self.bgcolor == other.bgcolor {
            attrs
        } else {
            attrs.bgcolor(self.bgcolor)
        };
        let attrs = if self.intensity() == other.intensity() {
            attrs
        } else {
            attrs.intensity(match self.intensity() {
                0 => crate::term::Intensity::Normal,
                TEXT_MODE_BOLD => crate::term::Intensity::Bold,
                TEXT_MODE_DIM => crate::term::Intensity::Dim,
                _ => unreachable!(),
            })
        };
        let attrs = if self.italic() == other.italic() {
            attrs
        } else {
            attrs.italic(self.italic())
        };
        let attrs = if self.underline() == other.underline() {
            attrs
        } else {
            attrs.underline(self.underline())
        };
        let attrs = if self.inverse() == other.inverse() {
            attrs
        } else {
            attrs.inverse(self.inverse())
        };
        let attrs = if self.blink() == other.blink() {
            attrs
        } else {
            attrs.blink(self.blink())
        };
        let attrs = if self.hidden() == other.hidden() {
            attrs
        } else {
            attrs.hidden(self.hidden())
        };
        let attrs = if self.strikethrough() == other.strikethrough() {
            attrs
        } else {
            attrs.strikethrough(self.strikethrough())
        };

        attrs.write_buf(contents);
    }
}


================================================
FILE: crates/vt100-psmux/src/callbacks.rs
================================================
/// This trait is used by the parser to handle extra escape sequences that
/// don't have an impact on the terminal screen directly.
pub trait Callbacks {
    /// This callback is called when the terminal requests an audible bell
    /// (typically with `^G`).
    fn audible_bell(&mut self, _: &mut crate::Screen) {}
    /// This callback is called when the terminal requests a visual bell
    /// (typically with `\eg`).
    fn visual_bell(&mut self, _: &mut crate::Screen) {}
    /// This callback is called when the terminal requests a resize
    /// (typically with `\e[8;<rows>;<cols>t`).
    fn resize(&mut self, _: &mut crate::Screen, _request: (u16, u16)) {}
    /// This callback is called when the terminal requests the window title
    /// to be set (typically with `\e]1;<icon_name>\a`)
    fn set_window_icon_name(
        &mut self,
        _: &mut crate::Screen,
        _icon_name: &[u8],
    ) {
    }
    /// This callback is called when the terminal requests the window title
    /// to be set (typically with `\e]2;<title>\a`)
    fn set_window_title(&mut self, _: &mut crate::Screen, _title: &[u8]) {}
    /// This callback is called when the terminal requests data to be copied
    /// to the system clipboard (typically with `\e]52;<ty>;<data>\a`). Note
    /// that `data` will be encoded as base64.
    fn copy_to_clipboard(
        &mut self,
        _: &mut crate::Screen,
        _ty: &[u8],
        _data: &[u8],
    ) {
    }
    /// This callback is called when the terminal requests data to be pasted
    /// from the system clipboard (typically with `\e]52;<ty>;?\a`).
    fn paste_from_clipboard(&mut self, _: &mut crate::Screen, _ty: &[u8]) {}
    /// This callback is called when the terminal receives an escape sequence
    /// which is otherwise not implemented.
    fn unhandled_char(&mut self, _: &mut crate::Screen, _c: char) {}
    /// This callback is called when the terminal receives a control
    /// character which is otherwise not implemented.
    fn unhandled_control(&mut self, _: &mut crate::Screen, _b: u8) {}
    /// This callback is called when the terminal receives an escape sequence
    /// which is otherwise not implemented.
    fn unhandled_escape(
        &mut self,
        _: &mut crate::Screen,
        _i1: Option<u8>,
        _i2: Option<u8>,
        _b: u8,
    ) {
    }
    /// This callback is called when the terminal receives a CSI sequence
    /// (`\e[`) which is otherwise not implemented.
    fn unhandled_csi(
        &mut self,
        _: &mut crate::Screen,
        _i1: Option<u8>,
        _i2: Option<u8>,
        _params: &[&[u16]],
        _c: char,
    ) {
    }
    /// This callback is called when the terminal receives a OSC sequence
    /// (`\e]`) which is otherwise not implemented.
    fn unhandled_osc(&mut self, _: &mut crate::Screen, _params: &[&[u8]]) {}

    /// This callback is called when the terminal receives an OSC 9;4
    /// (Windows Terminal progress indicator) sequence.  State values:
    /// 0 = hide, 1 = default, 2 = error, 3 = indeterminate, 4 = warning.
    /// Progress is in 0..=100.
    fn set_progress(
        &mut self,
        _: &mut crate::Screen,
        _state: u8,
        _progress: u8,
    ) {
    }
}

impl Callbacks for () {}


================================================
FILE: crates/vt100-psmux/src/cell.rs
================================================
use unicode_width::UnicodeWidthChar as _;

// chosen to make the size of the cell struct 32 bytes
const CONTENT_BYTES: usize = 22;

const IS_WIDE: u8 = 0b1000_0000;
const IS_WIDE_CONTINUATION: u8 = 0b0100_0000;
const LEN_BITS: u8 = 0b0001_1111;

/// Represents a single terminal cell.
#[derive(Clone, Debug, Eq)]
pub struct Cell {
    contents: [u8; CONTENT_BYTES],
    len: u8,
    attrs: crate::attrs::Attrs,
}
const _: () = assert!(std::mem::size_of::<Cell>() == 32);

impl PartialEq<Self> for Cell {
    fn eq(&self, other: &Self) -> bool {
        if self.len != other.len {
            return false;
        }
        if self.attrs != other.attrs {
            return false;
        }
        let len = self.len();
        self.contents[..len] == other.contents[..len]
    }
}

impl Cell {
    pub(crate) fn new() -> Self {
        Self {
            contents: Default::default(),
            len: 0,
            attrs: crate::attrs::Attrs::default(),
        }
    }

    fn len(&self) -> usize {
        usize::from(self.len & LEN_BITS)
    }

    pub(crate) fn set(&mut self, c: char, a: crate::attrs::Attrs) {
        self.len = 0;
        self.append_char(0, c);
        // strings in this context should always be an arbitrary character
        // followed by zero or more zero-width characters, so we should only
        // have to look at the first character
        self.set_wide(c.width().unwrap_or(1) > 1);
        self.attrs = a;
    }

    pub(crate) fn append(&mut self, c: char) {
        let len = self.len();
        if len >= CONTENT_BYTES - 4 {
            return;
        }
        if len == 0 {
            self.contents[0] = b' ';
            self.len += 1;
        }

        // we already checked that we have space for another codepoint
        self.append_char(self.len(), c);
    }

    // Writes bytes representing c at start
    // Requires caller to verify start <= CODEPOINTS_IN_CELL * 4
    fn append_char(&mut self, start: usize, c: char) {
        c.encode_utf8(&mut self.contents[start..]);
        self.len += u8::try_from(c.len_utf8()).unwrap();
    }

    pub(crate) fn clear(&mut self, attrs: crate::attrs::Attrs) {
        self.len = 0;
        self.attrs = attrs;
    }

    /// Returns the text contents of the cell.
    ///
    /// Can include multiple unicode characters if combining characters are
    /// used, but will contain at most one character with a non-zero character
    /// width.
    // Since contents has been constructed by appending chars encoded as UTF-8 it will be valid UTF-8
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn contents(&self) -> &str {
        std::str::from_utf8(&self.contents[..self.len()]).unwrap()
    }

    /// Returns whether the cell contains any text data.
    #[must_use]
    pub fn has_contents(&self) -> bool {
        self.len() > 0
    }

    /// Returns whether the text data in the cell represents a wide character.
    #[must_use]
    pub fn is_wide(&self) -> bool {
        self.len & IS_WIDE != 0
    }

    /// Returns whether the cell contains the second half of a wide character
    /// (in other words, whether the previous cell in the row contains a wide
    /// character)
    #[must_use]
    pub fn is_wide_continuation(&self) -> bool {
        self.len & IS_WIDE_CONTINUATION != 0
    }

    fn set_wide(&mut self, wide: bool) {
        if wide {
            self.len |= IS_WIDE;
        } else {
            self.len &= !IS_WIDE;
        }
    }

    pub(crate) fn set_wide_continuation(&mut self, wide: bool) {
        if wide {
            self.len |= IS_WIDE_CONTINUATION;
        } else {
            self.len &= !IS_WIDE_CONTINUATION;
        }
    }

    pub(crate) fn attrs(&self) -> &crate::attrs::Attrs {
        &self.attrs
    }

    /// Returns the foreground color of the cell.
    #[must_use]
    pub fn fgcolor(&self) -> crate::Color {
        self.attrs.fgcolor
    }

    /// Returns the background color of the cell.
    #[must_use]
    pub fn bgcolor(&self) -> crate::Color {
        self.attrs.bgcolor
    }

    /// Returns whether the cell should be rendered with the bold text
    /// attribute.
    #[must_use]
    pub fn bold(&self) -> bool {
        self.attrs.bold()
    }

    /// Returns whether the cell should be rendered with the dim text
    /// attribute.
    #[must_use]
    pub fn dim(&self) -> bool {
        self.attrs.dim()
    }

    /// Returns whether the cell should be rendered with the italic text
    /// attribute.
    #[must_use]
    pub fn italic(&self) -> bool {
        self.attrs.italic()
    }

    /// Returns whether the cell should be rendered with the underlined text
    /// attribute.
    #[must_use]
    pub fn underline(&self) -> bool {
        self.attrs.underline()
    }

    /// Returns whether the cell should be rendered with the inverse text
    /// attribute.
    #[must_use]
    pub fn inverse(&self) -> bool {
        self.attrs.inverse()
    }

    /// Returns whether the cell should be rendered with the blink text
    /// attribute.
    #[must_use]
    pub fn blink(&self) -> bool {
        self.attrs.blink()
    }

    /// Returns whether the cell should be rendered with the hidden/invisible
    /// text attribute.
    #[must_use]
    pub fn hidden(&self) -> bool {
        self.attrs.hidden()
    }

    /// Returns whether the cell should be rendered with the strikethrough
    /// text attribute.
    #[must_use]
    pub fn strikethrough(&self) -> bool {
        self.attrs.strikethrough()
    }
}


================================================
FILE: crates/vt100-psmux/src/grid.rs
================================================
use crate::term::BufWrite as _;

#[derive(Clone, Debug)]
pub struct Grid {
    size: Size,
    pos: Pos,
    saved_pos: Pos,
    rows: Vec<crate::row::Row>,
    scroll_top: u16,
    scroll_bottom: u16,
    origin_mode: bool,
    saved_origin_mode: bool,
    scrollback: std::collections::VecDeque<crate::row::Row>,
    scrollback_len: usize,
    scrollback_offset: usize,
}

impl Grid {
    pub fn new(size: Size, scrollback_len: usize) -> Self {
        Self {
            size,
            pos: Pos::default(),
            saved_pos: Pos::default(),
            rows: vec![],
            scroll_top: 0,
            scroll_bottom: size.rows - 1,
            origin_mode: false,
            saved_origin_mode: false,
            scrollback: std::collections::VecDeque::new(),
            scrollback_len,
            scrollback_offset: 0,
        }
    }

    pub fn allocate_rows(&mut self) {
        if self.rows.is_empty() {
            self.rows.extend(
                std::iter::repeat_with(|| {
                    crate::row::Row::new(self.size.cols)
                })
                .take(usize::from(self.size.rows)),
            );
        }
    }

    fn new_row(&self) -> crate::row::Row {
        crate::row::Row::new(self.size.cols)
    }

    pub fn clear(&mut self) {
        self.pos = Pos::default();
        self.saved_pos = Pos::default();
        for row in self.drawing_rows_mut() {
            row.clear(crate::attrs::Attrs::default());
        }
        self.scroll_top = 0;
        self.scroll_bottom = self.size.rows - 1;
        self.origin_mode = false;
        self.saved_origin_mode = false;
    }

    pub fn size(&self) -> Size {
        self.size
    }

    pub fn set_size(&mut self, size: Size) {
        if size.cols != self.size.cols {
            for row in &mut self.rows {
                row.wrap(false);
            }
        }

        if self.scroll_bottom == self.size.rows - 1 {
            self.scroll_bottom = size.rows - 1;
        }

        self.size = size;
        for row in &mut self.rows {
            row.resize(size.cols, crate::Cell::new());
        }
        self.rows.resize(usize::from(size.rows), self.new_row());

        if self.scroll_bottom >= size.rows {
            self.scroll_bottom = size.rows - 1;
        }
        if self.scroll_bottom < self.scroll_top {
            self.scroll_top = 0;
        }

        self.row_clamp_top(false);
        self.row_clamp_bottom(false);
        self.col_clamp();

        if self.saved_pos.row > self.size.rows - 1 {
            self.saved_pos.row = self.size.rows - 1;
        }
        if self.saved_pos.col > self.size.cols - 1 {
            self.saved_pos.col = self.size.cols - 1;
        }
    }

    pub fn pos(&self) -> Pos {
        self.pos
    }

    pub fn set_pos(&mut self, mut pos: Pos) {
        if self.origin_mode {
            pos.row = pos.row.saturating_add(self.scroll_top);
        }
        self.pos = pos;
        self.row_clamp_top(self.origin_mode);
        self.row_clamp_bottom(self.origin_mode);
        self.col_clamp();
    }

    pub fn save_cursor(&mut self) {
        self.saved_pos = self.pos;
        self.saved_origin_mode = self.origin_mode;
    }

    pub fn restore_cursor(&mut self) {
        self.pos = self.saved_pos;
        self.origin_mode = self.saved_origin_mode;
    }

    pub fn visible_rows(&self) -> impl Iterator<Item = &crate::row::Row> {
        let scrollback_len = self.scrollback.len();
        let rows_len = self.rows.len();
        self.scrollback
            .iter()
            .skip(scrollback_len - self.scrollback_offset)
            // when scrollback_offset > rows_len (e.g. rows = 3,
            // scrollback_len = 10, offset = 9) the skip(10 - 9)
            // will take 9 rows instead of 3. we need to set
            // the upper bound to rows_len (e.g. 3)
            .take(rows_len)
            // same for rows_len - scrollback_offset (e.g. 3 - 9).
            // it'll panic with overflow. we have to saturate the subtraction.
            .chain(
                self.rows
                    .iter()
                    .take(rows_len.saturating_sub(self.scrollback_offset)),
            )
    }

    pub fn drawing_rows(&self) -> impl Iterator<Item = &crate::row::Row> {
        self.rows.iter()
    }

    pub fn drawing_rows_mut(
        &mut self,
    ) -> impl Iterator<Item = &mut crate::row::Row> {
        self.rows.iter_mut()
    }

    pub fn visible_row(&self, row: u16) -> Option<&crate::row::Row> {
        self.visible_rows().nth(usize::from(row))
    }

    pub fn drawing_row(&self, row: u16) -> Option<&crate::row::Row> {
        self.drawing_rows().nth(usize::from(row))
    }

    pub fn drawing_row_mut(
        &mut self,
        row: u16,
    ) -> Option<&mut crate::row::Row> {
        self.drawing_rows_mut().nth(usize::from(row))
    }

    pub fn current_row_mut(&mut self) -> &mut crate::row::Row {
        self.drawing_row_mut(self.pos.row)
            // we assume self.pos.row is always valid
            .unwrap()
    }

    pub fn visible_cell(&self, pos: Pos) -> Option<&crate::Cell> {
        self.visible_row(pos.row).and_then(|r| r.get(pos.col))
    }

    pub fn drawing_cell(&self, pos: Pos) -> Option<&crate::Cell> {
        self.drawing_row(pos.row).and_then(|r| r.get(pos.col))
    }

    pub fn drawing_cell_mut(&mut self, pos: Pos) -> Option<&mut crate::Cell> {
        self.drawing_row_mut(pos.row)
            .and_then(|r| r.get_mut(pos.col))
    }

    pub fn scrollback_len(&self) -> usize {
        self.scrollback_len
    }

    pub fn scrollback(&self) -> usize {
        self.scrollback_offset
    }

    pub fn set_scrollback(&mut self, rows: usize) {
        self.scrollback_offset = rows.min(self.scrollback.len());
    }

    /// Returns the number of rows currently held in the scrollback buffer
    /// (distinct from `scrollback_len`, which is the configured maximum).
    pub fn scrollback_filled(&self) -> usize {
        self.scrollback.len()
    }

    /// Updates the scrollback buffer's maximum size.  When `new_len` is
    /// smaller than the current fill, the oldest rows are trimmed away.
    pub fn set_scrollback_len(&mut self, new_len: usize) {
        self.scrollback_len = new_len;
        while self.scrollback.len() > self.scrollback_len {
            self.scrollback.pop_front();
        }
        if self.scrollback_offset > self.scrollback.len() {
            self.scrollback_offset = self.scrollback.len();
        }
    }

    /// Append a row to the back of scrollback, evicting the oldest if
    /// the cap is reached.  Used by the alt-screen-to-scrollback copy
    /// path (psmux issue #88).  Honours `scrollback_len = 0` (no-op),
    /// matching how the normal in-flow scrolling treats that case.
    pub fn push_row_to_scrollback(&mut self, row: crate::row::Row) {
        if self.scrollback_len == 0 {
            return;
        }
        self.scrollback.push_back(row);
        while self.scrollback.len() > self.scrollback_len {
            self.scrollback.pop_front();
        }
        if self.scrollback_offset > 0 {
            self.scrollback_offset =
                self.scrollback.len().min(self.scrollback_offset + 1);
        }
    }

    pub fn write_contents(&self, contents: &mut String) {
        let mut wrapping = false;
        for row in self.visible_rows() {
            row.write_contents(contents, 0, self.size.cols, wrapping);
            if !row.wrapped() {
                contents.push('\n');
            }
            wrapping = row.wrapped();
        }

        while contents.ends_with('\n') {
            contents.truncate(contents.len() - 1);
        }
    }

    pub fn write_contents_formatted(
        &self,
        contents: &mut Vec<u8>,
    ) -> crate::attrs::Attrs {
        crate::term::ClearAttrs.write_buf(contents);
        crate::term::ClearScreen.write_buf(contents);

        let mut prev_attrs = crate::attrs::Attrs::default();
        let mut prev_pos = Pos::default();
        let mut wrapping = false;
        for (i, row) in self.visible_rows().enumerate() {
            // we limit the number of cols to a u16 (see Size), so
            // visible_rows() can never return more rows than will fit
            let i = i.try_into().unwrap();
            let (new_pos, new_attrs) = row.write_contents_formatted(
                contents,
                0,
                self.size.cols,
                i,
                wrapping,
                Some(prev_pos),
                Some(prev_attrs),
            );
            prev_pos = new_pos;
            prev_attrs = new_attrs;
            wrapping = row.wrapped();
        }

        self.write_cursor_position_formatted(
            contents,
            Some(prev_pos),
            Some(prev_attrs),
        );

        prev_attrs
    }

    pub fn write_contents_diff(
        &self,
        contents: &mut Vec<u8>,
        prev: &Self,
        mut prev_attrs: crate::attrs::Attrs,
    ) -> crate::attrs::Attrs {
        let mut prev_pos = prev.pos;
        let mut wrapping = false;
        let mut prev_wrapping = false;
        for (i, (row, prev_row)) in
            self.visible_rows().zip(prev.visible_rows()).enumerate()
        {
            // we limit the number of cols to a u16 (see Size), so
            // visible_rows() can never return more rows than will fit
            let i = i.try_into().unwrap();
            let (new_pos, new_attrs) = row.write_contents_diff(
                contents,
                prev_row,
                0,
                self.size.cols,
                i,
                wrapping,
                prev_wrapping,
                prev_pos,
                prev_attrs,
            );
            prev_pos = new_pos;
            prev_attrs = new_attrs;
            wrapping = row.wrapped();
            prev_wrapping = prev_row.wrapped();
        }

        self.write_cursor_position_formatted(
            contents,
            Some(prev_pos),
            Some(prev_attrs),
        );

        prev_attrs
    }

    pub fn write_cursor_position_formatted(
        &self,
        contents: &mut Vec<u8>,
        prev_pos: Option<Pos>,
        prev_attrs: Option<crate::attrs::Attrs>,
    ) {
        let prev_attrs = prev_attrs.unwrap_or_default();
        // writing a character to the last column of a row doesn't wrap the
        // cursor immediately - it waits until the next character is actually
        // drawn. it is only possible for the cursor to have this kind of
        // position after drawing a character though, so if we end in this
        // position, we need to redraw the character at the end of the row.
        if prev_pos != Some(self.pos) && self.pos.col >= self.size.cols {
            let mut pos = Pos {
                row: self.pos.row,
                col: self.size.cols - 1,
            };
            if self
                .drawing_cell(pos)
                // we assume self.pos.row is always valid, and self.size.cols
                // - 1 is always a valid column
                .unwrap()
                .is_wide_continuation()
            {
                pos.col = self.size.cols - 2;
            }
            let cell =
                // we assume self.pos.row is always valid, and self.size.cols
                // - 2 must be a valid column because self.size.cols - 1 is
                // always valid and we just checked that the cell at
                // self.size.cols - 1 is a wide continuation character, which
                // means that the first half of the wide character must be
                // before it
                self.drawing_cell(pos).unwrap();
            if cell.has_contents() {
                if let Some(prev_pos) = prev_pos {
                    crate::term::MoveFromTo::new(prev_pos, pos)
                        .write_buf(contents);
                } else {
                    crate::term::MoveTo::new(pos).write_buf(contents);
                }
                cell.attrs().write_escape_code_diff(contents, &prev_attrs);
                contents.extend(cell.contents().as_bytes());
                prev_attrs.write_escape_code_diff(contents, cell.attrs());
            } else {
                // if the cell doesn't have contents, we can't have gotten
                // here by drawing a character in the last column. this means
                // that as far as i'm aware, we have to have reached here from
                // a newline when we were already after the end of an earlier
                // row. in the case where we are already after the end of an
                // earlier row, we can just write a few newlines, otherwise we
                // also need to do the same as above to get ourselves to after
                // the end of a row.
                let mut found = false;
                for i in (0..self.pos.row).rev() {
                    pos.row = i;
                    pos.col = self.size.cols - 1;
                    if self
                        .drawing_cell(pos)
                        // i is always less than self.pos.row, which we assume
                        // to be always valid, so it must also be valid.
                        // self.size.cols - 1 is always a valid col.
                        .unwrap()
                        .is_wide_continuation()
                    {
                        pos.col = self.size.cols - 2;
                    }
                    let cell = self
                        .drawing_cell(pos)
                        // i is always less than self.pos.row, which we assume
                        // to be always valid, so it must also be valid.
                        // self.size.cols - 2 is valid because self.size.cols
                        // - 1 is always valid, and col gets set to
                        // self.size.cols - 2 when the cell at self.size.cols
                        // - 1 is a wide continuation character, meaning that
                        // the first half of the wide character must be before
                        // it
                        .unwrap();
                    if cell.has_contents() {
                        if let Some(prev_pos) = prev_pos {
                            if prev_pos.row != i
                                || prev_pos.col < self.size.cols
                            {
                                crate::term::MoveFromTo::new(prev_pos, pos)
                                    .write_buf(contents);
                                cell.attrs().write_escape_code_diff(
                                    contents,
                                    &prev_attrs,
                                );
                                contents.extend(cell.contents().as_bytes());
                                prev_attrs.write_escape_code_diff(
                                    contents,
                                    cell.
Download .txt
gitextract_ld4ke3i2/

├── .cargo/
│   └── config.toml
├── .github/
│   ├── ASSETS.md
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── choco-pkg/
│   ├── psmux.nuspec
│   └── tools/
│       ├── chocolateyinstall.ps1
│       └── chocolateyuninstall.ps1
├── crates/
│   ├── portable-pty-psmux/
│   │   ├── .cargo-ok
│   │   ├── .cargo_vcs_info.json
│   │   ├── Cargo.toml
│   │   ├── Cargo.toml.orig
│   │   ├── LICENSE.md
│   │   ├── README.md
│   │   ├── examples/
│   │   │   ├── bash.rs
│   │   │   ├── narrow.rs
│   │   │   ├── whoami.rs
│   │   │   └── whoami_async.rs
│   │   └── src/
│   │       ├── cmdbuilder.rs
│   │       ├── lib.rs
│   │       ├── serial.rs
│   │       ├── unix.rs
│   │       └── win/
│   │           ├── conpty.rs
│   │           ├── mod.rs
│   │           ├── procthreadattr.rs
│   │           └── psuedocon.rs
│   └── vt100-psmux/
│       ├── .cargo-ok
│       ├── .cargo_vcs_info.json
│       ├── CHANGELOG.md
│       ├── Cargo.toml
│       ├── Cargo.toml.orig
│       ├── LICENSE
│       ├── README.md
│       └── src/
│           ├── attrs.rs
│           ├── callbacks.rs
│           ├── cell.rs
│           ├── grid.rs
│           ├── lib.rs
│           ├── parser.rs
│           ├── perform.rs
│           ├── row.rs
│           ├── screen.rs
│           └── term.rs
├── docker/
│   ├── Dockerfile
│   ├── Profile/
│   │   └── Microsoft.PowerShell_profile.ps1
│   ├── README.md
│   ├── Run-PsmuxDev.ps1
│   └── Tools/
│       ├── ImportVsDevEnv.ps1
│       ├── InstallAll.ps1
│       ├── InstallGit.ps1
│       ├── InstallOpenSSH.ps1
│       ├── InstallRust.ps1
│       ├── InstallVsBuildTools.ps1
│       └── StartContainer.ps1
├── docs/
│   ├── claude-code.md
│   ├── compatibility.md
│   ├── configuration.md
│   ├── control-mode.md
│   ├── faq.md
│   ├── features.md
│   ├── integration.md
│   ├── iterm2-control-mode.md
│   ├── keybindings.md
│   ├── mouse-ssh.md
│   ├── multi-shell.md
│   ├── pane-titles.md
│   ├── performance.md
│   ├── plugins.md
│   ├── preview.md
│   ├── scripting.md
│   ├── tmux_args_reference.md
│   └── warm-sessions.md
├── examples/
│   ├── crossterm_sgr_diag.rs
│   ├── enter_diag.rs
│   ├── key_diag.rs
│   ├── key_test.rs
│   ├── latency_harness.rs
│   ├── pipeline_diag.rs
│   ├── pty_diag.rs
│   ├── pty_sgr_diag.rs
│   ├── ratatui_render_diag.rs
│   └── test_cursor_debug.rs
├── installer/
│   └── psmux.nsi
├── packages/
│   └── chocolatey/
│       ├── psmux.nuspec
│       └── tools/
│           ├── chocolateyinstall.ps1
│           └── chocolateyuninstall.ps1
├── psmux.json
├── rust-toolchain.toml
├── scoop/
│   └── psmux.json
├── scripts/
│   ├── build.ps1
│   ├── install.ps1
│   ├── pmux-title.ps1
│   ├── pmux-title.sh
│   ├── publish-choco.ps1
│   └── uninstall.ps1
├── src/
│   ├── cli.rs
│   ├── client.rs
│   ├── clipboard.rs
│   ├── commands.rs
│   ├── config.rs
│   ├── control.rs
│   ├── copy_mode.rs
│   ├── cross_session.rs
│   ├── cross_session_server.rs
│   ├── debug_log.rs
│   ├── format.rs
│   ├── help.rs
│   ├── input.rs
│   ├── layout.rs
│   ├── main.rs
│   ├── pane.rs
│   ├── platform.rs
│   ├── popup.rs
│   ├── preview.rs
│   ├── proxy_pane.rs
│   ├── rendering.rs
│   ├── server/
│   │   ├── connection.rs
│   │   ├── helpers.rs
│   │   ├── mod.rs
│   │   ├── option_catalog.rs
│   │   └── options.rs
│   ├── session.rs
│   ├── ssh_input.rs
│   ├── style.rs
│   ├── tree.rs
│   ├── types.rs
│   ├── util.rs
│   ├── warm_pane_sync.rs
│   └── window_ops.rs
├── tests/
│   ├── _batch_runner.ps1
│   ├── _full_run.ps1
│   ├── _launch_debug.bat
│   ├── _run_batch3.ps1
│   ├── alt_emit.ps1
│   ├── alt_emit_inner.ps1
│   ├── alt_emit_simple.ps1
│   ├── battle_test.ps1
│   ├── battle_test.py
│   ├── bench_squelch_cwd.ps1
│   ├── bench_startup_exit.ps1
│   ├── burst_bench2.cs
│   ├── burst_benchmark.cs
│   ├── cursor_bench.cs
│   ├── debug_paste_trace.ps1
│   ├── destructive_test.ps1
│   ├── diag_cursor_claude.ps1
│   ├── diag_cursor_raw.ps1
│   ├── diag_enter_selfcontained.ps1
│   ├── diag_key_events.ps1
│   ├── diag_scroll_inject.ps1
│   ├── disable_processed_input.ps1
│   ├── injector.cs
│   ├── injector_batch.cs
│   ├── inspect_issue263_dump.ps1
│   ├── inspect_issue263_runs.ps1
│   ├── investigate_274_attach_kill.ps1
│   ├── investigate_274_clean_recovery.ps1
│   ├── investigate_274_long.ps1
│   ├── investigate_274_node_daemon.ps1
│   ├── investigate_274_unresponsive_proc.ps1
│   ├── investigate_274_wedge.ps1
│   ├── issue246_emitter.py
│   ├── mouse_diag.ps1
│   ├── mouse_injector.cs
│   ├── repro_enter_bugs.ps1
│   ├── repro_issue303.ps1
│   ├── repro_issue303b.ps1
│   ├── repro_issue303c.ps1
│   ├── repro_preview_compare.ps1
│   ├── repro_preview_layout.ps1
│   ├── repro_pstop_preview.ps1
│   ├── repro_seven_panes.ps1
│   ├── run_all_tests.ps1
│   ├── run_batch_fast.ps1
│   ├── run_fmt_test.ps1
│   ├── test_advanced.ps1
│   ├── test_agent_teams_e2e.ps1
│   ├── test_all.ps1
│   ├── test_all.sh
│   ├── test_alt_key.ps1
│   ├── test_bell_activity_silence.ps1
│   ├── test_bind_key.ps1
│   ├── test_bind_pipe_key.ps1
│   ├── test_bug_detection.ps1
│   ├── test_bugfixes.ps1
│   ├── test_burst_typing_benchmark.ps1
│   ├── test_capture_pane.ps1
│   ├── test_cc_iterm2_compat.ps1
│   ├── test_choose_tree_preview.ps1
│   ├── test_cjk_paste_split.ps1
│   ├── test_claude_agent_teams.ps1
│   ├── test_claude_compat_fixes.ps1
│   ├── test_claude_cursor_diag.ps1
│   ├── test_claude_mouse.ps1
│   ├── test_cli_flag_parity.ps1
│   ├── test_cli_handlers.ps1
│   ├── test_cli_mega_suite.ps1
│   ├── test_combined_flags.ps1
│   ├── test_config.ps1
│   ├── test_config_exhaustive_cli.ps1
│   ├── test_config_exhaustive_tcp.ps1
│   ├── test_config_exhaustive_tui.ps1
│   ├── test_config_plugin_loading.ps1
│   ├── test_conpty_mouse.ps1
│   ├── test_control_mode.ps1
│   ├── test_copy_mode_advanced.ps1
│   ├── test_copy_mode_bracket_paragraph.ps1
│   ├── test_copy_mode_full.ps1
│   ├── test_cross_session_join_pane.ps1
│   ├── test_cross_shell_backslash.ps1
│   ├── test_cursor_fallback.ps1
│   ├── test_cursor_style.ps1
│   ├── test_debug_focus.ps1
│   ├── test_default_command_format.ps1
│   ├── test_default_shell_cmd.ps1
│   ├── test_default_shell_wsl.ps1
│   ├── test_display_message_duration.ps1
│   ├── test_e2e_latency.ps1
│   ├── test_env_shim.ps1
│   ├── test_extreme_perf.ps1
│   ├── test_f_flag_config.ps1
│   ├── test_features.ps1
│   ├── test_features2.ps1
│   ├── test_features3.ps1
│   ├── test_features4.ps1
│   ├── test_features5.ps1
│   ├── test_format_engine.ps1
│   ├── test_format_vars.ps1
│   ├── test_full_feature.ps1
│   ├── test_github_issues.ps1
│   ├── test_github_issues_all.ps1
│   ├── test_hide_window_e2e.ps1
│   ├── test_install_speed.ps1
│   ├── test_issue100_key_names.ps1
│   ├── test_issue105_plugin_env_leak.ps1
│   ├── test_issue108_ctrl_tab.ps1
│   ├── test_issue110_popup_scroll.ps1
│   ├── test_issue111_format_cwd.ps1
│   ├── test_issue111_starship_compat.ps1
│   ├── test_issue112_113.ps1
│   ├── test_issue121_shift_enter.ps1
│   ├── test_issue125_per_window_zoom.ps1
│   ├── test_issue125_zoom_flag.ps1
│   ├── test_issue126_client_prefix.ps1
│   ├── test_issue133_hook_append.ps1
│   ├── test_issue133_hook_duplicates.ps1
│   ├── test_issue134_zoom_wrap_nav.ps1
│   ├── test_issue136_auth_failed.ps1
│   ├── test_issue137_default_terminal.ps1
│   ├── test_issue140_kill_pane_focus_loss.ps1
│   ├── test_issue146_list_commands.ps1
│   ├── test_issue146_popup_via_command_prompt.ps1
│   ├── test_issue151_strict_mode.ps1
│   ├── test_issue154_popup_fixes.ps1
│   ├── test_issue15_altgr.ps1
│   ├── test_issue165_prediction_view_style.ps1
│   ├── test_issue167_conpty_probe.ps1
│   ├── test_issue167_repro.ps1
│   ├── test_issue171_layout.ps1
│   ├── test_issue197_exact_text.ps1
│   ├── test_issue197_paste_tilde.ps1
│   ├── test_issue197_paste_validation.ps1
│   ├── test_issue197_win32_paste.ps1
│   ├── test_issue198_cv_unbind_persist.ps1
│   ├── test_issue198_cv_unbind_proof.ps1
│   ├── test_issue198_paste_detection.ps1
│   ├── test_issue198_paste_detection_proof.ps1
│   ├── test_issue19_config.ps1
│   ├── test_issue200_new_session.ps1
│   ├── test_issue200_proof.ps1
│   ├── test_issue200_sendkeys_proof.ps1
│   ├── test_issue201_rename_dialog.ps1
│   ├── test_issue201_win32_tui_proof.ps1
│   ├── test_issue202_cli_routing.ps1
│   ├── test_issue204_stale_port_files.ps1
│   ├── test_issue205_new_session_env.ps1
│   ├── test_issue206_tui_auth.ps1
│   ├── test_issue209_e2e_verify.ps1
│   ├── test_issue209_functional_proof.ps1
│   ├── test_issue209_tmux_parity_deep.ps1
│   ├── test_issue210_gastown_captures.ps1
│   ├── test_issue210_gastown_fixes.ps1
│   ├── test_issue211_pwsh_mouse_selection.ps1
│   ├── test_issue211_win32_mouse.ps1
│   ├── test_issue215_session_persistence.ps1
│   ├── test_issue217_pane_title_identify.ps1
│   ├── test_issue217_win32_tui_proof.ps1
│   ├── test_issue221_run_shell.ps1
│   ├── test_issue226_ctrl_slash.ps1
│   ├── test_issue226_full_proof.ps1
│   ├── test_issue227_remain_on_exit_hooks.ps1
│   ├── test_issue229_window_name_flash.ps1
│   ├── test_issue229_window_name_initial_command.ps1
│   ├── test_issue230_join_pane_and_ctrl_c.ps1
│   ├── test_issue230_join_pane_and_ctrl_c_proof.ps1
│   ├── test_issue230_send_keys_ctrl_c.ps1
│   ├── test_issue231_osc_title_propagation.ps1
│   ├── test_issue232_status_interval.ps1
│   ├── test_issue234_choose_buffer.ps1
│   ├── test_issue234_choose_buffer_proof.ps1
│   ├── test_issue235_display_panes_base_index.ps1
│   ├── test_issue237_final_proof.ps1
│   ├── test_issue237_typing_freeze.ps1
│   ├── test_issue237_typing_freeze_perf.ps1
│   ├── test_issue239_repro.ps1
│   ├── test_issue242_pageup_copy_mode.ps1
│   ├── test_issue244_capture_scrollback.ps1
│   ├── test_issue244_capture_scrollback_proof.ps1
│   ├── test_issue245_mouse_selection.ps1
│   ├── test_issue246_sparse_render.ps1
│   ├── test_issue247_session_picker_digit.ps1
│   ├── test_issue25.ps1
│   ├── test_issue250_root_cause.ps1
│   ├── test_issue253_repro.ps1
│   ├── test_issue253_repro2.ps1
│   ├── test_issue253_repro3.ps1
│   ├── test_issue257_preview.ps1
│   ├── test_issue259_picker_hjkl.ps1
│   ├── test_issue261_cc_verify.ps1
│   ├── test_issue261_proof.ps1
│   ├── test_issue263_box_drawing_color.ps1
│   ├── test_issue263_byte_proof.ps1
│   ├── test_issue263_definitive.ps1
│   ├── test_issue263_dump_state.ps1
│   ├── test_issue263_final.ps1
│   ├── test_issue263_irrefutable.ps1
│   ├── test_issue263_nested.ps1
│   ├── test_issue263_proof.ps1
│   ├── test_issue263_python_raw.ps1
│   ├── test_issue263_raw.ps1
│   ├── test_issue263_raw_bytes.ps1
│   ├── test_issue263_v2.ps1
│   ├── test_issue264_paste_buffer_proof.ps1
│   ├── test_issue264_paste_buffer_repro.ps1
│   ├── test_issue265_argv_backslash.ps1
│   ├── test_issue266_autorename_override.ps1
│   ├── test_issue266_autorename_override_proof.ps1
│   ├── test_issue266_explicit_name.ps1
│   ├── test_issue266_with_python.ps1
│   ├── test_issue268_dump_state.ps1
│   ├── test_issue269_byte_capture.ps1
│   ├── test_issue269_osc94_dropped.ps1
│   ├── test_issue269_osc94_dropped_proof.ps1
│   ├── test_issue271_runtime_set_propagation.ps1
│   ├── test_issue271_warm_pane_history.ps1
│   ├── test_issue271_warm_pane_history_proof.ps1
│   ├── test_issue272_status_format_perf.ps1
│   ├── test_issue273_send_prefix.ps1
│   ├── test_issue274_pane_isolation.ps1
│   ├── test_issue274_sustained_load.ps1
│   ├── test_issue274_tui_wedge_repro.ps1
│   ├── test_issue274_wezterm_repro.ps1
│   ├── test_issue275_detach_client.ps1
│   ├── test_issue275_detach_keystroke.ps1
│   ├── test_issue277_definitive.ps1
│   ├── test_issue277_scroll_controlled.ps1
│   ├── test_issue277_scroll_repro.ps1
│   ├── test_issue277_tcp_scroll.ps1
│   ├── test_issue284_pageup_wsl.ps1
│   ├── test_issue285_nvim_mouse.ps1
│   ├── test_issue286_ime_prefix.ps1
│   ├── test_issue287_german_keyboard.ps1
│   ├── test_issue288_pane_border_status.ps1
│   ├── test_issue295_scroll_regression.ps1
│   ├── test_issue296_nvim_hang.ps1
│   ├── test_issue33_remaining.ps1
│   ├── test_issue36.ps1
│   ├── test_issue41_btab.ps1
│   ├── test_issue42_version.ps1
│   ├── test_issue43_copy_pane_local.ps1
│   ├── test_issue43_prefix_o_l.ps1
│   ├── test_issue44_zoom_buffer.ps1
│   ├── test_issue45_unzoom_cursor.ps1
│   ├── test_issue46_zoom_nav_desync.ps1
│   ├── test_issue47_bare_run.ps1
│   ├── test_issue49_ctlseq.ps1
│   ├── test_issue50_chinese_chars.ps1
│   ├── test_issue52_claude.ps1
│   ├── test_issue52_cursor.ps1
│   ├── test_issue60_native_tui_mouse.ps1
│   ├── test_issue63_status_off.ps1
│   ├── test_issue70_mouse_mru_and_detached.ps1
│   ├── test_issue70_mru_navigation.ps1
│   ├── test_issue70_select_pane_mru.ps1
│   ├── test_issue71_kill_pane_focus.ps1
│   ├── test_issue74_paste.ps1
│   ├── test_issue82_zoom_split_borders.ps1
│   ├── test_issue88_alt_screen_proof.ps1
│   ├── test_issue88_alt_screen_v2.ps1
│   ├── test_issue88_clean_e2e.ps1
│   ├── test_issue88_codex_scrollback.ps1
│   ├── test_issue88_debug_b.ps1
│   ├── test_issue88_debug_v2.ps1
│   ├── test_issue88_fix_proof.ps1
│   ├── test_issue88_irrefutable_proof.ps1
│   ├── test_issue91_ime_paste.ps1
│   ├── test_issue94_split_percent.ps1
│   ├── test_issue95_commands.ps1
│   ├── test_issue98_bracketed_paste.ps1
│   ├── test_issue99_default_shell_bash.ps1
│   ├── test_issues_107_109_110.ps1
│   ├── test_keybinding_options.ps1
│   ├── test_keystroke_injection.ps1
│   ├── test_kill_pane_by_id.ps1
│   ├── test_kill_server.ps1
│   ├── test_kill_tree.ps1
│   ├── test_layout_engine.ps1
│   ├── test_load_buffer_w_clipboard.ps1
│   ├── test_long_paragraph_benchmark.ps1
│   ├── test_mouse_handling.ps1
│   ├── test_mouse_hover.ps1
│   ├── test_named_buffers.ps1
│   ├── test_named_session_parity.ps1
│   ├── test_new_features.ps1
│   ├── test_new_parity_features.ps1
│   ├── test_newsession_flags.ps1
│   ├── test_nsis_installer.ps1
│   ├── test_osc7_pane_path.ps1
│   ├── test_overlay_bugfixes.ps1
│   ├── test_overlay_rendering.ps1
│   ├── test_pane_mru.ps1
│   ├── test_pane_navigation.ps1
│   ├── test_pane_startup_perf.ps1
│   ├── test_parity.ps1
│   ├── test_perf.ps1
│   ├── test_perf_vs_wt.ps1
│   ├── test_picker_digit_jump_all.ps1
│   ├── test_plugins_themes.ps1
│   ├── test_pr118_bugs.ps1
│   ├── test_pr207_claims.ps1
│   ├── test_pr207_compat_bugs.ps1
│   ├── test_pr207_libtmux.py
│   ├── test_pr207_retest.ps1
│   ├── test_pr207_workaround_elimination.ps1
│   ├── test_pr222_223_run_shell_paths.ps1
│   ├── test_pr255_active_border.ps1
│   ├── test_pr255_visual_proof.ps1
│   ├── test_pr27.ps1
│   ├── test_preview_stuck_repro.ps1
│   ├── test_production_readiness.ps1
│   ├── test_pty_stability.ps1
│   ├── test_real_plugins.ps1
│   ├── test_realistic_typing.ps1
│   ├── test_round9.ps1
│   ├── test_run_shell.ps1
│   ├── test_scroll_memory.ps1
│   ├── test_scroll_viewport_proof.ps1
│   ├── test_scroll_viewport_tracking.ps1
│   ├── test_session.ps1
│   ├── test_session_mgmt.ps1
│   ├── test_showw_sendkeys_p.ps1
│   ├── test_spaces_in_paths.ps1
│   ├── test_split_limits.ps1
│   ├── test_split_window_target_focus.ps1
│   ├── test_squelch_visibility.ps1
│   ├── test_startup_exit_bench.ps1
│   ├── test_startup_perf.ps1
│   ├── test_stress.ps1
│   ├── test_stress_50.ps1
│   ├── test_stress_aggressive.ps1
│   ├── test_stress_attached.ps1
│   ├── test_sustained_fast_typing.ps1
│   ├── test_switch_client.ps1
│   ├── test_switch_client_live_proof.ps1
│   ├── test_tab_spacing.ps1
│   ├── test_target_focus_stability.ps1
│   ├── test_tcp_flag_parity.ps1
│   ├── test_tcp_mega_suite.ps1
│   ├── test_theme_rendering.ps1
│   ├── test_tmux_compat.ps1
│   ├── test_tui_exit_cleanup.ps1
│   ├── test_tui_win32_proof.ps1
│   ├── test_typing_benchmark.ps1
│   ├── test_typing_render_latency.ps1
│   ├── test_unbind_key_a.ps1
│   ├── test_vim_nav_keys.ps1
│   ├── test_vt_paste_missing_close.ps1
│   ├── test_vt_paste_ssh_real.ps1
│   ├── test_warm_off.ps1
│   ├── test_warm_pane.ps1
│   ├── test_warm_pane_sync_options.ps1
│   ├── test_warm_session_claim.ps1
│   ├── test_win32_tui_flag_parity.ps1
│   ├── test_win32_tui_mega_proof.ps1
│   ├── test_window_exit_statusbar.ps1
│   ├── test_window_index_prompt.ps1
│   ├── test_wsl_in_pwsh_latency.ps1
│   ├── test_wsl_in_pwsh_latency2.ps1
│   ├── test_wsl_latency.ps1
│   ├── test_wsl_pwsh_latency3.ps1
│   ├── test_wsl_pwsh_latency4.ps1
│   ├── test_wsl_pwsh_latency5.ps1
│   ├── test_zoom_resize.ps1
│   ├── timed_injector.cs
│   ├── tui_helper.ps1
│   ├── typing_bench.cs
│   └── typing_benchmark.cs
└── tests-rs/
    ├── test_client.rs
    ├── test_cmdbuilder.rs
    ├── test_commands.rs
    ├── test_commands_audit.rs
    ├── test_commands_new.rs
    ├── test_config_exhaustive.rs
    ├── test_config_plugin_paths.rs
    ├── test_cpr_responder.rs
    ├── test_flag_parity.rs
    ├── test_format.rs
    ├── test_gastown_scenarios.rs
    ├── test_h1_osc52_clipboard_capture.rs
    ├── test_h1_osc52_end_to_end.rs
    ├── test_hide_window.rs
    ├── test_input.rs
    ├── test_issue137_env_leak.rs
    ├── test_issue145_source_file.rs
    ├── test_issue151_strict_mode.rs
    ├── test_issue155_output_rendering.rs
    ├── test_issue155_rendering.rs
    ├── test_issue155_sgr_attrs.rs
    ├── test_issue157_bind_key_case.rs
    ├── test_issue165_prediction_view_style.rs
    ├── test_issue167_startup_log.rs
    ├── test_issue169_manual_rename.rs
    ├── test_issue171_layout_bugs.rs
    ├── test_issue179_bind_key_uppercase.rs
    ├── test_issue185_layout_directives.rs
    ├── test_issue192_command_chaining.rs
    ├── test_issue193_scroll_enter_copy_mode.rs
    ├── test_issue196_flag_equals.rs
    ├── test_issue198_cv_persist.rs
    ├── test_issue198_unbind_individual.rs
    ├── test_issue200_new_session.rs
    ├── test_issue201_rename_dialog.rs
    ├── test_issue202_switch_client.rs
    ├── test_issue209_tmux_compat.rs
    ├── test_issue210_gastown_captures.rs
    ├── test_issue210_gastown_fixes.rs
    ├── test_issue215_session_persistence.rs
    ├── test_issue226_ctrl_slash.rs
    ├── test_issue227_remain_on_exit_hooks.rs
    ├── test_issue235_display_panes_base_index.rs
    ├── test_issue244_capture_scrollback.rs
    ├── test_issue245_mouse_selection.rs
    ├── test_issue250_root_cause.rs
    ├── test_issue265_argv_backslash.rs
    ├── test_issue266_per_window_autorename.rs
    ├── test_issue268_set_titles.rs
    ├── test_issue269_osc94_dropped.rs
    ├── test_issue271_warm_pane_history.rs
    ├── test_issue272_format_shell_cache.rs
    ├── test_issue273_send_prefix.rs
    ├── test_issue275_detach_client.rs
    ├── test_issue278_toggle_bool_option.rs
    ├── test_issue284_pageup_wsl.rs
    ├── test_issue287_german_keyboard.rs
    ├── test_issue81_resize_direction.rs
    ├── test_issue88_alt_screen_toggle.rs
    ├── test_layout.rs
    ├── test_mega_unit_coverage.rs
    ├── test_named_buffers.rs
    ├── test_new_session_env.rs
    ├── test_pane_title.rs
    ├── test_parity.rs
    ├── test_pr207_compat_bugs.rs
    ├── test_pr255_active_border.rs
    ├── test_pr267_backpressure_proof.rs
    ├── test_run_shell_resolve.rs
    ├── test_server.rs
    ├── test_session.rs
    ├── test_ssh_vt_paste.rs
    ├── test_vt100_mouse.rs
    ├── test_vt100_screen.rs
    ├── test_warm_pane_sync.rs
    └── test_zoom_bleed.rs
Download .txt
Showing preview only (371K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3943 symbols across 153 files)

FILE: crates/portable-pty-psmux/examples/bash.rs
  function main (line 9) | fn main() {
  function handle_input_stream (line 78) | fn handle_input_stream(rx: std::sync::mpsc::Receiver<String>, mut writer...

FILE: crates/portable-pty-psmux/examples/narrow.rs
  function main (line 7) | fn main() {

FILE: crates/portable-pty-psmux/examples/whoami.rs
  function main (line 8) | fn main() {

FILE: crates/portable-pty-psmux/examples/whoami_async.rs
  function main (line 8) | fn main() -> anyhow::Result<()> {

FILE: crates/portable-pty-psmux/src/cmdbuilder.rs
  type EnvEntry (line 16) | struct EnvEntry {
    method map_key (line 29) | fn map_key(k: OsString) -> OsString {
  function get_shell (line 43) | fn get_shell() -> String {
  function get_base_env (line 74) | fn get_base_env() -> BTreeMap<OsString, EnvEntry> {
  type CommandBuilder (line 203) | pub struct CommandBuilder {
    method new (line 215) | pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
    method from_argv (line 227) | pub fn from_argv(args: Vec<OsString>) -> Self {
    method set_controlling_tty (line 244) | pub fn set_controlling_tty(&mut self, controlling_tty: bool) {
    method get_controlling_tty (line 248) | pub fn get_controlling_tty(&self) -> bool {
    method new_default_prog (line 254) | pub fn new_default_prog() -> Self {
    method is_default_prog (line 266) | pub fn is_default_prog(&self) -> bool {
    method arg (line 272) | pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) {
    method args (line 280) | pub fn args<I, S>(&mut self, args: I)
    method get_argv (line 290) | pub fn get_argv(&self) -> &Vec<OsString> {
    method get_argv_mut (line 294) | pub fn get_argv_mut(&mut self) -> &mut Vec<OsString> {
    method env (line 299) | pub fn env<K, V>(&mut self, key: K, value: V)
    method env_remove (line 316) | pub fn env_remove<K>(&mut self, key: K)
    method env_clear (line 324) | pub fn env_clear(&mut self) {
    method get_env (line 328) | pub fn get_env<K>(&self, key: K) -> Option<&OsStr>
    method cwd (line 342) | pub fn cwd<D>(&mut self, dir: D)
    method clear_cwd (line 349) | pub fn clear_cwd(&mut self) {
    method get_cwd (line 353) | pub fn get_cwd(&self) -> Option<&OsString> {
    method iter_extra_env_as_str (line 360) | pub fn iter_extra_env_as_str(&self) -> impl Iterator<Item = (&str, &st...
    method iter_full_env_as_str (line 378) | pub fn iter_full_env_as_str(&self) -> impl Iterator<Item = (&str, &str...
    method as_unix_command_line (line 394) | pub fn as_unix_command_line(&self) -> anyhow::Result<String> {
    method umask (line 408) | pub fn umask(&mut self, mask: Option<libc::mode_t>) {
    method resolve_path (line 412) | fn resolve_path(&self) -> Option<&OsStr> {
    method search_path (line 416) | fn search_path(&self, exe: &OsStr, cwd: &OsStr) -> anyhow::Result<OsSt...
    method as_command (line 498) | pub(crate) fn as_command(&self) -> anyhow::Result<std::process::Comman...
    method get_shell (line 544) | pub fn get_shell(&self) -> String {
    method get_home_dir (line 560) | fn get_home_dir(&self) -> anyhow::Result<String> {
    method search_path (line 581) | fn search_path(&self, exe: &OsStr) -> OsString {
    method current_directory (line 609) | pub(crate) fn current_directory(&self) -> Option<Vec<u16>> {
    method environment_block (line 638) | pub(crate) fn environment_block(&self) -> Vec<u16> {
    method get_shell (line 659) | pub fn get_shell(&self) -> String {
    method cmdline (line 668) | pub(crate) fn cmdline(&self) -> anyhow::Result<(Vec<u16>, Vec<u16>)> {
    method append_quoted (line 702) | fn append_quoted(arg: &OsStr, cmdline: &mut Vec<u16>) {
  function is_cwd_relative_path (line 750) | fn is_cwd_relative_path<P: AsRef<Path>>(p: P) -> bool {

FILE: crates/portable-pty-psmux/src/lib.rs
  type PtySize (line 63) | pub struct PtySize {
  method default (line 77) | fn default() -> Self {
  type MasterPty (line 88) | pub trait MasterPty: Downcast + Send {
    method resize (line 92) | fn resize(&self, size: PtySize) -> Result<(), Error>;
    method get_size (line 94) | fn get_size(&self) -> Result<PtySize, Error>;
    method try_clone_reader (line 97) | fn try_clone_reader(&self) -> Result<Box<dyn std::io::Read + Send>, Er...
    method take_writer (line 102) | fn take_writer(&self) -> Result<Box<dyn std::io::Write + Send>, Error>;
    method process_group_leader (line 107) | fn process_group_leader(&self) -> Option<libc::pid_t>;
    method as_raw_fd (line 114) | fn as_raw_fd(&self) -> Option<unix::RawFd>;
    method tty_name (line 117) | fn tty_name(&self) -> Option<std::path::PathBuf>;
    method get_termios (line 122) | fn get_termios(&self) -> Option<nix::sys::termios::Termios> {
  type Child (line 130) | pub trait Child: std::fmt::Debug + ChildKiller + Downcast + Send {
    method try_wait (line 135) | fn try_wait(&mut self) -> IoResult<Option<ExitStatus>>;
    method wait (line 138) | fn wait(&mut self) -> IoResult<ExitStatus>;
    method process_id (line 141) | fn process_id(&self) -> Option<u32>;
    method as_raw_handle (line 145) | fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle>;
    method try_wait (line 272) | fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
    method wait (line 279) | fn wait(&mut self) -> IoResult<ExitStatus> {
    method process_id (line 283) | fn process_id(&self) -> Option<u32> {
    method as_raw_handle (line 288) | fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
  type ChildKiller (line 150) | pub trait ChildKiller: std::fmt::Debug + Downcast + Send {
    method kill (line 152) | fn kill(&mut self) -> IoResult<()>;
    method clone_killer (line 157) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync>;
    method kill (line 303) | fn kill(&mut self) -> IoResult<()> {
    method clone_killer (line 315) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
    method kill (line 325) | fn kill(&mut self) -> IoResult<()> {
    method clone_killer (line 335) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
    method kill (line 341) | fn kill(&mut self) -> IoResult<()> {
    method clone_killer (line 376) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
    method clone_killer (line 393) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
  type SlavePty (line 163) | pub trait SlavePty {
    method spawn_command (line 165) | fn spawn_command(&self, cmd: CommandBuilder) -> Result<Box<dyn Child +...
  type ExitStatus (line 170) | pub struct ExitStatus {
    method with_exit_code (line 177) | pub fn with_exit_code(code: u32) -> Self {
    method with_signal (line 182) | pub fn with_signal(signal: &str) -> Self {
    method success (line 190) | pub fn success(&self) -> bool {
    method exit_code (line 198) | pub fn exit_code(&self) -> u32 {
    method signal (line 203) | pub fn signal(&self) -> Option<&str> {
    method from (line 209) | fn from(status: std::process::ExitStatus) -> ExitStatus {
    method fmt (line 241) | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
  type PtyPair (line 253) | pub struct PtyPair {
  type PtySystem (line 263) | pub trait PtySystem: Downcast {
    method openpty (line 267) | fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair>;
  type ProcessSignaller (line 294) | struct ProcessSignaller {
  function native_pty_system (line 400) | pub fn native_pty_system() -> Box<dyn PtySystem + Send> {
  type NativePtySystem (line 405) | pub type NativePtySystem = unix::UnixPtySystem;
  type NativePtySystem (line 407) | pub type NativePtySystem = win::conpty::ConPtySystem;

FILE: crates/portable-pty-psmux/src/serial.rs
  type Handle (line 23) | type Handle = Arc<SerialPort>;
  type SerialTty (line 25) | pub struct SerialTty {
    method new (line 35) | pub fn new<T: AsRef<OsStr> + ?Sized>(port: &T) -> Self {
    method set_baud_rate (line 46) | pub fn set_baud_rate(&mut self, baud: u32) {
    method set_char_size (line 50) | pub fn set_char_size(&mut self, char_size: CharSize) {
    method set_parity (line 54) | pub fn set_parity(&mut self, parity: Parity) {
    method set_stop_bits (line 58) | pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
    method set_flow_control (line 62) | pub fn set_flow_control(&mut self, flow_control: FlowControl) {
  method openpty (line 68) | fn openpty(&self, _size: PtySize) -> anyhow::Result<PtyPair> {
  type Slave (line 104) | struct Slave {
  method spawn_command (line 109) | fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn C...
  type SerialChild (line 122) | struct SerialChild {
    method fmt (line 128) | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::E...
  method try_wait (line 134) | fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
  method wait (line 138) | fn wait(&mut self) -> IoResult<ExitStatus> {
  method process_id (line 159) | fn process_id(&self) -> Option<u32> {
  method as_raw_handle (line 164) | fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
  method kill (line 170) | fn kill(&mut self) -> IoResult<()> {
  method clone_killer (line 174) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
  type SerialChildKiller (line 180) | struct SerialChildKiller;
  method kill (line 183) | fn kill(&mut self) -> IoResult<()> {
  method clone_killer (line 187) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
  type Master (line 192) | struct Master {
  type MasterWriter (line 197) | struct MasterWriter {
  method write (line 202) | fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
  method flush (line 206) | fn flush(&mut self) -> Result<(), std::io::Error> {
  method resize (line 212) | fn resize(&self, _size: PtySize) -> anyhow::Result<()> {
  method get_size (line 217) | fn get_size(&self) -> anyhow::Result<PtySize> {
  method try_clone_reader (line 222) | fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Sen...
  method take_writer (line 230) | fn take_writer(&self) -> anyhow::Result<Box<dyn std::io::Write + Send>> {
  method process_group_leader (line 240) | fn process_group_leader(&self) -> Option<libc::pid_t> {
  method as_raw_fd (line 246) | fn as_raw_fd(&self) -> Option<crate::unix::RawFd> {
  method tty_name (line 251) | fn tty_name(&self) -> Option<PathBuf> {
  type Reader (line 256) | struct Reader {
  method read (line 261) | fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {

FILE: crates/portable-pty-psmux/src/unix.rs
  type UnixPtySystem (line 20) | pub struct UnixPtySystem {}
  function openpty (line 22) | fn openpty(size: PtySize) -> anyhow::Result<(UnixMasterPty, UnixSlavePty...
  method openpty (line 71) | fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
  type PtyFd (line 80) | struct PtyFd(pub FileDescriptor);
    type Target (line 82) | type Target = FileDescriptor;
    method deref (line 83) | fn deref(&self) -> &FileDescriptor {
    method deref_mut (line 88) | fn deref_mut(&mut self) -> &mut FileDescriptor {
    method resize (line 180) | fn resize(&self, size: PtySize) -> Result<(), Error> {
    method get_size (line 205) | fn get_size(&self) -> Result<PtySize, Error> {
    method spawn_command (line 228) | fn spawn_command(&self, builder: CommandBuilder) -> anyhow::Result<std...
  method read (line 94) | fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
  function tty_name (line 108) | fn tty_name(fd: RawFd) -> Option<PathBuf> {
  function close_random_fds (line 152) | pub fn close_random_fds() {
  type UnixMasterPty (line 303) | struct UnixMasterPty {
  type UnixSlavePty (line 311) | struct UnixSlavePty {
  function cloexec (line 316) | fn cloexec(fd: RawFd) -> Result<(), Error> {
  method spawn_command (line 335) | fn spawn_command(
  method resize (line 344) | fn resize(&self, size: PtySize) -> Result<(), Error> {
  method get_size (line 348) | fn get_size(&self) -> Result<PtySize, Error> {
  method try_clone_reader (line 352) | fn try_clone_reader(&self) -> Result<Box<dyn Read + Send>, Error> {
  method take_writer (line 357) | fn take_writer(&self) -> Result<Box<dyn Write + Send>, Error> {
  method as_raw_fd (line 366) | fn as_raw_fd(&self) -> Option<RawFd> {
  method tty_name (line 370) | fn tty_name(&self) -> Option<PathBuf> {
  method process_group_leader (line 374) | fn process_group_leader(&self) -> Option<libc::pid_t> {
  method get_termios (line 381) | fn get_termios(&self) -> Option<nix::sys::termios::Termios> {
  type UnixMasterWriter (line 389) | struct UnixMasterWriter {
  method drop (line 394) | fn drop(&mut self) {
  method write (line 408) | fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
  method flush (line 411) | fn flush(&mut self) -> Result<(), io::Error> {

FILE: crates/portable-pty-psmux/src/win/conpty.rs
  function create_pipe_with_buffer (line 16) | fn create_pipe_with_buffer(size: u32) -> anyhow::Result<(FileDescriptor,...
  type ConPtySystem (line 42) | pub struct ConPtySystem {}
  method openpty (line 45) | fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
  type Inner (line 81) | struct Inner {
    method resize (line 89) | pub fn resize(
  type ConPtyMasterPty (line 111) | pub struct ConPtyMasterPty {
  type ConPtySlavePty (line 115) | pub struct ConPtySlavePty {
  method resize (line 120) | fn resize(&self, size: PtySize) -> anyhow::Result<()> {
  method get_size (line 125) | fn get_size(&self) -> Result<PtySize, Error> {
  method try_clone_reader (line 130) | fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Sen...
  method take_writer (line 134) | fn take_writer(&self) -> anyhow::Result<Box<dyn std::io::Write + Send>> {
  method spawn_command (line 147) | fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn C...
  function is_invalid_parameter (line 196) | fn is_invalid_parameter(e: &anyhow::Error) -> bool {

FILE: crates/portable-pty-psmux/src/win/mod.rs
  type WinChild (line 21) | pub struct WinChild {
    method is_complete (line 26) | fn is_complete(&mut self) -> IoResult<Option<ExitStatus>> {
    method do_kill (line 41) | fn do_kill(&mut self) -> IoResult<()> {
    type Output (line 125) | type Output = anyhow::Result<ExitStatus>;
    method poll (line 127) | fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<anyhow::Re...
  method kill (line 54) | fn kill(&mut self) -> IoResult<()> {
  method clone_killer (line 59) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
  type WinChildKiller (line 66) | pub struct WinChildKiller {
  method kill (line 71) | fn kill(&mut self) -> IoResult<()> {
  method clone_killer (line 81) | fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
  method try_wait (line 88) | fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
  method wait (line 92) | fn wait(&mut self) -> IoResult<ExitStatus> {
  method process_id (line 109) | fn process_id(&self) -> Option<u32> {
  method as_raw_handle (line 118) | fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {

FILE: crates/portable-pty-psmux/src/win/procthreadattr.rs
  constant PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE (line 8) | const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 0x00020016;
  type ProcThreadAttributeList (line 10) | pub struct ProcThreadAttributeList {
    method with_capacity (line 15) | pub fn with_capacity(num_attributes: DWORD) -> Result<Self, Error> {
    method as_mut_ptr (line 43) | pub fn as_mut_ptr(&mut self) -> LPPROC_THREAD_ATTRIBUTE_LIST {
    method set_pty (line 47) | pub fn set_pty(&mut self, con: HPCON) -> Result<(), Error> {
  method drop (line 69) | fn drop(&mut self) {

FILE: crates/portable-pty-psmux/src/win/psuedocon.rs
  type HPCON (line 25) | pub type HPCON = HANDLE;
  constant PSUEDOCONSOLE_INHERIT_CURSOR (line 27) | pub const PSUEDOCONSOLE_INHERIT_CURSOR: DWORD = 0x1;
  constant PSEUDOCONSOLE_RESIZE_QUIRK (line 28) | pub const PSEUDOCONSOLE_RESIZE_QUIRK: DWORD = 0x2;
  constant PSEUDOCONSOLE_WIN32_INPUT_MODE (line 29) | pub const PSEUDOCONSOLE_WIN32_INPUT_MODE: DWORD = 0x4;
  constant PSEUDOCONSOLE_PASSTHROUGH_MODE (line 30) | pub const PSEUDOCONSOLE_PASSTHROUGH_MODE: DWORD = 0x8;
  function load_conpty (line 44) | fn load_conpty() -> ConPtyFuncs {
  type PsuedoCon (line 61) | pub struct PsuedoCon {
    method new (line 123) | pub fn new(size: COORD, input: FileDescriptor, output: FileDescriptor)...
    method new_without_passthrough (line 173) | pub fn new_without_passthrough(size: COORD, input: FileDescriptor, out...
    method resize (line 196) | pub fn resize(&self, size: COORD) -> Result<(), Error> {
    method spawn_command (line 208) | pub fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Win...
  method drop (line 73) | fn drop(&mut self) {
  function supports_passthrough_mode (line 86) | fn supports_passthrough_mode() -> bool {

FILE: crates/vt100-psmux/src/attrs.rs
  type Color (line 5) | pub enum Color {
  constant TEXT_MODE_INTENSITY (line 17) | const TEXT_MODE_INTENSITY: u8 = 0b0000_0011;
  constant TEXT_MODE_BOLD (line 18) | const TEXT_MODE_BOLD: u8 = 0b0000_0001;
  constant TEXT_MODE_DIM (line 19) | const TEXT_MODE_DIM: u8 = 0b0000_0010;
  constant TEXT_MODE_ITALIC (line 20) | const TEXT_MODE_ITALIC: u8 = 0b0000_0100;
  constant TEXT_MODE_UNDERLINE (line 21) | const TEXT_MODE_UNDERLINE: u8 = 0b0000_1000;
  constant TEXT_MODE_INVERSE (line 22) | const TEXT_MODE_INVERSE: u8 = 0b0001_0000;
  constant TEXT_MODE_BLINK (line 23) | const TEXT_MODE_BLINK: u8 = 0b0010_0000;
  constant TEXT_MODE_HIDDEN (line 24) | const TEXT_MODE_HIDDEN: u8 = 0b0100_0000;
  constant TEXT_MODE_STRIKETHROUGH (line 25) | const TEXT_MODE_STRIKETHROUGH: u8 = 0b1000_0000;
  type Attrs (line 28) | pub struct Attrs {
    method bold (line 35) | pub fn bold(&self) -> bool {
    method dim (line 39) | pub fn dim(&self) -> bool {
    method intensity (line 43) | fn intensity(&self) -> u8 {
    method set_bold (line 47) | pub fn set_bold(&mut self) {
    method set_dim (line 52) | pub fn set_dim(&mut self) {
    method set_normal_intensity (line 57) | pub fn set_normal_intensity(&mut self) {
    method italic (line 61) | pub fn italic(&self) -> bool {
    method set_italic (line 65) | pub fn set_italic(&mut self, italic: bool) {
    method underline (line 73) | pub fn underline(&self) -> bool {
    method set_underline (line 77) | pub fn set_underline(&mut self, underline: bool) {
    method inverse (line 85) | pub fn inverse(&self) -> bool {
    method set_inverse (line 89) | pub fn set_inverse(&mut self, inverse: bool) {
    method blink (line 97) | pub fn blink(&self) -> bool {
    method set_blink (line 101) | pub fn set_blink(&mut self, blink: bool) {
    method hidden (line 109) | pub fn hidden(&self) -> bool {
    method set_hidden (line 113) | pub fn set_hidden(&mut self, hidden: bool) {
    method strikethrough (line 121) | pub fn strikethrough(&self) -> bool {
    method set_strikethrough (line 125) | pub fn set_strikethrough(&mut self, strikethrough: bool) {
    method write_escape_code_diff (line 133) | pub fn write_escape_code_diff(

FILE: crates/vt100-psmux/src/callbacks.rs
  type Callbacks (line 3) | pub trait Callbacks {
    method audible_bell (line 6) | fn audible_bell(&mut self, _: &mut crate::Screen) {}
    method visual_bell (line 9) | fn visual_bell(&mut self, _: &mut crate::Screen) {}
    method resize (line 12) | fn resize(&mut self, _: &mut crate::Screen, _request: (u16, u16)) {}
    method set_window_icon_name (line 15) | fn set_window_icon_name(
    method set_window_title (line 23) | fn set_window_title(&mut self, _: &mut crate::Screen, _title: &[u8]) {}
    method copy_to_clipboard (line 27) | fn copy_to_clipboard(
    method paste_from_clipboard (line 36) | fn paste_from_clipboard(&mut self, _: &mut crate::Screen, _ty: &[u8]) {}
    method unhandled_char (line 39) | fn unhandled_char(&mut self, _: &mut crate::Screen, _c: char) {}
    method unhandled_control (line 42) | fn unhandled_control(&mut self, _: &mut crate::Screen, _b: u8) {}
    method unhandled_escape (line 45) | fn unhandled_escape(
    method unhandled_csi (line 55) | fn unhandled_csi(
    method unhandled_osc (line 66) | fn unhandled_osc(&mut self, _: &mut crate::Screen, _params: &[&[u8]]) {}
    method set_progress (line 72) | fn set_progress(

FILE: crates/vt100-psmux/src/cell.rs
  constant CONTENT_BYTES (line 4) | const CONTENT_BYTES: usize = 22;
  constant IS_WIDE (line 6) | const IS_WIDE: u8 = 0b1000_0000;
  constant IS_WIDE_CONTINUATION (line 7) | const IS_WIDE_CONTINUATION: u8 = 0b0100_0000;
  constant LEN_BITS (line 8) | const LEN_BITS: u8 = 0b0001_1111;
  type Cell (line 12) | pub struct Cell {
    method eq (line 20) | fn eq(&self, other: &Self) -> bool {
    method new (line 33) | pub(crate) fn new() -> Self {
    method len (line 41) | fn len(&self) -> usize {
    method set (line 45) | pub(crate) fn set(&mut self, c: char, a: crate::attrs::Attrs) {
    method append (line 55) | pub(crate) fn append(&mut self, c: char) {
    method append_char (line 71) | fn append_char(&mut self, start: usize, c: char) {
    method clear (line 76) | pub(crate) fn clear(&mut self, attrs: crate::attrs::Attrs) {
    method contents (line 89) | pub fn contents(&self) -> &str {
    method has_contents (line 95) | pub fn has_contents(&self) -> bool {
    method is_wide (line 101) | pub fn is_wide(&self) -> bool {
    method is_wide_continuation (line 109) | pub fn is_wide_continuation(&self) -> bool {
    method set_wide (line 113) | fn set_wide(&mut self, wide: bool) {
    method set_wide_continuation (line 121) | pub(crate) fn set_wide_continuation(&mut self, wide: bool) {
    method attrs (line 129) | pub(crate) fn attrs(&self) -> &crate::attrs::Attrs {
    method fgcolor (line 135) | pub fn fgcolor(&self) -> crate::Color {
    method bgcolor (line 141) | pub fn bgcolor(&self) -> crate::Color {
    method bold (line 148) | pub fn bold(&self) -> bool {
    method dim (line 155) | pub fn dim(&self) -> bool {
    method italic (line 162) | pub fn italic(&self) -> bool {
    method underline (line 169) | pub fn underline(&self) -> bool {
    method inverse (line 176) | pub fn inverse(&self) -> bool {
    method blink (line 183) | pub fn blink(&self) -> bool {
    method hidden (line 190) | pub fn hidden(&self) -> bool {
    method strikethrough (line 197) | pub fn strikethrough(&self) -> bool {
  constant _ (line 17) | const _: () = assert!(std::mem::size_of::<Cell>() == 32);

FILE: crates/vt100-psmux/src/grid.rs
  type Grid (line 4) | pub struct Grid {
    method new (line 19) | pub fn new(size: Size, scrollback_len: usize) -> Self {
    method allocate_rows (line 35) | pub fn allocate_rows(&mut self) {
    method new_row (line 46) | fn new_row(&self) -> crate::row::Row {
    method clear (line 50) | pub fn clear(&mut self) {
    method size (line 62) | pub fn size(&self) -> Size {
    method set_size (line 66) | pub fn set_size(&mut self, size: Size) {
    method pos (line 102) | pub fn pos(&self) -> Pos {
    method set_pos (line 106) | pub fn set_pos(&mut self, mut pos: Pos) {
    method save_cursor (line 116) | pub fn save_cursor(&mut self) {
    method restore_cursor (line 121) | pub fn restore_cursor(&mut self) {
    method visible_rows (line 126) | pub fn visible_rows(&self) -> impl Iterator<Item = &crate::row::Row> {
    method drawing_rows (line 146) | pub fn drawing_rows(&self) -> impl Iterator<Item = &crate::row::Row> {
    method drawing_rows_mut (line 150) | pub fn drawing_rows_mut(
    method visible_row (line 156) | pub fn visible_row(&self, row: u16) -> Option<&crate::row::Row> {
    method drawing_row (line 160) | pub fn drawing_row(&self, row: u16) -> Option<&crate::row::Row> {
    method drawing_row_mut (line 164) | pub fn drawing_row_mut(
    method current_row_mut (line 171) | pub fn current_row_mut(&mut self) -> &mut crate::row::Row {
    method visible_cell (line 177) | pub fn visible_cell(&self, pos: Pos) -> Option<&crate::Cell> {
    method drawing_cell (line 181) | pub fn drawing_cell(&self, pos: Pos) -> Option<&crate::Cell> {
    method drawing_cell_mut (line 185) | pub fn drawing_cell_mut(&mut self, pos: Pos) -> Option<&mut crate::Cel...
    method scrollback_len (line 190) | pub fn scrollback_len(&self) -> usize {
    method scrollback (line 194) | pub fn scrollback(&self) -> usize {
    method set_scrollback (line 198) | pub fn set_scrollback(&mut self, rows: usize) {
    method scrollback_filled (line 204) | pub fn scrollback_filled(&self) -> usize {
    method set_scrollback_len (line 210) | pub fn set_scrollback_len(&mut self, new_len: usize) {
    method push_row_to_scrollback (line 224) | pub fn push_row_to_scrollback(&mut self, row: crate::row::Row) {
    method write_contents (line 238) | pub fn write_contents(&self, contents: &mut String) {
    method write_contents_formatted (line 253) | pub fn write_contents_formatted(
    method write_contents_diff (line 290) | pub fn write_contents_diff(
    method write_cursor_position_formatted (line 331) | pub fn write_cursor_position_formatted(
    method clear_scrollback (line 491) | pub fn clear_scrollback(&mut self) {
    method erase_all (line 496) | pub fn erase_all(&mut self, attrs: crate::attrs::Attrs) {
    method erase_all_forward (line 502) | pub fn erase_all_forward(&mut self, attrs: crate::attrs::Attrs) {
    method erase_all_backward (line 511) | pub fn erase_all_backward(&mut self, attrs: crate::attrs::Attrs) {
    method erase_row (line 520) | pub fn erase_row(&mut self, attrs: crate::attrs::Attrs) {
    method erase_row_forward (line 524) | pub fn erase_row_forward(&mut self, attrs: crate::attrs::Attrs) {
    method erase_row_backward (line 533) | pub fn erase_row_backward(&mut self, attrs: crate::attrs::Attrs) {
    method insert_cells (line 542) | pub fn insert_cells(&mut self, count: u16) {
    method delete_cells (line 566) | pub fn delete_cells(&mut self, count: u16) {
    method erase_cells (line 576) | pub fn erase_cells(&mut self, count: u16, attrs: crate::attrs::Attrs) {
    method insert_lines (line 585) | pub fn insert_lines(&mut self, count: u16) {
    method delete_lines (line 594) | pub fn delete_lines(&mut self, count: u16) {
    method scroll_up (line 602) | pub fn scroll_up(&mut self, count: u16) {
    method scroll_down (line 620) | pub fn scroll_down(&mut self, count: u16) {
    method set_scroll_region (line 630) | pub fn set_scroll_region(&mut self, top: u16, bottom: u16) {
    method in_scroll_region (line 643) | fn in_scroll_region(&self) -> bool {
    method scroll_region_active (line 647) | fn scroll_region_active(&self) -> bool {
    method set_origin_mode (line 651) | pub fn set_origin_mode(&mut self, mode: bool) {
    method row_inc_clamp (line 656) | pub fn row_inc_clamp(&mut self, count: u16) {
    method row_inc_scroll (line 662) | pub fn row_inc_scroll(&mut self, count: u16) -> u16 {
    method row_dec_clamp (line 674) | pub fn row_dec_clamp(&mut self, count: u16) {
    method row_dec_scroll (line 680) | pub fn row_dec_scroll(&mut self, count: u16) {
    method row_set (line 690) | pub fn row_set(&mut self, i: u16) {
    method col_inc (line 695) | pub fn col_inc(&mut self, count: u16) {
    method col_inc_clamp (line 699) | pub fn col_inc_clamp(&mut self, count: u16) {
    method col_dec (line 704) | pub fn col_dec(&mut self, count: u16) {
    method col_tab (line 708) | pub fn col_tab(&mut self) {
    method col_set (line 714) | pub fn col_set(&mut self, i: u16) {
    method col_wrap (line 719) | pub fn col_wrap(&mut self, width: u16, wrap: bool) {
    method row_clamp_top (line 735) | fn row_clamp_top(&mut self, limit_to_scroll_region: bool) -> u16 {
    method row_clamp_bottom (line 745) | fn row_clamp_bottom(&mut self, limit_to_scroll_region: bool) -> u16 {
    method row_clamp (line 760) | fn row_clamp(&mut self) {
    method col_clamp (line 766) | fn col_clamp(&mut self) {
  type Size (line 774) | pub struct Size {
  type Pos (line 780) | pub struct Pos {

FILE: crates/vt100-psmux/src/parser.rs
  type Parser (line 3) | pub struct Parser<CB: crate::callbacks::Callbacks = ()> {
    method new (line 12) | pub fn new(rows: u16, cols: u16, scrollback_len: usize) -> Self {
    method write (line 88) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
    method flush (line 93) | fn flush(&mut self) -> std::io::Result<()> {
  function new_with_callbacks (line 29) | pub fn new_with_callbacks(
  function process (line 48) | pub fn process(&mut self, bytes: &[u8]) {
  function screen (line 55) | pub fn screen(&self) -> &crate::Screen {
  function screen_mut (line 62) | pub fn screen_mut(&mut self) -> &mut crate::Screen {
  function callbacks (line 68) | pub fn callbacks(&self) -> &CB {
  function callbacks_mut (line 75) | pub fn callbacks_mut(&mut self) -> &mut CB {
  method default (line 82) | fn default() -> Self {

FILE: crates/vt100-psmux/src/perform.rs
  constant BASE64 (line 1) | const BASE64: &[u8] =
  constant CLIPBOARD_SELECTOR (line 3) | const CLIPBOARD_SELECTOR: &[u8] = b"cpqs01234567";
  type WrappedScreen (line 5) | pub struct WrappedScreen<CB: crate::callbacks::Callbacks = ()> {
  function new (line 11) | pub fn new(rows: u16, cols: u16, scrollback_len: usize) -> Self {
  function new_with_callbacks (line 17) | pub fn new_with_callbacks(
  function print (line 34) | fn print(&mut self, c: char) {
  function execute (line 42) | fn execute(&mut self, b: u8) {
  function esc_dispatch (line 61) | fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, b: u8) {
  function csi_dispatch (line 90) | fn csi_dispatch(
  function osc_dispatch (line 209) | fn osc_dispatch(&mut self, params: &[&[u8]], _bel_terminated: bool) {
  function canonicalize_params_1 (line 281) | fn canonicalize_params_1(params: &vte::Params, default: u16) -> u16 {
  function canonicalize_params_2 (line 290) | fn canonicalize_params_2(
  function canonicalize_params_decstbm (line 305) | fn canonicalize_params_decstbm(

FILE: crates/vt100-psmux/src/row.rs
  type Row (line 4) | pub struct Row {
    method new (line 10) | pub fn new(cols: u16) -> Self {
    method cols (line 17) | fn cols(&self) -> u16 {
    method clear (line 25) | pub fn clear(&mut self, attrs: crate::attrs::Attrs) {
    method is_blank (line 35) | pub fn is_blank(&self) -> bool {
    method cells (line 39) | fn cells(&self) -> impl Iterator<Item = &crate::Cell> {
    method get (line 43) | pub fn get(&self, col: u16) -> Option<&crate::Cell> {
    method get_mut (line 47) | pub fn get_mut(&mut self, col: u16) -> Option<&mut crate::Cell> {
    method insert (line 51) | pub fn insert(&mut self, i: u16, cell: crate::Cell) {
    method remove (line 56) | pub fn remove(&mut self, i: u16) {
    method erase (line 62) | pub fn erase(&mut self, i: u16, attrs: crate::attrs::Attrs) {
    method truncate (line 71) | pub fn truncate(&mut self, len: u16) {
    method resize (line 80) | pub fn resize(&mut self, len: u16, cell: crate::Cell) {
    method wrap (line 85) | pub fn wrap(&mut self, wrap: bool) {
    method wrapped (line 89) | pub fn wrapped(&self) -> bool {
    method clear_wide (line 93) | pub fn clear_wide(&mut self, col: u16) {
    method write_contents (line 114) | pub fn write_contents(
    method write_contents_formatted (line 153) | pub fn write_contents_formatted(
    method write_contents_diff (line 300) | pub fn write_contents_diff(

FILE: crates/vt100-psmux/src/screen.rs
  function parse_osc7_uri (line 7) | fn parse_osc7_uri(raw: &str) -> String {
  function percent_decode (line 22) | fn percent_decode(input: &str) -> String {
  function hex_val (line 43) | fn hex_val(b: u8) -> Option<u8> {
  constant MODE_APPLICATION_KEYPAD (line 52) | const MODE_APPLICATION_KEYPAD: u8 = 0b0000_0001;
  constant MODE_APPLICATION_CURSOR (line 53) | const MODE_APPLICATION_CURSOR: u8 = 0b0000_0010;
  constant MODE_HIDE_CURSOR (line 54) | const MODE_HIDE_CURSOR: u8 = 0b0000_0100;
  constant MODE_ALTERNATE_SCREEN (line 55) | const MODE_ALTERNATE_SCREEN: u8 = 0b0000_1000;
  constant MODE_BRACKETED_PASTE (line 56) | const MODE_BRACKETED_PASTE: u8 = 0b0001_0000;
  type MouseProtocolMode (line 60) | pub enum MouseProtocolMode {
  type MouseProtocolEncoding (line 88) | pub enum MouseProtocolEncoding {
  type Screen (line 103) | pub struct Screen {
    method new (line 169) | pub(crate) fn new(
    method set_size (line 197) | pub fn set_size(&mut self, rows: u16, cols: u16) {
    method size (line 207) | pub fn size(&self) -> (u16, u16) {
    method set_scrollback (line 222) | pub fn set_scrollback(&mut self, rows: usize) {
    method scrollback_filled (line 233) | pub fn scrollback_filled(&self) -> usize {
    method set_scrollback_len (line 241) | pub fn set_scrollback_len(&mut self, new_len: usize) {
    method scrollback_len (line 247) | pub fn scrollback_len(&self) -> usize {
    method allow_alternate_screen (line 253) | pub fn allow_alternate_screen(&self) -> bool {
    method set_allow_alternate_screen (line 263) | pub fn set_allow_alternate_screen(&mut self, allowed: bool) {
    method scrollback (line 276) | pub fn scrollback(&self) -> usize {
    method contents (line 285) | pub fn contents(&self) -> String {
    method write_contents (line 291) | fn write_contents(&self, contents: &mut String) {
    method rows (line 302) | pub fn rows(
    method contents_between (line 321) | pub fn contents_between(
    method state_formatted (line 378) | pub fn state_formatted(&self) -> Vec<u8> {
    method state_diff (line 390) | pub fn state_diff(&self, prev: &Self) -> Vec<u8> {
    method contents_formatted (line 403) | pub fn contents_formatted(&self) -> Vec<u8> {
    method write_contents_formatted (line 409) | fn write_contents_formatted(&self, contents: &mut Vec<u8>) {
    method rows_formatted (line 427) | pub fn rows_formatted(
    method contents_diff (line 465) | pub fn contents_diff(&self, prev: &Self) -> Vec<u8> {
    method write_contents_diff (line 471) | fn write_contents_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
    method rows_diff (line 494) | pub fn rows_diff<'a>(
    method input_mode_formatted (line 533) | pub fn input_mode_formatted(&self) -> Vec<u8> {
    method write_input_mode_formatted (line 539) | fn write_input_mode_formatted(&self, contents: &mut Vec<u8>) {
    method input_mode_diff (line 566) | pub fn input_mode_diff(&self, prev: &Self) -> Vec<u8> {
    method write_input_mode_diff (line 572) | fn write_input_mode_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
    method attributes_formatted (line 625) | pub fn attributes_formatted(&self) -> Vec<u8> {
    method write_attributes_formatted (line 631) | fn write_attributes_formatted(&self, contents: &mut Vec<u8>) {
    method cursor_position (line 643) | pub fn cursor_position(&self) -> (u16, u16) {
    method cursor_state_formatted (line 666) | pub fn cursor_state_formatted(&self) -> Vec<u8> {
    method write_cursor_state_formatted (line 672) | fn write_cursor_state_formatted(&self, contents: &mut Vec<u8>) {
    method cell (line 688) | pub fn cell(&self, row: u16, col: u16) -> Option<&crate::Cell> {
    method row_wrapped (line 694) | pub fn row_wrapped(&self, row: u16) -> bool {
    method alternate_screen (line 702) | pub fn alternate_screen(&self) -> bool {
    method application_keypad (line 708) | pub fn application_keypad(&self) -> bool {
    method application_cursor (line 714) | pub fn application_cursor(&self) -> bool {
    method hide_cursor (line 720) | pub fn hide_cursor(&self) -> bool {
    method bracketed_paste (line 726) | pub fn bracketed_paste(&self) -> bool {
    method mouse_protocol_mode (line 732) | pub fn mouse_protocol_mode(&self) -> MouseProtocolMode {
    method mouse_protocol_encoding (line 738) | pub fn mouse_protocol_encoding(&self) -> MouseProtocolEncoding {
    method title (line 744) | pub fn title(&self) -> &str {
    method set_title (line 749) | pub fn set_title(&mut self, raw: &[u8]) {
    method path (line 757) | pub fn path(&self) -> Option<&str> {
    method set_path (line 763) | pub fn set_path(&mut self, raw: &[u8]) {
    method progress (line 778) | pub fn progress(&self) -> Option<(u8, u8)> {
    method set_progress (line 784) | pub fn set_progress(&mut self, state: u8, value: u8) {
    method set_clipboard (line 794) | pub fn set_clipboard(&mut self, selector: &[u8], data: &[u8]) {
    method take_clipboard (line 804) | pub fn take_clipboard(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
    method clipboard (line 811) | pub fn clipboard(&self) -> Option<(&[u8], &[u8])> {
    method squelch_cleared (line 822) | pub fn squelch_cleared(&self) -> bool {
    method take_squelch_cleared (line 827) | pub fn take_squelch_cleared(&mut self) -> bool {
    method take_audible_bell (line 835) | pub fn take_audible_bell(&mut self) -> bool {
    method set_squelch_clear_pending (line 843) | pub fn set_squelch_clear_pending(&mut self, v: bool) {
    method check_squelch_signal (line 848) | fn check_squelch_signal(&mut self) {
    method fgcolor (line 857) | pub fn fgcolor(&self) -> crate::Color {
    method bgcolor (line 863) | pub fn bgcolor(&self) -> crate::Color {
    method bold (line 870) | pub fn bold(&self) -> bool {
    method dim (line 877) | pub fn dim(&self) -> bool {
    method italic (line 884) | pub fn italic(&self) -> bool {
    method underline (line 891) | pub fn underline(&self) -> bool {
    method inverse (line 898) | pub fn inverse(&self) -> bool {
    method grid (line 902) | pub(crate) fn grid(&self) -> &crate::grid::Grid {
    method grid_mut (line 910) | fn grid_mut(&mut self) -> &mut crate::grid::Grid {
    method enter_alternate_grid (line 918) | fn enter_alternate_grid(&mut self) {
    method exit_alternate_grid (line 924) | fn exit_alternate_grid(&mut self) {
    method copy_alt_visible_to_main_scrollback (line 943) | fn copy_alt_visible_to_main_scrollback(&mut self) {
    method save_cursor (line 965) | fn save_cursor(&mut self) {
    method restore_cursor (line 970) | fn restore_cursor(&mut self) {
    method set_mode (line 975) | fn set_mode(&mut self, mode: u8) {
    method clear_mode (line 979) | fn clear_mode(&mut self, mode: u8) {
    method mode (line 983) | fn mode(&self, mode: u8) -> bool {
    method set_mouse_mode (line 987) | fn set_mouse_mode(&mut self, mode: MouseProtocolMode) {
    method clear_mouse_mode (line 991) | fn clear_mouse_mode(&mut self, mode: MouseProtocolMode) {
    method set_mouse_encoding (line 997) | fn set_mouse_encoding(&mut self, encoding: MouseProtocolEncoding) {
    method clear_mouse_encoding (line 1001) | fn clear_mouse_encoding(&mut self, encoding: MouseProtocolEncoding) {
    method text (line 1009) | pub(crate) fn text(&mut self, c: char) {
    method bs (line 1205) | pub(crate) fn bs(&mut self) {
    method tab (line 1209) | pub(crate) fn tab(&mut self) {
    method lf (line 1213) | pub(crate) fn lf(&mut self) {
    method vt (line 1217) | pub(crate) fn vt(&mut self) {
    method ff (line 1221) | pub(crate) fn ff(&mut self) {
    method cr (line 1225) | pub(crate) fn cr(&mut self) {
    method decsc (line 1232) | pub(crate) fn decsc(&mut self) {
    method decrc (line 1237) | pub(crate) fn decrc(&mut self) {
    method deckpam (line 1242) | pub(crate) fn deckpam(&mut self) {
    method deckpnm (line 1247) | pub(crate) fn deckpnm(&mut self) {
    method ri (line 1252) | pub(crate) fn ri(&mut self) {
    method ris (line 1257) | pub(crate) fn ris(&mut self) {
    method ich (line 1264) | pub(crate) fn ich(&mut self, count: u16) {
    method cuu (line 1269) | pub(crate) fn cuu(&mut self, offset: u16) {
    method cud (line 1274) | pub(crate) fn cud(&mut self, offset: u16) {
    method cuf (line 1279) | pub(crate) fn cuf(&mut self, offset: u16) {
    method cub (line 1284) | pub(crate) fn cub(&mut self, offset: u16) {
    method cnl (line 1289) | pub(crate) fn cnl(&mut self, offset: u16) {
    method cpl (line 1295) | pub(crate) fn cpl(&mut self, offset: u16) {
    method cha (line 1301) | pub(crate) fn cha(&mut self, col: u16) {
    method cup (line 1306) | pub(crate) fn cup(&mut self, (row, col): (u16, u16)) {
    method ed (line 1314) | pub(crate) fn ed(
    method decsed (line 1336) | pub(crate) fn decsed(
    method el (line 1345) | pub(crate) fn el(
    method decsel (line 1360) | pub(crate) fn decsel(
    method il (line 1369) | pub(crate) fn il(&mut self, count: u16) {
    method dl (line 1374) | pub(crate) fn dl(&mut self, count: u16) {
    method dch (line 1379) | pub(crate) fn dch(&mut self, count: u16) {
    method su (line 1384) | pub(crate) fn su(&mut self, count: u16) {
    method sd (line 1389) | pub(crate) fn sd(&mut self, count: u16) {
    method ech (line 1394) | pub(crate) fn ech(&mut self, count: u16) {
    method vpa (line 1400) | pub(crate) fn vpa(&mut self, row: u16) {
    method decset (line 1405) | pub(crate) fn decset(
    method decrst (line 1442) | pub(crate) fn decrst(
    method sgr (line 1482) | pub(crate) fn sgr(
    method decstbm (line 1614) | pub(crate) fn decstbm(&mut self, (top, bottom): (u16, u16)) {
  function u16_to_u8 (line 1619) | fn u16_to_u8(i: u16) -> Option<u8> {

FILE: crates/vt100-psmux/src/term.rs
  type BufWrite (line 3) | pub trait BufWrite {
    method write_buf (line 4) | fn write_buf(&self, buf: &mut Vec<u8>);
    method write_buf (line 12) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 22) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 32) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 42) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 52) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 62) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 84) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 102) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 178) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 337) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 369) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 395) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 418) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 444) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 466) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 488) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 514) | fn write_buf(&self, buf: &mut Vec<u8>) {
    method write_buf (line 568) | fn write_buf(&self, buf: &mut Vec<u8>) {
  type ClearScreen (line 9) | pub struct ClearScreen;
  type ClearRowForward (line 19) | pub struct ClearRowForward;
  type Crlf (line 29) | pub struct Crlf;
  type Backspace (line 39) | pub struct Backspace;
  type SaveCursor (line 49) | pub struct SaveCursor;
  type RestoreCursor (line 59) | pub struct RestoreCursor;
  type MoveTo (line 69) | pub struct MoveTo {
    method new (line 75) | pub fn new(pos: crate::grid::Pos) -> Self {
  type ClearAttrs (line 99) | pub struct ClearAttrs;
  type Intensity (line 108) | pub enum Intensity {
  type Attrs (line 116) | pub struct Attrs {
    method fgcolor (line 129) | pub fn fgcolor(mut self, fgcolor: crate::Color) -> Self {
    method bgcolor (line 134) | pub fn bgcolor(mut self, bgcolor: crate::Color) -> Self {
    method intensity (line 139) | pub fn intensity(mut self, intensity: Intensity) -> Self {
    method italic (line 144) | pub fn italic(mut self, italic: bool) -> Self {
    method underline (line 149) | pub fn underline(mut self, underline: bool) -> Self {
    method inverse (line 154) | pub fn inverse(mut self, inverse: bool) -> Self {
    method blink (line 159) | pub fn blink(mut self, blink: bool) -> Self {
    method hidden (line 164) | pub fn hidden(mut self, hidden: bool) -> Self {
    method strikethrough (line 169) | pub fn strikethrough(mut self, strikethrough: bool) -> Self {
  type MoveRight (line 320) | pub struct MoveRight {
    method new (line 325) | pub fn new(count: u16) -> Self {
  method default (line 331) | fn default() -> Self {
  type EraseChar (line 352) | pub struct EraseChar {
    method new (line 357) | pub fn new(count: u16) -> Self {
  method default (line 363) | fn default() -> Self {
  type HideCursor (line 384) | pub struct HideCursor {
    method new (line 389) | pub fn new(state: bool) -> Self {
  type MoveFromTo (line 406) | pub struct MoveFromTo {
    method new (line 412) | pub fn new(from: crate::grid::Pos, to: crate::grid::Pos) -> Self {
  type ApplicationKeypad (line 433) | pub struct ApplicationKeypad {
    method new (line 438) | pub fn new(state: bool) -> Self {
  type ApplicationCursor (line 455) | pub struct ApplicationCursor {
    method new (line 460) | pub fn new(state: bool) -> Self {
  type BracketedPaste (line 477) | pub struct BracketedPaste {
    method new (line 482) | pub fn new(state: bool) -> Self {
  type MouseProtocolMode (line 499) | pub struct MouseProtocolMode {
    method new (line 505) | pub fn new(
  type MouseProtocolEncoding (line 553) | pub struct MouseProtocolEncoding {
    method new (line 559) | pub fn new(
  function extend_itoa (line 593) | fn extend_itoa<I: itoa::Integer>(buf: &mut Vec<u8>, i: I) {

FILE: examples/crossterm_sgr_diag.rs
  function main (line 5) | fn main() {

FILE: examples/enter_diag.rs
  function main (line 12) | fn main() {

FILE: examples/key_diag.rs
  function log_path (line 15) | fn log_path() -> PathBuf {
  function append (line 22) | fn append(line: &str) {
  function main (line 29) | fn main() {

FILE: examples/key_test.rs
  function main (line 3) | fn main() {

FILE: examples/latency_harness.rs
  function main (line 26) | fn main() {
  function find_psmux_exe (line 369) | fn find_psmux_exe() -> std::path::PathBuf {
  function wait_for_files (line 383) | fn wait_for_files(port_file: &str, key_file: &str, timeout: Duration) {
  function send_oneshot (line 395) | fn send_oneshot(psmux_exe: &std::path::Path, session: &str, cmd: &str) {
  function wait_for_quiesce (line 408) | fn wait_for_quiesce(

FILE: examples/pipeline_diag.rs
  function vt_to_color (line 18) | fn vt_to_color(c: vt100::Color) -> Color {
  function build_lines_from_screen (line 43) | fn build_lines_from_screen(screen: &vt100::Screen, rows: u16, cols: u16)...
  function main (line 91) | fn main() {

FILE: examples/pty_diag.rs
  function read_output (line 4) | fn read_output(reader: &mut dyn Read, mut writer: Option<&mut dyn Write>...
  function main (line 39) | fn main() {

FILE: examples/pty_sgr_diag.rs
  function main (line 8) | fn main() {
  function analyze_output (line 61) | fn analyze_output(all_data: &[u8]) {

FILE: examples/ratatui_render_diag.rs
  function main (line 10) | fn main() {

FILE: examples/test_cursor_debug.rs
  function main (line 3) | fn main() {

FILE: src/cli.rs
  function normalize_flag_equals (line 16) | pub fn normalize_flag_equals(args: Vec<String>) -> Vec<String> {
  function normalize_flag_equals_borrowed (line 39) | pub fn normalize_flag_equals_borrowed(args: &[&str]) -> Vec<String> {
  function get_program_name (line 58) | pub fn get_program_name() -> String {
  function print_help (line 67) | pub fn print_help() {
  function print_version (line 427) | pub fn print_version() {
  function print_commands (line 432) | pub fn print_commands() {
  function parse_target (line 515) | pub fn parse_target(target: &str) -> ParsedTarget {
  function extract_session_from_target (line 614) | pub fn extract_session_from_target(target: &str) -> String {
  function extract_flag_value (line 625) | pub fn extract_flag_value<'a>(args: &[&'a str], flag: &str) -> Option<St...
  function has_short_flag (line 659) | pub fn has_short_flag(args: &[&str], flag_char: char) -> bool {
  function parse_target_window_name (line 682) | fn parse_target_window_name() {
  function parse_target_window_index (line 690) | fn parse_target_window_index() {
  function parse_target_window_name_with_pane (line 698) | fn parse_target_window_name_with_pane() {
  function parse_target_bare_window_name (line 707) | fn parse_target_bare_window_name() {
  function parse_target_bare_window_index (line 716) | fn parse_target_bare_window_index() {
  function parse_target_session_only (line 724) | fn parse_target_session_only() {

FILE: src/client.rs
  function extract_confirm_command (line 25) | fn extract_confirm_command(args: &str) -> String {
  function modified_key_name (line 56) | fn modified_key_name(base: &str, mods: KeyModifiers) -> String {
  type PaneLeaf (line 71) | struct PaneLeaf<'a> {
  function collect_leaves (line 76) | fn collect_leaves<'a>(node: &'a LayoutJson, area: Rect, out: &mut Vec<Pa...
  function char_at_col (line 102) | fn char_at_col(runs: &[crate::layout::CellRunJson], local_col: usize) ->...
  function row_chars (line 118) | fn row_chars(runs: &[crate::layout::CellRunJson], width: usize) -> Vec<c...
  function downscale_rows_v2 (line 153) | pub(crate) fn downscale_rows_v2(
  function normalize_selection (line 189) | fn normalize_selection(start: (u16, u16), end: (u16, u16), block: bool) ...
  function extract_selection_text (line 199) | fn extract_selection_text(
  function active_pane_in_alt_screen (line 249) | fn active_pane_in_alt_screen(layout: &LayoutJson) -> bool {
  function active_pane_in_copy_mode (line 259) | fn active_pane_in_copy_mode(layout: &LayoutJson) -> bool {
  function is_word_char (line 266) | fn is_word_char(c: char) -> bool {
  function word_bounds_at (line 276) | fn word_bounds_at(
  function is_on_separator (line 313) | fn is_on_separator(layout: &LayoutJson, area: Rect, x: u16, y: u16) -> b...
  function collect_pane_rects (line 354) | fn collect_pane_rects(node: &LayoutJson, area: Rect, out: &mut Vec<(usiz...
  function collect_layout_borders (line 378) | fn collect_layout_borders(
  function compute_active_rect_json (line 415) | pub fn compute_active_rect_json(node: &LayoutJson, area: Rect) -> Option...
  function render_clock_overlay (line 443) | pub fn render_clock_overlay(f: &mut Frame, area: Rect, colour: Color) {
  function render_layout_json (line 489) | pub fn render_layout_json(
  type ClientDragState (line 871) | struct ClientDragState {
  function run_remote (line 880) | pub fn run_remote(terminal: &mut Terminal<CrosstermBackend<crate::platfo...
  function flush_paste_pend_as_text (line 5496) | fn flush_paste_pend_as_text(
  function paste_buffer_has_non_ascii (line 5539) | fn paste_buffer_has_non_ascii(buf: &str) -> bool {
  function route_paste_to_overlay (line 5548) | fn route_paste_to_overlay(

FILE: src/clipboard.rs
  function copy_to_system_clipboard (line 41) | pub fn copy_to_system_clipboard(text: &str) {
  function copy_to_system_clipboard (line 98) | pub fn copy_to_system_clipboard(_text: &str) {}
  function read_from_system_clipboard (line 108) | pub fn read_from_system_clipboard() -> Option<String> {
  function read_from_system_clipboard (line 157) | pub fn read_from_system_clipboard() -> Option<String> { None }

FILE: src/commands.rs
  function parse_popup_dim_local (line 16) | pub(crate) fn parse_popup_dim_local(spec: &str, term_dim: u16, default: ...
  constant DISPLAY_MESSAGE_DEFAULT_FMT (line 30) | pub(crate) const DISPLAY_MESSAGE_DEFAULT_FMT: &str =
  function resolve_run_shell (line 37) | pub fn resolve_run_shell() -> (String, Vec<String>) {
  function resolve_shell_binary (line 78) | fn resolve_shell_binary(name: &str) -> String {
  function find_file_in_command (line 111) | fn find_file_in_command(cmd: &str) -> Option<(String, String)> {
  function build_run_shell_command (line 142) | pub fn build_run_shell_command(shell_cmd: &str) -> std::process::Command {
  function show_output_popup (line 277) | fn show_output_popup(app: &mut AppState, title: &str, output: String) {
  function generate_list_windows (line 294) | fn generate_list_windows(app: &AppState) -> String {
  function generate_list_panes (line 299) | fn generate_list_panes(app: &AppState) -> String {
  function generate_list_clients (line 321) | fn generate_list_clients(app: &AppState) -> String {
  function generate_show_hooks (line 330) | fn generate_show_hooks(app: &AppState) -> String {
  function generate_show_options (line 348) | fn generate_show_options(app: &AppState) -> String {
  function join_pane_local (line 379) | fn join_pane_local(app: &mut AppState, src_win: Option<usize>, src_pane:...
  function generate_list_commands (line 438) | fn generate_list_commands() -> String {
  function build_choose_tree (line 443) | pub fn build_choose_tree(app: &AppState) -> Vec<crate::session::TreeEntr...
  function parse_window_target (line 454) | fn parse_window_target(target: &str) -> Option<usize> {
  function parse_command_to_action (line 460) | pub fn parse_command_to_action(cmd: &str) -> Option<Action> {
  function format_action (line 610) | pub fn format_action(action: &Action) -> String {
  function parse_command_line (line 642) | pub fn parse_command_line(line: &str) -> Vec<String> {
  function parse_menu_definition (line 698) | pub fn parse_menu_definition(def: &str, x: Option<i16>, y: Option<i16>) ...
  function ensure_background (line 763) | pub fn ensure_background(cmd: &str) -> String {
  function fire_hooks (line 784) | pub fn fire_hooks(app: &mut AppState, event: &str) {
  function execute_action (line 794) | pub fn execute_action(app: &mut AppState, action: &Action) -> io::Result...
  function execute_command_prompt (line 876) | pub fn execute_command_prompt(app: &mut AppState) -> io::Result<()> {
  function execute_command_string (line 920) | pub fn execute_command_string(app: &mut AppState, cmd: &str) -> io::Resu...
  function execute_command_string_single (line 932) | fn execute_command_string_single(app: &mut AppState, cmd: &str) -> io::R...

FILE: src/config.rs
  function current_config_file (line 14) | pub fn current_config_file() -> String {
  function set_current_config_file (line 19) | fn set_current_config_file(path: &str) {
  function is_warm_disabled_by_config (line 25) | pub fn is_warm_disabled_by_config() -> bool {
  function populate_default_bindings (line 71) | pub fn populate_default_bindings(app: &mut AppState) {
  function load_config (line 101) | pub fn load_config(app: &mut AppState) {
  function parse_config_content (line 135) | pub fn parse_config_content(app: &mut AppState, content: &str) {
  function expand_hidden_vars (line 277) | fn expand_hidden_vars(line: &str, env: &std::collections::HashMap<String...
  function is_truthy_config (line 331) | fn is_truthy_config(s: &str) -> bool {
  function parse_config_line (line 336) | pub fn parse_config_line(app: &mut AppState, line: &str) {
  function parse_set_option (line 429) | fn parse_set_option(app: &mut AppState, line: &str) {
  function parse_option_value (line 517) | pub fn parse_option_value(app: &mut AppState, rest: &str, _is_global: bo...
  function shell_words (line 863) | pub fn shell_words(s: &str) -> Vec<String> {
  function split_chained_commands_pub (line 895) | pub fn split_chained_commands_pub(command: &str) -> Vec<String> {
  function split_chained_commands (line 898) | fn split_chained_commands(command: &str) -> Vec<String> {
  function parse_bind_key (line 922) | pub fn parse_bind_key(app: &mut AppState, line: &str) {
  function parse_unbind_key (line 973) | pub fn parse_unbind_key(app: &mut AppState, line: &str) {
  function ensure_prefix_self_binding (line 1030) | pub fn ensure_prefix_self_binding(app: &mut AppState) {
  function normalize_key_for_binding (line 1050) | pub fn normalize_key_for_binding(key: (KeyCode, KeyModifiers)) -> (KeyCo...
  function named_key (line 1073) | fn named_key(name: &str) -> Option<KeyCode> {
  function parse_key_name (line 1107) | pub fn parse_key_name(name: &str) -> Option<(KeyCode, KeyModifiers)> {
  function source_file (line 1190) | pub fn source_file(app: &mut AppState, path: &str) {
  function parse_key_string (line 1245) | pub fn parse_key_string(key: &str) -> Option<(KeyCode, KeyModifiers)> {
  function format_key_binding (line 1318) | pub fn format_key_binding(key: &(KeyCode, KeyModifiers)) -> String {
  function parse_run_shell (line 1362) | fn parse_run_shell(app: &mut AppState, line: &str) {
  function parse_ps1_plugin_script (line 1423) | fn parse_ps1_plugin_script(app: &mut AppState, content: &str) -> bool {
  function parse_tmux_entry_script (line 1485) | fn parse_tmux_entry_script(app: &mut AppState, path: &std::path::Path) {
  function parse_if_shell (line 1596) | fn parse_if_shell(app: &mut AppState, line: &str) {

FILE: src/control.rs
  function layout_checksum (line 6) | fn layout_checksum(s: &str) -> u16 {
  function append_layout_body (line 20) | fn append_layout_body(node: &Node, area: Rect, out: &mut String) {
  function window_layout_string (line 52) | pub fn window_layout_string(window: &Window, area: Rect) -> String {
  function format_notification (line 60) | pub fn format_notification(notif: &ControlNotification) -> String {
  function escape_output (line 137) | pub fn escape_output(data: &str) -> String {
  function format_begin (line 153) | pub fn format_begin(timestamp: i64, cmd_number: u64) -> String {
  function format_end (line 158) | pub fn format_end(timestamp: i64, cmd_number: u64) -> String {
  function format_error (line 163) | pub fn format_error(timestamp: i64, cmd_number: u64) -> String {
  function emit_notification (line 169) | pub fn emit_notification(app: &AppState, notif: ControlNotification) {
  function emit_to_client (line 181) | pub fn emit_to_client(app: &AppState, client_id: u64, notif: ControlNoti...
  function emit_initial_state (line 192) | pub fn emit_initial_state(app: &AppState, client_id: u64) {
  function has_control_clients (line 236) | pub fn has_control_clients(app: &AppState) -> bool {
  function test_escape_output_printable (line 245) | fn test_escape_output_printable() {
  function test_escape_output_backslash (line 250) | fn test_escape_output_backslash() {
  function test_escape_output_control_chars (line 256) | fn test_escape_output_control_chars() {
  function test_escape_output_tab_passthrough (line 262) | fn test_escape_output_tab_passthrough() {
  function test_escape_output_high_bytes (line 267) | fn test_escape_output_high_bytes() {
  function test_format_begin_end_error (line 274) | fn test_format_begin_end_error() {
  function test_format_notification_window_add (line 281) | fn test_format_notification_window_add() {
  function test_format_notification_output (line 287) | fn test_format_notification_output() {
  function test_format_notification_exit (line 296) | fn test_format_notification_exit() {
  function test_format_notification_session_renamed (line 306) | fn test_format_notification_session_renamed() {
  function test_format_notification_layout_change (line 314) | fn test_format_notification_layout_change() {
  function test_format_notification_window_close (line 324) | fn test_format_notification_window_close() {
  function test_format_notification_window_renamed (line 330) | fn test_format_notification_window_renamed() {
  function test_format_notification_session_changed (line 339) | fn test_format_notification_session_changed() {
  function test_format_notification_session_window_changed (line 348) | fn test_format_notification_session_window_changed() {
  function test_format_notification_window_pane_changed (line 357) | fn test_format_notification_window_pane_changed() {
  function test_format_notification_continue_pause (line 366) | fn test_format_notification_continue_pause() {
  function test_format_notification_client_detached (line 372) | fn test_format_notification_client_detached() {
  function test_has_control_clients_empty (line 378) | fn test_has_control_clients_empty() {
  function test_has_control_clients_with_client (line 384) | fn test_has_control_clients_with_client() {
  function test_emit_notification_to_clients (line 404) | fn test_emit_notification_to_clients() {
  function test_emit_notification_skips_paused_pane (line 426) | fn test_emit_notification_skips_paused_pane() {
  function test_escape_output_empty (line 453) | fn test_escape_output_empty() {
  function test_escape_output_mixed (line 458) | fn test_escape_output_mixed() {
  function test_format_notification_extended_output (line 464) | fn test_format_notification_extended_output() {
  function test_format_notification_subscription_changed (line 474) | fn test_format_notification_subscription_changed() {
  function test_format_notification_paste_buffer_changed (line 487) | fn test_format_notification_paste_buffer_changed() {
  function test_format_notification_paste_buffer_deleted (line 495) | fn test_format_notification_paste_buffer_deleted() {
  function test_format_notification_client_session_changed (line 503) | fn test_format_notification_client_session_changed() {
  function test_format_notification_message (line 513) | fn test_format_notification_message() {
  function test_format_notification_sessions_changed (line 521) | fn test_format_notification_sessions_changed() {
  function test_format_notification_pane_mode_changed (line 527) | fn test_format_notification_pane_mode_changed() {
  function test_format_notification_extended_output_with_escape (line 533) | fn test_format_notification_extended_output_with_escape() {
  function test_format_notification_subscription_changed_empty_value (line 543) | fn test_format_notification_subscription_changed_empty_value() {

FILE: src/copy_mode.rs
  function emit_osc52 (line 11) | pub fn emit_osc52<W: Write>(writer: &mut W, text: &str) {
  function enter_copy_mode (line 19) | pub fn enter_copy_mode(app: &mut AppState) {
  function exit_copy_mode (line 40) | pub fn exit_copy_mode(app: &mut AppState) {
  function save_copy_state_to_pane (line 59) | pub fn save_copy_state_to_pane(app: &mut AppState) {
  function restore_copy_state_from_pane (line 92) | pub fn restore_copy_state_from_pane(app: &mut AppState) {
  function switch_with_copy_save (line 126) | pub fn switch_with_copy_save<F: FnOnce(&mut AppState)>(app: &mut AppStat...
  function current_prompt_pos (line 144) | pub fn current_prompt_pos(app: &mut AppState) -> Option<(u16,u16)> {
  function move_copy_cursor (line 152) | pub fn move_copy_cursor(app: &mut AppState, dx: i16, dy: i16) {
  function read_row_text (line 188) | fn read_row_text(app: &mut AppState, row: u16) -> Option<(String, u16)> {
  function get_copy_pos (line 207) | pub fn get_copy_pos(app: &mut AppState) -> Option<(u16, u16)> {
  function move_to_line_start (line 213) | pub fn move_to_line_start(app: &mut AppState) {
  function move_to_line_end (line 220) | pub fn move_to_line_end(app: &mut AppState) {
  function move_to_first_nonblank (line 231) | pub fn move_to_first_nonblank(app: &mut AppState) {
  function char_class (line 243) | fn char_class(ch: char, seps: &str) -> u8 {
  function move_word_forward (line 251) | pub fn move_word_forward(app: &mut AppState) {
  function move_word_backward (line 288) | pub fn move_word_backward(app: &mut AppState) {
  function move_word_end (line 324) | pub fn move_word_end(app: &mut AppState) {
  function scroll_pane_scrollback (line 363) | pub fn scroll_pane_scrollback(app: &mut AppState, lines: usize, up: bool) {
  function scroll_copy_up (line 372) | pub fn scroll_copy_up(app: &mut AppState, lines: usize) {
  function scroll_copy_down (line 380) | pub fn scroll_copy_down(app: &mut AppState, lines: usize) {
  function scroll_to_top (line 388) | pub fn scroll_to_top(app: &mut AppState) {
  function scroll_to_bottom (line 396) | pub fn scroll_to_bottom(app: &mut AppState) {
  function yank_selection (line 404) | pub fn yank_selection(app: &mut AppState) -> io::Result<()> {
  function pipe_text_to_command (line 514) | fn pipe_text_to_command(text: &str, cmd: &str) {
  function paste_latest (line 538) | pub fn paste_latest(app: &mut AppState) -> io::Result<()> {
  function capture_active_pane (line 554) | pub fn capture_active_pane(app: &mut AppState) -> io::Result<()> {
  function capture_active_pane_text (line 571) | pub fn capture_active_pane_text(app: &mut AppState) -> io::Result<Option...
  function save_latest_buffer (line 590) | pub fn save_latest_buffer(app: &mut AppState, file: &str) -> io::Result<...
  function search_copy_mode (line 598) | pub fn search_copy_mode(app: &mut AppState, query: &str, forward: bool) {
  function search_next (line 639) | pub fn search_next(app: &mut AppState) {
  function move_word_forward_big (line 654) | pub fn move_word_forward_big(app: &mut AppState) {
  function move_word_backward_big (line 682) | pub fn move_word_backward_big(app: &mut AppState) {
  function move_word_end_big (line 706) | pub fn move_word_end_big(app: &mut AppState) {
  function move_to_screen_top (line 733) | pub fn move_to_screen_top(app: &mut AppState) {
  function move_to_screen_middle (line 738) | pub fn move_to_screen_middle(app: &mut AppState) {
  function move_to_screen_bottom (line 746) | pub fn move_to_screen_bottom(app: &mut AppState) {
  function find_char_forward (line 754) | pub fn find_char_forward(app: &mut AppState, ch: char) {
  function find_char_backward (line 765) | pub fn find_char_backward(app: &mut AppState, ch: char) {
  function find_char_to_forward (line 776) | pub fn find_char_to_forward(app: &mut AppState, ch: char) {
  function find_char_to_backward (line 787) | pub fn find_char_to_backward(app: &mut AppState, ch: char) {
  function copy_end_of_line (line 798) | pub fn copy_end_of_line(app: &mut AppState) -> io::Result<()> {
  function search_prev (line 817) | pub fn search_prev(app: &mut AppState) {
  function compute_capture_range (line 838) | pub fn compute_capture_range(s: Option<i32>, e: Option<i32>, last_row: u...
  function capture_active_pane_range (line 852) | pub fn capture_active_pane_range(app: &mut AppState, s: Option<i32>, e: ...
  function capture_active_pane_styled (line 946) | pub fn capture_active_pane_styled(app: &mut AppState, s: Option<i32>, e:...
  function move_next_paragraph (line 1119) | pub fn move_next_paragraph(app: &mut AppState) {
  function move_prev_paragraph (line 1144) | pub fn move_prev_paragraph(app: &mut AppState) {
  function move_matching_bracket (line 1168) | pub fn move_matching_bracket(app: &mut AppState) {
  function select_inner_word (line 1229) | pub fn select_inner_word(app: &mut AppState) {
  function select_a_word (line 1250) | pub fn select_a_word(app: &mut AppState) {
  function select_inner_word_big (line 1273) | pub fn select_inner_word_big(app: &mut AppState) {
  function select_a_word_big (line 1302) | pub fn select_a_word_big(app: &mut AppState) {

FILE: src/cross_session.rs
  function resolve_session (line 22) | pub fn resolve_session(session_name: &str) -> io::Result<(u16, String)> {
  function send_to_session (line 38) | fn send_to_session(port: u16, key: &str, cmd: &str) -> io::Result<String> {
  function orchestrate_cross_session_join (line 74) | pub fn orchestrate_cross_session_join(

FILE: src/cross_session_server.rs
  function handle_pane_forward_extract (line 16) | pub fn handle_pane_forward_extract(
  function handle_pane_forward_inject (line 189) | pub fn handle_pane_forward_inject(

FILE: src/debug_log.rs
  function psmux_dir (line 28) | fn psmux_dir() -> String {
  function open_log (line 37) | fn open_log(filename: &str) -> Option<std::fs::File> {
  function env_enabled (line 49) | fn env_enabled(var: &str) -> bool {
  constant CLIENT_LOG_CAP (line 65) | const CLIENT_LOG_CAP: u32 = 5000;
  function client_log (line 72) | pub fn client_log(component: &str, msg: &str) {
  function client_log_enabled (line 97) | pub fn client_log_enabled() -> bool {
  constant STYLE_LOG_CAP (line 111) | const STYLE_LOG_CAP: u32 = 2000;
  function style_log (line 114) | pub fn style_log(component: &str, msg: &str) {
  function style_log_enabled (line 138) | pub fn style_log_enabled() -> bool {
  constant INPUT_LOG_CAP (line 152) | const INPUT_LOG_CAP: u32 = 10000;
  function input_log (line 155) | pub fn input_log(component: &str, msg: &str) {
  function input_log_enabled (line 179) | pub fn input_log_enabled() -> bool {
  constant SERVER_LOG_CAP (line 193) | const SERVER_LOG_CAP: u32 = 10000;
  function server_log (line 196) | pub fn server_log(component: &str, msg: &str) {
  function server_log_enabled (line 220) | pub fn server_log_enabled() -> bool {

FILE: src/format.rs
  function set_buffer_idx_override (line 27) | pub fn set_buffer_idx_override(idx: Option<usize>) {
  function set_named_buffer_override (line 32) | pub fn set_named_buffer_override(name: Option<String>) {
  function generate_window_layout (line 44) | pub fn generate_window_layout(node: &Node, area: ratatui::prelude::Rect)...
  function layout_node (line 50) | fn layout_node(node: &Node, area: ratatui::prelude::Rect) -> String {
  function tmux_layout_checksum (line 81) | fn tmux_layout_checksum(layout: &str) -> u16 {
  function expand_format (line 94) | pub fn expand_format(fmt: &str, app: &AppState) -> String {
  function expand_format_for_window (line 99) | pub fn expand_format_for_window(fmt: &str, app: &AppState, win_idx: usiz...
  function run_shell_command (line 262) | fn run_shell_command(cmd: &str, app: &AppState) -> String {
  function escape_strftime_percent (line 302) | fn escape_strftime_percent(s: &str) -> String {
  function expand_format_for_pane (line 311) | pub fn expand_format_for_pane(
  function expand_expression (line 326) | fn expand_expression(expr: &str, app: &AppState, win_idx: usize) -> Stri...
  function try_expand_modifier_chain (line 411) | fn try_expand_modifier_chain(expr: &str, app: &AppState, win_idx: usize)...
  function find_modifier_colon (line 475) | fn find_modifier_colon(s: &str) -> Option<usize> {
  type Modifier (line 503) | enum Modifier {
  function parse_modifier_chain (line 521) | fn parse_modifier_chain(spec: &str) -> Vec<Modifier> {
  function parse_single_modifier (line 533) | fn parse_single_modifier(spec: &str) -> Option<Modifier> {
  function apply_modifier (line 606) | fn apply_modifier(m: &Modifier, value: &str, app: &AppState, win_idx: us...
  function expand_var_or_format (line 800) | fn expand_var_or_format(target: &str, app: &AppState, win_idx: usize) ->...
  function lookup_option_pub (line 823) | pub fn lookup_option_pub(name: &str, app: &AppState) -> Option<String> {
  function lookup_option (line 827) | fn lookup_option(name: &str, app: &AppState) -> Option<String> {
  function try_comparison_op (line 909) | fn try_comparison_op(expr: &str, app: &AppState, win_idx: usize) -> Opti...
  function expand_boolean_or (line 931) | fn expand_boolean_or(body: &str, app: &AppState, win_idx: usize) -> Stri...
  function expand_boolean_and (line 940) | fn expand_boolean_and(body: &str, app: &AppState, win_idx: usize) -> Str...
  function is_truthy (line 950) | fn is_truthy(s: &str) -> bool {
  function expand_conditional (line 956) | fn expand_conditional(body: &str, app: &AppState, win_idx: usize) -> Str...
  function find_comparison_in_cond (line 990) | fn find_comparison_in_cond(cond: &str) -> Option<(&str, &str, &str)> {
  function expand_var (line 1025) | pub fn expand_var(var: &str, app: &AppState, win_idx: usize) -> String {
  function format_vt100_color (line 1637) | fn format_vt100_color(color: vt100::Color) -> String {
  function hostname_cached (line 1663) | pub(crate) fn hostname_cached() -> String {
  function find_matching_brace (line 1673) | fn find_matching_brace(s: &str, start: usize) -> Option<usize> {
  function split_at_depth0 (line 1690) | fn split_at_depth0(s: &str, delim: u8) -> Vec<String> {
  function split_conditional (line 1734) | fn split_conditional(s: &str) -> (String, String, String) {
  function glob_match (line 1744) | fn glob_match(pattern: &str, text: &str, case_insensitive: bool) -> bool {
  function glob_match_impl (line 1750) | fn glob_match_impl(pattern: &[u8], text: &[u8]) -> bool {
  function default_list_windows_format (line 1773) | pub fn default_list_windows_format() -> &'static str {
  function default_list_panes_format (line 1778) | pub fn default_list_panes_format() -> &'static str {
  function default_list_sessions_format (line 1783) | pub fn default_list_sessions_format() -> &'static str {
  function default_list_buffers_format (line 1788) | pub fn default_list_buffers_format() -> &'static str {
  function format_list_windows (line 1793) | pub fn format_list_windows(app: &AppState, fmt: &str) -> String {
  function format_list_sessions (line 1804) | pub fn format_list_sessions(app: &AppState, fmt: &str) -> String {
  function format_list_panes (line 1809) | pub fn format_list_panes(app: &AppState, fmt: &str, win_idx: usize) -> S...
  function collect_pane_ids (line 1824) | fn collect_pane_ids(node: &Node, ids: &mut Vec<usize>) {

FILE: src/help.rs
  constant ROOT_DEFAULTS (line 9) | pub const ROOT_DEFAULTS: &[(&str, &str)] = &[
  constant PREFIX_DEFAULTS (line 17) | pub const PREFIX_DEFAULTS: &[(&str, &str)] = &[
  function copy_mode_vi_lines (line 115) | pub fn copy_mode_vi_lines() -> Vec<String> {
  constant COPY_MODE_VI (line 125) | const COPY_MODE_VI: &[(&str, &str)] = &[
  function copy_search_lines (line 199) | pub fn copy_search_lines() -> Vec<String> {
  constant COPY_SEARCH (line 209) | const COPY_SEARCH: &[(&str, &str)] = &[
  function command_prompt_lines (line 217) | pub fn command_prompt_lines() -> Vec<String> {
  constant COMMAND_PROMPT (line 227) | const COMMAND_PROMPT: &[(&str, &str)] = &[
  function cli_command_lines (line 246) | pub fn cli_command_lines() -> Vec<String> {
  constant CLI_COMMANDS (line 262) | const CLI_COMMANDS: &[(&str, &str, &str)] = &[
  function options_lines (line 354) | pub fn options_lines() -> Vec<String> {
  constant OPTIONS_REF (line 365) | const OPTIONS_REF: &[(&str, &str)] = &[
  function format_vars_lines (line 442) | pub fn format_vars_lines() -> Vec<String> {
  constant FORMAT_GROUPS (line 458) | const FORMAT_GROUPS: &[(&str, &str)] = &[
  function hooks_lines (line 471) | pub fn hooks_lines() -> Vec<String> {
  function mouse_lines (line 486) | pub fn mouse_lines() -> Vec<String> {
  function build_overlay_lines (line 503) | pub fn build_overlay_lines(
  function build_list_keys_output (line 553) | pub fn build_list_keys_output<'a>(

FILE: src/input.rs
  function write_mouse_event (line 21) | fn write_mouse_event(master: &mut dyn std::io::Write, button: u8, col: u...
  function handle_key (line 42) | pub fn handle_key(app: &mut AppState, key: KeyEvent) -> io::Result<bool> {
  function move_focus (line 1374) | pub fn move_focus(app: &mut AppState, dir: FocusDir) {
  function move_focus_preserving_zoom (line 1398) | pub fn move_focus_preserving_zoom(app: &mut AppState, dir: FocusDir) {
  function find_best_pane_in_direction (line 1416) | pub fn find_best_pane_in_direction(
  function find_wrap_target (line 1524) | pub fn find_wrap_target(
  function modifier_param (line 1622) | fn modifier_param(mods: KeyModifiers) -> u8 {
  function parse_modified_special_key (line 1633) | pub fn parse_modified_special_key(s: &str) -> Option<String> {
  function encode_fkey (line 1676) | fn encode_fkey(n: u8, m: u8) -> Vec<u8> {
  function ctrl_char_send_keys_byte (line 1721) | pub fn ctrl_char_send_keys_byte(c: char) -> Option<u8> {
  function encode_key_event (line 1754) | pub fn encode_key_event(key: &KeyEvent) -> Option<Vec<u8>> {
  function forward_key_to_active (line 1872) | pub fn forward_key_to_active(app: &mut AppState, key: KeyEvent) -> io::R...
  function wheel_cell_for_area (line 1970) | fn wheel_cell_for_area(area: Rect, x: u16, y: u16) -> (u16, u16) {
  function paste_clipboard_to_active (line 1990) | fn paste_clipboard_to_active(app: &mut AppState) -> io::Result<()> {
  function forward_mouse_to_pane (line 2009) | fn forward_mouse_to_pane(pane: &mut Pane, area: Rect, abs_x: u16, abs_y:...
  function forward_mouse_to_pane_ex (line 2019) | fn forward_mouse_to_pane_ex(pane: &mut Pane, area: Rect, abs_x: u16, abs...
  function handle_mouse (line 2028) | pub fn handle_mouse(app: &mut AppState, me: MouseEvent, window_area: Rec...
  function write_paste_chunked (line 2518) | fn write_paste_chunked(writer: &mut dyn std::io::Write, text: &[u8], bra...
  function send_paste_to_active (line 2573) | pub fn send_paste_to_active(app: &mut AppState, text: &str) -> io::Resul...
  function send_text_to_active (line 2676) | pub fn send_text_to_active(app: &mut AppState, text: &str) -> io::Result...
  function handle_copy_mode_char (line 2784) | fn handle_copy_mode_char(app: &mut AppState, c: char) -> io::Result<()> {
  function send_key_to_active (line 2888) | pub fn send_key_to_active(app: &mut AppState, k: &str) -> io::Result<()> {

FILE: src/layout.rs
  function serialize_screen_rows (line 15) | pub fn serialize_screen_rows(screen: &vt100::Screen, rows: u16, cols: u1...
  function cycle_top_layout (line 87) | pub fn cycle_top_layout(app: &mut AppState) {
  type CellJson (line 102) | pub struct CellJson { pub text: String, pub fg: String, pub bg: String, ...
  type CellRunJson (line 105) | pub struct CellRunJson {
  type RowRunsJson (line 114) | pub struct RowRunsJson {
  type LayoutJson (line 120) | pub enum LayoutJson {
    method count_leaves (line 161) | pub fn count_leaves(&self) -> usize {
  function dump_layout_json (line 169) | pub fn dump_layout_json(app: &mut AppState) -> io::Result<String> {
  function dump_window_layout_json (line 179) | pub fn dump_window_layout_json(app: &mut AppState, win_id: usize) -> io:...
  function dump_layout_json_inner (line 183) | fn dump_layout_json_inner(app: &mut AppState, win_id_override: Option<us...
  function dump_layout_json_fast (line 519) | pub fn dump_layout_json_fast(app: &mut AppState) -> io::Result<String> {
  function apply_layout (line 933) | pub fn apply_layout(app: &mut AppState, layout: &str) {
  constant LAYOUT_NAMES (line 1053) | const LAYOUT_NAMES: [&str; 5] = ["even-horizontal", "even-vertical", "ma...
  function cycle_layout (line 1056) | pub fn cycle_layout(app: &mut AppState) {
  function cycle_layout_reverse (line 1065) | pub fn cycle_layout_reverse(app: &mut AppState) {
  type LayoutNode (line 1086) | pub enum LayoutNode {
    method count_leaves (line 1093) | pub fn count_leaves(&self) -> usize {
    method width (line 1100) | fn width(&self) -> u16 {
    method height (line 1104) | fn height(&self) -> u16 {
  function parse_layout_string (line 1113) | pub fn parse_layout_string(layout_str: &str) -> Option<LayoutNode> {
  function parse_tmux_layout_string (line 1133) | pub fn parse_tmux_layout_string(layout_str: &str, panes: &mut Vec<Node>)...
  function layout_node_to_node (line 1140) | fn layout_node_to_node(layout: &LayoutNode, panes: &mut Vec<Node>) -> Op...
  function parse_layout_node (line 1176) | fn parse_layout_node(s: &str) -> Option<(LayoutNode, usize)> {
  function parse_dimensions (line 1213) | fn parse_dimensions(s: &str) -> Option<(u16, u16, u16, u16, usize)> {
  function parse_layout_children (line 1231) | fn parse_layout_children(s: &str, closing: char) -> Option<(Vec<LayoutNo...

FILE: src/main.rs
  function color_to_ansi (line 57) | fn color_to_ansi(c: ratatui::style::Color, fg: bool) -> String {
  function main (line 84) | fn main() {
  function run_main (line 94) | fn run_main() -> io::Result<()> {
  function run_control_mode (line 3218) | fn run_control_mode(mode: u8) -> io::Result<()> {
  function stdout_is_console (line 3654) | fn stdout_is_console() -> bool {
  function is_ssh_session (line 3674) | fn is_ssh_session() -> bool {

FILE: src/pane.rs
  constant CURSOR_SHAPE_UNSET (line 18) | pub const CURSOR_SHAPE_UNSET: u8 = 255;
  function conpty_preemptive_dsr_response (line 28) | pub fn conpty_preemptive_dsr_response(writer: &mut dyn std::io::Write) {
  function cached_shell (line 38) | pub fn cached_shell() -> Option<&'static str> {
  function default_shell_name (line 48) | fn default_shell_name(command: Option<&str>, configured_shell: Option<&s...
  function create_window (line 73) | pub fn create_window(pty_system: &dyn portable_pty::PtySystem, app: &mut...
  function spawn_warm_pane (line 186) | pub fn spawn_warm_pane(pty_system: &dyn portable_pty::PtySystem, app: &m...
  function split_active (line 237) | pub fn split_active(app: &mut AppState, kind: LayoutKind) -> io::Result<...
  function create_window_raw (line 242) | pub fn create_window_raw(pty_system: &dyn portable_pty::PtySystem, app: ...
  constant MIN_PANE_DIM (line 299) | pub const MIN_PANE_DIM: u16 = 2;
  constant MIN_SPLIT_ROWS (line 303) | const MIN_SPLIT_ROWS: u16 = 2;
  constant MIN_SPLIT_COLS (line 305) | const MIN_SPLIT_COLS: u16 = 10;
  function split_active_with_command (line 307) | pub fn split_active_with_command(app: &mut AppState, kind: LayoutKind, c...
  function kill_pane_at_path (line 456) | fn kill_pane_at_path(win: &mut Window, path: &Vec<usize>) {
  function kill_active_pane (line 498) | pub fn kill_active_pane(app: &mut AppState) -> io::Result<()> {
  function kill_pane_by_id (line 505) | pub fn kill_pane_by_id(app: &mut AppState, pane_id: usize) -> io::Result...
  function detect_shell (line 540) | pub fn detect_shell() -> CommandBuilder {
  function apply_bare_env_if_set (line 554) | pub fn apply_bare_env_if_set(builder: &mut CommandBuilder) -> bool {
  function set_tmux_env (line 585) | pub fn set_tmux_env(builder: &mut CommandBuilder, pane_id: usize, contro...
  function apply_user_environment (line 624) | pub fn apply_user_environment(builder: &mut CommandBuilder, environment:...
  constant ENV_SHIM_PS (line 648) | const ENV_SHIM_PS: &str = concat!(
  constant PSRL_FIX (line 704) | const PSRL_FIX: &str = concat!(
  constant PSRL_CRASH_GUARD (line 715) | const PSRL_CRASH_GUARD: &str = concat!(
  constant PSRL_PRED_RESTORE (line 724) | const PSRL_PRED_RESTORE: &str = concat!(
  constant PROFILE_SOURCE (line 735) | const PROFILE_SOURCE: &str = concat!(
  constant CWD_SYNC (line 755) | const CWD_SYNC: &str = concat!(
  function build_psrl_init (line 781) | fn build_psrl_init(env_shim: bool, allow_predictions: bool) -> String {
  function resolve_unix_path (line 807) | fn resolve_unix_path(cmd: &str) -> String {
  function detect_bash_c_wrapper (line 835) | fn detect_bash_c_wrapper(cmd: &str) -> Option<(&str, &str)> {
  function parse_bash_env_script (line 870) | fn parse_bash_env_script(script: &str) -> (Vec<String>, Vec<(String, Str...
  function build_command (line 918) | pub fn build_command(command: Option<&str>, env_shim: bool, allow_predic...
  function cached_which (line 1032) | fn cached_which(program: &str) -> String {
  function resolve_shell_program (line 1054) | fn resolve_shell_program(shell_path: &str) -> (String, Vec<String>) {
  function build_default_shell (line 1075) | pub fn build_default_shell(shell_path: &str, env_shim: bool, allow_predi...
  function build_raw_command (line 1130) | pub fn build_raw_command(raw_args: &[String]) -> CommandBuilder {
  function scan_cursor_shape (line 1161) | fn scan_cursor_shape(data: &[u8]) -> Option<u8> {
  function scan_rmcup (line 1187) | fn scan_rmcup(data: &[u8]) -> bool {
  function scan_cpr_query (line 1196) | fn scan_cpr_query(data: &[u8]) -> bool {
  function spawn_reader_thread (line 1203) | pub fn spawn_reader_thread(
  function bell_after (line 1416) | fn bell_after(data: &[u8]) -> bool {
  function bell_after_two_chunks (line 1424) | fn bell_after_two_chunks(chunk1: &[u8], chunk2: &[u8]) -> bool {
  function bare_bel (line 1434) | fn bare_bel() {
  function bel_in_plain_text (line 1439) | fn bel_in_plain_text() {
  function osc_title_with_bel_terminator (line 1444) | fn osc_title_with_bel_terminator() {
  function osc_title_with_st_terminator (line 1450) | fn osc_title_with_st_terminator() {
  function osc_then_standalone_bel (line 1455) | fn osc_then_standalone_bel() {
  function multiple_osc_no_real_bel (line 1461) | fn multiple_osc_no_real_bel() {
  function empty_data (line 1466) | fn empty_data() {
  function no_bel_at_all (line 1471) | fn no_bel_at_all() {
  function powershell_prompt_title_no_bell (line 1476) | fn powershell_prompt_title_no_bell() {
  function take_clears_flag (line 1483) | fn take_clears_flag() {
  function cross_chunk_osc_then_real_bel (line 1492) | fn cross_chunk_osc_then_real_bel() {
  function cross_chunk_osc_no_real_bel (line 1505) | fn cross_chunk_osc_no_real_bel() {

FILE: src/platform.rs
  constant CREATE_NO_WINDOW (line 18) | const CREATE_NO_WINDOW: u32 = 0x08000000;
  type HideWindowCommandExt (line 34) | pub trait HideWindowCommandExt {
    method hide_window (line 35) | fn hide_window(&mut self) -> &mut Self;
    method hide_window (line 40) | fn hide_window(&mut self) -> &mut Self {
    method hide_window (line 48) | fn hide_window(&mut self) -> &mut Self {
  function escape_arg_msvcrt (line 68) | pub(crate) fn escape_arg_msvcrt(arg: &str) -> String {
  function spawn_server_hidden (line 106) | pub fn spawn_server_hidden(exe: &std::path::Path, args: &[String]) -> st...
  function enable_virtual_terminal_processing (line 239) | pub fn enable_virtual_terminal_processing() {
  function enable_virtual_terminal_processing (line 270) | pub fn enable_virtual_terminal_processing() {
  function disable_vti_on_stdin (line 289) | pub fn disable_vti_on_stdin() {
  function disable_vti_on_stdin (line 323) | pub fn disable_vti_on_stdin() {
  function install_console_ctrl_handler (line 329) | pub fn install_console_ctrl_handler() {
  function install_console_ctrl_handler (line 354) | pub fn install_console_ctrl_handler() {
  constant GENERIC_READ (line 379) | const GENERIC_READ: u32  = 0x80000000;
  constant GENERIC_WRITE (line 380) | const GENERIC_WRITE: u32 = 0x40000000;
  constant FILE_SHARE_READ (line 381) | const FILE_SHARE_READ: u32  = 0x00000001;
  constant FILE_SHARE_WRITE (line 382) | const FILE_SHARE_WRITE: u32 = 0x00000002;
  constant OPEN_EXISTING (line 383) | const OPEN_EXISTING: u32 = 3;
  constant INVALID_HANDLE (line 384) | const INVALID_HANDLE: isize = -1;
  constant MOUSE_EVENT (line 386) | const MOUSE_EVENT: u16 = 0x0002;
  constant ATTACH_PARENT_PROCESS (line 387) | const ATTACH_PARENT_PROCESS: u32 = 0xFFFFFFFF;
  constant FROM_LEFT_1ST_BUTTON_PRESSED (line 390) | pub const FROM_LEFT_1ST_BUTTON_PRESSED: u32 = 0x0001;
  constant RIGHTMOST_BUTTON_PRESSED (line 391) | pub const RIGHTMOST_BUTTON_PRESSED: u32     = 0x0002;
  constant FROM_LEFT_2ND_BUTTON_PRESSED (line 392) | pub const FROM_LEFT_2ND_BUTTON_PRESSED: u32 = 0x0004;
  constant MOUSE_MOVED (line 395) | pub const MOUSE_MOVED: u32       = 0x0001;
  constant MOUSE_WHEELED (line 396) | pub const MOUSE_WHEELED: u32     = 0x0004;
  constant DRAG_THROTTLE (line 401) | const DRAG_THROTTLE: Duration = Duration::from_millis(16);
  type COORD (line 405) | struct COORD {
  type MOUSE_EVENT_RECORD (line 412) | struct MOUSE_EVENT_RECORD {
  type INPUT_RECORD (line 420) | struct INPUT_RECORD {
  function FreeConsole (line 428) | fn FreeConsole() -> i32;
  function AttachConsole (line 429) | fn AttachConsole(process_id: u32) -> i32;
  function GetConsoleWindow (line 430) | fn GetConsoleWindow() -> isize;
  function CreateFileW (line 431) | fn CreateFileW(
  function WriteConsoleInputW (line 440) | fn WriteConsoleInputW(
  function CloseHandle (line 446) | fn CloseHandle(handle: isize) -> i32;
  function GetProcessId (line 447) | fn GetProcessId(process: isize) -> u32;
  function GetLastError (line 448) | fn GetLastError() -> u32;
  constant ENABLE_MOUSE_INPUT (line 452) | const ENABLE_MOUSE_INPUT: u32         = 0x0010;
  constant ENABLE_EXTENDED_FLAGS (line 453) | const ENABLE_EXTENDED_FLAGS: u32      = 0x0080;
  constant ENABLE_QUICK_EDIT_MODE (line 454) | const ENABLE_QUICK_EDIT_MODE: u32     = 0x0040;
  constant ENABLE_VIRTUAL_TERMINAL_INPUT (line 455) | const ENABLE_VIRTUAL_TERMINAL_INPUT: u32 = 0x0200;
  function debug_log (line 458) | fn debug_log(msg: &str) {
  function get_child_pid (line 481) | pub fn get_child_pid(child: &dyn portable_pty::Child) -> Option<u32> {
  function query_vti_enabled (line 494) | pub fn query_vti_enabled(child_pid: u32) -> Option<bool> {
  function send_mouse_event (line 559) | pub fn send_mouse_event(
  function query_mouse_input_enabled (line 678) | pub fn query_mouse_input_enabled(child_pid: u32) -> Option<bool> {
  function send_vt_sequence (line 744) | pub fn send_vt_sequence(child_pid: u32, sequence: &[u8]) -> bool {
  function send_bracketed_paste (line 865) | pub fn send_bracketed_paste(child_pid: u32, text: &str, bracket: bool) -...
  function send_ctrl_c_event (line 1044) | pub fn send_ctrl_c_event(child_pid: u32, reattach: bool) -> bool {
  function send_modified_key_event (line 1161) | pub fn send_modified_key_event(child_pid: u32, ch: char, ctrl: bool, alt...
  function send_alt_key_event (line 1306) | pub fn send_alt_key_event(child_pid: u32, ch: char) -> bool {
  function send_modified_enter_event (line 1316) | pub fn send_modified_enter_event(child_pid: u32, ctrl: bool, alt: bool, ...
  function get_child_pid (line 1436) | pub fn get_child_pid(_child: &dyn portable_pty::Child) -> Option<u32> { ...
  function send_mouse_event (line 1437) | pub fn send_mouse_event(_pid: u32, _col: i16, _row: i16, _btn: u32, _fla...
  function send_vt_sequence (line 1438) | pub fn send_vt_sequence(_pid: u32, _sequence: &[u8]) -> bool { false }
  function query_vti_enabled (line 1439) | pub fn query_vti_enabled(_pid: u32) -> Option<bool> { None }
  function send_ctrl_c_event (line 1440) | pub fn send_ctrl_c_event(_pid: u32, _reattach: bool) -> bool { false }
  function query_mouse_input_enabled (line 1441) | pub fn query_mouse_input_enabled(_pid: u32) -> Option<bool> { None }
  function send_bracketed_paste (line 1442) | pub fn send_bracketed_paste(_pid: u32, _text: &str, _bracket: bool) -> b...
  function send_modified_key_event (line 1443) | pub fn send_modified_key_event(_pid: u32, _ch: char, _ctrl: bool, _alt: ...
  function send_alt_key_event (line 1444) | pub fn send_alt_key_event(_pid: u32, _ch: char) -> bool { false }
  function send_modified_enter_event (line 1445) | pub fn send_modified_enter_event(_pid: u32, _ctrl: bool, _alt: bool, _sh...
  constant TH32CS_SNAPPROCESS (line 1454) | const TH32CS_SNAPPROCESS: u32 = 0x00000002;
  constant PROCESS_TERMINATE (line 1455) | const PROCESS_TERMINATE: u32 = 0x0001;
  constant PROCESS_QUERY_INFORMATION (line 1456) | const PROCESS_QUERY_INFORMATION: u32 = 0x0400;
  constant INVALID_HANDLE (line 1457) | const INVALID_HANDLE: isize = -1;
  type PROCESSENTRY32W (line 1460) | struct PROCESSENTRY32W {
  function CreateToolhelp32Snapshot (line 1475) | fn CreateToolhelp32Snapshot(dw_flags: u32, th32_process_id: u32) -> isize;
  function Process32FirstW (line 1476) | fn Process32FirstW(h_snapshot: isize, lppe: *mut PROCESSENTRY32W) -> i32;
  function Process32NextW (line 1477) | fn Process32NextW(h_snapshot: isize, lppe: *mut PROCESSENTRY32W) -> i32;
  function OpenProcess (line 1478) | fn OpenProcess(desired_access: u32, inherit_handle: i32, process_id: u32...
  function TerminateProcess (line 1479) | fn TerminateProcess(h_process: isize, exit_code: u32) -> i32;
  function CloseHandle (line 1480) | fn CloseHandle(handle: isize) -> i32;
  function collect_descendants (line 1485) | fn collect_descendants(root_pid: u32) -> Vec<u32> {
  function terminate_pid (line 1522) | fn terminate_pid(pid: u32) {
  function current_parent_pid (line 1535) | pub fn current_parent_pid() -> Option<u32> {
  function GetCurrentProcessIdSafe (line 1561) | fn GetCurrentProcessIdSafe() -> u32;
  function kill_parent_process (line 1568) | pub fn kill_parent_process() -> bool {
  function kill_process_tree (line 1586) | pub fn kill_process_tree(child: &mut Box<dyn portable_pty::Child>) {
  function kill_process_trees_batch (line 1610) | pub fn kill_process_trees_batch(children: &mut [&mut Box<dyn portable_pt...
  function snapshot_process_table (line 1634) | fn snapshot_process_table() -> Vec<(u32, u32)> {
  function collect_descendants_from_table (line 1655) | fn collect_descendants_from_table(entries: &[(u32, u32)], root_pid: u32)...
  function kill_process_tree (line 1676) | pub fn kill_process_tree(child: &mut Box<dyn portable_pty::Child>) {
  function kill_process_trees_batch (line 1681) | pub fn kill_process_trees_batch(children: &mut [&mut Box<dyn portable_pt...
  constant PROCESS_QUERY_LIMITED_INFORMATION (line 1697) | const PROCESS_QUERY_LIMITED_INFORMATION: u32 = 0x1000;
  constant PROCESS_QUERY_INFORMATION (line 1698) | const PROCESS_QUERY_INFORMATION: u32 = 0x0400;
  constant PROCESS_VM_READ (line 1699) | const PROCESS_VM_READ: u32 = 0x0010;
  constant MAX_PATH (line 1700) | const MAX_PATH: usize = 260;
  constant TH32CS_SNAPPROCESS (line 1701) | const TH32CS_SNAPPROCESS: u32 = 0x00000002;
  constant INVALID_HANDLE (line 1702) | const INVALID_HANDLE: isize = -1;
  type PROCESS_BASIC_INFORMATION (line 1706) | struct PROCESS_BASIC_INFORMATION {
  type UNICODE_STRING (line 1716) | struct UNICODE_STRING {
  type PROCESSENTRY32W (line 1723) | struct PROCESSENTRY32W {
  function OpenProcess (line 1738) | fn OpenProcess(desired_access: u32, inherit_handle: i32, process_id: u32...
  function CloseHandle (line 1739) | fn CloseHandle(handle: isize) -> i32;
  function QueryFullProcessImageNameW (line 1740) | fn QueryFullProcessImageNameW(h: isize, flags: u32, name: *mut u16, size...
  function ReadProcessMemory (line 1741) | fn ReadProcessMemory(
  function CreateToolhelp32Snapshot (line 1748) | fn CreateToolhelp32Snapshot(dw_flags: u32, th32_process_id: u32) -> isize;
  function Process32FirstW (line 1749) | fn Process32FirstW(h_snapshot: isize, lppe: *mut PROCESSENTRY32W) -> i32;
  function Process32NextW (line 1750) | fn Process32NextW(h_snapshot: isize, lppe: *mut PROCESSENTRY32W) -> i32;
  function NtQueryInformationProcess (line 1755) | fn NtQueryInformationProcess(
  function get_process_name (line 1765) | pub fn get_process_name(pid: u32) -> Option<String> {
  function get_process_cwd (line 1786) | pub fn get_process_cwd(pid: u32) -> Option<String> {
  function read_process_cwd (line 1797) | unsafe fn read_process_cwd(h: isize) -> Option<String> {
  function autorename_log (line 1861) | fn autorename_log(msg: &str) {
  function get_foreground_process_name (line 1877) | pub fn get_foreground_process_name(pid: u32) -> Option<String> {
  function get_foreground_cwd (line 1904) | pub fn get_foreground_cwd(pid: u32) -> Option<String> {
  function is_system_exe (line 1917) | fn is_system_exe(name: &str) -> bool {
  function find_foreground_child_pid (line 1931) | fn find_foreground_child_pid(root_pid: u32) -> Option<u32> {
  function exe_name_from_entry (line 2028) | fn exe_name_from_entry(pe: &PROCESSENTRY32W) -> String {
  function is_vt_bridge_exe (line 2035) | fn is_vt_bridge_exe(name: &str) -> bool {
  function has_vt_bridge_descendant (line 2046) | pub fn has_vt_bridge_descendant(root_pid: u32) -> bool {
  function get_process_name (line 2089) | pub fn get_process_name(_pid: u32) -> Option<String> { None }
  function get_process_cwd (line 2090) | pub fn get_process_cwd(_pid: u32) -> Option<String> { None }
  function get_foreground_process_name (line 2091) | pub fn get_foreground_process_name(_pid: u32) -> Option<String> { None }
  function get_foreground_cwd (line 2092) | pub fn get_foreground_cwd(_pid: u32) -> Option<String> { None }
  function has_vt_bridge_descendant (line 2093) | pub fn has_vt_bridge_descendant(_root_pid: u32) -> bool { false }
  type Utf16ConsoleWriter (line 2121) | pub struct Utf16ConsoleWriter {
    method new (line 2136) | pub fn new() -> Self {
    method write_wide (line 2149) | fn write_wide(&self, s: &str) -> std::io::Result<()> {
    method write (line 2193) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
    method flush (line 2201) | fn flush(&mut self) -> std::io::Result<()> {
  type PsmuxWriter (line 2250) | pub type PsmuxWriter = Utf16ConsoleWriter;
  type PsmuxWriter (line 2252) | pub type PsmuxWriter = std::io::Stdout;
  function create_writer (line 2255) | pub fn create_writer() -> PsmuxWriter {
  function GetConsoleWindow (line 2286) | fn GetConsoleWindow() -> isize;
  function GetCurrentConsoleFontEx (line 2287) | fn GetCurrentConsoleFontEx(
  function GetStdHandle (line 2292) | fn GetStdHandle(nStdHandle: u32) -> *mut std::ffi::c_void;
  function CreateCaret (line 2297) | fn CreateCaret(hWnd: isize, hBitmap: isize, nWidth: i32, nHeight: i32) -...
  function SetCaretPos (line 2298) | fn SetCaretPos(x: i32, y: i32) -> i32;
  function ShowCaret (line 2299) | fn ShowCaret(hWnd: isize) -> i32;
  function DestroyCaret (line 2300) | fn DestroyCaret() -> i32;
  type CONSOLE_FONT_INFOEX (line 2305) | struct CONSOLE_FONT_INFOEX {
  function console_cell_size (line 2317) | fn console_cell_size() -> (i32, i32) {
  function update (line 2341) | pub fn update(col: u16, row: u16) {
  function destroy (line 2360) | pub fn destroy() {
  function update (line 2369) | pub fn update(_col: u16, _row: u16) {}
  function destroy (line 2370) | pub fn destroy() {}
  function augment_enter_shift (line 2382) | pub fn augment_enter_shift(key: &mut crossterm::event::KeyEvent) {
  function ime_disable (line 2439) | pub fn ime_disable() -> bool {
  function ime_restore (line 2467) | pub fn ime_restore() {

FILE: src/popup.rs
  function create_popup_pane (line 26) | pub fn create_popup_pane(
  function serialize_popup_overlay (line 142) | pub fn serialize_popup_overlay(app: &AppState) -> String {
  function json_esc_inline (line 311) | fn json_esc_inline(s: &str, out: &mut String) {
  function render_popup_overlay (line 331) | pub fn render_popup_overlay(

FILE: src/preview.rs
  type PreviewCache (line 19) | pub type PreviewCache = HashMap<String, (String, Instant)>;
  constant PREVIEW_TTL (line 21) | pub const PREVIEW_TTL: Duration = Duration::from_millis(1500);
  constant CONNECT_TIMEOUT (line 22) | const CONNECT_TIMEOUT: Duration = Duration::from_millis(150);
  constant READ_TIMEOUT (line 23) | const READ_TIMEOUT: Duration = Duration::from_millis(400);
  function cache_key (line 25) | pub fn cache_key(sess: &str, win_id: usize, pane_id: usize) -> String {
  function fetch_pane_preview (line 34) | pub fn fetch_pane_preview(home: &str, sess: &str, win_id: usize, pane_id...
  function get_or_fetch (line 61) | pub fn get_or_fetch(
  function clip_lines (line 82) | pub fn clip_lines(text: &str, width: u16, height: u16) -> Vec<String> {
  function sgr_color_from_8bit (line 123) | fn sgr_color_from_8bit(n: u8) -> Color {
  function apply_sgr (line 134) | fn apply_sgr(style: &mut Style, params: &[u32]) {
  function parse_sgr_line (line 184) | fn parse_sgr_line(line: &str, max_width: usize, style: &mut Style) -> Ve...
  function strip_ansi (line 234) | fn strip_ansi(s: &str) -> String {
  function parse_ansi_lines (line 254) | pub fn parse_ansi_lines(text: &str, width: u16, height: u16) -> Vec<Line...
  type LayoutCache (line 282) | pub type LayoutCache = HashMap<String, (LayoutSimple, Instant)>;
  constant LAYOUT_TTL (line 284) | pub const LAYOUT_TTL: Duration = Duration::from_millis(2500);
  function fetch_window_layout (line 287) | pub fn fetch_window_layout(home: &str, sess: &str, win_id: usize) -> Opt...
  function get_or_fetch_layout (line 306) | pub fn get_or_fetch_layout(
  function flatten_layout_to_rects (line 329) | pub fn flatten_layout_to_rects(
  function layout_separators (line 390) | pub fn layout_separators(
  type DumpCache (line 458) | pub type DumpCache = HashMap<String, (crate::layout::LayoutJson, Instant)>;
  constant DUMP_TTL (line 460) | pub const DUMP_TTL: Duration = Duration::from_millis(1500);
  function fetch_window_dump (line 464) | pub fn fetch_window_dump(home: &str, sess: &str, win_id: usize) -> Optio...
  function get_or_fetch_dump (line 483) | pub fn get_or_fetch_dump(
  function run_style (line 503) | fn run_style(fg: &str, bg: &str, flags: u8) -> Style {
  function render_runs_line (line 520) | pub fn render_runs_line(
  function flatten_dump_rects (line 570) | pub fn flatten_dump_rects<'a>(
  function dump_separators (line 631) | pub fn dump_separators(
  function render_dump_tree (line 689) | pub fn render_dump_tree(
  function parse_ansi_lines_preserves_red_marker (line 722) | fn parse_ansi_lines_preserves_red_marker() {
  function parse_ansi_lines_clips_to_width (line 740) | fn parse_ansi_lines_clips_to_width() {
  function parse_ansi_lines_handles_bold (line 749) | fn parse_ansi_lines_handles_bold() {

FILE: src/proxy_pane.rs
  type ProxyMasterPty (line 24) | pub struct ProxyMasterPty {
    method new (line 39) | pub fn new(
  method resize (line 62) | fn resize(&self, size: PtySize) -> Result<(), anyhow::Error> {
  method get_size (line 83) | fn get_size(&self) -> Result<PtySize, anyhow::Error> {
  method try_clone_reader (line 87) | fn try_clone_reader(&self) -> Result<Box<dyn Read + Send>, anyhow::Error> {
  method take_writer (line 95) | fn take_writer(&self) -> Result<Box<dyn Write + Send>, anyhow::Error> {
  type ProxyChild (line 108) | pub struct ProxyChild {
    method new (line 117) | pub fn new(
    method send_control (line 126) | fn send_control(&self, cmd: &str) -> io::Result<String> {
    method try_wait (line 152) | fn try_wait(&mut self) -> io::Result<Option<portable_pty::ExitStatus>> {
    method wait (line 163) | fn wait(&mut self) -> io::Result<portable_pty::ExitStatus> {
    method process_id (line 170) | fn process_id(&self) -> Option<u32> { self.pid }
    method as_raw_handle (line 173) | fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> { N...
    method kill (line 177) | fn kill(&mut self) -> io::Result<()> {
    method clone_killer (line 183) | fn clone_killer(&self) -> Box<dyn portable_pty::ChildKiller + Send + S...
  type ProxyChildKiller (line 193) | struct ProxyChildKiller {
    method kill (line 200) | fn kill(&mut self) -> io::Result<()> {
    method clone_killer (line 210) | fn clone_killer(&self) -> Box<dyn portable_pty::ChildKiller + Send + S...
  function create_proxy_pane (line 224) | pub fn create_proxy_pane(

FILE: src/rendering.rs
  function vt_to_color (line 26) | pub fn vt_to_color(c: vt100::Color) -> Color {
  function dim_color (line 55) | pub fn dim_color(c: Color) -> Color {
  function dim_predictions_enabled (line 70) | pub fn dim_predictions_enabled() -> bool {
  function has_conpty_passthrough (line 83) | pub fn has_conpty_passthrough() -> bool {
  function configured_cursor_code (line 98) | pub fn configured_cursor_code() -> u8 {
  function apply_cursor_style (line 110) | pub fn apply_cursor_style<W: Write>(out: &mut W) -> io::Result<()> {
  function render_window (line 118) | pub fn render_window(f: &mut Frame, app: &mut AppState, area: Rect) {
  function fix_border_intersections (line 136) | pub fn fix_border_intersections(buf: &mut Buffer) {
  function render_node (line 195) | pub fn render_node(
  function compute_active_rect (line 435) | fn compute_active_rect(node: &Node, active_path: &[usize], area: Rect) -...
  function compute_active_rect_pub (line 441) | pub fn compute_active_rect_pub(node: &Node, active_path: &[usize], area:...
  function expand_status (line 467) | pub fn expand_status(fmt: &str, app: &AppState, time_str: &str) -> String {
  function parse_status (line 474) | pub fn parse_status(fmt: &str, app: &AppState, time_str: &str) -> Vec<Sp...
  function centered_rect (line 482) | pub fn centered_rect(percent_x: u16, height: u16, r: Rect) -> Rect {

FILE: src/server/connection.rs
  function split_top_level_semicolons (line 20) | fn split_top_level_semicolons(s: &str) -> Vec<String> {
  function decode_send_command (line 61) | fn decode_send_command(line: &str) -> Option<(String, Vec<u8>)> {
  function shell_quote_bytes (line 126) | fn shell_quote_bytes(b: &[u8]) -> String {
  function coalesce_send_commands (line 136) | fn coalesce_send_commands(parts: Vec<String>) -> Vec<String> {
  function handle_connection (line 176) | pub(crate) fn handle_connection(
  function dispatch_control_command (line 2839) | fn dispatch_control_command(

FILE: src/server/helpers.rs
  function collect_pane_paths_server (line 8) | pub(crate) fn collect_pane_paths_server(
  function serialize_bindings_json (line 29) | pub(crate) fn serialize_bindings_json(app: &AppState) -> String {
  function json_escape_string (line 55) | pub(crate) fn json_escape_string(s: &str) -> String {
  function list_windows_json_with_tabs (line 75) | pub(crate) fn list_windows_json_with_tabs(app: &AppState) -> io::Result<...
  function combined_data_version (line 98) | pub(crate) fn combined_data_version(app: &AppState) -> u64 {
  function window_data_version (line 161) | pub(crate) fn window_data_version(win: &Window) -> u64 {
  function check_window_activity (line 182) | pub(crate) fn check_window_activity(app: &mut AppState) -> Vec<&'static ...
  function propagate_osc_titles (line 263) | pub(crate) fn propagate_osc_titles(app: &mut AppState) -> bool {
  function active_pane_progress (line 280) | pub(crate) fn active_pane_progress(app: &AppState) -> Option<(u8, u8)> {
  function take_pane_clipboard (line 296) | pub(crate) fn take_pane_clipboard(app: &AppState) -> Option<(Vec<u8>, Ve...
  function drain_clipboard_in_node (line 305) | fn drain_clipboard_in_node(node: &Node) -> Option<(Vec<u8>, Vec<u8>)> {
  function propagate_osc_titles_in_tree (line 325) | fn propagate_osc_titles_in_tree(node: &mut Node, dirty: &mut bool) {
  function check_pane_bells (line 353) | fn check_pane_bells(node: &Node) -> bool {
  function drain_cpr_pending (line 373) | pub(crate) fn drain_cpr_pending(node: &mut crate::types::Node) {
  constant TMUX_COMMANDS (line 399) | pub(crate) const TMUX_COMMANDS: &[&str] = &[

FILE: src/server/mod.rs
  function serialize_overlay_json (line 49) | fn serialize_overlay_json(app: &AppState) -> String {
  function should_spawn_warm_server (line 74) | fn should_spawn_warm_server(app: &AppState) -> bool {
  function is_active_pane_squelched (line 81) | fn is_active_pane_squelched(app: &AppState) -> bool {
  function spawn_warm_server (line 98) | fn spawn_warm_server(app: &AppState) {
  function parse_popup_dim (line 160) | fn parse_popup_dim(spec: &str, term_dim: u16, default: u16) -> u16 {
  function compute_effective_client_size (line 175) | fn compute_effective_client_size(app: &AppState) -> Option<(u16, u16)> {
  function drain_plugin_req (line 204) | fn drain_plugin_req(
  function write_startup_error_log (line 350) | pub(crate) fn write_startup_error_log(err: &dyn std::fmt::Display) {
  function run_server (line 426) | pub fn run_server(session_name: String, socket_name: Option<String>, ini...

FILE: src/server/option_catalog.rs
  type OptionDef (line 3) | pub struct OptionDef {
  function build_option_list (line 95) | pub fn build_option_list(app: &crate::types::AppState) -> Vec<(String, S...
  function default_for (line 104) | pub fn default_for(name: &str) -> Option<&'static str> {

FILE: src/server/options.rs
  function is_window_option (line 4) | fn is_window_option(name: &str) -> bool {
  function get_option_value (line 25) | pub(crate) fn get_option_value(app: &AppState, name: &str) -> String {
  function get_window_option_value (line 128) | pub(crate) fn get_window_option_value(app: &AppState, name: &str) -> Str...
  function get_window_option_value_for (line 152) | pub(crate) fn get_window_option_value_for(
  function render_window_options (line 171) | pub(crate) fn render_window_options(app: &AppState) -> String {
  function is_boolean_option (line 199) | pub(crate) fn is_boolean_option(name: &str) -> bool {
  function toggle_option (line 235) | pub(crate) fn toggle_option(app: &mut AppState, option: &str) -> bool {
  function apply_set_option (line 246) | pub(crate) fn apply_set_option(app: &mut AppState, option: &str, value: ...

FILE: src/session.rs
  function is_warm_session (line 7) | pub fn is_warm_session(base: &str) -> bool {
  function next_session_name (line 16) | pub fn next_session_name(ns_prefix: Option<&str>) -> String {
  function cleanup_stale_port_files (line 56) | pub fn cleanup_stale_port_files() {
  function read_session_key (line 91) | pub fn read_session_key(session: &str) -> io::Result<String> {
  constant MAX_AUTHED_RESPONSE_BYTES (line 104) | pub const MAX_AUTHED_RESPONSE_BYTES: u64 = 256 * 1024;
  function validate_auth_key (line 115) | pub fn validate_auth_key(key: &str) -> Option<&str> {
  function send_auth_cmd (line 131) | pub fn send_auth_cmd(addr: &str, key: &str, cmd: &[u8]) -> io::Result<()> {
  function send_auth_cmd_response (line 153) | pub fn send_auth_cmd_response(addr: &str, key: &str, cmd: &[u8]) -> io::...
  function open_authed (line 184) | fn open_authed(
  function read_authed_line (line 210) | fn read_authed_line<R: std::io::BufRead>(br: &mut R) -> Option<String> {
  function read_authed_all (line 240) | fn read_authed_all<R: std::io::Read>(rd: &mut R) -> Option<String> {
  function fetch_authed_response (line 265) | pub fn fetch_authed_response(
  function fetch_authed_response_multi (line 282) | pub fn fetch_authed_response_multi(
  function fetch_session_info (line 297) | pub fn fetch_session_info(
  function fetch_session_infos_parallel (line 316) | pub fn fetch_session_infos_parallel<F>(
  function send_control (line 355) | pub fn send_control(line: String) -> io::Result<()> {
  function send_control_with_response (line 386) | pub fn send_control_with_response(line: String) -> io::Result<String> {
  function send_control_to_port (line 431) | pub fn send_control_to_port(port: u16, msg: &str, session_key: &str) -> ...
  function resolve_last_session_name (line 446) | pub fn resolve_last_session_name() -> Option<String> {
  function resolve_last_session_name_ns (line 454) | pub fn resolve_last_session_name_ns(ns: Option<&str>) -> Option<String> {
  function resolve_default_session_name (line 491) | pub fn resolve_default_session_name() -> Option<String> {
  function reap_children_placeholder (line 510) | pub fn reap_children_placeholder() -> io::Result<bool> { Ok(false) }
  function list_session_names (line 513) | pub fn list_session_names() -> Vec<String> {
  function list_session_names_ns (line 518) | pub fn list_session_names_ns(ns: Option<&str>) -> Vec<String> {
  type TreeEntry (line 549) | pub struct TreeEntry {
  function list_all_sessions_tree (line 563) | pub fn list_all_sessions_tree(current_session: &str, current_windows: &[...
  function kill_remaining_server_processes (line 665) | pub fn kill_remaining_server_processes() {
  function kill_remaining_server_processes (line 738) | pub fn kill_remaining_server_processes() {

FILE: src/ssh_input.rs
  function send_mouse_enable (line 69) | pub fn send_mouse_enable() {
  function send_mouse_enable (line 179) | pub fn send_mouse_enable() {
  function is_ssh_session (line 186) | pub fn is_ssh_session() -> bool {
  function needs_vt_input (line 204) | pub fn needs_vt_input() -> bool {
  function windows_build_number (line 213) | pub fn windows_build_number() -> Option<u32> {
  function windows_build_number (line 234) | pub fn windows_build_number() -> Option<u32> {
  type InputSource (line 249) | pub enum InputSource {
    method new (line 265) | pub fn new(ssh: bool) -> io::Result<Self> {
    method read_timeout (line 292) | pub fn read_timeout(&self, timeout: Duration) -> io::Result<Option<Eve...
    method try_read (line 312) | pub fn try_read(&self) -> io::Result<Option<Event>> {
  function make_key (line 334) | fn make_key(code: KeyCode, modifiers: KeyModifiers) -> Event {
  function decode_modifiers (line 345) | fn decode_modifiers(n: u16) -> KeyModifiers {
  function decode_utf16_unit (line 362) | fn decode_utf16_unit(unit: u16, high_surrogate: &mut Option<u16>) -> Opt...
  type PS (line 385) | enum PS {
  type VtParser (line 404) | struct VtParser {
    method new (line 439) | fn new() -> Self {
    method reset_csi (line 458) | fn reset_csi(&mut self) {
    method feed (line 468) | fn feed<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method has_pending_escape (line 489) | fn has_pending_escape(&self) -> bool {
    method flush_escape (line 494) | fn flush_escape<F: FnMut(Event)>(&mut self, emit: &mut F) {
    method cancel_escape (line 518) | fn cancel_escape(&mut self) {
    method is_in_paste (line 526) | fn is_in_paste(&self) -> bool {
    constant PASTE_MAX_BYTES (line 532) | const PASTE_MAX_BYTES: usize = 1_048_576;
    constant PASTE_TIMEOUT_SECS (line 538) | const PASTE_TIMEOUT_SECS: u64 = 2;
    method flush_stale_paste (line 543) | fn flush_stale_paste<F: FnMut(Event)>(&mut self, emit: &mut F) {
    method on_ground (line 621) | fn on_ground<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_escape (line 646) | fn on_escape<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_csi_entry (line 680) | fn on_csi_entry<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_csi_param (line 724) | fn on_csi_param<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method finish_param (line 755) | fn finish_param(&mut self) {
    method dispatch_csi (line 768) | fn dispatch_csi<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method dispatch_tilde (line 819) | fn dispatch_tilde<F: FnMut(Event)>(&self, mods: KeyModifiers, emit: &m...
    method dispatch_sgr_mouse (line 848) | fn dispatch_sgr_mouse<F: FnMut(Event)>(&self, final_ch: char, emit: &m...
    method on_x10 (line 915) | fn on_x10<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_ss3 (line 964) | fn on_ss3<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_paste (line 986) | fn on_paste<F: FnMut(Event)>(&mut self, ch: char, _emit: &mut F) {
    method on_paste_esc (line 994) | fn on_paste_esc<F: FnMut(Event)>(&mut self, ch: char, _emit: &mut F) {
    method on_paste_brk (line 1004) | fn on_paste_brk<F: FnMut(Event)>(&mut self, ch: char, _emit: &mut F) {
    method on_paste_num (line 1016) | fn on_paste_num<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_paste_drain (line 1041) | fn on_paste_drain<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_osc (line 1068) | fn on_osc<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method on_osc_esc (line 1088) | fn on_osc_esc<F: FnMut(Event)>(&mut self, ch: char, emit: &mut F) {
    method dispatch_osc (line 1101) | fn dispatch_osc<F: FnMut(Event)>(&self, emit: &mut F) {
  function vk_to_keycode (line 1126) | fn vk_to_keycode(vk: u16) -> Option<KeyCode> {
  function vk_modifiers (line 1161) | fn vk_modifiers(state: u32) -> KeyModifiers {
  function ssh_debug_log (line 1192) | fn ssh_debug_log(msg: &str) {
  function ssh_verbose (line 1204) | fn ssh_verbose() -> bool {
  function start_ssh_reader (line 1211) | fn start_ssh_reader() -> io::Result<std::sync::mpsc::Receiver<Event>> {

FILE: src/style.rs
  function map_color (line 18) | pub fn map_color(name: &str) -> Color {
  function parse_tmux_color (line 83) | pub fn parse_tmux_color(s: &str) -> Option<Color> {
  function parse_tmux_style (line 99) | pub fn parse_tmux_style(style_str: &str) -> Style {
  function parse_tmux_style_components (line 115) | pub fn parse_tmux_style_components(style: &str) -> (Option<Color>, Optio...
  function apply_modifier (line 135) | fn apply_modifier(token: &str, style: &mut Style) {
  function parse_inline_styles (line 180) | pub fn parse_inline_styles(text: &str, base_style: Style) -> Vec<Span<'s...
  function spans_visual_width (line 232) | pub fn spans_visual_width(spans: &[Span]) -> usize {
  function truncate_spans_to_width (line 241) | pub fn truncate_spans_to_width(spans: &mut Vec<Span<'static>>, max_width...
  function expand_status (line 274) | pub fn expand_status(fmt: &str, session_name: &str, win_name: &str, win_...
  function parse_status (line 286) | pub fn parse_status(fmt: &str, session_name: &str, win_name: &str, win_i...
  type StatusAlignment (line 326) | pub enum StatusAlignment {
  type StatusRangeType (line 334) | pub enum StatusRangeType {
  type FormatToken (line 340) | pub enum FormatToken {
  type LayoutResult (line 364) | pub struct LayoutResult {
  function parse_format_segments (line 375) | pub fn parse_format_segments(text: &str, base_style: Style) -> Vec<Forma...
  function extract_span_range (line 468) | fn extract_span_range(spans: &[Span<'static>], col_start: usize, max_wid...
  function layout_format_line (line 505) | pub fn layout_format_line(text: &str, width: usize, base_style: Style) -...
  function parse_inline_styles_fg_red (line 778) | fn parse_inline_styles_fg_red() {
  function parse_inline_styles_align_left (line 795) | fn parse_inline_styles_align_left() {
  function parse_inline_styles_multiple_directives (line 806) | fn parse_inline_styles_multiple_directives() {
  function parse_inline_styles_fg_and_bg (line 819) | fn parse_inline_styles_fg_and_bg() {
  function parse_inline_styles_plain_text (line 831) | fn parse_inline_styles_plain_text() {
  function parse_inline_styles_empty (line 842) | fn parse_inline_styles_empty() {
  function parse_tmux_color_default_returns_reset (line 851) | fn parse_tmux_color_default_returns_reset() {
  function parse_tmux_style_components_bg_default (line 859) | fn parse_tmux_style_components_bg_default() {
  function map_color_default_is_reset (line 869) | fn map_color_default_is_reset() {
  function parse_tmux_color_empty_returns_none (line 876) | fn parse_tmux_color_empty_returns_none() {

FILE: src/tree.rs
  function split_with_gaps (line 9) | pub fn split_with_gaps(is_horizontal: bool, sizes: &[u16], area: Rect) -...
  function active_pane_mut (line 76) | pub fn active_pane_mut<'a>(node: &'a mut Node, path: &Vec<usize>) -> Opt...
  function replace_leaf_with_split (line 87) | pub fn replace_leaf_with_split(node: &mut Node, path: &Vec<usize>, kind:...
  function kill_leaf (line 113) | pub fn kill_leaf(node: &mut Node, path: &Vec<usize>) {
  function kill_node (line 120) | pub fn kill_node(mut n: Node) {
  function remove_node (line 131) | pub fn remove_node(n: Node, path: &Vec<usize>) -> Node {
  function extract_node (line 162) | pub fn extract_node(root: Node, path: &[usize]) -> (Option<Node>, Option...
  function compute_rects (line 221) | pub fn compute_rects(node: &Node, area: Rect, out: &mut Vec<(Vec<usize>,...
  function resize_all_panes (line 242) | pub fn resize_all_panes(app: &mut AppState) {
  function kill_all_children (line 305) | pub fn kill_all_children(node: &mut Node) {
  function collect_child_refs (line 313) | fn collect_child_refs<'a>(node: &'a mut Node, out: &mut Vec<&'a mut Box<...
  function kill_all_children_batch (line 322) | pub fn kill_all_children_batch(windows: &mut [crate::types::Window]) {
  function compute_split_borders (line 333) | pub fn compute_split_borders(node: &Node, area: Rect, out: &mut Vec<(Vec...
  function split_sizes_at (line 364) | pub fn split_sizes_at<'a>(node: &'a Node, path: Vec<usize>, idx: usize) ...
  function adjust_split_sizes (line 374) | pub fn adjust_split_sizes(root: &mut Node, d: &DragState, x: u16, y: u16) {
  function get_split_mut (line 392) | pub fn get_split_mut<'a>(node: &'a mut Node, path: &Vec<usize>) -> Optio...
  function prune_exited (line 404) | pub fn prune_exited(n: Node, remain_on_exit: bool) -> (Option<Node>, usi...
  function path_exists (line 457) | pub fn path_exists(node: &Node, path: &Vec<usize>) -> bool {
  function first_leaf_path (line 470) | pub fn first_leaf_path(node: &Node) -> Vec<usize> {
  function find_path_by_id (line 488) | pub fn find_path_by_id(node: &Node, id: usize) -> Option<Vec<usize>> {
  function collect_leaf_paths (line 506) | fn collect_leaf_paths(node: &Node, path: &mut Vec<usize>, out: &mut Vec<...
  function collect_leaf_paths_pub (line 520) | pub fn collect_leaf_paths_pub(node: &Node, path: &mut Vec<usize>, out: &...
  function touch_mru (line 526) | pub fn touch_mru(mru: &mut Vec<usize>, pane_id: usize) {
  function remove_from_mru (line 534) | pub fn remove_from_mru(mru: &mut Vec<usize>, pane_id: usize) {
  function mru_rank (line 539) | pub fn mru_rank(mru: &[usize], pane_id: usize) -> usize {
  function for_each_pane (line 544) | pub fn for_each_pane(node: &Node, f: &mut dyn FnMut(&Pane)) {
  function collect_pane_ids (line 554) | pub fn collect_pane_ids(node: &Node) -> Vec<usize> {
  function next_leaf_path (line 570) | pub fn next_leaf_path(node: &Node, active_path: &[usize]) -> Option<Vec<...
  function get_active_pane_id (line 580) | pub fn get_active_pane_id(node: &Node, path: &[usize]) -> Option<usize> {
  function get_active_pane_id_at_path (line 595) | pub fn get_active_pane_id_at_path(node: &Node, path: &[usize]) -> Option...
  function get_pane_position_in_window (line 601) | pub fn get_pane_position_in_window(node: &Node, target_id: usize) -> Opt...
  function get_nth_pane (line 616) | pub fn get_nth_pane(node: &Node, n: usize) -> Option<&Pane> {
  function find_window_index_by_id (line 630) | pub fn find_window_index_by_id(app: &AppState, wid: usize) -> Option<usi...
  function focus_pane_by_id (line 634) | pub fn focus_pane_by_id(app: &mut AppState, pid: usize) {
  function focus_pane_by_id_no_mru (line 641) | pub fn focus_pane_by_id_no_mru(app: &mut AppState, pid: usize) {
  function focus_pane_by_id_inner (line 645) | fn focus_pane_by_id_inner(app: &mut AppState, pid: usize, update_mru: bo...
  function focus_pane_by_index (line 662) | pub fn focus_pane_by_index(app: &mut AppState, idx: usize) {
  function count_panes (line 685) | pub fn count_panes(node: &Node) -> usize {
  function active_pane (line 693) | pub fn active_pane<'a>(node: &'a Node, path: &[usize]) -> Option<&'a Pan...
  function pane_index_in_window (line 705) | pub fn pane_index_in_window(node: &Node, path: &[usize]) -> Option<usize> {
  function has_any_exited (line 738) | fn has_any_exited(node: &mut Node) -> bool {
  function reap_children (line 750) | pub fn reap_children(app: &mut AppState) -> io::Result<(bool, bool, bool...
  function collect_leaves (line 815) | pub fn collect_leaves(node: Node) -> Vec<Node> {

FILE: src/types.rs
  constant VERSION (line 10) | pub const VERSION: &str = env!("CARGO_PKG_VERSION");
  type ControlNotification (line 14) | pub enum ControlNotification {
  type ControlClient (line 48) | pub struct ControlClient {
  type ClientInfo (line 72) | pub struct ClientInfo {
  type Pane (line 84) | pub struct Pane {
  type WarmPane (line 155) | pub struct WarmPane {
  type ForwardedPane (line 173) | pub struct ForwardedPane {
  type LayoutKind (line 186) | pub enum LayoutKind { Horizontal, Vertical }
  type Node (line 188) | pub enum Node {
  type Window (line 193) | pub struct Window {
  type MenuItem (line 228) | pub struct MenuItem {
  type Menu (line 237) | pub struct Menu {
  type Hook (line 247) | pub struct Hook {
  type PipePaneState (line 256) | pub struct PipePaneState {
  type WaitChannel (line 264) | pub struct WaitChannel {
  type Mode (line 269) | pub enum Mode {
  type SelectionMode (line 325) | pub enum SelectionMode { Char, Line, Rect }
  type CopyModeState (line 330) | pub struct CopyModeState {
  type FocusDir (line 354) | pub enum FocusDir { Left, Right, Up, Down }
  type AppState (line 356) | pub struct AppState {
    method new (line 684) | pub fn new(session_name: String) -> Self {
    method port_file_base (line 857) | pub fn port_file_base(&self) -> String {
  type DragState (line 866) | pub struct DragState {
  type Action (line 879) | pub enum Action {
  type Bind (line 905) | pub struct Bind { pub key: (KeyCode, KeyModifiers), pub action: Action, ...
  type CtrlReq (line 907) | pub enum CtrlReq {
  function register_persistent_stream (line 1263) | pub fn register_persistent_stream(client_id: u64, stream: &std::net::Tcp...
  function shutdown_persistent_streams (line 1272) | pub fn shutdown_persistent_streams() {
  function shutdown_client_stream (line 1282) | pub fn shutdown_client_stream(client_id: u64) {
  constant FRAME_CHANNEL_CAPACITY (line 1313) | const FRAME_CHANNEL_CAPACITY: usize = 16;
  type FrameChannel (line 1315) | pub type FrameChannel = std::sync::Arc<FrameChannelInner>;
  type FrameChannelInner (line 1317) | pub struct FrameChannelInner {
  function register_frame_channel (line 1328) | pub fn register_frame_channel(client_id: u64) -> FrameChannel {
  function push_frame (line 1345) | pub fn push_frame(frame: &str) {
  function has_frame_receivers (line 1377) | pub fn has_frame_receivers() -> bool {
  function register_directive_channel (line 1389) | pub fn register_directive_channel(client_id: u64) -> std::sync::mpsc::Re...
  function send_directive_to_client (line 1398) | pub fn send_directive_to_client(client_id: u64, directive: &str) -> bool {
  function send_directive_to_all_clients (line 1410) | pub fn send_directive_to_all_clients(directive: &str) {
  function remove_directive_channel (line 1419) | pub fn remove_directive_channel(client_id: u64) {
  function next_control_client_id (line 1429) | pub fn next_control_client_id() -> u64 {
  type WaitForOp (line 1435) | pub enum WaitForOp {
  type ParsedTarget (line 1444) | pub struct ParsedTarget {

FILE: src/util.rs
  function expand_run_shell_path (line 10) | pub fn expand_run_shell_path(cmd: &str) -> String {
  function infer_title_from_prompt (line 45) | pub fn infer_title_from_prompt(screen: &vt100::Screen, rows: u16, cols: ...
  type WinInfo (line 87) | pub struct WinInfo { pub id: usize, pub name: String, pub active: bool, ...
  type PaneInfo (line 90) | pub struct PaneInfo { pub id: usize, pub title: String }
  type WinTree (line 93) | pub struct WinTree { pub id: usize, pub name: String, pub active: bool, ...
  type LayoutSimple (line 101) | pub enum LayoutSimple {
  function list_windows_json (line 108) | pub fn list_windows_json(app: &AppState) -> io::Result<String> {
  function list_windows_tmux (line 117) | pub fn list_windows_tmux(app: &AppState) -> String {
  function list_tree_json (line 137) | pub fn list_tree_json(app: &AppState) -> io::Result<String> {
  function window_layout_simple (line 156) | pub fn window_layout_simple(app: &AppState, win_id: usize) -> Option<Lay...
  function window_layout_json (line 183) | pub fn window_layout_json(app: &AppState, win_id: usize) -> io::Result<S...
  constant BASE64_CHARS (line 190) | pub const BASE64_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl...
  function base64_encode (line 192) | pub fn base64_encode(data: &str) -> String {
  function base64_decode (line 215) | pub fn base64_decode(encoded: &str) -> Option<String> {
  function quote_arg (line 239) | pub fn quote_arg(s: &str) -> String {
  function parse_env_assignment (line 246) | pub fn parse_env_assignment(s: &str) -> Result<(String, String), &'stati...
  function parse_new_session_e_value_token (line 262) | pub fn parse_new_session_e_value_token(next_arg: Option<&str>) -> Result...
  function is_valid_env_var_name (line 269) | fn is_valid_env_var_name(name: &str) -> bool {
  function merge_session_env_into_app (line 286) | pub fn merge_session_env_into_app(app: &mut crate::types::AppState, sess...
  function collect_server_session_env_args (line 293) | pub fn collect_server_session_env_args(args: &[String]) -> Result<Vec<(S...
  function test_quote_arg_simple (line 315) | fn test_quote_arg_simple() {
  function test_quote_arg_with_spaces (line 320) | fn test_quote_arg_with_spaces() {
  function test_quote_arg_with_embedded_quotes (line 325) | fn test_quote_arg_with_embedded_quotes() {
  function test_quote_arg_with_backslash (line 330) | fn test_quote_arg_with_backslash() {
  function test_quote_arg_empty (line 335) | fn test_quote_arg_empty() {
  function test_rename_session_roundtrip_with_spaces (line 340) | fn test_rename_session_roundtrip_with_spaces() {
  function test_rename_window_roundtrip_with_spaces (line 348) | fn test_rename_window_roundtrip_with_spaces() {
  function test_set_pane_title_roundtrip_with_spaces (line 356) | fn test_set_pane_title_roundtrip_with_spaces() {
  function test_source_file_roundtrip_windows_path_with_spaces (line 364) | fn test_source_file_roundtrip_windows_path_with_spaces() {
  function test_claim_session_roundtrip_with_spaces (line 372) | fn test_claim_session_roundtrip_with_spaces() {
  function test_roundtrip_name_with_embedded_quotes (line 381) | fn test_roundtrip_name_with_embedded_quotes() {
  function test_roundtrip_no_spaces_still_works (line 389) | fn test_roundtrip_no_spaces_still_works() {
  function test_claim_session_roundtrip_root_dir (line 397) | fn test_claim_session_roundtrip_root_dir() {
  function test_claim_session_roundtrip_trailing_backslash_dir (line 408) | fn test_claim_session_roundtrip_trailing_backslash_dir() {
  function test_claim_session_roundtrip_path_with_spaces (line 417) | fn test_claim_session_roundtrip_path_with_spaces() {
  function test_claim_session_roundtrip_deep_nested_path (line 425) | fn test_claim_session_roundtrip_deep_nested_path() {
  function test_claim_session_roundtrip_unc_path (line 433) | fn test_claim_session_roundtrip_unc_path() {
  function test_claim_session_roundtrip_path_with_parens (line 441) | fn test_claim_session_roundtrip_path_with_parens() {
  function test_claim_session_roundtrip_path_with_ampersand (line 449) | fn test_claim_session_roundtrip_path_with_ampersand() {
  function test_send_keys_claude_code_agent_command_preserves_backslashes (line 461) | fn test_send_keys_claude_code_agent_command_preserves_backslashes() {
  function test_send_keys_single_quoted_windows_path (line 473) | fn test_send_keys_single_quoted_windows_path() {
  function parse_env_assignment_basic (line 481) | fn parse_env_assignment_basic() {
  function parse_env_assignment_empty_value (line 489) | fn parse_env_assignment_empty_value() {
  function parse_env_assignment_value_with_equals (line 497) | fn parse_env_assignment_value_with_equals() {
  function parse_env_assignment_rejects_no_equals (line 505) | fn parse_env_assignment_rejects_no_equals() {
  function parse_env_assignment_rejects_bad_name (line 510) | fn parse_env_assignment_rejects_bad_name() {
  function parse_new_session_e_value_token_missing (line 516) | fn parse_new_session_e_value_token_missing() {
  function parse_new_session_e_value_token_ok (line 524) | fn parse_new_session_e_value_token_ok() {
  function collect_server_session_env_skips_after_dd (line 530) | fn collect_server_session_env_skips_after_dd() {
  function collect_server_session_env_duplicate_key_last_wins (line 541) | fn collect_server_session_env_duplicate_key_last_wins() {
  function color_to_name (line 555) | pub fn color_to_name(c: vt100::Color) -> std::borrow::Cow<'static, str> {

FILE: src/warm_pane_sync.rs
  type WarmPaneSync (line 38) | pub enum WarmPaneSync {
  type WarmPanePatch (line 46) | pub enum WarmPanePatch {
  function for_option_change (line 64) | pub fn for_option_change(name: &str, app: &AppState) -> WarmPaneSync {
  function for_env_change (line 109) | pub fn for_env_change() -> WarmPaneSync {
  function for_resize (line 116) | pub fn for_resize(app: &AppState, new_rows: u16, new_cols: u16) -> WarmP...
  function for_post_config (line 130) | pub fn for_post_config(app: &AppState) -> WarmPaneSync {
  function apply (line 180) | pub fn apply(
  function apply_patch (line 192) | fn apply_patch(app: &mut AppState, patch: WarmPanePatch) {
  function apply_patch_to_existing_panes (line 228) | fn apply_patch_to_existing_panes(app: &mut AppState, patch: &WarmPanePat...
  function respawn (line 260) | fn respawn(app: &mut AppState, pty_system: &dyn portable_pty::PtySystem) {
  function reconcile_consumed_parser (line 289) | pub fn reconcile_consumed_parser(parser: &mut vt100::Parser, app: &AppSt...

FILE: src/window_ops.rs
  function mouse_log (line 16) | fn mouse_log(msg: &str) {
  function pane_inner_cell_0based (line 37) | fn pane_inner_cell_0based(area: Rect, abs_x: u16, abs_y: u16) -> (i16, i...
  function pane_inner_cell (line 44) | fn pane_inner_cell(area: Rect, abs_x: u16, abs_y: u16) -> (u16, u16) {
  function map_client_coords (line 55) | fn map_client_coords(app: &AppState, x: u16, y: u16) -> (u16, u16) {
  function write_mouse_event_remote (line 75) | pub fn write_mouse_event_remote(master: &mut dyn std::io::Write, button:...
  function inject_mouse (line 98) | fn inject_mouse(pane: &mut Pane, col: i16, row: i16, button_state: u32, ...
  function is_vt_bridge (line 111) | fn is_vt_bridge(name: &str) -> bool {
  function screen_has_tui_content (line 128) | pub(crate) fn screen_has_tui_content(pane: &Pane) -> bool {
  function is_fullscreen_tui (line 154) | pub(crate) fn is_fullscreen_tui(pane: &Pane) -> bool {
  function pane_wants_mouse (line 212) | pub(crate) fn pane_wants_mouse(pane: &Pane) -> bool {
  function pane_wants_hover (line 238) | pub(crate) fn pane_wants_hover(pane: &Pane) -> bool {
  function detect_vt_bridge (line 251) | fn detect_vt_bridge(pane: &mut Pane) -> bool {
  function detect_mouse_input (line 278) | fn detect_mouse_input(pane: &mut Pane) -> bool {
  function inject_sgr_mouse (line 300) | fn inject_sgr_mouse(pane: &mut Pane, col: i16, row: i16, vt_button: u8, ...
  function write_mouse_to_pty (line 329) | fn write_mouse_to_pty(pane: &mut Pane, col: i16, row: i16, vt_button: u8...
  function inject_mouse_combined (line 364) | pub(crate) fn inject_mouse_combined(pane: &mut Pane, col: i16, row: i16,...
  function push_zoom (line 429) | pub fn push_zoom(app: &mut AppState) -> bool {
  function pop_zoom (line 442) | pub fn pop_zoom(app: &mut AppState, was_zoomed: bool) {
  function unzoom_if_zoomed (line 450) | pub fn unzoom_if_zoomed(app: &mut AppState) -> bool {
  function toggle_zoom (line 463) | pub fn toggle_zoom(app: &mut AppState) {
  function update_tab_positions (line 495) | pub fn update_tab_positions(app: &mut AppState) {
  function remote_mouse_down (line 512) | pub fn remote_mouse_down(app: &mut AppState, x: u16, y: u16) {
  function remote_mouse_drag (line 579) | pub fn remote_mouse_drag(app: &mut AppState, x: u16, y: u16) {
  function remote_mouse_up (line 621) | pub fn remote_mouse_up(app: &mut AppState, x: u16, y: u16) {
  function remote_mouse_button (line 679) | pub fn remote_mouse_button(app: &mut AppState, x: u16, y: u16, button: u...
  function remote_mouse_motion (line 722) | pub fn remote_mouse_motion(app: &mut AppState, x: u16, y: u16) {
  function wheel_cell_for_area (line 751) | fn wheel_cell_for_area(area: Rect, x: u16, y: u16) -> (u16, u16) {
  function copy_cell_for_area (line 758) | fn copy_cell_for_area(area: Rect, x: u16, y: u16) -> (u16, u16) {
  function remote_scroll_wheel (line 765) | fn remote_scroll_wheel(app: &mut AppState, x: u16, y: u16, up: bool) {
  function remote_scroll_up (line 862) | pub fn remote_scroll_up(app: &mut AppState, x: u16, y: u16) { remote_scr...
  function remote_scroll_down (line 863) | pub fn remote_scroll_down(app: &mut AppState, x: u16, y: u16) { remote_s...
  function handle_pane_mouse (line 868) | pub fn handle_pane_mouse(app: &mut AppState, pane_id: usize, button: u8,...
  function handle_pane_scroll (line 954) | pub fn handle_pane_scroll(app: &mut AppState, pane_id: usize, up: bool) {
  function handle_split_set_sizes (line 1019) | pub fn handle_split_set_sizes(app: &mut AppState, path: &[usize], sizes:...
  function handle_split_resize_done (line 1042) | pub fn handle_split_resize_done(app: &mut AppState) {
  function swap_pane (line 1046) | pub fn swap_pane(app: &mut AppState, dir: FocusDir) {
  function resize_pane_vertical (line 1073) | pub fn resize_pane_vertical(app: &mut AppState, amount: i16) {
  function resize_pane_horizontal (line 1104) | pub fn resize_pane_horizontal(app: &mut AppState, amount: i16) {
  function resize_pane_absolute (line 1137) | pub fn resize_pane_absolute(app: &mut AppState, axis: &str, target: u16) {
  function rotate_panes (line 1164) | pub fn rotate_panes(app: &mut AppState, reverse: bool) {
  function break_pane_to_window (line 1182) | pub fn break_pane_to_window(app: &mut AppState) {
  function respawn_active_pane (line 1238) | pub fn respawn_active_pane(app: &mut AppState, pty_system_ref: Option<&d...

FILE: tests-rs/test_client.rs
  function ime_detection_ascii_only (line 6) | fn ime_detection_ascii_only() {
  function ime_detection_japanese (line 16) | fn ime_detection_japanese() {
  function ime_detection_chinese (line 25) | fn ime_detection_chinese() {
  function ime_detection_korean (line 32) | fn ime_detection_korean() {
  function ime_detection_mixed (line 38) | fn ime_detection_mixed() {
  function flush_paste_pend_ascii_sends_as_paste (line 46) | fn flush_paste_pend_ascii_sends_as_paste() {
  function flush_paste_pend_cjk_sends_as_text (line 59) | fn flush_paste_pend_cjk_sends_as_text() {
  function flush_paste_pend_short_ascii_sends_as_text (line 76) | fn flush_paste_pend_short_ascii_sends_as_text() {
  function status_format_inline_styles_end_to_end (line 94) | fn status_format_inline_styles_end_to_end() {
  function status_format_json_roundtrip_preserves_styles (line 149) | fn status_format_json_roundtrip_preserves_styles() {
  function make_run (line 186) | fn make_run(text: &str, width: u16) -> crate::layout::CellRunJson {
  function make_row (line 198) | fn make_row(runs: Vec<crate::layout::CellRunJson>) -> crate::layout::Row...
  function normalize_selection_reading_order (line 204) | fn normalize_selection_reading_order() {
  function normalize_selection_block_mode (line 216) | fn normalize_selection_block_mode() {
  function row_chars_basic (line 224) | fn row_chars_basic() {
  function row_chars_width_clamp (line 236) | fn row_chars_width_clamp() {
  function is_word_char_basics (line 244) | fn is_word_char_basics() {
  function char_at_col_basics (line 256) | fn char_at_col_basics() {
  function extract_selection_text_block_mode (line 272) | fn extract_selection_text_block_mode() {
  function word_bounds_at_finds_word (line 314) | fn word_bounds_at_finds_word() {
  function pwsh_mouse_selection_option_default_off (line 357) | fn pwsh_mouse_selection_option_default_off() {
  function paste_into_command_prompt_inserts_and_advances_cursor (line 368) | fn paste_into_command_prompt_inserts_and_advances_cursor() {
  function paste_into_command_prompt_inserts_at_cursor_position (line 387) | fn paste_into_command_prompt_inserts_at_cursor_position() {
  function paste_with_no_overlay_active_is_not_consumed (line 407) | fn paste_with_no_overlay_active_is_not_consumed() {
  function paste_into_rename_prompt_appends (line 429) | fn paste_into_rename_prompt_appends() {
  function paste_into_pane_title_appends (line 447) | fn paste_into_pane_title_appends() {
  function paste_into_window_idx_prompt_keeps_only_digits (line 465) | fn paste_into_window_idx_prompt_keeps_only_digits() {
  function paste_command_prompt_takes_precedence_over_other_overlays (line 483) | fn paste_command_prompt_takes_precedence_over_other_overlays() {

FILE: tests-rs/test_cmdbuilder.rs
  function test_cwd_relative (line 5) | fn test_cwd_relative() {
  function test_env (line 14) | fn test_env() {
  function test_env_case_insensitive_override (line 57) | fn test_env_case_insensitive_override() {

FILE: tests-rs/test_commands.rs
  function mock_app (line 5) | fn mock_app() -> AppState {
  function test_generate_list_clients (line 13) | fn test_generate_list_clients() {
  function test_generate_show_hooks_empty (line 39) | fn test_generate_show_hooks_empty() {
  function test_generate_show_hooks_with_hooks (line 46) | fn test_generate_show_hooks_with_hooks() {
  function test_generate_list_commands (line 55) | fn test_generate_list_commands() {
  function test_show_output_popup_sets_mode (line 64) | fn test_show_output_popup_sets_mode() {
  function mock_app_with_window (line 77) | fn mock_app_with_window() -> AppState {
  function test_list_windows_command_prompt_sets_popup (line 103) | fn test_list_windows_command_prompt_sets_popup() {
  function test_list_panes_command_prompt_sets_popup (line 117) | fn test_list_panes_command_prompt_sets_popup() {
  function test_list_clients_command_prompt_sets_popup (line 130) | fn test_list_clients_command_prompt_sets_popup() {
  function test_list_commands_command_prompt_sets_popup (line 144) | fn test_list_commands_command_prompt_sets_popup() {
  function test_show_hooks_command_prompt_sets_popup (line 158) | fn test_show_hooks_command_prompt_sets_popup() {
  function test_list_panes_alias_lsp_command_prompt (line 172) | fn test_list_panes_alias_lsp_command_prompt() {
  function test_list_windows_alias_lsw_command_prompt (line 185) | fn test_list_windows_alias_lsw_command_prompt() {
  function test_popup_dimensions_reasonable (line 198) | fn test_popup_dimensions_reasonable() {
  function test_command_prompt_unknown_cmd_stays_passthrough (line 213) | fn test_command_prompt_unknown_cmd_stays_passthrough() {

FILE: tests-rs/test_commands_audit.rs
  function mock_app (line 8) | fn mock_app() -> AppState {
  function make_window (line 15) | fn make_window(name: &str, id: usize) -> crate::types::Window {
  function mock_app_with_window (line 34) | fn mock_app_with_window() -> AppState {
  function mock_app_with_windows (line 40) | fn mock_app_with_windows(names: &[&str]) -> AppState {
  function extract_popup (line 49) | fn extract_popup(app: &AppState) -> (&str, &str) {
  function extract_status_message (line 57) | fn extract_status_message(app: &AppState) -> &str {
  function display_message_shows_plain_text_in_status (line 69) | fn display_message_shows_plain_text_in_status() {
  function display_message_expands_session_name_format (line 77) | fn display_message_expands_session_name_format() {
  function display_alias_works (line 86) | fn display_alias_works() {
  function show_options_displays_popup_with_key_options (line 98) | fn show_options_displays_popup_with_key_options() {
  function show_options_reflects_current_settings (line 111) | fn show_options_reflects_current_settings() {
  function show_alias_same_as_show_options (line 122) | fn show_alias_same_as_show_options() {
  function showw_alias_same_as_show_options (line 130) | fn showw_alias_same_as_show_options() {
  function set_environment_updates_local_env (line 142) | fn set_environment_updates_local_env() {
  function setenv_alias_works (line 149) | fn setenv_alias_works() {
  function set_environment_unset_removes_var (line 156) | fn set_environment_unset_removes_var() {
  function show_environment_displays_vars_in_popup (line 164) | fn show_environment_displays_vars_in_popup() {
  function show_environment_empty_shows_message (line 176) | fn show_environment_empty_shows_message() {
  function showenv_alias_works (line 184) | fn showenv_alias_works() {
  function set_hook_creates_new_hook (line 198) | fn set_hook_creates_new_hook() {
  function set_hook_append_adds_to_existing (line 206) | fn set_hook_append_adds_to_existing() {
  function set_hook_unset_removes_hook (line 215) | fn set_hook_unset_removes_hook() {
  function find_window_shows_matching_windows (line 227) | fn find_window_shows_matching_windows() {
  function find_window_no_match_shows_feedback (line 240) | fn find_window_no_match_shows_feedback() {
  function findw_alias_works (line 248) | fn findw_alias_works() {
  function move_window_changes_position (line 261) | fn move_window_changes_position() {
  function movew_alias_works (line 272) | fn movew_alias_works() {
  function swap_window_swaps_two_windows (line 284) | fn swap_window_swaps_two_windows() {
  function swapw_alias_works (line 294) | fn swapw_alias_works() {
  function swap_window_same_index_is_noop (line 303) | fn swap_window_same_index_is_noop() {
  function link_window_accepted (line 315) | fn link_window_accepted() {
  function linkw_alias_accepted (line 323) | fn linkw_alias_accepted() {
  function lock_server_shows_not_available_message (line 334) | fn lock_server_shows_not_available_message() {
  function lock_client_shows_not_available_message (line 342) | fn lock_client_shows_not_available_message() {
  function lock_session_shows_not_available_message (line 350) | fn lock_session_shows_not_available_message() {
  function lock_alias_shows_not_available (line 358) | fn lock_alias_shows_not_available() {
  function lockc_alias_shows_not_available (line 366) | fn lockc_alias_shows_not_available() {
  function locks_alias_shows_not_available (line 374) | fn locks_alias_shows_not_available() {
  function suspend_client_shows_not_available (line 386) | fn suspend_client_shows_not_available() {
  function suspendc_alias_shows_not_available (line 394) | fn suspendc_alias_shows_not_available() {
  function choose_client_shows_single_client_message (line 406) | fn choose_client_shows_single_client_message() {
  function customize_mode_shows_options_popup (line 419) | fn customize_mode_shows_options_popup() {
  function refresh_client_shows_status_message (line 436) | fn refresh_client_shows_status_message() {
  function refresh_alias_works (line 444) | fn refresh_alias_works() {
  function server_info_shows_popup_with_version_and_session (line 455) | fn server_info_shows_popup_with_version_and_session() {
  function info_alias_works (line 467) | fn info_alias_works() {
  function show_messages_shows_popup (line 479) | fn show_messages_shows_popup() {
  function showmsgs_alias_works (line 488) | fn showmsgs_alias_works() {
  function set_option_local_changes_mouse (line 500) | fn set_option_local_changes_mouse() {
  function set_option_local_changes_history_limit (line 508) | fn set_option_local_changes_history_limit() {
  function bind_key_local_adds_binding (line 515) | fn bind_key_local_adds_binding() {
  function source_file_loads_config_locally (line 530) | fn source_file_loads_config_locally() {
  function if_shell_format_mode_true_runs_true_cmd (line 546) | fn if_shell_format_mode_true_runs_true_cmd() {
  function if_shell_format_mode_false_runs_false_cmd (line 555) | fn if_shell_format_mode_false_runs_false_cmd() {
  function if_shell_literal_true_runs_true_cmd (line 564) | fn if_shell_literal_true_runs_true_cmd() {
  function if_shell_literal_false_runs_false_cmd (line 572) | fn if_shell_literal_false_runs_false_cmd() {
  function if_shell_format_expands_user_option_truthy (line 582) | fn if_shell_format_expands_user_option_truthy() {
  function if_shell_format_expands_user_option_falsy (line 593) | fn if_shell_format_expands_user_option_falsy() {
  function if_shell_format_expands_unset_option_as_falsy (line 603) | fn if_shell_format_expands_unset_option_as_falsy() {
  function if_shell_format_expands_session_name (line 612) | fn if_shell_format_expands_session_name() {
  function if_shell_format_expands_window_zoomed_flag (line 621) | fn if_shell_format_expands_window_zoomed_flag() {
  function previous_layout_changes_layout_index (line 634) | fn previous_layout_changes_layout_index() {
  function prevl_alias_works (line 647) | fn prevl_alias_works() {
  function select_layout_applies_tiled (line 658) | fn select_layout_applies_tiled() {
  function selectl_alias_works (line 665) | fn selectl_alias_works() {
  function next_layout_changes_layout_index (line 675) | fn next_layout_changes_layout_index() {
  function unlink_window_removes_active_window (line 688) | fn unlink_window_removes_active_window() {
  function unlink_window_refuses_last_window (line 698) | fn unlink_window_refuses_last_window() {
  function unlinkw_alias_works (line 705) | fn unlinkw_alias_works() {
  function clear_history_does_not_panic_on_empty_window (line 716) | fn clear_history_does_not_panic_on_empty_window() {
  function clearhist_alias_does_not_panic (line 723) | fn clearhist_alias_does_not_panic() {
  function break_pane_empty_split_does_not_crash (line 733) | fn break_pane_empty_split_does_not_crash() {
  function breakp_alias_does_not_crash (line 740) | fn breakp_alias_does_not_crash() {
  function respawn_pane_empty_does_not_crash (line 750) | fn respawn_pane_empty_does_not_crash() {
  function respawnp_alias_does_not_crash (line 757) | fn respawnp_alias_does_not_crash() {
  function swap_pane_does_not_crash_on_empty (line 767) | fn swap_pane_does_not_crash_on_empty() {
  function swapp_alias_does_not_crash (line 774) | fn swapp_alias_does_not_crash() {
  function rotate_window_does_not_crash_on_empty (line 784) | fn rotate_window_does_not_crash_on_empty() {
  function rotate_window_reverse_does_not_crash (line 790) | fn rotate_window_reverse_does_not_crash() {
  function rotatew_alias_does_not_crash (line 796) | fn rotatew_alias_does_not_crash() {
  function resize_pane_up_does_not_crash (line 806) | fn resize_pane_up_does_not_crash() {
  function resize_pane_down_does_not_crash (line 812) | fn resize_pane_down_does_not_crash() {
  function resize_pane_left_does_not_crash (line 818) | fn resize_pane_left_does_not_crash() {
  function resize_pane_right_does_not_crash (line 824) | fn resize_pane_right_does_not_crash() {
  function resizep_alias_zoom (line 830) | fn resizep_alias_zoom() {
  function every_listed_command_parses_to_action (line 840) | fn every_listed_command_parses_to_action() {
  function every_command_does_not_panic_embedded_mode (line 878) | fn every_command_does_not_panic_embedded_mode() {

FILE: tests-rs/test_commands_new.rs
  function mock_app (line 8) | fn mock_app() -> AppState {
  function make_window (line 15) | fn make_window(name: &str, id: usize) -> crate::types::Window {
  function mock_app_with_window (line 34) | fn mock_app_with_window() -> AppState {
  function mock_app_with_windows (line 40) | fn mock_app_with_windows(names: &[&str]) -> AppState {
  function extract_popup (line 49) | fn extract_popup(app: &AppState) -> (&str, &str) {
  function list_buffers_empty_says_no_buffers (line 61) | fn list_buffers_empty_says_no_buffers() {
  function list_buffers_shows_all_buffer_details (line 70) | fn list_buffers_shows_all_buffer_details() {
  function lsb_alias_produces_identical_output_to_list_buffers (line 93) | fn lsb_alias_produces_identical_output_to_list_buffers() {
  function show_buffer_displays_first_buffer_content_verbatim (line 113) | fn show_buffer_displays_first_buffer_content_verbatim() {
  function show_buffer_empty_does_not_crash (line 124) | fn show_buffer_empty_does_not_crash() {
  function showb_alias_same_as_show_buffer (line 132) | fn showb_alias_same_as_show_buffer() {
  function list_keys_empty_says_no_bindings (line 145) | fn list_keys_empty_says_no_bindings() {
  function list_keys_shows_bound_keys_with_table_key_command (line 154) | fn list_keys_shows_bound_keys_with_table_key_command() {
  function list_keys_shows_multiple_tables (line 189) | fn list_keys_shows_multiple_tables() {
  function lsk_alias_produces_same_output (line 206) | fn lsk_alias_produces_same_output() {
  function list_windows_output_has_window_names_and_active_flag (line 228) | fn list_windows_output_has_window_names_and_active_flag() {
  function list_windows_respects_window_base_index (line 250) | fn list_windows_respects_window_base_index() {
  function list_windows_shows_pane_count (line 261) | fn list_windows_shows_pane_count() {
  function list_windows_shows_activity_flag (line 270) | fn list_windows_shows_activity_flag() {
  function lsw_alias_matches_list_windows (line 282) | fn lsw_alias_matches_list_windows() {
  function list_clients_output_has_session_and_window_info (line 298) | fn list_clients_output_has_session_and_window_info() {
  function lsc_alias_matches_list_clients (line 312) | fn lsc_alias_matches_list_clients() {
  function list_commands_contains_all_major_commands (line 325) | fn list_commands_contains_all_major_commands() {
  function lscm_alias_matches_list_commands (line 344) | fn lscm_alias_matches_list_commands() {
  function show_hooks_empty_says_no_hooks (line 356) | fn show_hooks_empty_says_no_hooks() {
  function show_hooks_lists_all_hooks_with_commands (line 365) | fn show_hooks_lists_all_hooks_with_commands() {
  function set_buffer_inserts_at_front_lifo (line 388) | fn set_buffer_inserts_at_front_lifo() {
  function set_buffer_caps_at_10_evicts_oldest (line 400) | fn set_buffer_caps_at_10_evicts_oldest() {
  function setb_alias_inserts_same_as_set_buffer (line 414) | fn setb_alias_inserts_same_as_set_buffer() {
  function delete_buffer_removes_first_buffer (line 421) | fn delete_buffer_removes_first_buffer() {
  function deleteb_alias_works (line 429) | fn deleteb_alias_works() {
  function delete_buffer_on_empty_is_safe (line 437) | fn delete_buffer_on_empty_is_safe() {
  function set_then_show_then_delete_roundtrip (line 444) | fn set_then_show_then_delete_roundtrip() {
  function next_window_advances_and_tracks_last (line 465) | fn next_window_advances_and_tracks_last() {
  function next_window_wraps_around (line 477) | fn next_window_wraps_around() {
  function previous_window_goes_back_and_wraps (line 485) | fn previous_window_goes_back_and_wraps() {
  function last_window_swaps_active_and_last (line 496) | fn last_window_swaps_active_and_last() {
  function select_window_plain_target (line 510) | fn select_window_plain_target() {
  function select_window_colon_target (line 518) | fn select_window_colon_target() {
  function select_window_colon_equals_target (line 525) | fn select_window_colon_equals_target() {
  function selectw_alias_works (line 532) | fn selectw_alias_works() {
  function select_window_out_of_range_is_ignored (line 539) | fn select_window_out_of_range_is_ignored() {
  function select_window_with_base_index_offset (line 546) | fn select_window_with_base_index_offset() {
  function kill_window_removes_active_window (line 559) | fn kill_window_removes_active_window() {
  function kill_window_adjusts_active_idx_when_killing_last (line 569) | fn kill_window_adjusts_active_idx_when_killing_last() {
  function kill_window_refuses_last_window (line 578) | fn kill_window_refuses_last_window() {
  function killw_alias_works (line 585) | fn killw_alias_works() {
  function rename_window_changes_active_window_name (line 596) | fn rename_window_changes_active_window_name() {
  function renamew_alias_works (line 605) | fn renamew_alias_works() {
  function rename_session_changes_session_name (line 612) | fn rename_session_changes_session_name() {
  function toggle_sync_flips_state_correctly (line 627) | fn toggle_sync_flips_state_correctly() {
  function choose_tree_enters_window_chooser_mode (line 643) | fn choose_tree_enters_window_chooser_mode() {
  function choose_tree_builds_correct_tree_from_list_all_sessions (line 674) | fn choose_tree_builds_correct_tree_from_list_all_sessions() {
  function choose_window_and_choose_session_all_enter_window_chooser (line 710) | fn choose_window_and_choose_session_all_enter_window_chooser() {
  function confirm_before_stores_command_and_prompt (line 724) | fn confirm_before_stores_command_and_prompt() {
  function confirm_alias_works_same_as_confirm_before (line 738) | fn confirm_alias_works_same_as_confirm_before() {
  function display_menu_parses_items (line 752) | fn display_menu_parses_items() {
  function display_popup_default_dimensions (line 768) | fn display_popup_default_dimensions() {
  function display_popup_custom_dimensions (line 782) | fn display_popup_custom_dimensions() {
  function display_popup_close_on_exit_flag (line 795) | fn display_popup_close_on_exit_flag() {
  function popup_alias_works_same (line 807) | fn popup_alias_works_same() {
  function command_prompt_default_empty (line 824) | fn command_prompt_default_empty() {
  function command_prompt_initial_text_sets_cursor_at_end (line 837) | fn command_prompt_initial_text_sets_cursor_at_end() {
  function clock_mode_enters_clock (line 854) | fn clock_mode_enters_clock() {
  function copy_mode_enters_copy (line 861) | fn copy_mode_enters_copy() {
  function choose_buffer_enters_buffer_chooser_at_0 (line 868) | fn choose_buffer_enters_buffer_chooser_at_0() {
  function chooseb_alias_enters_buffer_chooser (line 878) | fn chooseb_alias_enters_buffer_chooser() {
  function display_panes_populates_display_map (line 885) | fn display_panes_populates_display_map() {
  function displayp_alias_works (line 893) | fn displayp_alias_works() {
  function new_session_does_not_block_with_popup (line 904) | fn new_session_does_not_block_with_popup() {
  function new_alias_does_not_block (line 915) | fn new_alias_does_not_block() {
  function attach_session_is_noop_preserves_state (line 927) | fn attach_session_is_noop_preserves_state() {
  function start_server_is_noop (line 940) | fn start_server_is_noop() {
  function has_session_is_noop (line 949) | fn has_session_is_noop() {
  function choose_client_is_noop (line 958) | fn choose_client_is_noop() {
  function customize_mode_shows_options_popup (line 965) | fn customize_mode_shows_options_popup() {
  function assert_server_forward_noop (line 976) | fn assert_server_forward_noop(cmd: &str) {
  function server_forwarded_show_options (line 989) | fn server_forwarded_show_options() { assert_server_forward_noop("show-op...
  function server_forwarded_show (line 991) | fn server_forwarded_show() { assert_server_forward_noop("show"); }
  function server_forwarded_showw (line 993) | fn server_forwarded_showw() { assert_server_forward_noop("showw"); }
  function server_forwarded_display_message (line 995) | fn server_forwarded_display_message() { assert_server_forward_noop("disp...
  function server_forwarded_display (line 997) | fn server_forwarded_display() { assert_server_forward_noop("display hell...
  function server_forwarded_show_messages (line 999) | fn server_forwarded_show_messages() { assert_server_forward_noop("show-m...
  function server_forwarded_showmsgs (line 1001) | fn server_forwarded_showmsgs() { assert_server_forward_noop("showmsgs"); }
  function server_forwarded_set_environment (line 1003) | fn server_forwarded_set_environment() { assert_server_forward_noop("set-...
  function server_forwarded_setenv (line 1005) | fn server_forwarded_setenv() { assert_server_forward_noop("setenv FOO ba...
  function server_forwarded_show_environment (line 1007) | fn server_forwarded_show_environment() { assert_server_forward_noop("sho...
  function server_forwarded_showenv (line 1009) | fn server_forwarded_showenv() { assert_server_forward_noop("showenv"); }
  function server_forwarded_set_hook (line 1011) | fn server_forwarded_set_hook() { assert_server_forward_noop("set-hook af...
  function server_forwarded_send_prefix (line 1013) | fn server_forwarded_send_prefix() { assert_server_forward_noop("send-pre...
  function server_forwarded_if_shell (line 1015) | fn server_forwarded_if_shell() { assert_server_forward_noop("if-shell tr...
  function server_forwarded_if_alias (line 1017) | fn server_forwarded_if_alias() { assert_server_forward_noop("if true new...
  function server_forwarded_wait_for (line 1019) | fn server_forwarded_wait_for() { assert_server_forward_noop("wait-for do...
  function server_forwarded_wait (line 1021) | fn server_forwarded_wait() { assert_server_forward_noop("wait done"); }
  function server_forwarded_find_window (line 1023) | fn server_forwarded_find_window() { assert_server_forward_noop("find-win...
  function server_forwarded_findw (line 1025) | fn server_forwarded_findw() { assert_server_forward_noop("findw pattern"...
  function server_forwarded_move_window (line 1027) | fn server_forwarded_move_window() { assert_server_forward_noop("move-win...
  function server_forwarded_movew (line 1029) | fn server_forwarded_movew() { assert_server_forward_noop("movew -t 1"); }
  function server_forwarded_swap_window (line 1031) | fn server_forwarded_swap_window() { assert_server_forward_noop("swap-win...
  function server_forwarded_swapw (line 1033) | fn server_forwarded_swapw() { assert_server_forward_noop("swapw -t 1"); }
  function server_forwarded_link_window (line 1035) | fn server_forwarded_link_window() {
  function server_forwarded_linkw (line 1043) | fn server_forwarded_linkw() {
  function server_forwarded_unlink_window (line 1049) | fn server_forwarded_unlink_window() { assert_server_forward_noop("unlink...
  function server_forwarded_unlinkw (line 1051) | fn server_forwarded_unlinkw() { assert_server_forward_noop("unlinkw"); }
  function server_forwarded_move_pane (line 1053) | fn server_forwarded_move_pane() { assert_server_forward_noop("move-pane"...
  function server_forwarded_movep (line 1055) | fn server_forwarded_movep() { assert_server_forward_noop("movep"); }
  function server_forwarded_join_pane (line 1057) | fn server_forwarded_join_pane() { assert_server_forward_noop("join-pane ...
  function server_forwarded_joinp (line 1059) | fn server_forwarded_joinp() { assert_server_forward_noop("joinp -t 1"); }
  function server_forwarded_resize_window (line 1061) | fn server_forwarded_resize_window() { assert_server_forward_noop("resize...
  function server_forwarded_resizew (line 1063) | fn server_forwarded_resizew() { assert_server_forward_noop("resizew -x 8...
  function server_forwarded_server_info (line 1065) | fn server_forwarded_server_info() { assert_server_forward_noop("server-i...
  function server_forwarded_info (line 1067) | fn server_forwarded_info() { assert_server_forward_noop("info"); }
  function server_forwarded_lock_variants (line 1069) | fn server_forwarded_lock_variants() {
  function server_forwarded_refresh (line 1075) | fn server_forwarded_refresh() { assert_server_forward_noop("refresh-clie...
  function server_forwarded_refresh_alias (line 1077) | fn server_forwarded_refresh_alias() { assert_server_forward_noop("refres...
  function server_forwarded_suspend (line 1079) | fn server_forwarded_suspend() { assert_server_forward_noop("suspend-clie...
  function server_forwarded_suspendc (line 1081) | fn server_forwarded_suspendc() { assert_server_forward_noop("suspendc"); }
  function server_forwarded_send_keys (line 1083) | fn server_forwarded_send_keys() { assert_server_forward_noop("send-keys ...
  function server_forwarded_send (line 1085) | fn server_forwarded_send() { assert_server_forward_noop("send Enter"); }
  function server_forwarded_pipe_pane (line 1087) | fn server_forwarded_pipe_pane() { assert_server_forward_noop("pipe-pane ...
  function server_forwarded_pipep (line 1089) | fn server_forwarded_pipep() { assert_server_forward_noop("pipep cat"); }
  function server_forwarded_kill_session (line 1091) | fn server_forwarded_kill_session() { assert_server_forward_noop("kill-se...
  function server_forwarded_kill_ses (line 1093) | fn server_forwarded_kill_ses() { assert_server_forward_noop("kill-ses"); }
  function server_forwarded_kill_server (line 1095) | fn server_forwarded_kill_server() { assert_server_forward_noop("kill-ser...
  function server_forwarded_clear_history (line 1097) | fn server_forwarded_clear_history() { assert_server_forward_noop("clear-...
  function server_forwarded_clearhist (line 1099) | fn server_forwarded_clearhist() { assert_server_forward_noop("clearhist"...
  function server_forwarded_respawn_window (line 1101) | fn server_forwarded_respawn_window() { assert_server_forward_noop("respa...
  function server_forwarded_respawnw (line 1103) | fn server_forwarded_respawnw() { assert_server_forward_noop("respawnw"); }
  function server_forwarded_previous_layout (line 1105) | fn server_forwarded_previous_layout() { assert_server_forward_noop("prev...
  function server_forwarded_prevl (line 1107) | fn server_forwarded_prevl() { assert_server_forward_noop("prevl"); }
  function server_forwarded_next_layout (line 1109) | fn server_forwarded_next_layout() { assert_server_forward_noop("next-lay...
  function server_forwarded_select_layout (line 1111) | fn server_forwarded_select_layout() { assert_server_forward_noop("select...
  function server_forwarded_selectl (line 1113) | fn server_forwarded_selectl() { assert_server_forward_noop("selectl even...
  function server_forwarded_set_option (line 1115) | fn server_forwarded_set_option() { assert_server_forward_noop("set-optio...
  function server_forwarded_setw (line 1117) | fn server_forwarded_setw() { assert_server_forward_noop("setw mode-keys ...
  function run_via_prompt (line 1123) | fn run_via_prompt(app: &mut AppState, cmd: &str) {
  function prompt_delegates_clock_mode (line 1129) | fn prompt_delegates_clock_mode() {
  function prompt_delegates_toggle_sync (line 1136) | fn prompt_delegates_toggle_sync() {
  function prompt_delegates_rename_session_with_state_verification (line 1143) | fn prompt_delegates_rename_session_with_state_verification() {
  function prompt_delegates_set_buffer_then_list_shows_it (line 1150) | fn prompt_delegates_set_buffer_then_list_shows_it() {
  function prompt_delegates_choose_tree (line 1161) | fn prompt_delegates_choose_tree() {
  function prompt_delegates_list_keys (line 1168) | fn prompt_delegates_list_keys() {
  function prompt_delegates_new_session_creates_session (line 1176) | fn prompt_delegates_new_session_creates_session() {
  function prompt_unknown_command_falls_through (line 1185) | fn prompt_unknown_command_falls_through() {
  function parse_action_direct_commands (line 1196) | fn parse_action_direct_commands() {
  function parse_action_command_wrapping_aliases (line 1222) | fn parse_action_command_wrapping_aliases() {
  function parse_action_split_window_variants (line 1257) | fn parse_action_split_window_variants() {
  function parse_action_select_pane_directions (line 1267) | fn parse_action_select_pane_directions() {
  function parse_action_switch_client_table (line 1279) | fn parse_action_switch_client_table() {
  function parse_action_empty_and_whitespace (line 1293) | fn parse_action_empty_and_whitespace() {
  function format_action_roundtrips (line 1303) | fn format_action_roundtrips() {
  function workflow_create_buffers_list_delete_roundtrip (line 1339) | fn workflow_create_buffers_list_delete_roundtrip() {
  function workflow_navigate_windows_verify_tracking (line 1366) | fn workflow_navigate_windows_verify_tracking() {
  function workflow_complex_command_sequence_via_prompt (line 1392) | fn workflow_complex_command_sequence_via_prompt() {
  function popup_width_scales_to_longest_line (line 1418) | fn popup_width_scales_to_longest_line() {
  function popup_height_scales_to_line_count (line 1434) | fn popup_height_scales_to_line_count() {
  function popup_height_not_capped_allows_scroll (line 1448) | fn popup_height_not_capped_allows_scroll() {
  function popup_width_capped_at_120 (line 1462) | fn popup_width_capped_at_120() {
  function popup_minimum_dimensions (line 1475) | fn popup_minimum_dimensions() {
  function empty_command_string_is_noop (line 1492) | fn empty_command_string_is_noop() {
  function unknown_command_does_not_mutate_critical_state (line 1501) | fn unknown_command_does_not_mutate_critical_state() {
  function zoom_pane_on_empty_split_does_not_crash (line 1513) | fn zoom_pane_on_empty_split_does_not_crash() {
  function resize_pane_zoom_flag_does_not_crash (line 1520) | fn resize_pane_zoom_flag_does_not_crash() {
  function swap_pane_without_port_does_not_crash (line 1526) | fn swap_pane_without_port_does_not_crash() {
  function rotate_window_without_port_does_not_crash (line 1534) | fn rotate_window_without_port_does_not_crash() {
  function break_pane_without_port_does_not_crash (line 1542) | fn break_pane_without_port_does_not_crash() {
  function respawn_pane_without_port_does_not_crash (line 1550) | fn respawn_pane_without_port_does_not_crash() {
  function press (line 1564) | fn press(code: KeyCode) -> KeyEvent {
  function prefix_single_quote_enters_window_index_prompt (line 1574) | fn prefix_single_quote_enters_window_index_prompt() {
  function window_index_prompt_accepts_digits_only (line 1582) | fn window_index_prompt_accepts_digits_only() {
  function run_shell_captures_and_displays_output (line 1606) | fn run_shell_captures_and_displays_output() {
  function run_shell_background_does_not_show_popup (line 1630) | fn run_shell_background_does_not_show_popup() {
  function run_shell_alias_captures_output (line 1648) | fn run_shell_alias_captures_output() {
  function run_shell_stderr_is_captured (line 1669) | fn run_shell_stderr_is_captured() {
  function run_shell_empty_output_no_popup (line 1690) | fn run_shell_empty_output_no_popup() {
  function window_index_prompt_backspace_removes_digit (line 1710) | fn window_index_prompt_backspace_removes_digit() {
  function window_index_prompt_esc_cancels (line 1722) | fn window_index_prompt_esc_cancels() {
  function window_index_prompt_enter_jumps_to_window (line 1731) | fn window_index_prompt_enter_jumps_to_window() {
  function window_index_prompt_enter_multidigit (line 1741) | fn window_index_prompt_enter_multidigit() {
  function window_index_prompt_out_of_range_stays_put (line 1750) | fn window_index_prompt_out_of_range_stays_put() {
  function window_index_prompt_empty_enter_stays_put (line 1759) | fn window_index_prompt_empty_enter_stays_put() {
  function window_index_prompt_respects_base_index (line 1768) | fn window_index_prompt_respects_base_index() {
  function window_index_prompt_full_flow_via_prefix (line 1778) | fn window_index_prompt_full_flow_via_prefix() {
  function parse_popup_dim_absolute_value (line 1794) | fn parse_popup_dim_absolute_value() {
  function parse_popup_dim_percentage_value (line 1801) | fn parse_popup_dim_percentage_value() {
  function parse_popup_dim_percentage_clamped_at_100 (line 1813) | fn parse_popup_dim_percentage_clamped_at_100() {
  function parse_popup_dim_invalid_falls_back_to_default (line 1819) | fn parse_popup_dim_invalid_falls_back_to_default() {
  function display_popup_d_flag_stripped_from_command (line 1826) | fn display_popup_d_flag_stripped_from_command() {
  function display_popup_c_flag_also_works_for_directory (line 1842) | fn display_popup_c_flag_also_works_for_directory() {
  function display_popup_d_flag_with_percent_dims (line 1855) | fn display_popup_d_flag_with_percent_dims() {
  function new_window_bare_returns_action_new_window (line 1874) | fn new_window_bare_returns_action_new_window() {
  function new_window_with_c_flag_returns_command_preserving_args (line 1881) | fn new_window_with_c_flag_returns_command_preserving_args() {
  function new_window_with_name_flag_returns_command (line 1894) | fn new_window_with_name_flag_returns_command() {
  function new_window_with_shell_command_returns_command (line 1906) | fn new_window_with_shell_command_returns_command() {
  function run_shell_no_args_shows_usage (line 1921) | fn run_shell_no_args_shows_usage() {
  function run_alias_no_args_shows_usage (line 1931) | fn run_alias_no_args_shows_usage() {
  function display_message_no_args_uses_default_format (line 1940) | fn display_message_no_args_uses_default_format() {
  function display_alias_no_args_uses_default_format (line 1952) | fn display_alias_no_args_uses_default_format() {
  function display_message_with_args_still_works (line 1961) | fn display_message_with_args_still_works() {
  function run_shell_error_shows_on_status_bar (line 1970) | fn run_shell_error_shows_on_status_bar() {
  function resolve_run_shell_returns_valid_shell (line 1989) | fn resolve_run_shell_returns_valid_shell() {
  function resolve_run_shell_returns_absolute_windows_shell_path (line 2003) | fn resolve_run_shell_returns_absolute_windows_shell_path() {
  function prefix_dollar_enters_rename_session_prompt_not_rename_window (line 2024) | fn prefix_dollar_enters_rename_session_prompt_not_rename_window() {
  function prefix_comma_enters_rename_window_prompt_not_session (line 2041) | fn prefix_comma_enters_rename_window_prompt_not_session() {
  function rename_session_prompt_typing_and_enter_applies_session_name (line 2056) | fn rename_session_prompt_typing_and_enter_applies_session_name() {
  function rename_window_prompt_typing_and_enter_applies_window_name (line 2076) | fn rename_window_prompt_typing_and_enter_applies_window_name() {
  function rename_session_prompt_esc_cancels_without_changing_name (line 2089) | fn rename_session_prompt_esc_cancels_without_changing_name() {

FILE: tests-rs/test_config_exhaustive.rs
  function mock_app (line 25) | fn mock_app() -> AppState {
  function default_escape_time (line 34) | fn default_escape_time() {
  function default_mouse (line 40) | fn default_mouse() {
  function default_status_visible (line 46) | fn default_status_visible() {
  function default_status_position (line 52) | fn default_status_position() {
  function default_status_style (line 58) | fn default_status_style() {
  function default_status_left (line 64) | fn default_status_left() {
  function default_status_right (line 70) | fn default_status_right() {
  function default_status_interval (line 76) | fn default_status_interval() {
  function default_status_justify (line 82) | fn default_status_justify() {
  function default_status_left_length (line 88) | fn default_status_left_length() {
  function default_status_right_length (line 94) | fn default_status_right_length() {
  function default_status_lines (line 100) | fn default_status_lines() {
  function default_window_base_index (line 106) | fn default_window_base_index() {
  function default_pane_base_index (line 112) | fn default_pane_base_index() {
  function default_history_limit (line 118) | fn default_history_limit() {
  function default_display_time (line 124) | fn default_display_time() {
  function default_display_panes_time (line 130) | fn default_display_panes_time() {
  function default_focus_events (line 136) | fn default_focus_events() {
  function default_mode_keys (line 142) | fn default_mode_keys() {
  function default_word_separators (line 148) | fn default_word_separators() {
  function default_renumber_windows (line 154) | fn default_renumber_windows() {
  function default_automatic_rename (line 160) | fn default_automatic_rename() {
  function default_allow_rename (line 166) | fn default_allow_rename() {
  function default_monitor_activity (line 172) | fn default_monitor_activity() {
  function default_visual_activity (line 178) | fn default_visual_activity() {
  function default_remain_on_exit (line 184) | fn default_remain_on_exit() {
  function default_destroy_unattached (line 190) | fn default_destroy_unattached() {
  function default_exit_empty (line 196) | fn default_exit_empty() {
  function default_aggressive_resize (line 202) | fn default_aggressive_resize() {
  function default_set_titles (line 208) | fn default_set_titles() {
  function default_set_titles_string (line 214) | fn default_set_titles_string() {
  function default_activity_action (line 220) | fn default_activity_action() {
  function default_silence_action (line 226) | fn default_silence_action() {
  function default_bell_action (line 232) | fn default_bell_action() {
  function default_visual_bell (line 238) | fn default_visual_bell() {
  function default_monitor_silence (line 244) | fn default_monitor_silence() {
  function default_scroll_enter_copy_mode (line 250) | fn default_scroll_enter_copy_mode() {
  function default_pwsh_mouse_selection (line 256) | fn default_pwsh_mouse_selection() {
  function default_sync_input (line 262) | fn default_sync_input() {
  function default_pane_border_style (line 268) | fn default_pane_border_style() {
  function default_pane_active_border_style (line 274) | fn default_pane_active_border_style() {
  function default_pane_border_hover_style (line 280) | fn default_pane_border_hover_style() {
  function default_window_status_format (line 286) | fn default_window_status_format() {
  function default_window_status_current_format (line 292) | fn default_window_status_current_format() {
  function default_window_status_separator (line 298) | fn default_window_status_separator() {
  function default_window_status_style (line 304) | fn default_window_status_style() {
  function default_window_status_current_style (line 310) | fn default_window_status_current_style() {
  function default_window_status_activity_style (line 316) | fn default_window_status_activity_style() {
  function default_window_status_bell_style (line 322) | fn default_window_status_bell_style() {
  function default_window_status_last_style (line 328) | fn default_window_status_last_style() {
  function default_message_style (line 334) | fn default_message_style() {
  function default_message_command_style (line 340) | fn default_message_command_style() {
  function default_mode_style (line 346) | fn default_mode_style() {
  function default_status_left_style (line 352) | fn default_status_left_style() {
  function default_status_right_style (line 358) | fn default_status_right_style() {
  function default_main_pane_width (line 364) | fn default_main_pane_width() {
  function default_main_pane_height (line 370) | fn default_main_pane_height() {
  function default_window_size (line 376) | fn default_window_size() {
  function default_allow_passthrough (line 382) | fn default_allow_passthrough() {
  function default_copy_command (line 388) | fn default_copy_command() {
  function default_set_clipboard (line 394) | fn default_set_clipboard() {
  function default_env_shim (line 400) | fn default_env_shim() {
  function default_claude_code_fix_tty (line 406) | fn default_claude_code_fix_tty() {
  function default_claude_code_force_interactive (line 412) | fn default_claude_code_force_interactive() {
  function default_default_shell (line 418) | fn default_default_shell() {
  function default_prediction_dimming (line 424) | fn default_prediction_dimming() {
  function default_allow_predictions (line 432) | fn default_allow_predictions() {
  function default_update_environment (line 438) | fn default_update_environment() {
  function config_file_mouse_on (line 449) | fn config_file_mouse_on() {
  function config_file_mouse_off (line 456) | fn config_file_mouse_off() {
  function config_file_escape_time (line 463) | fn config_file_escape_time() {
  function config_file_status_on (line 470) | fn config_file_status_on() {
  function config_file_status_off (line 477) | fn config_file_status_off() {
  function config_file_status_numeric_0 (line 484) | fn config_file_status_numeric_0() {
  function config_file_status_numeric_2_multi_line (line 491) | fn config_file_status_numeric_2_multi_line() {
  function config_file_status_numeric_5_multi_line (line 499) | fn config_file_status_numeric_5_multi_line() {
  function config_file_status_position_top (line 507) | fn config_file_status_position_top() {
  function config_file_status_position_bottom (line 514) | fn config_file_status_position_bottom() {
  function config_file_status_style (line 521) | fn config_file_status_style() {
  function config_file_status_left (line 528) | fn config_file_status_left() {
  function config_file_status_right (line 535) | fn config_file_status_right() {
  function config_file_status_interval (line 542) | fn config_file_status_interval() {
  function config_file_status_justify_centre (line 549) | fn config_file_status_justify_centre() {
  function config_file_status_justify_right (line 556) | fn config_file_status_justify_right() {
  function config_file_status_left_length (line 563) | fn config_file_status_left_length() {
  function config_file_status_right_length (line 570) | fn config_file_status_right_length() {
  function config_file_status_left_style (line 577) | fn config_file_status_left_style() {
  function config_file_status_right_style (line 584) | fn config_file_status_right_style() {
  function config_file_base_index (line 591) | fn config_file_base_index() {
  function config_file_pane_base_index (line 598) | fn config_file_pane_base_index() {
  function config_file_history_limit (line 605) | fn config_file_history_limit() {
  function config_file_display_time (line 612) | fn config_file_display_time() {
  function config_file_display_panes_time (line 619) | fn config_file_display_panes_time() {
  function config_file_focus_events_on (line 626) | fn config_file_focus_events_on() {
  function config_file_focus_events_off (line 633) | fn config_file_focus_events_off() {
  function config_file_mode_keys_vi (line 641) | fn config_file_mode_keys_vi() {
  function config_file_mode_keys_emacs (line 648) | fn config_file_mode_keys_emacs() {
  function config_file_word_separators (line 655) | fn config_file_word_separators() {
  function config_file_renumber_windows_on (line 662) | fn config_file_renumber_windows_on() {
  function config_file_renumber_windows_off (line 669) | fn config_file_renumber_windows_off() {
  function config_file_automatic_rename_on (line 677) | fn config_file_automatic_rename_on() {
  function config_file_automatic_rename_off (line 684) | fn config_file_automatic_rename_off() {
  function config_file_allow_rename_on (line 691) | fn config_file_allow_rename_on() {
  function config_file_allow_rename_off (line 698) | fn config_file_allow_rename_off() {
  function config_file_monitor_activity_on (line 705) | fn config_file_monitor_activity_on() {
  function config_file_visual_activity_on (line 712) | fn config_file_visual_activity_on() {
  function config_file_remain_on_exit_on (line 719) | fn config_file_remain_on_exit_on() {
  function config_file_destroy_unattached_on (line 726) | fn config_file_destroy_unattached_on() {
  function config_file_exit_empty_off (line 733) | fn config_file_exit_empty_off() {
  function config_file_aggressive_resize_on (line 740) | fn config_file_aggressive_resize_on() {
  function config_file_set_titles_on (line 747) | fn config_file_set_titles_on() {
  function config_file_set_titles_string (line 754) | fn config_file_set_titles_string() {
  function config_file_activity_action (line 761) | fn config_file_activity_action() {
  function config_file_silence_action (line 768) | fn config_file_silence_action() {
  function config_file_bell_action (line 775) | fn config_file_bell_action() {
  function config_file_visual_bell_on (line 782) | fn config_file_visual_bell_on() {
  function config_file_monitor_silence (line 789) | fn config_file_monitor_silence() {
  function config_file_scroll_enter_copy_mode_off (line 796) | fn config_file_scroll_enter_copy_mode_off() {
  function config_file_pwsh_mouse_selection_on (line 803) | fn config_file_pwsh_mouse_selection_on() {
  function config_file_synchronize_panes_on (line 810) | fn config_file_synchronize_panes_on() {
  function config_file_synchronize_panes_off (line 817) | fn config_file_synchronize_panes_off() {
  function config_file_pane_border_style (line 825) | fn config_file_pane_border_style() {
  function config_file_pane_active_border_style (line 832) | fn config_file_pane_active_border_style() {
  function config_file_pane_border_hover_style (line 839) | fn config_file_pane_border_hover_style() {
  function config_file_window_status_format (line 846) | fn config_file_window_status_format() {
  function config_file_window_status_current_format (line 853) | fn config_file_window_status_current_format() {
  function config_file_window_status_separator (line 860) | fn config_file_window_status_separator() {
  function config_file_window_status_style (line 867) | fn config_file_window_status_style() {
  function config_file_window_status_current_style (line 874) | fn config_file_window_status_current_style() {
  function config_file_window_status_activity_style (line 881) | fn config_file_window_status_activity_style() {
  function config_file_window_status_bell_style (line 888) | fn config_file_window_status_bell_style() {
  function config_file_window_status_last_style (line 895) | fn config_file_window_status_last_style() {
  function config_file_message_style (line 902) | fn config_file_message_style() {
  function config_file_message_command_style (line 909) | fn config_file_message_command_style() {
  function config_file_mode_style (line 916) | fn config_file_mode_style() {
  function config_file_main_pane_width (line 923) | fn config_file_main_pane_width() {
  function config_file_main_pane_height (line 930) | fn config_file_main_pane_height() {
  function config_file_window_size (line 937) | fn config_file_window_size() {
  function config_file_allow_passthrough_on (line 944) | fn config_file_allow_passthrough_on() {
  function config_file_allow_passthrough_all (line 951) | fn config_file_allow_passthrough_all() {
  function config_file_copy_command (line 958) | fn config_file_copy_command() {
  function config_file_set_clipboard_external (line 965) | fn config_file_set_clipboard_external() {
  function config_file_set_clipboard_off (line 972) | fn config_file_set_clipboard_off() {
  function config_file_env_shim_off (line 979) | fn config_file_env_shim_off() {
  function config_file_claude_code_fix_tty_off (line 986) | fn config_file_claude_code_fix_tty_off() {
  function config_file_claude_code_force_interactive_off (line 993) | fn config_file_claude_code_force_interactive_off() {
  function config_file_warm_off (line 1000) | fn config_file_warm_off() {
  function config_file_warm_on (line 1007) | fn config_file_warm_on() {
  function config_file_default_shell (line 1015) | fn config_file_default_shell() {
  function config_file_default_command (line 1022) | fn config_file_default_command() {
  function config_file_prediction_dimming_on (line 1029) | fn config_file_prediction_dimming_on() {
  function config_file_dim_predictions_alias (line 1036) | fn config_file_dim_predictions_alias() {
  function config_file_allow_predictions_on (line 1043) | fn config_file_allow_predictions_on() {
  function config_file_update_environment (line 1050) | fn config_file_update_environment() {
  function config_file_default_terminal (line 1057) | fn config_file_default_terminal() {
  function config_file_terminal_overrides_accepted (line 1064) | fn config_file_terminal_overrides_accepted() {
  function config_file_command_alias (line 1072) | fn config_file_command_alias() {
  function config_file_status_format_indexed (line 1079) | fn config_file_status_format_indexed() {
  function config_file_status_format_indexed_1 (line 1086) | fn config_file_status_format_indexed_1() {
  function config_file_user_option_at_prefix (line 1094) | fn config_file_user_option_at_prefix() {
  function config_file_user_option_stored_in_user_options (line 1101) | fn config_file_user_option_stored_in_user_options() {
  function config_file_hyphenated_option_stored_in_user_options (line 1110) | fn config_file_hyphenated_option_stored_in_user_options() {
  function config_file_popup_style_stored_in_user_options (line 1119) | fn config_file_popup_style_stored_in_user_options() {
  function config_file_popup_border_style (line 1126) | fn config_file_popup_border_style() {
  function config_file_popup_border_lines (line 1133) | fn config_file_popup_border_lines() {
  function config_file_window_style (line 1140) | fn config_file_window_style() {
  function config_file_window_active_style (line 1147) | fn config_file_window_active_style() {
  function config_file_wrap_search (line 1154) | fn config_file_wrap_search() {
  function config_file_lock_options (line 1161) | fn config_file_lock_options() {
  function config_file_pane_border_format (line 1168) | fn config_file_pane_border_format() {
  function config_file_pane_border_status (line 1175) | fn config_file_pane_border_status() {
  function config_set_alias (line 1186) | fn config_set_alias() {
  function config_set_option_full (line 1193) | fn config_set_option_full() {
  function config_setw_alias (line 1200) | fn config_setw_alias() {
  function config_set_window_option_full (line 1207) | fn config_set_window_option_full() {
  function config_set_without_g_flag (line 1214) | fn config_set_without_g_flag() {
  function config_flag_g_global (line 1227) | fn config_flag_g_global() {
  function config_flag_u_unset_user_option (line 1234) | fn config_flag_u_unset_user_option() {
  function config_flag_u_unset_numeric_option (line 1242) | fn config_flag_u_unset_numeric_option() {
  function config_flag_u_unset_string_option (line 1251) | fn config_flag_u_unset_string_option() {
  function config_flag_a_append_string (line 1259) | fn config_flag_a_append_string() {
  function config_flag_a_append_user_option (line 1266) | fn config_flag_a_append_user_option() {
  function config_flag_q_quiet (line 1273) | fn config_flag_q_quiet() {
  function config_flag_o_only_if_unset_already_set (line 1282) | fn config_flag_o_only_if_unset_already_set() {
  function config_flag_o_only_if_unset_not_set (line 1290) | fn config_flag_o_only_if_unset_not_set() {
  function config_flag_o_does_not_overwrite (line 1298) | fn config_flag_o_does_not_overwrite() {
  function config_flag_w_window_scope (line 1306) | fn config_flag_w_window_scope() {
  function config_flag_F_format_expand (line 1314) | fn config_flag_F_format_expand() {
  function config_combined_flags_gu (line 1322) | fn config_combined_flags_gu() {
  function config_combined_flags_ga (line 1329) | fn config_combined_flags_ga() {
  function config_combined_flags_go (line 1336) | fn config_combined_flags_go() {
  function config_flag_t_target_consumed (line 1343) | fn config_flag_t_target_consumed() {
  function cli_set_mouse (line 1355) | fn cli_set_mouse() {
  function cli_set_escape_time (line 1362) | fn cli_set_escape_time() {
  function cli_set_status_off (line 1369) | fn cli_set_status_off() {
  function cli_set_status_position (line 1376) | fn cli_set_status_position() {
  function cli_set_status_style (line 1383) | fn cli_set_status_style() {
  function cli_set_base_index (line 1390) | fn cli_set_base_index() {
  function cli_set_history_limit (line 1397) | fn cli_set_history_limit() {
  function cli_set_focus_events (line 1404) | fn cli_set_focus_events() {
  function cli_set_mode_keys (line 1411) | fn cli_set_mode_keys() {
  function cli_set_renumber_windows (line 1418) | fn cli_set_renumber_windows() {
  function cli_set_pane_border_style (line 1425) | fn cli_set_pane_border_style() {
  function cli_set_window_status_format (line 1432) | fn cli_set_window_status_format() {
  function cli_set_message_style (line 1439) | fn cli_set_message_style() {
  function cli_set_mode_style (line 1446) | fn cli_set_mode_style() {
  function cli_set_status_interval (line 1453) | fn cli_set_status_interval() {
  function cli_set_status_justify (line 1460) | fn cli_set_status_justify() {
  function cli_set_main_pane_width (line 1467) | fn cli_set_main_pane_width() {
  function cli_set_main_pane_height (line 1474) | fn cli_set_main_pane_height() {
  function cli_set_display_time (line 1481) | fn cli_set_display_time() {
  function cli_set_window_size (line 1488) | fn cli_set_window_size() {
  function cli_set_copy_command (line 1495) | fn cli_set_copy_command() {
  function cli_set_allow_passthrough (line 1502) | fn cli_set_allow_passthrough() {
  function cli_set_command_alias (line 1509) | fn cli_set_command_alias() {
  function cli_set_env_shim (line 1516) | fn cli_set_env_shim() {
  function cli_set_warm (line 1523) | fn cli_set_warm() {
  function cli_set_user_option (line 1530) | fn cli_set_user_option() {
  function direct_set_mouse (line 1541) | fn direct_set_mouse() {
  function direct_set_escape_time (line 1548) | fn direct_set_escape_time() {
  function direct_set_status (line 1555) | fn direct_set_status() {
  function direct_bind_key (line 1562) | fn direct_bind_key() {
  function direct_unbind_key (line 1570) | fn direct_unbind_key() {
  function direct_set_hook (line 1580) | fn direct_set_hook() {
  function direct_set_environment (line 1587) | fn direct_set_environment() {
  function direct_setenv_alias (line 1594) | fn direct_setenv_alias() {
  function config_skips_comments (line 1607) | fn config_skips_comments() {
  function config_skips_empty_lines (line 1614) | fn config_skips_empty_lines() {
  function config_comment_after_not_parsed (line 1621) | fn config_comment_after_not_parsed() {
  function config_continuation_line_basic (line 1631) | fn config_continuation_line_basic() {
  function config_continuation_line_bind (line 1638) | fn config_continuation_line_bind() {
  function config_continuation_line_three_lines (line 1646) | fn config_continuation_line_three_lines() {
  function config_continuation_at_eof (line 1653) | fn config_continuation_at_eof() {
  function config_if_true_executes (line 1663) | fn config_if_true_executes() {
  function config_if_false_skips (line 1672) | fn config_if_false_skips() {
  function config_if_empty_is_false (line 1681) | fn config_if_empty_is_false() {
  function config_if_else_true_branch (line 1688) | fn config_if_else_true_branch() {
  function config_if_else_false_branch (line 1695) | fn config_if_else_false_branch() {
  function config_elif_first_true (line 1702) | fn config_elif_first_true() {
  function config_elif_second_true (line 1709) | fn config_elif_second_true() {
  function config_elif_else_branch (line 1716) | fn config_elif_else_branch() {
  function config_nested_if (line 1723) | fn config_nested_if() {
  function config_nested_if_outer_false (line 1730) | fn config_nested_if_outer_false() {
  function config_nested_if_inner_false (line 1738) | fn config_nested_if_inner_false() {
  function config_if_with_format_condition (line 1745) | fn config_if_with_format_condition() {
  function config_if_after_endif_still_active (line 1754) | fn config_if_after_endif_still_active() {
  function config_hidden_basic (line 1764) | fn config_hidden_basic() {
  function config_hidden_in_environment (line 1771) | fn config_hidden_in_environment() {
  function config_hidden_dollar_brace_syntax (line 1778) | fn config_hidden_dollar_brace_syntax() {
  function config_hidden_multiple_vars (line 1785) | fn config_hidden_multiple_vars() {
  function config_hidden_undefined_var_literal (line 1792) | fn config_hidden_undefined_var_literal() {
  function config_hidden_inside_if_false (line 1800) | fn config_hidden_inside_if_false() {
  function config_hidden_inside_if_true (line 1808) | fn config_hidden_inside_if_true() {
  function config_hidden_quoted_value (line 1815) | fn config_hidden_quoted_value() {
  function config_utf8_bom_stripped (line 1824) | fn config_utf8_bom_stripped() {
  function config_utf8_bom_first_line_works (line 1831) | fn config_utf8_bom_first_line_works() {
  function config_bind_key_basic (line 1840) | fn config_bind_key_basic() {
  function config_bind_alias (line 1848) | fn config_bind_alias() {
  function config_bind_n_root_table (line 1856) | fn config_bind_n_root_table() {
  function config_bind_T_custom_table (line 1864) | fn config_bind_T_custom_table() {
  function config_bind_r_repeat (line 1872) | fn config_bind_r_repeat() {
  function config_bind_command_chain (line 1881) | fn config_bind_command_chain() {
  function config_bind_ctrl_modifier (line 1895) | fn config_bind_ctrl_modifier() {
  function config_bind_alt_modifier (line 1906) | fn config_bind_alt_modifier() {
  function config_unbind_specific_key (line 1919) | fn config_unbind_specific_key() {
  function config_unbind_all (line 1928) | fn config_unbind_all() {
  function config_unbind_n_root (line 1935) | fn config_unbind_n_root() {
  function config_set_hook_basic (line 1945) | fn config_set_hook_basic() {
  function config_set_hook_append (line 1953) | fn config_set_hook_append() {
  function config_set_hook_unset (line 1960) | fn config_set_hook_unset() {
  function config_set_hook_replace_no_duplicates (line 1967) | fn config_set_hook_replace_no_duplicates() {
  function config_set_environment_basic (line 1978) | fn config_set_environment_basic() {
  function config_setenv_alias (line 1985) | fn config_setenv_alias() {
  function config_set_environment_with_flags (line 1992) | fn config_set_environment_with_flags() {
  function config_source_file_via_config_line (line 2001) | fn config_source_file_via_config_line() {
  function config_source_alias (line 2010) | fn config_source_alias() {
  function config_run_shell_recognized (line 2019) | fn config_run_shell_recognized() {
  function config_run_alias (line 2027) | fn config_run_alias() {
  function config_if_shell_recognized (line 2036) | fn config_if_shell_recognized() {
  function config_realistic_minimal (line 2049) | fn config_realistic_minimal() {
  function config_realistic_with_bindings (line 2070) | fn config_realistic_with_bindings() {
  function config_realistic_with_styles (line 2095) | fn config_realistic_with_styles() {
  function config_realistic_with_conditionals (line 2117) | fn config_realistic_with_conditionals() {
  function config_realistic_plugin_option (line 2134) | fn config_realistic_plugin_option() {
  function config_realistic_with_continuations (line 2151) | fn config_realistic_with_continuations() {
  function config_empty_content (line 2163) | fn config_empty_content() {
  function config_only_comments (line 2171) | fn config_only_comments() {
  function config_only_whitespace (line 2179) | fn config_only_whitespace() {
  function config_duplicate_option_last_wins (line 2186) | fn config_duplicate_option_last_wins() {
  function config_invalid_numeric_ignored (line 2193) | fn config_invalid_numeric_ignored() {
  function config_boolean_true_variants (line 2201) | fn config_boolean_true_variants() {
  function config_boolean_false_variants (line 2217) | fn config_boolean_false_variants() {
  function config_quoted_value_double (line 2232) | fn config_quoted_value_double() {
  function config_quoted_value_single (line 2239) | fn config_quoted_value_single() {
  function config_unquoted_value (line 2246) | fn config_unquoted_value() {
  function config_prefix_c_a (line 2253) | fn config_prefix_c_a() {
  function config_prefix2 (line 2261) | fn config_prefix2() {
  function config_prefix2_none (line 2270) | fn config_prefix2_none() {
  function config_status_format_0_and_1 (line 2278) | fn config_status_format_0_and_1() {
  function config_multiple_command_aliases (line 2286) | fn config_multiple_command_aliases() {
  function config_cursor_style_sets_env (line 2298) | fn config_cursor_style_sets_env() {
  function config_cursor_blink_on (line 2308) | fn config_cursor_blink_on() {
  function config_cursor_blink_off (line 2317) | fn config_cursor_blink_off() {
  function cross_channel_mouse_config_vs_cli (line 2330) | fn cross_channel_mouse_config_vs_cli() {
  function cross_channel_escape_time_all_paths (line 2349) | fn cross_channel_escape_time_all_paths() {
  function cross_channel_status_style_all_paths (line 2365) | fn cross_channel_status_style_all_paths() {
  function cross_channel_base_index_all_paths (line 2381) | fn cross_channel_base_index_all_paths() {
  function cross_channel_focus_events_all_paths (line 2397) | fn cross_channel_focus_events_all_paths() {
  function cross_channel_user_option_all_paths (line 2413) | fn cross_channel_user_option_all_paths() {
  function cross_channel_pane_border_style_all_paths (line 2429) | fn cross_channel_pane_border_style_all_paths() {
  function cross_channel_window_status_format_all_paths (line 2445) | fn cross_channel_window_status_format_all_paths() {
  function cross_channel_bind_key_all_paths (line 2461) | fn cross_channel_bind_key_all_paths() {
  function cross_channel_hook_all_paths (line 2481) | fn cross_channel_hook_all_paths() {
  function flag_append_via_config (line 2501) | fn flag_append_via_config() {
  function flag_append_via_cli (line 2508) | fn flag_append_via_cli() {
  function flag_unset_then_set_via_config (line 2516) | fn flag_unset_then_set_via_config() {
  function flag_format_via_config (line 2523) | fn flag_format_via_config() {
  function flag_format_via_cli (line 2531) | fn flag_format_via_cli() {
  function flag_only_if_unset_via_config (line 2539) | fn flag_only_if_unset_via_config() {
  function flag_only_if_unset_via_cli (line 2546) | fn flag_only_if_unset_via_cli() {

FILE: tests-rs/test_config_plugin_paths.rs
  function mock_app (line 10) | fn mock
Condensed preview — 576 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (8,885K chars).
[
  {
    "path": ".cargo/config.toml",
    "chars": 355,
    "preview": "[alias]\nlint = \"clippy -- -D warnings\"\n\n# Statically link the C runtime so binaries don't need vcruntime140.dll\n[target."
  },
  {
    "path": ".github/ASSETS.md",
    "chars": 1414,
    "preview": "# Repository Assets\n\n## Social Card Setup\n\nTo enable the social card on GitHub:\n\n1. **Convert SVG to PNG** (if not alrea"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 810,
    "preview": "name: CI\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n  workflow_dispatch:\n\npe"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 28658,
    "preview": "name: Release\n\non:\n  workflow_dispatch:\n    inputs:\n      tag:\n        description: 'Release tag to publish (e.g. v3.3.3"
  },
  {
    "path": ".gitignore",
    "chars": 902,
    "preview": "# Build artifacts\ntarget/\n\n# Backup and temp files\n*.rs.bk\n*.swp\n*.tmp\n~*\n\n# IDE/editor\n.vscode/\n.idea/\n*.code-workspace"
  },
  {
    "path": "Cargo.toml",
    "chars": 2199,
    "preview": "[package]\nname = \"psmux\"\nversion = \"3.3.4\"\nedition = \"2021\"\ndescription = \"Terminal multiplexer for Windows - tmux alter"
  },
  {
    "path": "LICENSE",
    "chars": 1061,
    "preview": "MIT License\n\nCopyright (c) 2025 Josh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
  },
  {
    "path": "README.md",
    "chars": 7583,
    "preview": "```\n╔═══════════════════════════════════════════════════════════╗\n║   ██████╗ ███████╗███╗   ███╗██╗   ██╗██╗  ██╗      "
  },
  {
    "path": "choco-pkg/psmux.nuspec",
    "chars": 1173,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd\">\n  <me"
  },
  {
    "path": "choco-pkg/tools/chocolateyinstall.ps1",
    "chars": 748,
    "preview": "$ErrorActionPreference = 'Stop'\n\n$toolsDir = \"$(Split-Path -Parent $MyInvocation.MyCommand.Definition)\"\n$url64 = 'https:"
  },
  {
    "path": "choco-pkg/tools/chocolateyuninstall.ps1",
    "chars": 93,
    "preview": "Uninstall-BinFile -Name \"psmux\"\nUninstall-BinFile -Name \"pmux\"\nUninstall-BinFile -Name \"tmux\""
  },
  {
    "path": "crates/portable-pty-psmux/.cargo-ok",
    "chars": 7,
    "preview": "{\"v\":1}"
  },
  {
    "path": "crates/portable-pty-psmux/.cargo_vcs_info.json",
    "chars": 94,
    "preview": "{\n  \"git\": {\n    \"sha1\": \"d389cf717cdb7702c9a732d1d9bc0b6f08603b4a\"\n  },\n  \"path_in_vcs\": \"\"\n}"
  },
  {
    "path": "crates/portable-pty-psmux/Cargo.toml",
    "chars": 2392,
    "preview": "# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n#\n# When uploading crates to the registry Cargo will automatically\n# \"no"
  },
  {
    "path": "crates/portable-pty-psmux/Cargo.toml.orig",
    "chars": 2437,
    "preview": "# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n#\n# When uploading crates to the registry Cargo will automatically\n# \"no"
  },
  {
    "path": "crates/portable-pty-psmux/LICENSE.md",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2018 Wez Furlong\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "crates/portable-pty-psmux/README.md",
    "chars": 1982,
    "preview": "# portable-pty-patched\n\nPatched version of [portable-pty](https://crates.io/crates/portable-pty) v0.9.0 (originally from"
  },
  {
    "path": "crates/portable-pty-psmux/examples/bash.rs",
    "chars": 2492,
    "preview": "//! This example demonstrates how to spawn a Bash shell using the `portable_pty` crate.\n//! based on pty/examples/whoami"
  },
  {
    "path": "crates/portable-pty-psmux/examples/narrow.rs",
    "chars": 3305,
    "preview": "//! Runs a command with a fixed terminal size.\n//! This is used by wezterm's doc building automation to keep\n//! the --h"
  },
  {
    "path": "crates/portable-pty-psmux/examples/whoami.rs",
    "chars": 3587,
    "preview": "//! This is a conceptually simple example that spawns the `whoami` program\n//! to print your username.  It is made more "
  },
  {
    "path": "crates/portable-pty-psmux/examples/whoami_async.rs",
    "chars": 2529,
    "preview": "use anyhow::anyhow;\nuse futures::prelude::*;\nuse portable_pty::{native_pty_system, CommandBuilder, PtySize};\n\n// This ex"
  },
  {
    "path": "crates/portable-pty-psmux/src/cmdbuilder.rs",
    "chars": 25252,
    "preview": "#[cfg(unix)]\nuse anyhow::Context;\n#[cfg(feature = \"serde_support\")]\nuse serde_derive::*;\nuse std::collections::BTreeMap;"
  },
  {
    "path": "crates/portable-pty-psmux/src/lib.rs",
    "chars": 13378,
    "preview": "//! This crate provides a cross platform API for working with the\n//! psuedo terminal (pty) interfaces provided by the s"
  },
  {
    "path": "crates/portable-pty-psmux/src/serial.rs",
    "chars": 9219,
    "preview": "//! This module implements a serial port based tty.\n//! This is a bit different from the other implementations in that\n/"
  },
  {
    "path": "crates/portable-pty-psmux/src/unix.rs",
    "chars": 12978,
    "preview": "//! Working with pseudo-terminals\n\nuse crate::{Child, CommandBuilder, MasterPty, PtyPair, PtySize, PtySystem, SlavePty};"
  },
  {
    "path": "crates/portable-pty-psmux/src/win/conpty.rs",
    "chars": 6876,
    "preview": "use crate::cmdbuilder::CommandBuilder;\nuse crate::win::psuedocon::PsuedoCon;\nuse crate::{Child, MasterPty, PtyPair, PtyS"
  },
  {
    "path": "crates/portable-pty-psmux/src/win/mod.rs",
    "chars": 4398,
    "preview": "use crate::{Child, ChildKiller, ExitStatus};\nuse anyhow::Context as _;\nuse std::io::{Error as IoError, Result as IoResul"
  },
  {
    "path": "crates/portable-pty-psmux/src/win/procthreadattr.rs",
    "chars": 2183,
    "preview": "use crate::win::psuedocon::HPCON;\nuse anyhow::{ensure, Error};\nuse std::io::Error as IoError;\nuse std::{mem, ptr};\nuse w"
  },
  {
    "path": "crates/portable-pty-psmux/src/win/psuedocon.rs",
    "chars": 10515,
    "preview": "use super::WinChild;\nuse crate::cmdbuilder::CommandBuilder;\nuse crate::win::procthreadattr::ProcThreadAttributeList;\nuse"
  },
  {
    "path": "crates/vt100-psmux/.cargo-ok",
    "chars": 7,
    "preview": "{\"v\":1}"
  },
  {
    "path": "crates/vt100-psmux/.cargo_vcs_info.json",
    "chars": 94,
    "preview": "{\n  \"git\": {\n    \"sha1\": \"e79e0d68ab3875f045bc3cc3120907a0e5b3bb0f\"\n  },\n  \"path_in_vcs\": \"\"\n}"
  },
  {
    "path": "crates/vt100-psmux/CHANGELOG.md",
    "chars": 11182,
    "preview": "# Changelog\n\n## [0.16.2] - 2025-07-11\n\n### Fixed\n\n* Fixed potential cursor out of bounds when using decrc after resizing"
  },
  {
    "path": "crates/vt100-psmux/Cargo.toml",
    "chars": 1664,
    "preview": "# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n#\n# When uploading crates to the registry Cargo will automatically\n# \"no"
  },
  {
    "path": "crates/vt100-psmux/Cargo.toml.orig",
    "chars": 838,
    "preview": "[package]\nname = \"vt100-psmux\"\nversion = \"0.16.2\"\nauthors = [\"Jesse Luehrs <doy@tozt.net>\"]\nedition = \"2021\"\nrust-versio"
  },
  {
    "path": "crates/vt100-psmux/LICENSE",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Jesse Luehrs\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "crates/vt100-psmux/README.md",
    "chars": 1050,
    "preview": "# vt100\n\nThis crate parses a terminal byte stream and provides an in-memory\nrepresentation of the rendered contents.\n\n##"
  },
  {
    "path": "crates/vt100-psmux/src/attrs.rs",
    "chars": 5121,
    "preview": "use crate::term::BufWrite as _;\n\n/// Represents a foreground or background color for cells.\n#[derive(Eq, PartialEq, Debu"
  },
  {
    "path": "crates/vt100-psmux/src/callbacks.rs",
    "chars": 3256,
    "preview": "/// This trait is used by the parser to handle extra escape sequences that\n/// don't have an impact on the terminal scre"
  },
  {
    "path": "crates/vt100-psmux/src/cell.rs",
    "chars": 5512,
    "preview": "use unicode_width::UnicodeWidthChar as _;\n\n// chosen to make the size of the cell struct 32 bytes\nconst CONTENT_BYTES: u"
  },
  {
    "path": "crates/vt100-psmux/src/grid.rs",
    "chars": 27302,
    "preview": "use crate::term::BufWrite as _;\n\n#[derive(Clone, Debug)]\npub struct Grid {\n    size: Size,\n    pos: Pos,\n    saved_pos: "
  },
  {
    "path": "crates/vt100-psmux/src/lib.rs",
    "chars": 1953,
    "preview": "#![allow(dead_code)]\n//! This crate parses a terminal byte stream and provides an in-memory\n//! representation of the re"
  },
  {
    "path": "crates/vt100-psmux/src/parser.rs",
    "chars": 2824,
    "preview": "/// A parser for terminal output which produces an in-memory representation of\n/// the terminal contents.\npub struct Par"
  },
  {
    "path": "crates/vt100-psmux/src/perform.rs",
    "chars": 11992,
    "preview": "const BASE64: &[u8] =\n    b\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\nconst CLIPBOARD_SELECTOR"
  },
  {
    "path": "crates/vt100-psmux/src/row.rs",
    "chars": 17208,
    "preview": "use crate::term::BufWrite as _;\n\n#[derive(Clone, Debug)]\npub struct Row {\n    cells: Vec<crate::Cell>,\n    wrapped: bool"
  },
  {
    "path": "crates/vt100-psmux/src/screen.rs",
    "chars": 57031,
    "preview": "use crate::term::BufWrite as _;\nuse unicode_width::UnicodeWidthChar as _;\n\n/// Parse an OSC 7 URI into a filesystem path"
  },
  {
    "path": "crates/vt100-psmux/src/term.rs",
    "chars": 15137,
    "preview": "// TODO: read all of this from terminfo\n\npub trait BufWrite {\n    fn write_buf(&self, buf: &mut Vec<u8>);\n}\n\n#[derive(De"
  },
  {
    "path": "docker/Dockerfile",
    "chars": 1280,
    "preview": "# escape=`\n# psmux build environment: Windows + Rust (MSVC) + OpenSSH (key-only auth)\n#\n# Build:  docker build -t psmux-"
  },
  {
    "path": "docker/Profile/Microsoft.PowerShell_profile.ps1",
    "chars": 567,
    "preview": "$ErrorActionPreference = \"Continue\"\n\n# Ensure Cargo bin is on PATH\nif ($env:CARGO_HOME -and (Test-Path \"$env:CARGO_HOME\\"
  },
  {
    "path": "docker/README.md",
    "chars": 3163,
    "preview": "# psmux Docker Dev Environment\n\nA Windows container with Rust (MSVC), Visual Studio Build Tools, and OpenSSH — ready to "
  },
  {
    "path": "docker/Run-PsmuxDev.ps1",
    "chars": 3809,
    "preview": "<#\n.SYNOPSIS\n    Build (if needed) and run the psmux-dev Docker container with SSH key auth.\n\n.DESCRIPTION\n    - Generat"
  },
  {
    "path": "docker/Tools/ImportVsDevEnv.ps1",
    "chars": 412,
    "preview": "param(\n  [string]$VsInstallPath = $env:VS_INSTALL_PATH\n)\n\n$ErrorActionPreference = \"Stop\"\n\n$vsDevCmd = Join-Path $VsInst"
  },
  {
    "path": "docker/Tools/InstallAll.ps1",
    "chars": 5111,
    "preview": "$ErrorActionPreference = \"Continue\"\n\n# ============================================\n# 0. Download everything first (befo"
  },
  {
    "path": "docker/Tools/InstallGit.ps1",
    "chars": 498,
    "preview": "$ErrorActionPreference = \"Stop\"\n\n$url = \"https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.2/MinG"
  },
  {
    "path": "docker/Tools/InstallOpenSSH.ps1",
    "chars": 884,
    "preview": "$ErrorActionPreference = \"Stop\"\n\n$url = \"https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.8.3.0p2-Previe"
  },
  {
    "path": "docker/Tools/InstallRust.ps1",
    "chars": 439,
    "preview": "$ErrorActionPreference = \"Stop\"\n\nWrite-Host \"Downloading rustup...\"\nInvoke-WebRequest https://win.rustup.rs -OutFile C:\\"
  },
  {
    "path": "docker/Tools/InstallVsBuildTools.ps1",
    "chars": 1861,
    "preview": "$ErrorActionPreference = \"Stop\"\n\n$installPath = \"C:\\BuildTools\"\n$logFile     = \"C:\\vsbuildtools-install.log\"\n\nWrite-Host"
  },
  {
    "path": "docker/Tools/StartContainer.ps1",
    "chars": 4533,
    "preview": "$ErrorActionPreference = \"Stop\"\n\n$opensshDir   = \"C:\\OpenSSH\"\n$sshdConfig   = \"C:\\ProgramData\\ssh\\sshd_config\"\n$adminKey"
  },
  {
    "path": "docs/claude-code.md",
    "chars": 9828,
    "preview": "# Claude Code Agent Teams\n\npsmux has first-class support for [Claude Code](https://docs.anthropic.com/en/docs/claude-cod"
  },
  {
    "path": "docs/compatibility.md",
    "chars": 17106,
    "preview": "# tmux Compatibility\n\npsmux is the most tmux-compatible terminal multiplexer on Windows.\n\n## Overview\n\n| Feature | Suppo"
  },
  {
    "path": "docs/configuration.md",
    "chars": 25061,
    "preview": "# Configuration\n\npsmux reads its config on startup from the **first file found** (in order):\n\n1. `~/.psmux.conf`\n2. `~/."
  },
  {
    "path": "docs/control-mode.md",
    "chars": 15109,
    "preview": "# Control Mode\n\nControl mode lets external programs drive psmux programmatically over a structured text protocol. Instea"
  },
  {
    "path": "docs/faq.md",
    "chars": 14337,
    "preview": "# FAQ\n\n**Q: Is psmux cross-platform?**\nA: No. psmux is built exclusively for Windows using the Windows ConPTY API. For L"
  },
  {
    "path": "docs/features.md",
    "chars": 10861,
    "preview": "# Features\n\n## Highlights\n\n- 🦠 **Made in Rust** : opt-level 3, full LTO, single codegen unit. Maximum performance.\n- 🖱️ "
  },
  {
    "path": "docs/integration.md",
    "chars": 17076,
    "preview": "# Developer Integration Guide\n\nThis guide is for developers who want to build tools, scripts, IDE extensions, or automat"
  },
  {
    "path": "docs/iterm2-control-mode.md",
    "chars": 9228,
    "preview": "# Using psmux with iTerm2 (`tmux -CC` integration)\n\niTerm2's [tmux integration](https://iterm2.com/documentation-tmux-in"
  },
  {
    "path": "docs/keybindings.md",
    "chars": 11574,
    "preview": "# Key Bindings\n\nDefault prefix: `Ctrl+b` (same as tmux). Change with `set -g prefix C-a`.\n\nSupported prefix keys include"
  },
  {
    "path": "docs/mouse-ssh.md",
    "chars": 1480,
    "preview": "# Mouse Over SSH\n\npsmux has **first-class mouse support over SSH** when the server runs **Windows 11 build 22523+ (22H2+"
  },
  {
    "path": "docs/multi-shell.md",
    "chars": 7226,
    "preview": "# Multi-Shell Workflows\n\npsmux lets you run **any combination of shells** side by side in the same session.\nPowerShell, "
  },
  {
    "path": "docs/pane-titles.md",
    "chars": 7454,
    "preview": "# Pane Titles and OSC Escape Sequences\n\n## How Pane Titles Work\n\nEvery pane in psmux has a **title**. By default this is"
  },
  {
    "path": "docs/performance.md",
    "chars": 1588,
    "preview": "# Performance\n\npsmux is built for speed. The Rust release binary is compiled with **opt-level 3**, **full LTO**, and **s"
  },
  {
    "path": "docs/plugins.md",
    "chars": 3716,
    "preview": "# Plugins & Themes\n\npsmux has a full plugin ecosystem — ports of the most popular tmux plugins, reimplemented in PowerSh"
  },
  {
    "path": "docs/preview.md",
    "chars": 9268,
    "preview": "# Live Preview in Choosers\n\nThe `choose-session` and `choose-tree` pickers in psmux include a live preview pane that sho"
  },
  {
    "path": "docs/scripting.md",
    "chars": 17634,
    "preview": "# Scripting & Automation\n\npsmux supports tmux-compatible commands for scripting and automation.\n\n## Window & Pane Contro"
  },
  {
    "path": "docs/tmux_args_reference.md",
    "chars": 18404,
    "preview": "\n## Complete Command Table\n\n| Command | Alias | Args Template | Min | Max | Source File |\n|---|---|---|---|---|---|\n| `a"
  },
  {
    "path": "docs/warm-sessions.md",
    "chars": 2911,
    "preview": "# Warm Sessions\n\npsmux uses a background **warm session** (`__warm__`) to make new session creation nearly instant. This"
  },
  {
    "path": "examples/crossterm_sgr_diag.rs",
    "chars": 2583,
    "preview": "/// Diagnostic: verify what crossterm emits for CROSSED_OUT, HIDDEN modifiers.\n/// Run with: cargo run --example crosste"
  },
  {
    "path": "examples/enter_diag.rs",
    "chars": 2373,
    "preview": "/// Diagnostic tool: dumps ALL raw crossterm events (Press, Release, Repeat)\n/// for Enter and modified-Enter to prove w"
  },
  {
    "path": "examples/key_diag.rs",
    "chars": 2989,
    "preview": "// Diagnostic for issue #226: dump every key event crossterm produces,\n// plus the raw INPUT_RECORD as seen by ReadConso"
  },
  {
    "path": "examples/key_test.rs",
    "chars": 932,
    "preview": "use crossterm::event::{self, Event, KeyCode, KeyModifiers, KeyEventKind};\nuse crossterm::terminal::{enable_raw_mode, dis"
  },
  {
    "path": "examples/latency_harness.rs",
    "chars": 14211,
    "preview": "// examples/latency_harness.rs\n//\n// ConPTY-based latency harness for psmux.\n//\n// This is the most accurate test possib"
  },
  {
    "path": "examples/pipeline_diag.rs",
    "chars": 12521,
    "preview": "// Diagnostic: replicate the EXACT psmux rendering pipeline end-to-end\n// and verify whether strikethrough (SGR 9) actua"
  },
  {
    "path": "examples/pty_diag.rs",
    "chars": 4946,
    "preview": "use portable_pty::{native_pty_system, PtySize, CommandBuilder};\nuse std::io::{Read, Write};\n\nfn read_output(reader: &mut"
  },
  {
    "path": "examples/pty_sgr_diag.rs",
    "chars": 5132,
    "preview": "/// Diagnostic: verify which SGR attributes survive ConPTY passthrough mode.\n/// Run with: cargo run --example pty_sgr_d"
  },
  {
    "path": "examples/ratatui_render_diag.rs",
    "chars": 4617,
    "preview": "/// Diagnostic: verify ratatui crossterm backend emits correct SGR for all modifiers.\n/// Run with: cargo run --example "
  },
  {
    "path": "examples/test_cursor_debug.rs",
    "chars": 2572,
    "preview": "use vt100::Parser;\n\nfn main() {\n    // Test: what happens when we process \"\\x1b[?25l\" (hide cursor) after RMCUP\n    let "
  },
  {
    "path": "installer/psmux.nsi",
    "chars": 5619,
    "preview": "; psmux NSIS Installer Script\n; Builds a self-extracting installer that:\n;   1. Kills running psmux servers before insta"
  },
  {
    "path": "packages/chocolatey/psmux.nuspec",
    "chars": 1259,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd\">\n  <me"
  },
  {
    "path": "packages/chocolatey/tools/chocolateyinstall.ps1",
    "chars": 1591,
    "preview": "# ============================================================================\n# TEMPLATE ONLY - DO NOT PUSH THIS FILE D"
  },
  {
    "path": "packages/chocolatey/tools/chocolateyuninstall.ps1",
    "chars": 94,
    "preview": "Uninstall-BinFile -Name \"psmux\"\nUninstall-BinFile -Name \"pmux\"\nUninstall-BinFile -Name \"tmux\"\n"
  },
  {
    "path": "psmux.json",
    "chars": 1444,
    "preview": "{\n    \"version\": \"0.4.6\",\n    \"description\": \"Terminal multiplexer for Windows - tmux alternative for PowerShell and Win"
  },
  {
    "path": "rust-toolchain.toml",
    "chars": 35,
    "preview": "[toolchain]\ncomponents = [\"clippy\"]"
  },
  {
    "path": "scoop/psmux.json",
    "chars": 1554,
    "preview": "{\n    \"version\": \"0.4.9\",\n    \"description\": \"Terminal multiplexer for Windows - tmux alternative for PowerShell and Win"
  },
  {
    "path": "scripts/build.ps1",
    "chars": 5542,
    "preview": "# scripts/build.ps1 — Build psmux + NSIS installer\n# Usage:\n#   .\\scripts\\build.ps1              # full build: cargo ins"
  },
  {
    "path": "scripts/install.ps1",
    "chars": 5573,
    "preview": "# psmux installation script for Windows\n# Run as: irm https://raw.githubusercontent.com/psmux/psmux/master/scripts/insta"
  },
  {
    "path": "scripts/pmux-title.ps1",
    "chars": 684,
    "preview": "param()\n\nfunction Update-PmuxPaneTitle {\n    try {\n        $cwdLeaf = Split-Path -Leaf (Get-Location)\n        $lastCmd ="
  },
  {
    "path": "scripts/pmux-title.sh",
    "chars": 689,
    "preview": "#!/usr/bin/env bash\n\n# Update pmux pane title from bash prompt using cwd and last command.\n# Usage:\n#   source /path/to/"
  },
  {
    "path": "scripts/publish-choco.ps1",
    "chars": 6516,
    "preview": "<#\n.SYNOPSIS\n    Build and publish the psmux Chocolatey package with the correct SHA256 checksum.\n\n.DESCRIPTION\n    This"
  },
  {
    "path": "scripts/uninstall.ps1",
    "chars": 1879,
    "preview": "# psmux uninstall script for Windows\n\nparam(\n    [string]$InstallDir = \"$env:LOCALAPPDATA\\psmux\"\n)\n\n$ErrorActionPreferen"
  },
  {
    "path": "src/cli.rs",
    "chars": 30852,
    "preview": "use crate::types::{ParsedTarget, VERSION};\n\n/// Normalize `-x=VALUE` short-flag forms into `[\"-x\", \"VALUE\"]`.\n///\n/// tm"
  },
  {
    "path": "src/client.rs",
    "chars": 327994,
    "preview": "use std::io::{self, Write, BufRead, BufReader};\nuse std::time::{Duration, Instant};\nuse std::env;\n\nuse chrono::Local;\nus"
  },
  {
    "path": "src/clipboard.rs",
    "chars": 6043,
    "preview": "//! Windows system clipboard read/write.\n//!\n//! The Win32 clipboard helpers live in their own module so that any code\n/"
  },
  {
    "path": "src/commands.rs",
    "chars": 114275,
    "preview": "use std::io;\nuse std::time::Instant;\n#[cfg(windows)]\nuse std::path::PathBuf;\n\nuse std::io::Write;\nuse crate::types::{App"
  },
  {
    "path": "src/config.rs",
    "chars": 70357,
    "preview": "use std::env;\nuse std::cell::RefCell;\nuse crossterm::event::{KeyCode, KeyModifiers};\n\nuse crate::types::{AppState, Actio"
  },
  {
    "path": "src/control.rs",
    "chars": 21242,
    "preview": "use crate::types::{AppState, ControlNotification, Node, LayoutKind, Window};\nuse ratatui::layout::Rect;\n\n/// Compute tmu"
  },
  {
    "path": "src/copy_mode.rs",
    "chars": 56488,
    "preview": "use std::io::{self, Write};\n\nuse crate::clipboard::copy_to_system_clipboard;\nuse crate::types::{AppState, Mode, CopyMode"
  },
  {
    "path": "src/cross_session.rs",
    "chars": 6298,
    "preview": "//! Cross-session pane transfer orchestration.\n//!\n//! Coordinates moving a pane between two session servers via a TCP I"
  },
  {
    "path": "src/cross_session_server.rs",
    "chars": 10256,
    "preview": "//! Server-side handlers for cross-session pane forwarding.\n//!\n//! Extracted into its own module to keep server/mod.rs "
  },
  {
    "path": "src/debug_log.rs",
    "chars": 8788,
    "preview": "//! Centralized debug logging for psmux.\n//!\n//! All logs write to `~/.psmux/` and are gated by environment variables.\n/"
  },
  {
    "path": "src/format.rs",
    "chars": 79211,
    "preview": "// format.rs — tmux-compatible format expansion engine\n//\n// Supports: variables, #{?cond,t,f}, #{==:a,b}, #{!=:a,b}, #{"
  },
  {
    "path": "src/help.rs",
    "chars": 24068,
    "preview": "// ── src/help.rs ───────────────────────────────────────────────────────\n// Comprehensive help / reference data for the"
  },
  {
    "path": "src/input.rs",
    "chars": 154656,
    "preview": "use std::io::{self, Write};\nuse std::time::Instant;\n\nuse crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent}"
  },
  {
    "path": "src/layout.rs",
    "chars": 59751,
    "preview": "use std::io;\n\nuse serde::{Serialize, Deserialize};\nuse unicode_width::UnicodeWidthStr;\n\nuse crate::types::{AppState, Nod"
  },
  {
    "path": "src/main.rs",
    "chars": 181829,
    "preview": "// Multi-binary crate (psmux, pmux, tmux) sharing all modules —\n// suppress dead_code warnings for functions only used b"
  },
  {
    "path": "src/pane.rs",
    "chars": 75300,
    "preview": "use std::io;\nuse std::sync::{Arc, Condvar, Mutex};\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse std::thread;\nuse s"
  },
  {
    "path": "src/platform.rs",
    "chars": 96213,
    "preview": "// ---------------------------------------------------------------------------\n// CREATE_NO_WINDOW for background subpro"
  },
  {
    "path": "src/popup.rs",
    "chars": 19301,
    "preview": "//! Popup overlay module.\n//!\n//! A popup is a **Pane rendered as a floating overlay**, not part of the\n//! window tree."
  },
  {
    "path": "src/preview.rs",
    "chars": 30654,
    "preview": "//! Live preview helpers for the choose-tree / choose-session pickers.\n//!\n//! Fetches `capture-pane` output from any re"
  },
  {
    "path": "src/proxy_pane.rs",
    "chars": 10004,
    "preview": "//! Proxy PTY for cross-session pane transfer.\n//!\n//! When a pane is moved between sessions, the real ConPTY stays in t"
  },
  {
    "path": "src/rendering.rs",
    "chars": 24903,
    "preview": "//! TUI rendering — pane tree rendering, separator drawing, cursor positioning.\n//!\n//! Style/color parsing is in `style"
  },
  {
    "path": "src/server/connection.rs",
    "chars": 167231,
    "preview": "use std::io::{self, BufRead, Write};\nuse std::sync::mpsc;\nuse std::sync::atomic::{AtomicU64, Ordering};\nuse std::time::D"
  },
  {
    "path": "src/server/helpers.rs",
    "chars": 17196,
    "preview": "use std::io;\n\nuse crate::format::expand_format_for_window;\nuse crate::types::{AppState, Node, Window};\nuse crate::util::"
  },
  {
    "path": "src/server/mod.rs",
    "chars": 283135,
    "preview": "pub(crate) mod helpers;\npub(crate) mod options;\npub(crate) mod option_catalog;\nmod connection;\n\nuse std::io::{self, Writ"
  },
  {
    "path": "src/server/option_catalog.rs",
    "chars": 12602,
    "preview": "/// Static catalog of all supported tmux options for customize-mode.\n\npub struct OptionDef {\n    pub name: &'static str,"
  },
  {
    "path": "src/server/options.rs",
    "chars": 26245,
    "preview": "use crate::types::AppState;\nuse crate::config::{format_key_binding, parse_key_string};\n\nfn is_window_option(name: &str) "
  },
  {
    "path": "src/session.rs",
    "chars": 31734,
    "preview": "use std::io::{self, Write};\nuse std::time::Duration;\nuse std::env;\n\n/// Returns true if this port-file base name belongs"
  },
  {
    "path": "src/ssh_input.rs",
    "chars": 66688,
    "preview": "//! SSH VT Input — transparent mouse + keyboard support over SSH on Windows.\n//!\n//! ## Problem\n//!\n//! ConPTY does **no"
  },
  {
    "path": "src/style.rs",
    "chars": 36043,
    "preview": "//! Shared color and style parsing utilities.\n//!\n//! This module consolidates ALL tmux-compatible color/style parsing i"
  },
  {
    "path": "src/tree.rs",
    "chars": 34195,
    "preview": "use std::io;\nuse ratatui::prelude::*;\n\nuse crate::types::{AppState, Pane, Node, LayoutKind, DragState};\nuse crate::platf"
  },
  {
    "path": "src/types.rs",
    "chars": 63295,
    "preview": "use std::sync::{Arc, Mutex, mpsc};\nuse std::time::Instant;\nuse std::collections::{HashMap, HashSet, VecDeque};\n\nuse cros"
  },
  {
    "path": "src/util.rs",
    "chars": 22466,
    "preview": "use std::io;\n\nuse serde::{Serialize, Deserialize};\n\nuse crate::types::{AppState, Node};\n\n/// Expand `~` to the user's ho"
  },
  {
    "path": "src/warm_pane_sync.rs",
    "chars": 13035,
    "preview": "//! Centralised lifecycle for the warm pane.\n//!\n//! The warm pane is a snapshot of server state at spawn time: shell\n//"
  },
  {
    "path": "src/window_ops.rs",
    "chars": 58540,
    "preview": "use std::io::{self, Write};\nuse std::sync::{Arc, Mutex};\n\nuse portable_pty::{PtySize, native_pty_system};\nuse ratatui::p"
  },
  {
    "path": "tests/_batch_runner.ps1",
    "chars": 4377,
    "preview": "#!/usr/bin/env pwsh\n# Streamlined test runner - runs tests inline with timeout via job\nparam(\n    [string[]]$Tests,\n    "
  },
  {
    "path": "tests/_full_run.ps1",
    "chars": 7052,
    "preview": "#!/usr/bin/env pwsh\n# Full sequential test runner with result tracking\nparam(\n    [int]$TimeoutSec = 300,\n    [string]$F"
  },
  {
    "path": "tests/_launch_debug.bat",
    "chars": 44,
    "preview": "@echo off\nset PSMUX_INPUT_DEBUG=1\npsmux.exe\n"
  },
  {
    "path": "tests/_run_batch3.ps1",
    "chars": 4258,
    "preview": "#!/usr/bin/env pwsh\n# Batch 3: ALL previously skipped tests (perf, stress, interactive, mouse, paste, plugins, theme, wa"
  },
  {
    "path": "tests/alt_emit.ps1",
    "chars": 261,
    "preview": "# Tiny script: emit only the escape sequences requested via stdin,\n# nothing else.  Used to drive psmux pane parsers fro"
  },
  {
    "path": "tests/alt_emit_inner.ps1",
    "chars": 291,
    "preview": "# Helper: emit alt-screen enter, 5 INNER lines, alt-screen exit, then\n# exit.  No profile is loaded, so PSReadLine is no"
  },
  {
    "path": "tests/alt_emit_simple.ps1",
    "chars": 48,
    "preview": "1..5 | ForEach-Object { Write-Host \"INNER $_\" }\n"
  },
  {
    "path": "tests/battle_test.ps1",
    "chars": 24768,
    "preview": "# psmux Battle Test Suite\n# Comprehensive testing of all psmux features: sessions, windows, panes, resize, kill, etc.\n\n$"
  },
  {
    "path": "tests/battle_test.py",
    "chars": 19030,
    "preview": "#!/usr/bin/env python3\n\"\"\"\npsmux Battle Test Suite - Python Edition\nComprehensive testing with concurrent operations and"
  },
  {
    "path": "tests/bench_squelch_cwd.ps1",
    "chars": 11814,
    "preview": "# bench_squelch_cwd.ps1 - Benchmark warm session claim with CWD change (squelch)\n#\n# Measures the time from launching ps"
  },
  {
    "path": "tests/bench_startup_exit.ps1",
    "chars": 21667,
    "preview": "# bench_startup_exit.ps1 — Comprehensive startup and exit timing benchmark\n#\n# Measures with high precision:\n#   1. Cold"
  },
  {
    "path": "tests/burst_bench2.cs",
    "chars": 8271,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing Sy"
  },
  {
    "path": "tests/burst_benchmark.cs",
    "chars": 8418,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing Sy"
  },
  {
    "path": "tests/cursor_bench.cs",
    "chars": 7454,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing Sy"
  },
  {
    "path": "tests/debug_paste_trace.ps1",
    "chars": 2959,
    "preview": "#!/usr/bin/env pwsh\n# Quick paste debug trace: start psmux, send Ctrl+V via keybd_event, dump log\n$ErrorActionPreference"
  },
  {
    "path": "tests/destructive_test.ps1",
    "chars": 11365,
    "preview": "# psmux Destructive Operations Test\n# Tests specifically for kill operations, error handling, and recovery\n\n$ErrorAction"
  },
  {
    "path": "tests/diag_cursor_claude.ps1",
    "chars": 4428,
    "preview": "###############################################################################\n# diag_cursor_claude.ps1 – Diagnose curs"
  },
  {
    "path": "tests/diag_cursor_raw.ps1",
    "chars": 2554,
    "preview": "###############################################################################\n# diag_cursor_raw.ps1 – Raw dump of ALL "
  },
  {
    "path": "tests/diag_enter_selfcontained.ps1",
    "chars": 3057,
    "preview": "## Self-contained Shift+Enter diagnostic.\n## Launches psmux, then uses psmux send-keys from WITHIN the psmux session \n##"
  },
  {
    "path": "tests/diag_key_events.ps1",
    "chars": 1463,
    "preview": "# Diagnostic: Launch psmux with input debug enabled, wait for user to press\n# Shift+Enter, then read and display the ent"
  },
  {
    "path": "tests/diag_scroll_inject.ps1",
    "chars": 1252,
    "preview": "# Test script to inject scroll events to psmux server via TCP (persistent mode)\nparam(\n    [int]$Count = 10,\n    [string"
  },
  {
    "path": "tests/disable_processed_input.ps1",
    "chars": 798,
    "preview": "Add-Type -TypeDefinition @\"\nusing System;\nusing System.Runtime.InteropServices;\npublic class ConMode {\n    [DllImport(\"k"
  },
  {
    "path": "tests/injector.cs",
    "chars": 10926,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Thre"
  },
  {
    "path": "tests/injector_batch.cs",
    "chars": 4988,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\n// Batch keystro"
  },
  {
    "path": "tests/inspect_issue263_dump.ps1",
    "chars": 2704,
    "preview": "$dumpPath = 'C:\\Users\\uniqu\\AppData\\Local\\Temp\\psmux_issue263_dump.json'\n$json = Get-Content -Raw -Encoding UTF8 -Path $"
  },
  {
    "path": "tests/inspect_issue263_runs.ps1",
    "chars": 983,
    "preview": "$dumpPath = 'C:\\Users\\uniqu\\AppData\\Local\\Temp\\psmux_issue263_dump.json'\n$json = Get-Content -Raw -Encoding UTF8 -Path $"
  },
  {
    "path": "tests/investigate_274_attach_kill.ps1",
    "chars": 4621,
    "preview": "# Issue #274 - investigate attach client kill + re-attach scenario\n# Specifically: does killing the attached TUI client "
  },
  {
    "path": "tests/investigate_274_clean_recovery.ps1",
    "chars": 3484,
    "preview": "# Issue #274 - Clean recovery test after sustained heavy load\n# Goal: After 2 minutes of 3-pane spam, can we KILL the sp"
  },
  {
    "path": "tests/investigate_274_long.ps1",
    "chars": 5756,
    "preview": "# Issue #274 - long-duration test (5 minutes)\n# Watch for memory growth, latency degradation, pipe wedge under continuou"
  },
  {
    "path": "tests/investigate_274_node_daemon.ps1",
    "chars": 4086,
    "preview": "# Issue #274 - Test with actual node + http.server daemon (matches user's repro)\n# User reported: node serve --port 5155"
  },
  {
    "path": "tests/investigate_274_unresponsive_proc.ps1",
    "chars": 5664,
    "preview": "# Issue #274 - Test: what if a pane has a process that ignores stdin?\n# This simulates the user's \"claude.exe stops emit"
  },
  {
    "path": "tests/investigate_274_wedge.ps1",
    "chars": 6799,
    "preview": "# Investigation script for issue #274\n# Claim: A long-running daemon producing continuous stdout in one pane\n#        we"
  },
  {
    "path": "tests/issue246_emitter.py",
    "chars": 3128,
    "preview": "\"\"\"\nInk-style frame emitter for psmux issue #246 reproduction.\n\nEmits \"logical frames\" that consist of:\n  1. Cursor home"
  },
  {
    "path": "tests/mouse_diag.ps1",
    "chars": 6804,
    "preview": "#!/usr/bin/env pwsh\n# mouse_diag.ps1 — Comprehensive mouse hover diagnostic\n#\n# Tests every link in the chain:\n#   1. Cl"
  },
  {
    "path": "tests/mouse_injector.cs",
    "chars": 4457,
    "preview": "using System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Threading;\n\n// Injects mouse wheel eve"
  },
  {
    "path": "tests/repro_enter_bugs.ps1",
    "chars": 4110,
    "preview": "## Script to reproduce the four Shift+Enter bugs using SendInput injection.\n## Launches enter_diag in the specified term"
  },
  {
    "path": "tests/repro_issue303.ps1",
    "chars": 6907,
    "preview": "# Reproduction test for Issue #303: command-prompt keybindings don't open prompt\n$ErrorActionPreference = \"Continue\"\n$PS"
  },
  {
    "path": "tests/repro_issue303b.ps1",
    "chars": 4680,
    "preview": "# Verify keystroke injection works + examine raw dump-state JSON\n$ErrorActionPreference = \"Continue\"\n$PSMUX = (Get-Comma"
  },
  {
    "path": "tests/repro_issue303c.ps1",
    "chars": 7568,
    "preview": "# Functional test: Does command-prompt actually open after keybindings?\n# Strategy: After injecting prefix+key, type a c"
  },
  {
    "path": "tests/repro_preview_compare.ps1",
    "chars": 6425,
    "preview": "# Empirical REAL vs PREVIEW rendering comparison.\n# Builds windows with 7, 15, 20 panes (and an htop/tasklist loop in bi"
  },
  {
    "path": "tests/repro_preview_layout.ps1",
    "chars": 4366,
    "preview": "# Repro for \"preview does not replicate the real window\"\n# Creates two sessions with multiple windows + splits, runs a l"
  },
  {
    "path": "tests/repro_pstop_preview.ps1",
    "chars": 5620,
    "preview": "#!/usr/bin/env pwsh\n# Empirical test: pstop running in a split pane, compare REAL vs PREVIEW rendering.\n$ErrorActionPref"
  },
  {
    "path": "tests/repro_seven_panes.ps1",
    "chars": 3340,
    "preview": "# Hard repro: 7 panes in one window, verify window-dump returns 7 leaves\n$ErrorActionPreference = 'Stop'\n\nGet-Process | "
  },
  {
    "path": "tests/run_all_tests.ps1",
    "chars": 22162,
    "preview": "# psmux Comprehensive Test Runner\n# Runs ALL test suites sequentially with proper cleanup, captures results,\n# and produ"
  },
  {
    "path": "tests/run_batch_fast.ps1",
    "chars": 8892,
    "preview": "# run_batch_fast.ps1 - Run ALL test suites, skip ONLY those requiring visible TUI window\nparam([switch]$SkipPerf)\n\n$Erro"
  },
  {
    "path": "tests/run_fmt_test.ps1",
    "chars": 376,
    "preview": "# Wrapper: kill stale instances, clean up, then run format engine test\n$ErrorActionPreference = \"Continue\"\ntaskkill /f /"
  },
  {
    "path": "tests/test_advanced.ps1",
    "chars": 12883,
    "preview": "# psmux Advanced Features Test Suite\n# Tests for display-menu, display-popup, confirm-before, hooks, pipe-pane, wait-for"
  },
  {
    "path": "tests/test_agent_teams_e2e.ps1",
    "chars": 12746,
    "preview": "# test_agent_teams_e2e.ps1 — End-to-end Claude Code Agent Teams Test\n# ================================================="
  },
  {
    "path": "tests/test_all.ps1",
    "chars": 4513,
    "preview": "# psmux/tmux compatibility test suite\n# Run all tests for psmux tmux compatibility\n\n$ErrorActionPreference = \"Stop\"\n$scr"
  },
  {
    "path": "tests/test_all.sh",
    "chars": 2728,
    "preview": "#!/bin/bash\n# psmux/tmux compatibility test suite (bash version)\n# Run all tests for psmux tmux compatibility\n\nset -e\n\nT"
  },
  {
    "path": "tests/test_alt_key.ps1",
    "chars": 8940,
    "preview": "#!/usr/bin/env pwsh\n###############################################################################\n# test_alt_key.ps1 —"
  },
  {
    "path": "tests/test_bell_activity_silence.ps1",
    "chars": 9281,
    "preview": "#!/usr/bin/env pwsh\n# Test bell detection, activity/silence monitoring, allow-rename, update-environment\n# Tests the fea"
  },
  {
    "path": "tests/test_bind_key.ps1",
    "chars": 13376,
    "preview": "# psmux bind-key End-to-End Test Suite\n# Tests: bind-key server-side storage, binding sync to client via DumpState,\n#   "
  },
  {
    "path": "tests/test_bind_pipe_key.ps1",
    "chars": 12301,
    "preview": "# =============================================================================\n# ISSUE #19 FIX TEST: bind-key with pipe"
  },
  {
    "path": "tests/test_bug_detection.ps1",
    "chars": 12854,
    "preview": "# =============================================================================\n# PRECISE BUG DETECTION TESTS - Issues f"
  },
  {
    "path": "tests/test_bugfixes.ps1",
    "chars": 8367,
    "preview": "$psmux = \"$PSScriptRoot\\..\\target\\release\\psmux.exe\"\nif (-not (Test-Path $psmux)) { $psmux = \"$PSScriptRoot\\..\\target\\de"
  },
  {
    "path": "tests/test_burst_typing_benchmark.ps1",
    "chars": 15807,
    "preview": "# BURST TYPING BENCHMARK: PSMUX vs DIRECT POWERSHELL\n# Tests rapid burst typing (0-2ms between chars within words, 10ms "
  },
  {
    "path": "tests/test_capture_pane.ps1",
    "chars": 22235,
    "preview": "#!/usr/bin/env pwsh\n# =============================================================================\n# test_capture_pane."
  },
  {
    "path": "tests/test_cc_iterm2_compat.ps1",
    "chars": 13089,
    "preview": "# Comprehensive CC (control mode) drop-in compatibility test for psmux.\n#\n# Verifies that every iTerm2-style CC client t"
  },
  {
    "path": "tests/test_choose_tree_preview.ps1",
    "chars": 19284,
    "preview": "# Feature test: choose-tree-preview global option\n# Proves the option works through every code path:\n#   - Default value"
  },
  {
    "path": "tests/test_cjk_paste_split.ps1",
    "chars": 8667,
    "preview": "#!/usr/bin/env pwsh\n###############################################################################\n# test_cjk_paste_spl"
  },
  {
    "path": "tests/test_claude_agent_teams.ps1",
    "chars": 33209,
    "preview": "# psmux Claude Code Agent Teams — tmux Mode Compatibility Test Suite\n# ================================================="
  },
  {
    "path": "tests/test_claude_compat_fixes.ps1",
    "chars": 26458,
    "preview": "# test_claude_compat_fixes.ps1 — Tests for Claude Code compatibility fixes\n#\n# Verifies all fixes from this commit:\n#   "
  },
  {
    "path": "tests/test_claude_cursor_diag.ps1",
    "chars": 6423,
    "preview": "# test_claude_cursor_diag.ps1\n$ErrorActionPreference = \"Stop\"\n$SESSION = \"cursor_test_$(Get-Random -Maximum 9999)\"\n$PSMU"
  },
  {
    "path": "tests/test_claude_mouse.ps1",
    "chars": 5190,
    "preview": "# Test: Send mouse events to claude running inside psmux and check for escape garbage\n# Usage: Run after claude is alrea"
  },
  {
    "path": "tests/test_cli_flag_parity.ps1",
    "chars": 47500,
    "preview": "# =============================================================================\n# PSMUX CLI Flag Parity E2E Test Suite\n#"
  },
  {
    "path": "tests/test_cli_handlers.ps1",
    "chars": 17254,
    "preview": "#!/usr/bin/env pwsh\n# test_cli_handlers.ps1\n# Tests for CLI handlers that were previously missing or stub-only:\n# 1. com"
  },
  {
    "path": "tests/test_cli_mega_suite.ps1",
    "chars": 30144,
    "preview": "# =============================================================================\n# PSMUX CLI Mega Test Suite\n# =========="
  }
]

// ... and 376 more files (download for full content)

About this extraction

This page contains the full source code of the marlocarlo/psmux GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 576 files (7.9 MB), approximately 2.1M tokens, and a symbol index with 3943 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!