#!/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()