Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
cf42da6
Migrate single selection menus
Nov 8, 2025
912c832
Merge branch 'migrate-textual' of github.com:svartkanin/archinstall i…
Nov 8, 2025
2752599
Update
Nov 9, 2025
b7022d9
Update
Nov 17, 2025
d04f44d
Update
Nov 19, 2025
2cafde1
Fix input form alignment
Nov 22, 2025
d871b8c
Merge remote-tracking branch 'origin/master' into migrate-textual
Nov 23, 2025
8ddd4f7
Migrate more menus
Nov 24, 2025
3cd2a36
Merge remote-tracking branch 'origin/master' into migrate-textual
Nov 29, 2025
ce6b05e
Update
Dec 1, 2025
24c20dc
Merge remote-tracking branch 'origin/master' into migrate-textual
Dec 8, 2025
1c9597b
Update
Dec 8, 2025
4c6609c
Add scrollbar
Dec 10, 2025
bd5c4dc
Update
Dec 10, 2025
3866834
Update
Dec 10, 2025
bfe5423
Update
Dec 10, 2025
2dd56e2
Update
Dec 11, 2025
014e98f
Update
Dec 11, 2025
b83570f
update
Dec 11, 2025
77fbcd0
update
Dec 11, 2025
4b2b1b3
update
Dec 11, 2025
3c877a9
Update
Dec 15, 2025
aafd4ba
Update
Dec 15, 2025
bd4398c
Update
Dec 15, 2025
95316d0
Update
Dec 15, 2025
41be806
Update
Dec 15, 2025
648120e
Update
Dec 15, 2025
63d1de0
Update
Dec 15, 2025
3a54663
Update
Dec 15, 2025
abad73b
Update
Dec 15, 2025
fdb002f
Update
Dec 15, 2025
c0fcbbb
Updaet
Dec 15, 2025
8868173
Merge remote-tracking branch 'origin/master' into migrate-textual
Dec 16, 2025
fefe292
Update linting
Dec 16, 2025
ec2d342
Update
Dec 16, 2025
210d7fa
Update
Dec 16, 2025
4a00bf1
Update github action
Dec 16, 2025
ee3251f
Update
Dec 16, 2025
8a7a464
Update wifi
Dec 16, 2025
c4cc00b
Update wifi
Dec 16, 2025
68b3cd8
Update
Dec 17, 2025
c8e4141
Update
Dec 17, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/python-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
pacman --noconfirm -Sy archlinux-keyring
pacman --noconfirm -Syyu
pacman --noconfirm -Sy python-uv python-setuptools python-pip
pacman --noconfirm -Sy python-pyparted python-pydantic
pacman --noconfirm -Sy python-pyparted python-pydantic python-textual
- name: Remove existing archinstall (if any)
run:
uv pip uninstall archinstall --break-system-packages --system
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ requirements.txt
/actions-runner
/cmd_output.txt
uv.lock
pyrightconfig.json
11 changes: 3 additions & 8 deletions archinstall/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
from archinstall.lib.network.wifi_handler import wifi_handler
from archinstall.lib.networking import ping
from archinstall.lib.packages.packages import check_package_upgrade
from archinstall.tui.ui.components import tui as ttui
from archinstall.tui.ui.components import tui as tui

from .lib.general import running_from_host
from .lib.hardware import SysInfo
from .lib.output import FormattedOutput, debug, error, info, log, warn
from .lib.pacman import Pacman
from .lib.plugins import load_plugin, plugins
from .lib.translationhandler import Language, tr, translation_handler
from .tui.curses_menu import Tui


# @archinstall.plugin decorator hook to programmatically add
Expand Down Expand Up @@ -97,7 +96,7 @@ def main() -> int:

_log_sys_info()

ttui.global_header = 'Archinstall'
tui.global_header = 'Archinstall'

if not arch_config_handler.args.offline:
_check_online()
Expand All @@ -107,7 +106,7 @@ def main() -> int:
new_version = check_version_upgrade()

if new_version:
ttui.global_header = f'{ttui.global_header} {new_version}'
tui.global_header = f'{tui.global_header} {new_version}'
info(new_version)
time.sleep(3)

