Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion nb_cli/config/model.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from pydantic import BaseModel

from nb_cli.compat import PYDANTIC_V2, ConfigDict
Expand All @@ -13,24 +15,27 @@ class Adapter(SimpleInfo):

project_link: str
desc: str
is_official: Optional[bool] = None


class Plugin(SimpleInfo):
__module_name__ = "plugins"

project_link: str
desc: str
is_official: Optional[bool] = None
valid: Optional[bool] = None


class Driver(SimpleInfo):
__module_name__ = "drivers"

project_link: str
desc: str
is_official: Optional[bool] = None


class NoneBotConfig(BaseModel):

if PYDANTIC_V2: # pragma: pydantic-v2
model_config = ConfigDict(extra="allow")
else: # pragma: pydantic-v1
Expand Down
7 changes: 6 additions & 1 deletion nb_cli/handlers/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,10 @@ async def list_adapters(query: Optional[str] = None) -> list[Adapter]:
return [
adapter
for adapter in adapters
if any(query in value for value in model_dump(adapter).values())
if any(
query in value
for value in model_dump(
adapter, include={"name", "module_name", "project_link", "desc"}
).values()
)
]
7 changes: 6 additions & 1 deletion nb_cli/handlers/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ async def list_drivers(query: Optional[str] = None) -> list[Driver]:
return [
driver
for driver in drivers
if any(query in value for value in model_dump(driver).values())
if any(
query in value
for value in model_dump(
driver, include={"name", "module_name", "project_link", "desc"}
).values()
)
]
7 changes: 6 additions & 1 deletion nb_cli/handlers/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,10 @@ async def list_plugins(query: Optional[str] = None) -> list[Plugin]:
return [
plugin
for plugin in plugins
if any(query in value for value in model_dump(plugin).values())
if any(
query in value
for value in model_dump(
plugin, include={"name", "module_name", "project_link", "desc"}
).values()
)
]
68 changes: 48 additions & 20 deletions nb_cli/handlers/store.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import shutil
from statistics import median_high
from asyncio import create_task, as_completed
from typing import TYPE_CHECKING, Union, Literal, TypeVar, Optional, overload

Expand All @@ -25,14 +26,14 @@ async def load_module_data(module_type: Literal["plugin"]) -> list[Plugin]: ...
async def load_module_data(module_type: Literal["driver"]) -> list[Driver]: ...

async def load_module_data(
module_type: Literal["adapter", "plugin", "driver"]
module_type: Literal["adapter", "plugin", "driver"],
) -> Union[list[Adapter], list[Plugin], list[Driver]]: ...

else:

@cache(ttl=None)
async def load_module_data(
module_type: Literal["adapter", "plugin", "driver"]
module_type: Literal["adapter", "plugin", "driver"],
) -> Union[list[Adapter], list[Plugin], list[Driver]]:
if module_type == "adapter":
module_class = Adapter
Expand Down Expand Up @@ -79,6 +80,13 @@ async def _request(url: str) -> httpx.Response:
)


def split_text_by_wcswidth(text: str, width: int):
_width = width
while wcswidth(text[:_width]) > width:
_width = _width - 1
return text[:_width], text[_width:]


def format_package_results(
hits: list[T],
name_column_width: Optional[int] = None,
Expand All @@ -88,29 +96,49 @@ def format_package_results(
return ""

if name_column_width is None:
name_column_width = (
max(wcswidth(f"{hit.name} ({hit.project_link})") for hit in hits) + 4
name_column_width = median_high(
wcswidth(f"{hit.name} ({hit.project_link})") for hit in hits
)
if terminal_width is None:
terminal_width = shutil.get_terminal_size()[0]

desc_width = terminal_width - name_column_width - 8

lines: list[str] = []
for hit in hits:
name = f"{hit.name} ({hit.project_link})"
summary = hit.desc
target_width = terminal_width - name_column_width - 5
if target_width > 10:
# wrap and indent summary to fit terminal
summary_lines = []
while wcswidth(summary) > target_width:
tmp_length = target_width
while wcswidth(summary[:tmp_length]) > target_width:
tmp_length = tmp_length - 1
summary_lines.append(summary[:tmp_length])
summary = summary[tmp_length:]
summary_lines.append(summary)
summary = ("\n" + " " * (name_column_width + 3)).join(summary_lines)

lines.append(f"{name + ' ' * (name_column_width - wcswidth(name))} - {summary}")
is_official = "👍" if hit.is_official else " "
valid = " "
if isinstance(hit, Plugin):
valid = "✅" if hit.valid else "❌"
name = hit.name.replace("\n", "")
link = f"({hit.project_link})"
desc = hit.desc.replace("\n", "")
# wrap and indent summary to fit terminal
is_first_line = True
while (
wcswidth(f"{name} {link}") > name_column_width
or wcswidth(desc) > desc_width
):
name_column, name = split_text_by_wcswidth(name, name_column_width)
if name_column == "":
name_column, link = split_text_by_wcswidth(link, name_column_width)
desc_column, desc = split_text_by_wcswidth(desc, desc_width)
lines.append(
name_column
+ " " * (name_column_width - wcswidth(name_column))
+ (f" {valid} {is_official} " if is_first_line else " " * 7)
+ desc_column
+ " " * (desc_width - wcswidth(desc_column))
)
is_first_line = False

name_column = f"{name} {link}".strip()
lines.append(
name_column
+ " " * (name_column_width - wcswidth(name_column))
+ (f" {valid} {is_official} " if is_first_line else " " * 7)
+ desc
+ " " * (desc_width - wcswidth(desc))
)

return "\n".join(lines)