diff --git a/dot_config/kitty/__pycache__/tab_bar.cpython-314.pyc b/dot_config/kitty/__pycache__/tab_bar.cpython-314.pyc deleted file mode 100644 index 12d5947..0000000 Binary files a/dot_config/kitty/__pycache__/tab_bar.cpython-314.pyc and /dev/null differ diff --git a/dot_config/kitty/tab_bar.py b/dot_config/kitty/tab_bar.py index 22efeaf..20a069f 100644 --- a/dot_config/kitty/tab_bar.py +++ b/dot_config/kitty/tab_bar.py @@ -36,7 +36,7 @@ ICONS: dict[str, str] = { 'helix': EDITOR, # agents / harnesses 'claude': '\U000f06a9', # nf-md-robot - 'omp': '\U000f09da', # nf-md-brain + 'omp': '\uf2db', # nf-fa-microchip 'opencode': '\uf121', # nf-fa-code 'crush': '\uf0e7', # nf-fa-bolt 'codex': '\uf120', # nf-fa-terminal @@ -53,7 +53,7 @@ ICONS: dict[str, str] = { 'docker': '\uf308', 'docker-compose': '\uf308', 'podman': '\uf308', - 'kubectl': '\ue7b2', # nf-dev-kubernetes + 'kubectl': '\U000f10fe', # nf-md-kubernetes # multiplexers / terminals-in-terminals 'herdr': '\uf009', # nf-fa-th_large — panes 'tmux': '\uf00a', # nf-fa-th @@ -113,7 +113,7 @@ _repo: dict[str, str] = {} def draw_title(data: dict[str, Any]) -> str: tab = data['tab'] - program = _program(_cmdline(data['tab_id']), tab.active_exe) + program = _program(_cmdlines(data['tab_id']), tab.active_exe) index = data['index'] if program in EDITORS: edited = _nvim_file(data['title']) @@ -127,25 +127,47 @@ def draw_title(data: dict[str, Any]) -> str: return f'{index} {icon} {_elide(label or data["title"])}' -def _cmdline(tab_id: int) -> list[str]: - """argv of the tab's active window's foreground process, [] if unavailable.""" +def _cmdlines(tab_id: int) -> list[list[str]]: + """argv of every foreground process of the tab's active window. + + All of them, not just `foreground_cmdline`: an editor commonly has LSP/agent + children in the same process group, and kitty's single "process for cwd" can + be either one of them. + """ from kitty.boss import get_boss try: tab = get_boss().tab_for_id(tab_id) window = tab.active_window if tab is not None else None - return list(window.child.foreground_cmdline) if window is not None else [] + if window is None: + return [] + return [list(p['cmdline'] or ()) for p in window.child.foreground_processes] except Exception: return [] -def _program(cmdline: list[str], fallback_exe: str) -> str: - """Program name a tab should be iconified by. +def _program(cmdlines: list[list[str]], fallback_exe: str) -> str: + """Program a tab should be iconified by, across its foreground processes. - Walks the cmdline past runners and flags: `node …/claude` is claude, an - unknown script keeps its runtime's icon (`uv run python train.py` is - python, `bun run dev` is bun), and a bare `python` stays python. Falls back - to kitty's own exe for the active window when the cmdline is unreadable. + An editor wins over anything else (nvim with a node LSP child is nvim), then + the first process with an icon, then whatever the first process is. + """ + names = [name for cmdline in cmdlines if (name := _resolve(cmdline))] + for name in names: + if name in EDITORS: + return name + for name in names: + if name in ICONS: + return name + return names[0] if names else _canonical(os.path.basename(fallback_exe or '').lower()) + + +def _resolve(cmdline: list[str]) -> str: + """Program name of one cmdline. + + Walks past runners and flags: `node …/claude` is claude, an unknown script + keeps its runtime's icon (`uv run python train.py` is python, `bun run dev` + is bun), and a bare `python` stays python. """ runtime = '' skipped = False @@ -163,7 +185,7 @@ def _program(cmdline: list[str], fallback_exe: str) -> str: runtime = runtime or (name if name in ICONS else '') continue return name if name in ICONS or not runtime else runtime - return runtime or _canonical(os.path.basename(fallback_exe or '').lower()) + return runtime def _canonical(name: str) -> str: