2"""Detect whether the current environment can run the Aquin Textual TUI."""
4from __future__
import annotations
9from collections.abc
import Callable, Mapping, Sequence
10from dataclasses
import dataclass
11from typing
import Literal
13Platform = Literal[
"linux",
"darwin",
"windows",
"unknown"]
15_DUMB_TERMS = frozenset({
"",
"dumb",
"unknown"})
16_CI_TRUTHY = frozenset({
"1",
"true",
"yes",
"on"})
19@dataclass(frozen=True)
30 """Map ``sys.platform`` to a coarse OS bucket used for TUI routing."""
31 raw = (sys_platform
if sys_platform
is not None else sys.platform).lower()
32 if raw.startswith(
"linux"):
42 return (value
or "").strip().lower()
in _CI_TRUTHY
45def _opt_out_reason(argv: Sequence[str], environ: Mapping[str, str]) -> str |
None:
47 return "opt_out: --plain"
49 return "opt_out: NO_TUI"
57 stdin_isatty: Callable[[], bool],
58 stdout_isatty: Callable[[], bool],
60 if not stdin_isatty():
61 return False,
"not_tty: stdin"
62 if not stdout_isatty():
63 return False,
"not_tty: stdout"
68 term = (environ.get(
"TERM")
or "").strip().lower()
69 if term
in _DUMB_TERMS:
71 return False,
"term_dumb: TERM unset"
72 return False, f
"term_dumb: TERM={term}"
77 if environ.get(
"WT_SESSION"):
79 if environ.get(
"TERM_PROGRAM")
in {
"vscode",
"Cursor",
"iTerm.app"}:
82 if environ.get(
"VSCODE_INJECTION")
or environ.get(
"CURSOR_TRACE_ID"):
84 term = (environ.get(
"TERM")
or "").strip().lower()
85 if term.startswith(
"xterm")
or term.startswith(
"tmux")
or term ==
"ansi":
91 """Return whether stdout is a VT-capable Windows console."""
97 from ctypes
import wintypes
101 kernel32 = ctypes.windll.kernel32
102 std_output_handle = -11
103 enable_virtual_terminal_processing = 0x0004
105 handle = kernel32.GetStdHandle(std_output_handle)
106 if handle == wintypes.HANDLE(-1).value:
109 mode = ctypes.c_uint()
110 if not kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
113 if mode.value & enable_virtual_terminal_processing:
116 new_mode = mode.value | enable_virtual_terminal_processing
117 if kernel32.SetConsoleMode(handle, new_mode):
118 kernel32.SetConsoleMode(handle, mode.value)
125 environ: Mapping[str, str],
127 windows_vt_capable: Callable[[], bool],
128) -> tuple[bool, str]:
129 if platform ==
"windows":
132 return False,
"term_not_vt_capable"
139 return importlib.util.find_spec(
"textual")
is not None
144 argv: Sequence[str] |
None =
None,
145 environ: Mapping[str, str] |
None =
None,
146 stdin_isatty: Callable[[], bool] |
None =
None,
147 stdout_isatty: Callable[[], bool] |
None =
None,
148 sys_platform: str |
None =
None,
149 textual_importable: Callable[[], bool] |
None =
None,
150 windows_vt_capable: Callable[[], bool] |
None =
None,
152 """Return whether the Aquin Textual TUI should launch for this process."""
153 argv = list(argv
if argv
is not None else sys.argv)
154 environ = dict(environ
if environ
is not None else os.environ)
155 stdin_isatty = stdin_isatty
or sys.stdin.isatty
156 stdout_isatty = stdout_isatty
or sys.stdout.isatty
157 textual_importable = textual_importable
or _textual_importable_default
158 windows_vt_capable = windows_vt_capable
or _windows_vt_capable_default
174 stdin_isatty=stdin_isatty,
175 stdout_isatty=stdout_isatty,
190 windows_vt_capable=windows_vt_capable,
202 textual_ok = textual_importable()
210 reason=
"textual_not_installed",
tuple[bool, str] _term_ok(Platform platform, Mapping[str, str] environ, *, Callable[[], bool] windows_vt_capable)
TuiCapability detect_tui_capability(*, Sequence[str]|None argv=None, Mapping[str, str]|None environ=None, Callable[[], bool]|None stdin_isatty=None, Callable[[], bool]|None stdout_isatty=None, str|None sys_platform=None, Callable[[], bool]|None textual_importable=None, Callable[[], bool]|None windows_vt_capable=None)
bool _windows_vt_capable_default()
bool _truthy_env(str|None value)
bool _windows_vt_from_environ(Mapping[str, str] environ)
str|None _opt_out_reason(Sequence[str] argv, Mapping[str, str] environ)
Platform detect_platform(*, str|None sys_platform=None)
tuple[bool, str] _posix_term_ok(Mapping[str, str] environ)
tuple[bool, str] _tty_ok(*, Callable[[], bool] stdin_isatty, Callable[[], bool] stdout_isatty)
bool _textual_importable_default()