Expand Down Expand Up @@ -135,9 +134,6 @@ def run_as_a_module() -> None:
except Exception as e:
exc = e
finally:
# restore the terminal to the original state
Tui.shutdown()

if exc:
err = ''.join(traceback.format_exception(exc))
error(err)
Expand All @@ -159,7 +155,6 @@ def run_as_a_module() -> None:
'Language',
'Pacman',
'SysInfo',
'Tui',
'arch_config_handler',
'debug',
'disk_layouts',
Expand Down
17 changes: 7 additions & 10 deletions archinstall/default_profiles/desktop.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import TYPE_CHECKING, override

from archinstall.default_profiles.profile import GreeterType, Profile, ProfileType, SelectResult
from archinstall.lib.menu.helpers import Selection
from archinstall.lib.output import info
from archinstall.lib.profile.profiles_handler import profile_handler
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import FrameProperties, PreviewStyle
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType

if TYPE_CHECKING:
from archinstall.lib.installer import Installer
Expand Down Expand Up @@ -61,23 +60,21 @@ def do_on_select(self) -> SelectResult:
MenuItem(
p.name,
value=p,
preview_action=lambda x: x.value.preview_text(),
preview_action=lambda x: x.value.preview_text() if x.value else None,
)
for p in profile_handler.get_desktop_profiles()
]

group = MenuItemGroup(items, sort_items=True, sort_case_sensitive=False)
group.set_selected_by_value(self.current_selection)

result = SelectMenu[Profile](
result = Selection[Profile](
group,
multi=True,
allow_reset=True,
allow_skip=True,
preview_style=PreviewStyle.RIGHT,
preview_size='auto',
preview_frame=FrameProperties.max('Info'),
).run()
preview_location='right',
).show()

match result.type_:
case ResultType.Selection:
Expand Down
13 changes: 5 additions & 8 deletions archinstall/default_profiles/desktops/hyprland.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from archinstall.default_profiles.desktops import SeatAccess
from archinstall.default_profiles.profile import GreeterType, ProfileType
from archinstall.default_profiles.xorg import XorgProfile
from archinstall.lib.menu.helpers import Selection
from archinstall.lib.translationhandler import tr
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType


class HyprlandProfile(XorgProfile):
Expand Down Expand Up @@ -57,13 +56,11 @@ def _ask_seat_access(self) -> None:
default = self.custom_settings.get('seat_access', None)
group.set_default_by_value(default)

result = SelectMenu[SeatAccess](
result = Selection[SeatAccess](
group,
header=header,
allow_skip=False,
frame=FrameProperties.min(tr('Seat access')),
alignment=Alignment.CENTER,
).run()
).show()

if result.type_ == ResultType.Selection:
self.custom_settings['seat_access'] = result.get_value().value
Expand Down
13 changes: 5 additions & 8 deletions archinstall/default_profiles/desktops/labwc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from archinstall.default_profiles.desktops import SeatAccess
from archinstall.default_profiles.profile import GreeterType, ProfileType
from archinstall.default_profiles.xorg import XorgProfile
from archinstall.lib.menu.helpers import Selection
from archinstall.lib.translationhandler import tr
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType


class LabwcProfile(XorgProfile):
Expand Down Expand Up @@ -54,13 +53,11 @@ def _ask_seat_access(self) -> None:
default = self.custom_settings.get('seat_access', None)
group.set_default_by_value(default)

result = SelectMenu[SeatAccess](
result = Selection[SeatAccess](
group,
header=header,
allow_skip=False,
frame=FrameProperties.min(tr('Seat access')),
alignment=Alignment.CENTER,
).run()
).show()

if result.type_ == ResultType.Selection:
self.custom_settings['seat_access'] = result.get_value().value
Expand Down
13 changes: 5 additions & 8 deletions archinstall/default_profiles/desktops/niri.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from archinstall.default_profiles.desktops import SeatAccess
from archinstall.default_profiles.profile import GreeterType, ProfileType
from archinstall.default_profiles.xorg import XorgProfile
from archinstall.lib.menu.helpers import Selection
from archinstall.lib.translationhandler import tr
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType


