[PATCH 25/26] lucid: emit section banners via Display.banner

Daniel Gomez <[email protected]> Tue, 19 May 2026 15:28:22 +0200
Newsgroups dev.linux.lists.kdevops
Message-ID <[email protected]>
From: Daniel Gomez <[email protected]>

Ansible's built-in callbacks render the PLAYBOOK, PLAY, and PLAY RECAP
section boundaries through Display.banner, which centers the label and
fills the rest of the row with asterisks sized to the terminal width.
Lucid was emitting these three headers as plain colored lines, so a
user switching between lucid and default (or dense) for debugging saw
a different visual rhythm for the same structural events. Routing the
three top-level headers through self._display.banner restores that
shared rhythm and gives lucid width-responsive framing that matches
the rest of Ansible's output.

Each banner call passes cows=False explicitly so lucid's output stays
deterministic regardless of whether cowsay is installed or how the
user has configured ANSIBLE_NOCOWS. Task and handler headers remain
plain colored lines because tasks fire too frequently for banner
framing to aid readability, and the existing self.output_lock scope
is preserved around each banner call so concurrent dynamic-display
refreshes cannot interleave with the framed output.

Generated-by: Claude AI
Signed-off-by: Daniel Gomez <[email protected]>
---
 callback_plugins/lucid.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/callback_plugins/lucid.py b/callback_plugins/lucid.py
index df74a6f4..fa3e2c27 100644
--- a/callback_plugins/lucid.py
+++ b/callback_plugins/lucid.py
@@ -412,7 +412,8 @@ class CallbackModule(CallbackBase):
         self._create_log_file(playbook_name)
 
         msg = f"PLAYBOOK: {playbook_name}"
-        self._display_message(msg, C.COLOR_HIGHLIGHT)
+        with self.output_lock:
+            self._display.banner(msg, color=C.COLOR_HIGHLIGHT, cows=False)
         self._write_to_log(msg)
 
         # Show log file path early so user can tail -f
@@ -472,7 +473,10 @@ class CallbackModule(CallbackBase):
             header = self.pending_play_header
             self.pending_play_header = None
         if header and not self.dynamic_mode:
-            self._display_message(header, C.COLOR_HIGHLIGHT)
+            with self.output_lock:
+                self._display.banner(
+                    header, color=C.COLOR_HIGHLIGHT, cows=False
+                )
 
     def v2_playbook_on_task_start(self, task, is_conditional):
         """Task started"""
@@ -1120,7 +1124,10 @@ class CallbackModule(CallbackBase):
 
     def _display_recap(self, stats):
         """Display final statistics"""
-        self._display_message("\nPLAY RECAP", C.COLOR_HIGHLIGHT)
+        with self.output_lock:
+            self._display.banner(
+                "PLAY RECAP", color=C.COLOR_HIGHLIGHT, cows=False
+            )
 
         hosts = sorted(stats.processed.keys())
         for host in hosts:

-- 
2.53.0