From 7b5dddf34bfcf3c4101e89cd18d53750e4aa2a38 Mon Sep 17 00:00:00 2001 From: Softer Date: Thu, 7 May 2026 03:17:13 +0300 Subject: [PATCH] Fix truncated package metadata in additional packages preview (#3580) (#4510) * Fix truncated package metadata in additional packages preview (#3580) * Simplify package info fix: use rstrip and CSS wrap instead of env var plumbing * Apply preview text wrap conditionally via wrap_preview parameter * Add missing wrap-preview CSS to OptionListScreen and pass parameter through SelectMenu --- archinstall/lib/menu/helpers.py | 4 ++++ archinstall/lib/models/packages.py | 1 - archinstall/lib/packages/packages.py | 7 ++++--- archinstall/tui/components.py | 24 ++++++++++++++++++++++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/archinstall/lib/menu/helpers.py b/archinstall/lib/menu/helpers.py index b512c956..947f3c55 100644 --- a/archinstall/lib/menu/helpers.py +++ b/archinstall/lib/menu/helpers.py @@ -20,6 +20,7 @@ class Selection[ValueT]: preview_location: Literal['right', 'bottom'] | None = None, multi: bool = False, enable_filter: bool = False, + wrap_preview: bool = False, ): self._header = header self._title = title @@ -29,6 +30,7 @@ class Selection[ValueT]: self._preview_location = preview_location self._multi = multi self._enable_filter = enable_filter + self._wrap_preview = wrap_preview async def show(self) -> Result[ValueT]: if self._multi: @@ -39,6 +41,7 @@ class Selection[ValueT]: allow_reset=self._allow_reset, preview_location=self._preview_location, enable_filter=self._enable_filter, + wrap_preview=self._wrap_preview, ).run() else: result = await OptionListScreen[ValueT]( @@ -49,6 +52,7 @@ class Selection[ValueT]: allow_reset=self._allow_reset, preview_location=self._preview_location, enable_filter=self._enable_filter, + wrap_preview=self._wrap_preview, ).run() if result.type_ == ResultType.Reset: diff --git a/archinstall/lib/models/packages.py b/archinstall/lib/models/packages.py index 6ba6e134..205d653e 100644 --- a/archinstall/lib/models/packages.py +++ b/archinstall/lib/models/packages.py @@ -132,7 +132,6 @@ class AvailablePackage(BaseModel): def longest_key(self) -> int: return max(len(key) for key in self.model_dump().keys()) - # return all package info line by line def info(self) -> str: output = '' for key, value in self.model_dump().items(): diff --git a/archinstall/lib/packages/packages.py b/archinstall/lib/packages/packages.py index dcc4da9e..a7422986 100644 --- a/archinstall/lib/packages/packages.py +++ b/archinstall/lib/packages/packages.py @@ -14,7 +14,7 @@ def installed_package(package: str) -> LocalPackage | None: try: package_info = [] for line in Pacman.run(f'-Q --info {package}'): - package_info.append(line.decode().strip()) + package_info.append(line.decode().rstrip()) return _parse_package_output(package_info, LocalPackage) except SysCallError: @@ -53,7 +53,7 @@ def available_package(package: str) -> AvailablePackage | None: try: package_info: list[str] = [] for line in Pacman.run(f'-S --info {package}'): - package_info.append(line.decode().strip()) + package_info.append(line.decode().rstrip()) return _parse_package_output(package_info, AvailablePackage) except SysCallError: @@ -79,7 +79,7 @@ def list_available_packages( debug(f'Failed to sync Arch Linux package database: {e}') for line in Pacman.run('-S --info'): - dec_line = line.decode().strip() + dec_line = line.decode().rstrip() current_package.append(dec_line) if dec_line.startswith('Validated'): @@ -187,6 +187,7 @@ async def select_additional_packages( multi=True, preview_location='right', enable_filter=True, + wrap_preview=True, ).show() match pck_result.type_: diff --git a/archinstall/tui/components.py b/archinstall/tui/components.py index f92364bb..f732c21f 100644 --- a/archinstall/tui/components.py +++ b/archinstall/tui/components.py @@ -200,6 +200,11 @@ class OptionListScreen(BaseScreen[ValueT]): color: white; text-style: bold; } + + .wrap-preview { + width: 100%; + height: auto; + } """ def __init__( @@ -211,6 +216,7 @@ class OptionListScreen(BaseScreen[ValueT]): allow_reset: bool = False, preview_location: Literal['right', 'bottom'] | None = None, enable_filter: bool = False, + wrap_preview: bool = False, ): super().__init__(allow_skip, allow_reset) self._group = group @@ -218,6 +224,7 @@ class OptionListScreen(BaseScreen[ValueT]): self._title = title self._preview_location = preview_location self._filter = enable_filter + self._wrap_preview = wrap_preview self._show_frame = False self._options = self._get_options() @@ -280,7 +287,10 @@ class OptionListScreen(BaseScreen[ValueT]): with Container(): yield option_list yield Rule(orientation=rule_orientation) - yield ScrollableContainer(Label('', id='preview_content', markup=False)) + preview_label = Label('', id='preview_content', markup=False) + if self._wrap_preview: + preview_label.add_class('wrap-preview') + yield ScrollableContainer(preview_label) if self._filter: yield Input(placeholder='/filter', id='filter-input') @@ -433,6 +443,11 @@ class SelectListScreen(BaseScreen[ValueT]): color: white; text-style: bold; } + + .wrap-preview { + width: 100%; + height: auto; + } """ def __init__( @@ -443,6 +458,7 @@ class SelectListScreen(BaseScreen[ValueT]): allow_reset: bool = False, preview_location: Literal['right', 'bottom'] | None = None, enable_filter: bool = False, + wrap_preview: bool = False, ): super().__init__(allow_skip, allow_reset) self._group = group @@ -450,6 +466,7 @@ class SelectListScreen(BaseScreen[ValueT]): self._preview_location = preview_location self._show_frame = False self._filter = enable_filter + self._wrap_preview = wrap_preview self._selected_items: list[MenuItem] = self._group.selected_items self._options: list[Selection[MenuItem]] = self._get_selections() @@ -510,7 +527,10 @@ class SelectListScreen(BaseScreen[ValueT]): with Container(): yield selection_list yield Rule(orientation=rule_orientation) - yield ScrollableContainer(Label('', id='preview_content', markup=False)) + preview_label = Label('', id='preview_content', markup=False) + if self._wrap_preview: + preview_label.add_class('wrap-preview') + yield ScrollableContainer(preview_label) if self._filter: yield Input(placeholder='/filter', id='filter-input')