19
19
from textual .widgets import (
20
20
Static , Button , Input , Header , RichLog , TextArea , Select , ListView , Checkbox , Collapsible , ListItem , Label
21
21
)
22
+
22
23
from textual .containers import Container
23
24
from textual .reactive import reactive
24
25
from textual .worker import Worker , WorkerState
@@ -645,6 +646,21 @@ def compose_content_area(self) -> ComposeResult:
645
646
yield EvalsWindow (self , id = "evals-window" , classes = "window" )
646
647
yield CodingWindow (self , id = "coding-window" , classes = "window" )
647
648
649
+ @on (ChatMessage .Action )
650
+ async def handle_chat_message_action (self , event : ChatMessage .Action ) -> None :
651
+ """Handles actions (edit, copy, etc.) from within a ChatMessage widget."""
652
+ button_classes = " " .join (event .button .classes ) # Get class string for logging
653
+ self .loguru_logger .debug (
654
+ f"ChatMessage.Action received for button "
655
+ f"(Classes: { button_classes } , Label: '{ event .button .label } ') "
656
+ f"on message role: { event .message_widget .role } "
657
+ )
658
+ # The event directly gives us the context we need.
659
+ # Now we call the existing handler function with the correct arguments.
660
+ await chat_events .handle_chat_action_button_pressed (
661
+ self , event .button , event .message_widget
662
+ )
663
+
648
664
# --- Watcher for CCP Active View ---
649
665
def watch_ccp_active_view (self , old_view : Optional [str ], new_view : str ) -> None :
650
666
loguru_logger .debug (f"CCP active view changing from '{ old_view } ' to: '{ new_view } '" )
@@ -1990,17 +2006,7 @@ async def on_button_pressed(self, event: Button.Pressed) -> None:
1990
2006
await tab_events .handle_tab_button_pressed (self , event )
1991
2007
return
1992
2008
1993
- # 2. Handle dynamically generated ChatMessage action buttons
1994
- # This needs to check the current tab, as ChatMessages can appear in Chat and CCP tabs.
1995
- if self .current_tab in [TAB_CHAT , TAB_CCP ]:
1996
- action_widget = self ._get_chat_message_widget_from_button (event .button )
1997
- if action_widget :
1998
- self .loguru_logger .debug (
1999
- f"Button '{ button_id } ' is inside a ChatMessage, dispatching to action handler." )
2000
- await chat_events .handle_chat_action_button_pressed (self , event .button , action_widget )
2001
- return
2002
-
2003
- # 3. Use the handler map for all other tab-specific buttons
2009
+ # 2. Use the handler map for all other tab-specific buttons
2004
2010
current_tab_handlers = self .button_handler_map .get (self .current_tab , {})
2005
2011
handler = current_tab_handlers .get (button_id )
2006
2012
@@ -2021,28 +2027,9 @@ async def on_button_pressed(self, event: Button.Pressed) -> None:
2021
2027
self .loguru_logger .error (f"Handler for button '{ button_id } ' is not callable: { handler } " )
2022
2028
return # The button press was handled (or an error occurred).
2023
2029
2024
- # 4 . Fallback for unmapped buttons
2030
+ # 3 . Fallback for unmapped buttons
2025
2031
self .loguru_logger .warning (f"Unhandled button press for ID '{ button_id } ' on tab '{ self .current_tab } '." )
2026
2032
2027
- def _get_chat_message_widget_from_button (self , button : Button ) -> Optional [ChatMessage ]:
2028
- """Helper to find the parent ChatMessage widget from an action button within it."""
2029
- self .loguru_logger .debug (f"_get_chat_message_widget_from_button searching for parent of button ID: { button .id } , Classes: { button .classes } " )
2030
- node : Optional [DOMNode ] = button .parent
2031
- depth = 0
2032
- max_depth = 5 # Safety break
2033
- while node is not None and depth < max_depth :
2034
- self .loguru_logger .debug (f" Traversal depth { depth } : current node is { type (node )} , id: { getattr (node , 'id' , 'N/A' )} , classes: { getattr (node , 'classes' , '' )} " )
2035
- if isinstance (node , ChatMessage ):
2036
- self .loguru_logger .debug (f" Found ChatMessage parent!" )
2037
- return node
2038
- node = node .parent
2039
- depth += 1
2040
- if depth >= max_depth :
2041
- self .loguru_logger .warning (f" _get_chat_message_widget_from_button reached max depth for button: { button .id } " )
2042
- else :
2043
- self .loguru_logger .warning (f" _get_chat_message_widget_from_button could not find parent ChatMessage for button: { button .id } " )
2044
- return None
2045
-
2046
2033
async def on_text_area_changed (self , event : TextArea .Changed ) -> None :
2047
2034
"""Handles text area changes, e.g., for live updates to character data."""
2048
2035
control_id = event .control .id
0 commit comments