blob: c9cfb3a40dd90aff709bca17fa893d134c438567 [file] [log] [blame]
# Copyright 2021 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Help window container class."""
import logging
import inspect
from functools import partial
from pathlib import Path
from jinja2 import Template
from prompt_toolkit.filters import Condition
from prompt_toolkit.layout import (
ConditionalContainer,
FormattedTextControl,
Window,
)
from prompt_toolkit.widgets import (Box, Frame)
_LOG = logging.getLogger(__package__)
HELP_TEMPLATE_PATH = Path(__file__).parent / "templates" / "keybind_list.jinja"
with HELP_TEMPLATE_PATH.open() as tmpl:
KEYBIND_TEMPLATE = tmpl.read()
class HelpWindow(ConditionalContainer):
"""Help window container for displaying keybindings."""
def get_tokens(self, application):
"""Get all text for the help window."""
help_window_content = (
# Style
'class:help_window_content',
# Text
self.help_text,
)
if application.show_help_window:
return [help_window_content]
return []
def __init__(self, application):
# Dict containing key = section title and value = list of key bindings.
self.help_text_sections = {}
self.max_description_width = 0
# Generated keybinding text
self.help_text = ''
help_text_window = Window(
FormattedTextControl(partial(self.get_tokens, application)),
style='class:help_window_content',
)
help_text_window_with_padding = Box(
body=help_text_window,
padding=1,
char=' ',
)
super().__init__(
# Add a text border frame.
Frame(body=help_text_window_with_padding),
filter=Condition(lambda: application.show_help_window),
)
def generate_help_text(self):
"""Generate help text based on added key bindings."""
# pylint: disable=line-too-long
template = Template(
KEYBIND_TEMPLATE,
trim_blocks=True,
lstrip_blocks=True,
)
self.help_text = template.render(
sections=self.help_text_sections,
max_description_width=self.max_description_width,
)
return self.help_text
def add_keybind_help_text(self, section_name, key_bindings):
"""Append formatted key binding text to this help window."""
# Create a new keybind section
if section_name not in self.help_text_sections:
self.help_text_sections[section_name] = {}
# Loop through passed in prompt_toolkit key_bindings.
for binding in key_bindings.bindings:
# Get the key binding description from the function doctstring.
description = inspect.cleandoc(binding.handler.__doc__)
# Save the length of the description.
if len(description) > self.max_description_width:
self.max_description_width = len(description)
# Get the existing list of keys for this function or make a new one.
key_list = self.help_text_sections[section_name].get(
description, list())
# Save the name of the key e.g. F1, q, ControlQ, ControlUp
key_name = getattr(binding.keys[0], 'name', str(binding.keys[0]))
key_list.append(key_name)
# Update this functions key_list
self.help_text_sections[section_name][description] = key_list