Refactor keybindings and footer management: streamline keybinding processing and enhance footer item display with key-description pairs for improved clarity and usability.

This commit is contained in:
Philip Henning 2025-08-16 22:37:29 +02:00
parent 3f0892fb7b
commit 6107b43ac5
3 changed files with 133 additions and 24 deletions

View file

@ -147,26 +147,27 @@ class HostsManagerApp(App):
# Process keybindings and add to appropriate sections
for binding in self.BINDINGS:
# Skip tuple-style bindings and only process Binding objects
if not hasattr(binding, "show"):
continue
# Only show bindings marked with show=True
if hasattr(binding, "show") and binding.show:
if binding.show:
# Get the display key
key_display = getattr(binding, "key_display", None) or binding.key
# Get the description
description = binding.description or binding.action
# Format the item
item = f"{key_display}: {description}"
# Determine positioning from id attribute
binding_id = getattr(binding, "id", None)
if binding_id and binding_id.startswith("left:"):
footer.add_left_item(item)
footer.add_left_item(key_display, description)
elif binding_id and binding_id.startswith("right:"):
footer.add_right_item(item)
footer.add_right_item(key_display, description)
else:
# Default to right if no specific positioning
footer.add_right_item(item)
footer.add_right_item(key_display, description)
# Status section will be updated by update_status
self._update_footer_status()

View file

@ -11,6 +11,42 @@ from textual.app import ComposeResult
from textual.containers import Horizontal
from textual.widgets import Static
from textual.widget import Widget
from rich.text import Text
class FooterKey(Widget):
"""A key/action pair widget for the footer, styled similar to Textual's original FooterKey."""
DEFAULT_CSS = """
FooterKey {
width: auto;
height: 1;
content-align: center middle;
padding: 0 1;
}
.footer-key--key {
text-style: bold;
color: $text;
}
.footer-key--description {
color: $text-muted;
}
"""
def __init__(self, key: str, description: str, **kwargs):
super().__init__(**kwargs)
self.key = key
self.description = description
def render(self) -> Text:
"""Render the key-description pair with proper styling."""
text = Text()
text.append(f"{self.key}", style="bold")
text.append(" ")
text.append(self.description, style="dim")
return text
class CustomFooter(Widget):
@ -39,7 +75,6 @@ class CustomFooter(Widget):
.footer-left {
width: auto;
text-align: left;
text-style: dim;
height: 1;
content-align: left middle;
}
@ -52,7 +87,6 @@ class CustomFooter(Widget):
.footer-right {
width: auto;
text-align: right;
text-style: dim;
height: 1;
content-align: right middle;
}
@ -73,12 +107,25 @@ class CustomFooter(Widget):
height: 1;
content-align: right middle;
}
/* Enhanced styling for footer key components */
.footer-left .footer-key--key,
.footer-right .footer-key--key {
text-style: bold;
color: $text;
}
.footer-left .footer-key--description,
.footer-right .footer-key--description {
color: $text-muted;
text-style: dim;
}
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._left_items = []
self._right_items = []
self._left_items = [] # List of FooterKey widgets
self._right_items = [] # List of FooterKey widgets
self._status_text = ""
def compose(self) -> ComposeResult:
@ -90,16 +137,43 @@ class CustomFooter(Widget):
yield Static("", id="footer-separator", classes="footer-separator")
yield Static("", id="footer-status", classes="footer-status")
def add_left_item(self, item: str) -> None:
"""Add an item to the left section."""
self._left_items.append(item)
def add_left_item(self, key: str, description: str) -> None:
"""Add a key-description pair to the left section."""
footer_key = FooterKey(key, description)
self._left_items.append(footer_key)
self._update_left_section()
def add_right_item(self, item: str) -> None:
"""Add an item to the right section."""
self._right_items.append(item)
def add_right_item(self, key: str, description: str) -> None:
"""Add a key-description pair to the right section."""
footer_key = FooterKey(key, description)
self._right_items.append(footer_key)
self._update_right_section()
def add_left_item_legacy(self, item: str) -> None:
"""Add a legacy item (key: description format) to the left section."""
if ": " in item:
key, description = item.split(": ", 1)
self.add_left_item(key, description)
else:
self.add_left_item(item, "")
def add_right_item_legacy(self, item: str) -> None:
"""Add a legacy item (key: description format) to the right section."""
if ": " in item:
key, description = item.split(": ", 1)
self.add_right_item(key, description)
else:
self.add_right_item(item, "")
# Backward compatibility - temporarily add the old single parameter methods
def add_left_item_old(self, item: str) -> None:
"""Backward compatibility method."""
self.add_left_item_legacy(item)
def add_right_item_old(self, item: str) -> None:
"""Backward compatibility method."""
self.add_right_item_legacy(item)
def clear_left_items(self) -> None:
"""Clear all items from the left section."""
self._left_items.clear()
@ -119,7 +193,19 @@ class CustomFooter(Widget):
"""Update the left section display."""
try:
left_static = self.query_one("#footer-left", Static)
left_static.update(" ".join(self._left_items))
if self._left_items:
# Combine all FooterKey renderings with spacing
combined_text = Text()
for i, footer_key in enumerate(self._left_items):
if i > 0:
combined_text.append(" ") # Add spacing between items
# Render individual key-description pair with styling
combined_text.append(footer_key.key, style="bold")
combined_text.append(" ")
combined_text.append(footer_key.description, style="dim")
left_static.update(combined_text)
else:
left_static.update("")
except Exception:
pass # Widget not ready yet
@ -127,7 +213,19 @@ class CustomFooter(Widget):
"""Update the right section display."""
try:
right_static = self.query_one("#footer-right", Static)
right_static.update(" ".join(self._right_items))
if self._right_items:
# Combine all FooterKey renderings with spacing
combined_text = Text()
for i, footer_key in enumerate(self._right_items):
if i > 0:
combined_text.append(" ") # Add spacing between items
# Render individual key-description pair with styling
combined_text.append(footer_key.key, style="bold")
combined_text.append(" ")
combined_text.append(footer_key.description, style="dim")
right_static.update(combined_text)
else:
right_static.update("")
except Exception:
pass # Widget not ready yet

