Address review feedback.

This commit is contained in:
Rodrigo Girão Serrão
2023-05-23 11:46:05 +01:00
parent 124e62e41b
commit e63ec577cd
3 changed files with 21 additions and 18 deletions

View File

@@ -10,14 +10,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added ### Added
- `Suggester` API to compose with `Input` for automatic input suggestions while typing https://github.com/Textualize/textual/issues/2330 - `Suggester` API to compose with widgets for automatic suggestions https://github.com/Textualize/textual/issues/2330
- `SuggestFromList` class to let `Input` widgets get completions from a fixed set of options https://github.com/Textualize/textual/pull/2604 - `SuggestFromList` class to let widgets get completions from a fixed set of options https://github.com/Textualize/textual/pull/2604
- `Input` has new component class `input--suggestion` https://github.com/Textualize/textual/pull/2604 - `Input` has a new component class `input--suggestion` https://github.com/Textualize/textual/pull/2604
### Changed ### Changed
- Keybinding <kbd>right</kbd> in `Input` is also used to accept a suggestion if the cursor is at the end of the input https://github.com/Textualize/textual/pull/2604 - Keybinding <kbd>right</kbd> in `Input` is also used to accept a suggestion if the cursor is at the end of the input https://github.com/Textualize/textual/pull/2604
- `Input.__init__` now accepts a suggester for completion suggestions https://github.com/Textualize/textual/pull/2604 - `Input.__init__` now accepts a `suggester` attribute for completion suggestions https://github.com/Textualize/textual/pull/2604
## [0.25.0] - 2023-05-17 ## [0.25.0] - 2023-05-17

View File

@@ -1,11 +1,12 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING, Iterable, Optional from typing import Generic, Iterable, Optional, TypeVar
from ._types import MessageTarget
from .message import Message from .message import Message
if TYPE_CHECKING: _SuggestionRequester = TypeVar("_SuggestionRequester", bound=MessageTarget)
from .widgets import Input """Type variable for the message target that will request suggestions."""
@dataclass @dataclass
@@ -18,7 +19,7 @@ class SuggestionReady(Message):
"""The string suggestion.""" """The string suggestion."""
class Suggester(ABC): class Suggester(ABC, Generic[_SuggestionRequester]):
"""Defines how [inputs][textual.widgets.Input] generate completion suggestions. """Defines how [inputs][textual.widgets.Input] generate completion suggestions.
To define a custom suggester, subclass `Suggester` and implement the async method To define a custom suggester, subclass `Suggester` and implement the async method
@@ -26,22 +27,24 @@ class Suggester(ABC):
See [`SuggestFromList`][textual.suggester.SuggestFromList] for an example. See [`SuggestFromList`][textual.suggester.SuggestFromList] for an example.
""" """
async def get(self, input: "Input", value: str) -> None: async def _get_suggestion(
"""Used by [`Input`][textual.widgets.Input] to get completion suggestions. self, requester: _SuggestionRequester, value: str
) -> None:
"""Used by widgets to get completion suggestions.
Note: Note:
When implementing custom suggesters, this method does not need to be When implementing custom suggesters, this method does not need to be
overridden. overridden.
Args: Args:
input: The input widget that requested a suggestion. requester: The message target that requested a suggestion.
value: The current input value to complete. value: The current input value to complete.
""" """
suggestion = await self.get_suggestion(value) suggestion = await self.get_suggestion(value)
if suggestion is None: if suggestion is None:
return return
input.post_message(SuggestionReady(value, suggestion)) requester.post_message(SuggestionReady(value, suggestion))
@abstractmethod @abstractmethod
async def get_suggestion(self, value: str) -> Optional[str]: async def get_suggestion(self, value: str) -> Optional[str]:
@@ -55,10 +58,10 @@ class Suggester(ABC):
Returns: Returns:
A valid suggestion or `None`. A valid suggestion or `None`.
""" """
raise NotImplementedError() pass
class SuggestFromList(Suggester): class SuggestFromList(Suggester[_SuggestionRequester]):
"""Give completion suggestions based on a fixed list of options.""" """Give completion suggestions based on a fixed list of options."""
def __init__(self, suggestions: Iterable[str]) -> None: def __init__(self, suggestions: Iterable[str]) -> None:
@@ -73,10 +76,10 @@ class SuggestFromList(Suggester):
"""Gets a completion from the given possibilities. """Gets a completion from the given possibilities.
Args: Args:
value: The current value of the input widget. value: The current value.
Returns: Returns:
A valid suggestion or `None`. A valid completion suggestion or `None`.
""" """
for suggestion in self.suggestions: for suggestion in self.suggestions:
if suggestion.startswith(value): if suggestion.startswith(value):

View File

@@ -156,7 +156,7 @@ class Input(Widget, can_focus=True):
_cursor_visible = reactive(True) _cursor_visible = reactive(True)
password = reactive(False) password = reactive(False)
max_size: reactive[int | None] = reactive(None) max_size: reactive[int | None] = reactive(None)
suggester: Suggester | None suggester: Suggester[Input] | None
"""The suggester used to provide completions as the user types.""" """The suggester used to provide completions as the user types."""
_suggestion = reactive("") _suggestion = reactive("")
"""A completion suggestion for the current value in the input.""" """A completion suggestion for the current value in the input."""
@@ -284,7 +284,7 @@ class Input(Widget, can_focus=True):
async def watch_value(self, value: str) -> None: async def watch_value(self, value: str) -> None:
self._suggestion = "" self._suggestion = ""
if self.suggester and value: if self.suggester and value:
self.call_next(self.suggester.get, self, value) self.call_next(self.suggester._get_suggestion, self, value)
if self.styles.auto_dimensions: if self.styles.auto_dimensions:
self.refresh(layout=True) self.refresh(layout=True)
self.post_message(self.Changed(self, value)) self.post_message(self.Changed(self, value))