blob: b7eb83f70e616bd7d528f930bd7f3d7398b978d0 [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.
"""pw_console embed class."""
import asyncio
import logging
from typing import Dict, List, Iterable, Optional, Union
from prompt_toolkit.completion import WordCompleter
from pw_console.console_app import ConsoleApp
class PwConsoleEmbed:
"""Embed class for customizing the console before startup."""
def __init__(
self,
global_vars=None,
local_vars=None,
loggers: Optional[Union[Dict[str, Iterable[logging.Logger]],
Iterable]] = None,
test_mode=False,
repl_startup_message: Optional[str] = None,
help_text: Optional[str] = None,
app_title: Optional[str] = None,
) -> None:
"""Call this to embed pw console at the call point within your program.
Example usage: ::
import logging
from pw_console import PwConsoleEmbed
# Create the pw_console embed instance
console = PwConsoleEmbed(
global_vars=globals(),
local_vars=locals(),
loggers={
'Host Logs': [
logging.getLogger(__package__),
logging.getLogger(__file__)
],
'Device Logs': [
logging.getLogger('usb_gadget')
],
},
app_title='My Awesome Console',
)
# Optional: Add custom completions
console.add_sentence_completer(
{
'some_function', 'Function',
'some_variable', 'Variable',
}
)
# Then run the console with:
console.embed()
Args:
global_vars: Dictionary representing the desired global symbol
table. Similar to what is returned by `globals()`.
local_vars: Dictionary representing the desired local symbol
table. Similar to what is returned by `locals()`.
loggers: Dict with keys of log window titles and values of
`logging.getLogger()` instances in lists. Each key that should
be shown in the pw console user interface.
app_title: Custom title text displayed in the user interface.
repl_startup_message: Custom text shown by default in the repl
output pane.
help_text: Custom text shown at the top of the help window before
keyboard shortcuts.
"""
self.global_vars = global_vars
self.local_vars = local_vars
self.loggers = loggers
self.test_mode = test_mode
self.repl_startup_message = repl_startup_message
self.help_text = help_text
self.app_title = app_title
self.console_app = None
self.extra_completers: List = []
def add_sentence_completer(self,
word_meta_dict: Dict[str, str],
ignore_case=True):
"""Include a custom completer that matches on the entire repl input.
Args:
word_meta_dict: Dictionary representing the sentence completions
and descriptions. Keys are completion text, values are
descriptions.
"""
# Don't modify completion if empty.
if len(word_meta_dict) == 0:
return
sentences: List[str] = list(word_meta_dict.keys())
word_completer = WordCompleter(
sentences,
meta_dict=word_meta_dict,
ignore_case=ignore_case,
# Whole input field should match
sentence=True,
)
self.extra_completers.append(word_completer)
def _setup_log_panes(self):
"""Add loggers to the console app log pane(s)."""
if self.loggers:
if isinstance(self.loggers, list):
self.console_app.add_log_handler('Logs', self.loggers)
elif isinstance(self.loggers, dict):
for window_title, logger_instances in self.loggers.items():
self.console_app.add_log_handler(window_title,
logger_instances)
def embed(self):
"""Start the console."""
# Create the ConsoleApp instance.
self.console_app = ConsoleApp(
global_vars=self.global_vars,
local_vars=self.local_vars,
repl_startup_message=self.repl_startup_message,
help_text=self.help_text,
app_title=self.app_title,
extra_completers=self.extra_completers,
)
self._setup_log_panes()
# Start a thread for running user code.
self.console_app.start_user_code_thread()
# Start the prompt_toolkit UI app.
asyncio.run(self.console_app.run(test_mode=self.test_mode),
debug=self.test_mode)