class NiriProfile(XorgProfile):
Expand Down Expand Up @@ -62,13 +61,11 @@ def _ask_seat_access(self) -> None:
default = self.custom_settings.get('seat_access', None)
group.set_default_by_value(default)

result = SelectMenu[SeatAccess](
result = Selection[SeatAccess](
group,
header=header,
allow_skip=False,
frame=FrameProperties.min(tr('Seat access')),
alignment=Alignment.CENTER,
).run()
).show()

if result.type_ == ResultType.Selection:
self.custom_settings['seat_access'] = result.get_value().value
Expand Down
13 changes: 5 additions & 8 deletions archinstall/default_profiles/desktops/sway.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from archinstall.default_profiles.desktops import SeatAccess
from archinstall.default_profiles.profile import GreeterType, ProfileType
from archinstall.default_profiles.xorg import XorgProfile
from archinstall.lib.menu.helpers import Selection
from archinstall.lib.translationhandler import tr
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType


class SwayProfile(XorgProfile):
Expand Down Expand Up @@ -64,13 +63,11 @@ def _ask_seat_access(self) -> None:
default = self.custom_settings.get('seat_access', None)
group.set_default_by_value(default)

result = SelectMenu[SeatAccess](
result = Selection[SeatAccess](
group,
header=header,
allow_skip=False,
frame=FrameProperties.min(tr('Seat access')),
alignment=Alignment.CENTER,
).run()
).show()

if result.type_ == ResultType.Selection:
self.custom_settings['seat_access'] = result.get_value().value
Expand Down
17 changes: 7 additions & 10 deletions archinstall/default_profiles/server.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import TYPE_CHECKING, override

from archinstall.default_profiles.profile import Profile, ProfileType, SelectResult
from archinstall.lib.menu.helpers import Selection
from archinstall.lib.output import info
from archinstall.lib.profile.profiles_handler import profile_handler
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import FrameProperties, PreviewStyle
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType

if TYPE_CHECKING:
from archinstall.lib.installer import Installer
Expand All @@ -26,23 +25,21 @@ def do_on_select(self) -> SelectResult:
MenuItem(
p.name,
value=p,
preview_action=lambda x: x.value.preview_text(),
preview_action=lambda x: x.value.preview_text() if x.value else None,
)
for p in profile_handler.get_server_profiles()
]

group = MenuItemGroup(items, sort_items=True)
group.set_selected_by_value(self.current_selection)

result = SelectMenu[Profile](
result = Selection[Profile](
group,
allow_reset=True,
allow_skip=True,
preview_style=PreviewStyle.RIGHT,
preview_size='auto',
preview_frame=FrameProperties.max('Info'),
multi=True,
).run()
preview_location='right',
).show()

match result.type_:
case ResultType.Selection:
Expand Down
30 changes: 10 additions & 20 deletions archinstall/lib/applications/application_menu.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import override

from archinstall.lib.menu.abstract_menu import AbstractSubMenu
from archinstall.lib.menu.helpers import Confirmation, Selection
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration
from archinstall.lib.translationhandler import tr
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties, Orientation
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.ui.result import ResultType


class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
Expand Down Expand Up @@ -67,22 +66,14 @@ def _prev_audio(self, item: MenuItem) -> str | None:


def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
group = MenuItemGroup.yes_no()
group.focus_item = MenuItem.no()

if preset is not None:
group.set_selected_by_value(preset.enabled)

header = tr('Would you like to configure Bluetooth?') + '\n'
preset_val = preset.enabled if preset else False

result = SelectMenu[bool](
group,
result = Confirmation(
header=header,
alignment=Alignment.CENTER,
columns=2,
orientation=Orientation.HORIZONTAL,
allow_skip=True,
).run()
preset=preset_val,
).show()

match result.type_:
case ResultType.Selection:
Expand All @@ -101,12 +92,11 @@ def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration
if preset:
group.set_focus_by_value(preset.audio)

result = SelectMenu[Audio](
result = Selection[Audio](
group,
header=tr('Select audio configuration'),
allow_skip=True,
alignment=Alignment.CENTER,
frame=FrameProperties.min(tr('Audio')),
).run()
).show()

match result.type_:
case ResultType.Skip:
Expand Down
Loading