diff --git a/examples/dictionary.py b/examples/dictionary.py new file mode 100644 index 0000000..0e54a7d --- /dev/null +++ b/examples/dictionary.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +""" +Adapted from https://github.com/Textualize/textual/blob/main/examples/dictionary.py +""" + +from __future__ import annotations + +__import__("viv").use("textual", "httpx") # noqa + +try: + import httpx +except ImportError: + raise ImportError("Please install httpx with 'pip install httpx' ") + +from textual import work +from textual.app import App, ComposeResult +from textual.containers import VerticalScroll +from textual.widgets import Input, Markdown + + +class DictionaryApp(App): + """Searches ab dictionary API as-you-type.""" + + # CSS_PATH = "dictionary.css" + DEFAULT_CSS = """ +Screen { + background: $panel; +} + +Input { + dock: top; + margin: 1 0; +} + +#results { + width: 100%; + height: auto; + +} + +#results-container { + background: $background 50%; + margin: 0 0 1 0; + height: 100%; + overflow: hidden auto; + border: tall $background; +} + +#results-container:focus { + border: tall $accent; +} +""" + + def compose(self) -> ComposeResult: + yield Input(placeholder="Search for a word") + with VerticalScroll(id="results-container"): + yield Markdown(id="results") + + def on_mount(self) -> None: + """Called when app starts.""" + # Give the input focus, so we can start typing straight away + self.query_one(Input).focus() + + async def on_input_changed(self, message: Input.Changed) -> None: + """A coroutine to handle a text changed message.""" + if message.value: + self.lookup_word(message.value) + else: + # Clear the results + self.query_one("#results", Markdown).update("") + + @work(exclusive=True) + async def lookup_word(self, word: str) -> None: + """Looks up a word.""" + url = f"https://api.dictionaryapi.dev/api/v2/entries/en/{word}" + + async with httpx.AsyncClient() as client: + response = await client.get(url) + try: + results = response.json() + except Exception: + self.query_one("#results", Markdown).update(response.text) + + if word == self.query_one(Input).value: + markdown = self.make_word_markdown(results) + self.query_one("#results", Markdown).update(markdown) + + def make_word_markdown(self, results: object) -> str: + """Convert the results in to markdown.""" + lines = [] + if isinstance(results, dict): + lines.append(f"# {results['title']}") + lines.append(results["message"]) + elif isinstance(results, list): + for result in results: + lines.append(f"# {result['word']}") + lines.append("") + for meaning in result.get("meanings", []): + lines.append(f"_{meaning['partOfSpeech']}_") + lines.append("") + for definition in meaning.get("definitions", []): + lines.append(f" - {definition['definition']}") + lines.append("---") + + return "\n".join(lines) + + +if __name__ == "__main__": + app = DictionaryApp() + app.run()