Skip to content

Commit 6b81b0c

Browse files
committed
hooks.py(fix[show_hook]): Handle indexed hook queries correctly
why: When calling show_hook("session-renamed[0]"), the code attempted to find an attribute named "session_renamed[0]" on the Hooks dataclass, which doesn't exist. Per tmux.1, hooks are array options that can be queried by index. what: - Extract index from bracketed suffix before attribute lookup - Return specific indexed value from SparseArray when present - Add parametrized tests for indexed hook lookups
1 parent fa6117e commit 6b81b0c

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

src/libtmux/hooks.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from __future__ import annotations
3131

3232
import logging
33+
import re
3334
import typing as t
3435
import warnings
3536

@@ -411,7 +412,20 @@ def show_hook(
411412
if hooks_output is None:
412413
return None
413414
hooks = Hooks.from_stdout(hooks_output)
414-
return getattr(hooks, hook.lstrip("%").replace("-", "_"), None)
415+
416+
# Check if this is an indexed query (e.g., "session-renamed[0]")
417+
# For indexed queries, return the specific value like _show_option does
418+
hook_attr = hook.lstrip("%").replace("-", "_")
419+
index_match = re.search(r"\[(\d+)\]$", hook_attr)
420+
if index_match:
421+
# Strip the index for attribute lookup
422+
base_hook_attr = re.sub(r"\[\d+\]$", "", hook_attr)
423+
hook_val = getattr(hooks, base_hook_attr, None)
424+
if isinstance(hook_val, SparseArray):
425+
return hook_val.get(int(index_match.group(1)))
426+
return hook_val
427+
428+
return getattr(hooks, hook_attr, None)
415429

416430
def set_hooks(
417431
self,

tests/test_hooks.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,74 @@ def test_show_hook_returns_sparse_array(server: Server) -> None:
623623
session.unset_hook("session-renamed")
624624

625625

626+
class IndexedHookLookupCase(t.NamedTuple):
627+
"""Test fixture for indexed hook lookups."""
628+
629+
test_id: str
630+
hook_name: str
631+
hook_index: int
632+
hook_value: str
633+
634+
635+
@pytest.mark.parametrize(
636+
IndexedHookLookupCase._fields,
637+
[
638+
IndexedHookLookupCase(
639+
test_id="index_zero",
640+
hook_name="session-renamed",
641+
hook_index=0,
642+
hook_value="display-message 'test zero'",
643+
),
644+
IndexedHookLookupCase(
645+
test_id="index_five",
646+
hook_name="session-renamed",
647+
hook_index=5,
648+
hook_value="display-message 'test five'",
649+
),
650+
IndexedHookLookupCase(
651+
test_id="window_hook",
652+
hook_name="window-renamed",
653+
hook_index=0,
654+
hook_value="display-message 'window test'",
655+
),
656+
],
657+
ids=lambda x: x.test_id if isinstance(x, IndexedHookLookupCase) else x,
658+
)
659+
def test_show_hook_indexed_lookup(
660+
server: Server,
661+
test_id: str,
662+
hook_name: str,
663+
hook_index: int,
664+
hook_value: str,
665+
) -> None:
666+
"""Test that show_hook with indexed hook name returns the specific value.
667+
668+
Per tmux.1, hooks are array options that can be queried by index.
669+
When calling show_hook("session-renamed[0]"), it should return the string
670+
value at that index, not a SparseArray.
671+
"""
672+
session = server.new_session(session_name="test_indexed_lookup")
673+
indexed_hook = f"{hook_name}[{hook_index}]"
674+
675+
# Set the hook
676+
session.set_hook(indexed_hook, hook_value)
677+
678+
# Query with indexed name - should return the specific value, not SparseArray
679+
result = session.show_hook(indexed_hook)
680+
assert result is not None
681+
assert isinstance(result, str), f"Expected str, got {type(result)}"
682+
# tmux may normalize quotes, so check the essential parts are present
683+
assert "display-message" in result
684+
685+
# Verify base hook query still returns SparseArray
686+
base_result = session.show_hook(hook_name)
687+
assert isinstance(base_result, SparseArray)
688+
assert hook_index in base_result
689+
690+
# Cleanup
691+
session.unset_hook(hook_name)
692+
693+
626694
def test_set_hooks_with_sparse_array(server: Server) -> None:
627695
"""Test set_hooks with SparseArray input."""
628696
session = server.new_session(session_name="test_set_hooks_sparse")

0 commit comments

Comments
 (0)