diff --git a/README.md b/README.md index fa768fb..e7881a7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Das OS ### _A light, friendly Void Linux–based desktop with Xfce and a Ukrainian touch, plus a console server edition_ -[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Python](https://img.shields.io/badge/Python-3-blue)](https://www.python.org) [![Textual](https://img.shields.io/badge/Textual-8.2-blue)](https://textual.textualize.io) [![Version](https://img.shields.io/badge/version-0.9.1-lightgrey)](#) +[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Python](https://img.shields.io/badge/Python-3-blue)](https://www.python.org) [![Textual](https://img.shields.io/badge/Textual-8.2-blue)](https://textual.textualize.io) [![Version](https://img.shields.io/badge/version-0.9.2-lightgrey)](#) 🇺🇦 [Українська версія](README_ua.md) @@ -135,7 +135,7 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow - The installed system runs `sshd`, `chronyd`, `nftables`, `fail2ban`, `docker`, `socklog` and the chosen network service. - nftables lets in only SSH, ICMP and DHCPv6 (`/etc/nftables.conf`), more ports are opened with `dfw`. The rules live in their own table `inet das`, so reloading them keeps the Docker and fail2ban rules. Ports that containers publish pass through Docker's own rules. - fail2ban bans addresses that keep failing SSH logins, reading the socklog log. sshd doesn't accept root password logins. -- Tools: Docker with Compose, lazydocker, lazygit, Midnight Commander, tmux, htop, Python 3, curl, `das-update --cli`, the [helpers](#Helpers), [`dprompt` and `dbanner`](#Terminal) and xtools (`xi`, `xq`, `xrs`). There are no graphical libraries, and no firmware for NVIDIA graphics or sound cards (`/etc/xbps.d/das-server.conf` keeps updates from bringing it back). +- Tools: Docker with Compose, lazydocker, lazygit, Midnight Commander, tmux, htop, ncdu, Python 3, curl, `das-update --cli`, the [helpers](#Helpers), [`dprompt` and `dbanner`](#Terminal) and xtools (`xi`, `xq`, `xrs`). There are no graphical libraries, and no firmware for NVIDIA graphics or sound cards (`/etc/xbps.d/das-server.conf` keeps updates from bringing it back). #### Command-line helpers **_Short commands for tasks that systemd distributions handle with systemctl, hostnamectl and the like, and that Void leaves to manual editing._** @@ -222,6 +222,6 @@ make clean # remove build output, keep the download cache ``` The ISOs appear in `out/iso/dasos--x86_64.iso` and `out/iso/dasos-server--x86_64.iso`. Write them to a USB stick with `dd` or Ventoy. For a Ventoy theme there is a 48×48 menu icon `live/branding/ventoy/dasos.png`: copy it to the theme's `icons/` folder and add `{ "key": "dasos", "class": "dasos" }` to `menu_class` in `ventoy.json`. -**Note:** Das OS is an early version (0.9.1). Packages and ISOs are built in CI; signed repository hosting is planned for an upcoming stage. Until the repository is hosted, an installed system gets updates from Void only. Das OS is based on Void Linux but is not affiliated with it. +**Note:** Das OS is an early version (0.9.2). Packages and ISOs are built in CI; signed repository hosting is planned for an upcoming stage. Until the repository is hosted, an installed system gets updates from Void only. Das OS is based on Void Linux but is not affiliated with it. ###### _Made by -=:dAs:=-_ diff --git a/README_ua.md b/README_ua.md index 1f401ff..ad45640 100644 --- a/README_ua.md +++ b/README_ua.md @@ -1,7 +1,7 @@ ## Das OS ### _Легкий і дружній десктоп на базі Void Linux з Xfce та українським колоритом, а також консольна серверна версія_ -[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Python](https://img.shields.io/badge/Python-3-blue)](https://www.python.org) [![Textual](https://img.shields.io/badge/Textual-8.2-blue)](https://textual.textualize.io) [![Version](https://img.shields.io/badge/version-0.9.1-lightgrey)](#) +[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Python](https://img.shields.io/badge/Python-3-blue)](https://www.python.org) [![Textual](https://img.shields.io/badge/Textual-8.2-blue)](https://textual.textualize.io) [![Version](https://img.shields.io/badge/version-0.9.2-lightgrey)](#) 🇬🇧 [English version](README.md) @@ -135,7 +135,7 @@ Void Linux швидкий, простий і незалежний: runit зам - Встановлена система запускає `sshd`, `chronyd`, `nftables`, `fail2ban`, `docker`, `socklog` і вибрану мережеву службу. - nftables пропускає лише SSH, ICMP і DHCPv6 (`/etc/nftables.conf`), інші порти відкриває `dfw`. Правила лежать у власній таблиці `inet das`, тож їх перезавантаження не чіпає правил Docker і fail2ban. Порти, які публікують контейнери, проходять через власні правила Docker. - fail2ban блокує адреси, з яких раз у раз не вдається увійти по SSH, читаючи журнал socklog. sshd не приймає вхід root за паролем. -- Інструменти: Docker з Compose, lazydocker, lazygit, Midnight Commander, tmux, htop, Python 3, curl, `das-update --cli`, [помічники](#Helpers), [`dprompt` і `dbanner`](#Terminal) та xtools (`xi`, `xq`, `xrs`). Графічних бібліотек немає, як і прошивок для відеокарт NVIDIA та звукових карт (`/etc/xbps.d/das-server.conf` не дає оновленням повернути їх). +- Інструменти: Docker з Compose, lazydocker, lazygit, Midnight Commander, tmux, htop, ncdu, Python 3, curl, `das-update --cli`, [помічники](#Helpers), [`dprompt` і `dbanner`](#Terminal) та xtools (`xi`, `xq`, `xrs`). Графічних бібліотек немає, як і прошивок для відеокарт NVIDIA та звукових карт (`/etc/xbps.d/das-server.conf` не дає оновленням повернути їх). #### Консольні помічники **_Короткі команди для задач, які в дистрибутивах із systemd розв'язують systemctl, hostnamectl тощо, а у Void доводиться робити вручну._** @@ -222,6 +222,6 @@ make clean # видалити результати збиранн ``` ISO з'являються в `out/iso/dasos-<версія>-x86_64.iso` і `out/iso/dasos-server-<версія>-x86_64.iso`. Записати їх на флешку можна через `dd` або Ventoy. Для теми Ventoy є значок меню 48×48 `live/branding/ventoy/dasos.png`: скопіюйте його в теку `icons/` теми й додайте `{ "key": "dasos", "class": "dasos" }` до `menu_class` у `ventoy.json`. -**Примітка:** Das OS — рання версія (0.9.1). Пакети й ISO збираються в CI; підписаний репозиторій на хостингу заплановано на наступний етап. Поки репозиторій не розміщено на хостингу, встановлена система отримує оновлення лише з Void. Das OS базується на Void Linux, але не пов'язана з ним офіційно. +**Примітка:** Das OS — рання версія (0.9.2). Пакети й ISO збираються в CI; підписаний репозиторій на хостингу заплановано на наступний етап. Поки репозиторій не розміщено на хостингу, встановлена система отримує оновлення лише з Void. Das OS базується на Void Linux, але не пов'язана з ним офіційно. ###### _Made by -=:dAs:=-_ diff --git a/TODO.md b/TODO.md index 522ec82..bc18832 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,6 @@ # Das OS — що зробити далі -Стан на 2026-10-20: версія 0.8.0, етапи 1–8 готові (live ISO, власний репозиторій, оформлення, інсталятор Calamares зі знімками Btrfs, Go-утиліти `das-update` і `das-welcome`, серверний образ з консольним інсталятором, менші ISO, консольні помічники, профіль розробника), CI (етап 9: пакети й обидва ISO збираються на власному runner, ~45 хв). +Стан на 2026-10-21: версія 0.9.2, етапи 1–8 готові (live ISO, власний репозиторій, оформлення, інсталятор Calamares зі знімками Btrfs, Go-утиліти `das-update` і `das-welcome`, серверний образ з консольним інсталятором, менші ISO, консольні помічники, профіль розробника), CI (етап 9: пакети й обидва ISO збираються на власному runner, ~45 хв). ## Етап 5. Go-утиліти (готово, лишилися перевірки) - [x] `das-update`: вікно, значок у треї (лише коли є оновлення), консольний режим `--cli`, знімок snapper pre/post, встановлення через pkexec, підказка про відкат. @@ -27,6 +27,10 @@ Live ISO без графіки з консольним інсталятором: - [x] Перевірено в QEMU: встановлення через TUI на UEFI (з SSH-ключем) і BIOS (з паролем, NetworkManager, `ua-utf`), вхід по SSH лише за ключем, `docker run hello-world`, опублікований порт nginx, fail2ban бачить невдалі входи, `das-update --cli` зі знімками pre/post, `dsv`. - [x] `das-server-install --config` перевірено (0.5.0, UEFI). - [x] Розмір ISO: див. нижче. +- [x] Запрошення до входу (`/etc/issue`) показувало версію ядра (`\r` agetty, 6.18): тепер версія Das OS з `VERSION` (`@VERSION@` у `branding/issue`), серверний інсталятор переносить перший рядок у встановлену систему (0.9.2). +- [x] Українська в `das-server-install` на консолі показувалася латиницею («Ukra■ns'ka»): стандартний шрифт підміняє кирилицю схожими латинськими літерами, а `setfont` не спрацьовував, бо `sudo` запускає інсталятор у власному pty (`tty` → `/dev/pts/N`). Тепер `setfont -C /dev/tty0 cyr-sun16` до вибору мови (перевірено в QEMU: «Гаразд їєіґ»). +- [x] Серед дисків для встановлення був дисковод `/dev/fd0`: тепер пропускається. +- [x] Перевірено серверний ISO 0.9.2 у QEMU: «Das OS Server 0.9.2 (tty1)» у запрошенні, «Українська» в меню мови, `/dev/fd0` немає серед дисків. ### Розмір ISO: 0.4.0 → 0.5.0 Десктоп 1,96 → 1,72 ГБ, сервер 1,57 → 1,14 ГБ. @@ -75,6 +79,11 @@ Live ISO без графіки з консольним інсталятором: - [x] `dprompt`: конструктор запрошень (5 готових, сегменти, кольори, живий перегляд), застосування для себе або для всіх. - [x] `dbanner`: редактор банера при вході по SSH (7 готових, полотно з інструментами, поля зі змінними, віджети, служба `das-banner` для кешу), малюнки: логотип Das OS і тризуб (`tools/art`). - [x] `scripts/run-qemu.sh`: SSH гостя на `localhost:2222`. +- [x] Запрошення за замовчуванням: `└─╼` другого рядка міг бути білим, бо колір успадковувався з першого рядка, а readline перемальовує лише останній. Тепер кожен рядок задає колір заново (das-shell 0.2.0). +- [ ] Перевірити в терміналі автора, що `└─╼` червоний. +- [x] `dbanner`: кнопки внизу стартового екрана перекривав рядок підказок клавіш (обидва були прикріплені до низу): тепер кнопки — звичайний рядок під списком. +- [x] У консолі Linux (`TERM=linux`) рамки кнопок, полів і списків `dprompt`/`dbanner` були квадратиками: Textual малює їх символами `▊▎▔▁`, яких немає в жодному консольному шрифті (до 512 символів; перевірено `cyr-sun16`, `default8x16`, `eurlatgr`, Terminus). Тепер там рамки `┌─┐`, а решта відсутніх символів замінюється на наявні. Символи палітри малювання (★ ☀ ♥…) лишаються як є: це вміст банера для SSH-клієнтів. +- [ ] Перевірити `dprompt` і `dbanner` у консолі встановленої системи. - [ ] Перевірити в QEMU: сервер — банер при вході по SSH, `dbanner apply dashboard` зі службою, `ssh host cmd` без банера; десктоп — запрошення в xfce4-terminal, обидва редактори. ## Репозиторій пакетів @@ -98,6 +107,7 @@ Live ISO без графіки з консольним інсталятором: - [ ] Прибрати значки томів live-носія («Том 6,6 ГБ») з робочого столу live-сесії. - [ ] Тема GRUB у встановленій системі (зараз стандартний чорний екран). - [ ] Перевірити меню Whisker вручну. +- [x] `ncdu` (аналіз зайнятого місця на диску в терміналі): у десктопному образі й у `das-server` 0.4.0. - [x] Прискорити `make packages`: пакет перезбирається лише після змін у `srcpkgs/<назва>`, без бінарного пакета або коли у Void зникла потрібна йому бібліотека (`xbps-install -n`). `DASOS_REBUILD=1` перезбирає все. ## Відкладено diff --git a/VERSION b/VERSION index f374f66..2003b63 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.1 +0.9.2 diff --git a/live/branding/issue b/live/branding/issue index 741ca52..25d5385 100644 --- a/live/branding/issue +++ b/live/branding/issue @@ -1,2 +1,2 @@ -Das OS \r (\l) +Das OS @VERSION@ (\l) diff --git a/live/packages.x86_64 b/live/packages.x86_64 index 7ad737c..e759dec 100644 --- a/live/packages.x86_64 +++ b/live/packages.x86_64 @@ -40,6 +40,7 @@ firefox-i18n-uk udisks2 xdg-user-dirs xdg-utils +ncdu # Boot loader and disk tools, also kept by the installed system btrfs-progs diff --git a/scripts/container/build-iso.sh b/scripts/container/build-iso.sh index c5973ce..f74edba 100755 --- a/scripts/container/build-iso.sh +++ b/scripts/container/build-iso.sh @@ -82,8 +82,9 @@ done sed -i -e 's/echo void-live >/echo dasos >/' -e 's/voidlinux/live/g' "$adduser" # mklive copies its /etc/issue (Void live logins) into the image, and the # installers copy the image to disk, so use a Das OS one (the server's tells -# how to log in to the live system; its installer writes a neutral one). -cp "$dir/branding/issue" /opt/void-mklive/data/issue +# how to log in to the live system; its installer keeps only the first line). +# It names the Das OS version instead of agetty's \r (the kernel version). +sed "s/@VERSION@/$version/g" "$dir/branding/issue" >/opt/void-mklive/data/issue # Size, also patched into this container's mklive copy: # - the live initrd only has to find and mount the image, the GPU drivers and diff --git a/server/branding/issue b/server/branding/issue index bf2b91d..2002529 100644 --- a/server/branding/issue +++ b/server/branding/issue @@ -1,4 +1,4 @@ -Das OS Server \r (\l) +Das OS Server @VERSION@ (\l) Log in as "live" with the password "live", then run: sudo das-server-install diff --git a/srcpkgs/das-server-installer/files/das-server-install b/srcpkgs/das-server-installer/files/das-server-install index 702768e..8ddb05d 100755 --- a/srcpkgs/das-server-installer/files/das-server-install +++ b/srcpkgs/das-server-installer/files/das-server-install @@ -164,22 +164,24 @@ list_disks() { fi lsblk -dpno NAME,TYPE,RO,SIZE,MODEL | while read -r name type ro size model; do [[ $type == disk && $ro == 0 && $name != "$live" ]] || continue - [[ $name == /dev/zram* || $name == /dev/loop* ]] && continue + [[ $name == /dev/zram* || $name == /dev/loop* || $name == /dev/fd* ]] && continue printf '%s\t%s %s\n' "$name" "$size" "${model:-}" done } ask_language() { local choice + # The default console font shows Cyrillic as Latin look-alikes, so load one + # with Cyrillic before the first "Українська". sudo runs us on its own pty + # (tty says /dev/pts/N), so name the console; serial and ssh have TERM other + # than linux and no font to set. + [[ $TERM == linux ]] && { setfont -C /dev/tty0 cyr-sun16 2>/dev/null || true; } choice=$(dialog --backtitle "Das OS Server" --title "Das OS Server" \ --default-item "$lang" --menu "Language / Мова:" 10 50 2 \ en "English" uk "Українська" 3>&1 1>&2 2>&3) || cancelled lang=$choice if [[ $lang == uk ]]; then LOCALE=uk_UA.UTF-8 - # The default console font has no Cyrillic (a font needs a Unicode table, - # .psfu); there is no font to set on serial or ssh - case $(tty) in /dev/tty[0-9]*) setfont cyr-sun16 2>/dev/null || true ;; esac fi } @@ -404,8 +406,9 @@ disable_service() { configure() { local home - # The live image's /etc/issue tells how to log in to the live system - printf 'Das OS Server \\r (\\l)\n\n' >"$target/etc/issue" + # The live image's /etc/issue tells how to log in to the live system: keep + # its first line, with the Das OS version + printf '%s\n\n' "$(head -n1 /etc/issue)" >"$target/etc/issue" echo "$HOST_NAME" >"$target/etc/hostname" if ! grep -q "[[:space:]]$HOST_NAME\$" "$target/etc/hosts"; then printf '127.0.1.1\t%s\n' "$HOST_NAME" >>"$target/etc/hosts" diff --git a/srcpkgs/das-server-installer/template b/srcpkgs/das-server-installer/template index eb05ea2..0c4f159 100644 --- a/srcpkgs/das-server-installer/template +++ b/srcpkgs/das-server-installer/template @@ -1,6 +1,6 @@ # Template file for 'das-server-installer' pkgname=das-server-installer -version=0.4.0 +version=0.5.0 revision=1 depends="bash dialog das-install-common btrfs-progs dosfstools gptfdisk parted rsync util-linux grub grub-x86_64-efi efibootmgr" diff --git a/srcpkgs/das-server/template b/srcpkgs/das-server/template index 113b971..affbe18 100644 --- a/srcpkgs/das-server/template +++ b/srcpkgs/das-server/template @@ -1,9 +1,9 @@ # Template file for 'das-server' pkgname=das-server -version=0.3.0 +version=0.4.0 revision=1 depends="openssh chrony dhcpcd NetworkManager docker docker-compose nftables - fail2ban socklog-void python3 curl lazydocker lazygit mc tmux htop + fail2ban socklog-void python3 curl lazydocker lazygit mc tmux htop ncdu das-snapshots das-update das-helpers das-shell xtools-minimal" short_desc="Das OS server: packages and secure defaults for SSH, firewall and Docker" maintainer="Das " diff --git a/srcpkgs/das-shell/files/python/das_shell/banner_app.py b/srcpkgs/das-shell/files/python/das_shell/banner_app.py index 853827b..79024ca 100644 --- a/srcpkgs/das-shell/files/python/das_shell/banner_app.py +++ b/srcpkgs/das-shell/files/python/das_shell/banner_app.py @@ -17,7 +17,7 @@ from textual.widgets import (Button, Checkbox, Footer, Header, Input, Label, Lis from . import banner, widgets from .canvas import TOOLS, Canvas from .i18n import t, title -from .tui_common import AskDialog, Swatches, run_as_root +from .tui_common import AskDialog, Swatches, console_mode, run_as_root TOOL_NAMES = { "pen": ("Олівець", "Pen"), "eraser": ("Гумка", "Eraser"), "line": ("Лінія", "Line"), @@ -657,7 +657,8 @@ class StartScreen(Screen): CSS = """ #list { width: 46; border-right: solid $primary; } #start_preview { padding: 0 1; } - .buttons { height: 3; dock: bottom; } + #start_main { height: 1fr; } + .buttons { height: auto; } .buttons Button { margin-right: 1; } """ BINDINGS = [ @@ -671,7 +672,7 @@ class StartScreen(Screen): def compose(self): yield Header() - with Horizontal(): + with Horizontal(id="start_main"): yield ListView(id="list") yield VerticalScroll(Static(id="start_preview")) with Horizontal(classes="buttons"): @@ -769,6 +770,7 @@ class BannerApp(App): def __init__(self): # The terminal's own 16 colors: the picture looks as it will at login + console_mode() super().__init__(ansi_color=True) def on_mount(self): diff --git a/srcpkgs/das-shell/files/python/das_shell/prompt.py b/srcpkgs/das-shell/files/python/das_shell/prompt.py index ebfea53..4bfa235 100644 --- a/srcpkgs/das-shell/files/python/das_shell/prompt.py +++ b/srcpkgs/das-shell/files/python/das_shell/prompt.py @@ -275,6 +275,10 @@ class _Bash: current = style if isinstance(p, Lit): out.append(_ps1_text(self.glyphs(p.text))) + if p.text.endswith("\n"): + # Readline redraws only the last line of the prompt, so + # each line has to set its color again + current = None elif isinstance(p, Esc): out.append(p.code) elif isinstance(p, Dyn): diff --git a/srcpkgs/das-shell/files/python/das_shell/prompt_app.py b/srcpkgs/das-shell/files/python/das_shell/prompt_app.py index cc139e0..2b08adb 100644 --- a/srcpkgs/das-shell/files/python/das_shell/prompt_app.py +++ b/srcpkgs/das-shell/files/python/das_shell/prompt_app.py @@ -13,7 +13,7 @@ from textual.widgets import Button, Checkbox, Footer, Header, Input, Label, List from . import prompt from .cli_prompt import apply as apply_design, current from .i18n import t -from .tui_common import NONE, AskDialog, color_options, color_value, run_as_root, to_select +from .tui_common import NONE, AskDialog, color_options, color_value, console_mode, run_as_root, to_select # Settings of each segment type: (key, kind, Ukrainian label, English label) COLOR_KEYS = [("fg", "color", "Колір", "Color"), ("bold", "bool", "Жирний", "Bold")] @@ -83,6 +83,7 @@ class PromptApp(App): def __init__(self, design=None): # The terminal's own 16 colors, as the prompt will use them + console_mode() super().__init__(ansi_color=True) self.design, self.source = (design, None) if design else current() self.design = prompt.normalize(self.design) diff --git a/srcpkgs/das-shell/files/python/das_shell/tui_common.py b/srcpkgs/das-shell/files/python/das_shell/tui_common.py index 5a8dec1..285169b 100644 --- a/srcpkgs/das-shell/files/python/das_shell/tui_common.py +++ b/srcpkgs/das-shell/files/python/das_shell/tui_common.py @@ -15,9 +15,39 @@ from textual.widgets import Button, Input, Label, Select from . import colors from .i18n import t +from .prompt import CONSOLE_GLYPHS as PROMPT_CONSOLE_GLYPHS NONE = "-" # Select has no None value +# The Linux console's fonts hold at most 512 glyphs (cyr-sun16, Terminus: none has +# the eighth blocks ▊▎▔▁ Textual draws buttons, inputs and lists with), so the +# missing ones come out as squares. There we draw with what the fonts do have. +CONSOLE = os.environ.get("TERM") == "linux" +CONSOLE_BORDERS = ("tall", "wide", "panel", "tab", "hkey", "vkey", "round", "heavy", "dashed", "inner", "outer") +CONSOLE_GLYPHS = str.maketrans({ + **PROMPT_CONSOLE_GLYPHS, + "▁": "▄", "▂": "▄", "▃": "▄", "▅": "▄", "▆": "▄", "▇": "█", "▔": "▀", "▉": "█", + "▊": "▌", "▋": "▌", "▍": "▌", "▎": "▌", "▏": "▌", "▕": "▐", + "━": "─", "╸": "─", "╺": "─", "┃": "│", "┏": "┌", "┓": "┐", "┗": "└", "┛": "┘", + "╭": "┌", "╮": "┐", "╰": "└", "╯": "┘", "╱": "/", "╲": "\\", + "—": "-", "…": ".", "×": "x", "✕": "x", "✓": "v", "☑": "x", "○": "o", "⭘": "o", "◢": "▀", +}) + + +def console_mode(): + """On the Linux console: swaps the borders and glyphs its fonts lack. Call + before the app starts.""" + if not CONSOLE: + return + from textual import _border + from textual.drivers.linux_driver import LinuxDriver + for kind in CONSOLE_BORDERS: + _border.BORDER_CHARS[kind] = _border.BORDER_CHARS["solid"] + _border.BORDER_LOCATIONS[kind] = _border.BORDER_LOCATIONS["solid"] + _border.get_box.cache_clear() + write = LinuxDriver.write + LinuxDriver.write = lambda self, data: write(self, data.translate(CONSOLE_GLYPHS)) + def color_options(allow_none=True): names = { diff --git a/srcpkgs/das-shell/files/tests/test_prompt.py b/srcpkgs/das-shell/files/tests/test_prompt.py index 4e73d9b..4661739 100644 --- a/srcpkgs/das-shell/files/tests/test_prompt.py +++ b/srcpkgs/das-shell/files/tests/test_prompt.py @@ -35,6 +35,11 @@ class PresetTest(unittest.TestCase): self.assertNotIn("──", text(d)) self.assertIn("─[main*]─[.venv]─[jobs:2]", text(d, git="main*", venv=".venv", jobs=2)) + def test_each_line_sets_its_color(self): + # Readline redraws only the last line, so it must not rely on the first + ps1 = prompt.script(prompt.load_preset("das")).split("PS1='", 1)[1].split("'", 1)[0] + self.assertTrue(ps1.split("\n")[1].startswith("\\[\\e[0;31m\\]└"), ps1) + def test_unknown_segments_are_dropped(self): d = prompt.normalize({"segments": [{"type": "nope"}, {"type": "cwd"}]}) self.assertEqual([s["type"] for s in d["segments"]], ["cwd"]) diff --git a/srcpkgs/das-shell/template b/srcpkgs/das-shell/template index ec91bc1..ff0ee13 100644 --- a/srcpkgs/das-shell/template +++ b/srcpkgs/das-shell/template @@ -1,7 +1,7 @@ # Template file for 'das-shell' # In-tree package: sources are in files/ (FILESDIR). pkgname=das-shell -version=0.1.0 +version=0.2.0 revision=1 create_wrksrc=yes hostmakedepends="python3"