View file

@ -12,8 +12,20 @@ HOSTS_MANAGER_BINDINGS = [
Binding("a", "add_entry", "Add new entry", show=True, id="left:add_entry"),
Binding("d", "delete_entry", "Delete entry", show=True, id="left:delete_entry"),
Binding("e", "edit_entry", "Edit entry", show=True, id="left:edit_entry"),
Binding("space", "toggle_entry", "Toggle active/inactive", show=True, id="left:toggle_entry"),
Binding("ctrl+e", "toggle_edit_mode", "Toggle edit mode", show=True, id="left:toggle_edit_mode"),
Binding(
"space",
"toggle_entry",
"Toggle active/inactive",
show=True,
id="left:toggle_entry",
),
Binding(
"ctrl+e",
"toggle_edit_mode",
"Toggle edit mode",
show=True,
id="left:toggle_edit_mode",
),
Binding("c", "config", "Configuration", show=True, id="right:config"),
Binding(
"question_mark",
@ -26,9 +38,7 @@ HOSTS_MANAGER_BINDINGS = [
Binding("q", "quit", "Quit", show=True, id="right:quit"),
Binding("r", "reload", "Reload hosts file", show=False),
Binding("i", "sort_by_ip", "Sort by IP address", show=False),
Binding(
"h", "sort_by_hostname", "Sort by hostname", show=False
),
Binding("h", "sort_by_hostname", "Sort by hostname", show=False),
Binding("ctrl+s", "save_file", "Save hosts file", show=False),
Binding("shift+up", "move_entry_up", "Move entry up", show=False),
Binding("shift+down", "move_entry_down", "Move entry down", show=False),