База знаний (цифровой суверенитет)
  • Псевдографика в Rust

    Язык Rust
    1 6 3

    A
    951
    0

    Rust отлично подходит для псевдографики (TUI) — даже лучше, чем многие языки.

    Можно делать интерфейсы уровня Midnight Commander: окна, рамки, списки, меню, клавиши и т.д.


    🧩 1. Что такое «псевдографика» в Rust

    Это называется TUI (Text User Interface):

    • рамки (┌─┐)
    • панели
    • меню
    • обработка клавиш
    • обновление экрана без мерцания

    👉 всё это Rust умеет


    🛠 2. Основные библиотеки

    🔹 1. База (обязательно)

    • crossterm
      👉 управление терминалом:
    • курсор
    • цвета
    • клавиши
    • очистка экрана

    🔹 2. UI-уровень (как mc)

    • ratatui (бывший tui-rs)

    👉 даёт:

    • окна
    • layout (разделение экрана)
    • списки
    • таблицы
    • рамки

    🔥 3. Мини-пример (очень простой)

    Создайте проект:

    cargo new tui_test
    cd tui_test
    

    Добавьте в Cargo.toml:

    [dependencies]
    crossterm = "0.27"
    ratatui = "0.26"
    

    Код (main.rs)

    use std::io;
    use crossterm::{
        event::{self, Event, KeyCode},
        terminal::{enable_raw_mode, disable_raw_mode},
    };
    use ratatui::{
        backend::CrosstermBackend,
        Terminal,
        widgets::{Block, Borders, Paragraph},
    };
    
    fn main() -> Result<(), io::Error> {
        enable_raw_mode()?;
    
        let mut stdout = io::stdout();
        let backend = CrosstermBackend::new(stdout);
        let mut terminal = Terminal::new(backend)?;
    
        loop {
            terminal.draw(|f| {
                let size = f.size();
    
                let block = Block::default()
                    .title("Мой TUI (как mc 😄)")
                    .borders(Borders::ALL);
    
                let paragraph = Paragraph::new("Нажми q для выхода")
                    .block(block);
    
                f.render_widget(paragraph, size);
            })?;
    
            if let Event::Key(key) = event::read()? {
                if key.code == KeyCode::Char('q') {
                    break;
                }
            }
        }
    
        disable_raw_mode()?;
        Ok(())
    }
    

    ▶️ Запуск

    cargo run
    

    😎 Что вы получаете

    • рамку как в mc
    • текст внутри
    • обработку клавиш
  • A
    951
    0

    Сделаем мини-клон Midnight Commander на Rust — простой, но уже с настоящим TUI:

    👉 2 панели
    👉 список файлов
    👉 перемещение стрелками
    👉 базовая логика “как в mc”

    Мы сделаем упрощённую версию (без копирования файлов и F-клавиш — это потом можно добавить).


    🧱 1. Создайте проект

    cargo new mini_mc
    cd mini_mc
    

    📦 2. Добавьте зависимости

    Откройте Cargo.toml:

    [dependencies]
    crossterm = "0.27"
    ratatui = "0.26"
    

    🧠 3. Что мы делаем

    Мы создаём:

    • левую панель (каталог)
    • правую панель (пока тоже каталог)
    • выделение строки
    • переключение панелей (Tab)
    • выход (q)

    💻 4. Код src/main.rs

    use std::{fs, io};
    
    use crossterm::{
        event::{self, Event, KeyCode},
        terminal::{enable_raw_mode, disable_raw_mode},
    };
    use ratatui::{
        backend::CrosstermBackend,
        Terminal,
        widgets::{Block, Borders, List, ListItem, ListState},
        layout::{Layout, Direction, Constraint},
    };
    
    fn read_dir(path: &str) -> Vec<String> {
        let mut items = vec![];
    
        if let Ok(entries) = fs::read_dir(path) {
            for entry in entries.flatten() {
                if let Ok(name) = entry.file_name().into_string() {
                    items.push(name);
                }
            }
        }
    
        items.sort();
        items
    }
    
    fn main() -> Result<(), io::Error> {
        enable_raw_mode()?;
    
        let mut stdout = io::stdout();
        let backend = CrosstermBackend::new(stdout);
        let mut terminal = Terminal::new(backend)?;
    
        let mut left_items = read_dir(".");
        let mut right_items = read_dir(".");
    
        let mut left_state = ListState::default();
        let mut right_state = ListState::default();
    
        left_state.select(Some(0));
        right_state.select(Some(0));
    
        let mut active_left = true;
    
        loop {
            terminal.draw(|f| {
                let size = f.size();
    
                let chunks = Layout::default()
                    .direction(Direction::Horizontal)
                    .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
                    .split(size);
    
                let left_list: Vec<ListItem> = left_items
                    .iter()
                    .map(|i| ListItem::new(i.as_str()))
                    .collect();
    
                let right_list: Vec<ListItem> = right_items
                    .iter()
                    .map(|i| ListItem::new(i.as_str()))
                    .collect();
    
                let left_widget = List::new(left_list)
                    .block(Block::default().title("LEFT").borders(Borders::ALL))
                    .highlight_symbol(">> ");
    
                let right_widget = List::new(right_list)
                    .block(Block::default().title("RIGHT").borders(Borders::ALL))
                    .highlight_symbol(">> ");
    
                f.render_stateful_widget(left_widget, chunks[0], &mut left_state);
                f.render_stateful_widget(right_widget, chunks[1], &mut right_state);
            })?;
    
            if let Event::Key(key) = event::read()? {
                match key.code {
                    KeyCode::Char('q') => break,
    
                    KeyCode::Tab => {
                        active_left = !active_left;
                    }
    
                    KeyCode::Down => {
                        if active_left {
                            let i = left_state.selected().unwrap_or(0);
                            let next = (i + 1).min(left_items.len().saturating_sub(1));
                            left_state.select(Some(next));
                        } else {
                            let i = right_state.selected().unwrap_or(0);
                            let next = (i + 1).min(right_items.len().saturating_sub(1));
                            right_state.select(Some(next));
                        }
                    }
    
                    KeyCode::Up => {
                        if active_left {
                            let i = left_state.selected().unwrap_or(0);
                            let prev = i.saturating_sub(1);
                            left_state.select(Some(prev));
                        } else {
                            let i = right_state.selected().unwrap_or(0);
                            let prev = i.saturating_sub(1);
                            right_state.select(Some(prev));
                        }
                    }
    
                    _ => {}
                }
            }
        }
    
        disable_raw_mode()?;
        Ok(())
    }
    

    ▶️ 5. Запуск

    cargo run
    

    🎮 Управление

    Клавиша Действие
    ↑ ↓ перемещение
    Tab переключить панель
    q выход
  • A
    951
    0

    Нужно ли что-то дополнительно устанавливать?


    В большинстве случаев — почти ничего, кроме Rust — не нужно .


    ✅ Что уже достаточно

    Если у вас есть:

    • rustc / cargo (Rust установлен)
    • Termux или Linux-среда

    👉 всё, что нужно для мини-клона Midnight Commander, уже есть в проекте через Cargo.toml:

    crossterm
    ratatui
    

    Их cargo сам скачает при сборке.


    📦 Что произойдёт при первом запуске

    Когда вы делаете:

    cargo run
    

    Rust автоматически:

    • скачает crossterm
    • скачает ratatui
    • соберёт проект
    • закэширует зависимости

    👉 интернет нужен только 1 раз


    ⚠️ Единственный возможный нюанс (для Termux на Android)

    В Termux иногда может понадобиться:

    pkg install clang make pkg-config
    

    👉 это нужно, если:

    • не компилируются зависимости с C-зависимостями
    • или появляются ошибки линковки

    🟢 В 90% случаев у dfc уже всё готово

    Если Rust уже стоит:

    ✔ можно сразу:

    cargo new mini_mc
    cargo run
    

    🎯 Итог

    ✔ доп. библиотек руками ставить не нужно
    ✔ всё подтянется через Cargo
    ✔ максимум — системные build-tools (редко)
    ✔ TUI-движок уже внутри Rust-пакетов

  • A
    951
    0

    Где находится файл Cargo.toml?


    Файл Cargo.toml создаётся автоматически, когда твы создаёте проект через Cargo.


    📍 Где он находится

    Если вы сделали:

    cargo new mini_mc
    

    то структура будет такая:

    mini_mc/
    ├── Cargo.toml   ← ВОТ ОН
    └── src/
        └── main.rs
    

    📂 Как его открыть

    🔹 Вариант 1 (через mcedit)

    cd mini_mc
    mcedit Cargo.toml
    

    🔹 Вариант 2 (через путь)

    Если вы не внутри папки:

    mcedit ~/mini_mc/Cargo.toml
    

    🔹 Вариант 3 (проверить где вы)

    Сначала:

    pwd
    ls
    

    Если видите:

    Cargo.toml
    src
    

    👉 значит вы уже в правильной папке


    ⚠️ Частая ошибка

    Если пишеие:

    mcedit Cargo.toml
    

    и файл не открывается — значит выне в папке проекта


    🧠 Как быстро ориентироваться

    После cargo new всегда делайие:

    cd имя_проекта
    

    💡 Пример полного пути

    cd mini_mc
    ls
    

    Вывод:

    Cargo.toml  src
    

    🚀 Итог

    • Cargo.toml лежит в корне проекта
    • создаётся автоматически
    • открывается как обычный текстовый файл
  • A
    951
    0

    Как потом запустить как обычную программу, без cargo run?


    cargo run — это режим “собрал и сразу запустил”, но Rust также умеет делать обычный исполняемый файл, как любая программа в Linux/Termux.


    🧱 1. Где появляется готовая программа

    После сборки:

    cargo build
    

    или:

    cargo run
    

    (сборка всё равно происходит)

    👉 бинарник лежит тут:

    target/debug/mini_mc
    

    ▶️ 2. Запуск без cargo

    Просто:

    ./target/debug/mini_mc
    

    🚀 3. Режим “как настоящая программа”

    🔹 Release-версия (быстрее и чище)

    cargo build --release
    

    👉 результат:

    target/release/mini_mc
    

    Запуск:

    ./target/release/mini_mc
    

    📦 4. Можно ли запускать из любой папки?

    Да, если добавить в PATH:

    cp target/release/mini_mc ~/bin/
    

    (или любую папку в PATH)


    🧠 5. Как это выглядит “по-людски”

    Вы фактически получаете:

    Действие Результат
    cargo build сборка
    ./target/debug/app запуск как программа
    cargo run сборка + запуск
    cargo build --release “боевой” билд

    ⚡ 6. Важный момент (как у нормальных программ)

    Rust-программа:

    • НЕ требует Cargo для запуска
    • НЕ требует интерпретатора
    • это чистый бинарник

    👉 как ls, mc, nano


    🔥 Итог

    ✔ да, можно запускать без cargo
    ✔ файл лежит в target/debug или target/release
    ✔ можно копировать куда угодно
    ✔ это уже полноценная программа системы

  • A
    951
    0

    TUI на Rust сложнее писать, чем использовать Slint ?


    Да, обычно TUI на Rust сложнее, чем Slint — но зависит от того, что вы делаете


    ⚖️ 1. Разница по сути

    🖥 TUI (terminal UI)

    Вы сами управляете:

    • экраном
    • перерисовкой
    • клавишами
    • состоянием интерфейса
    • layout вручную

    Библиотеки:

    • crossterm
    • ratatui

    👉 это “низкий уровень UI”


    🪟 Slint

    Slint даёт:

    • готовую модель интерфейса (как “мини-QT”)
    • layout автоматически
    • события (кнопки, поля)
    • реактивность (state → UI)

    👉 это “высокий уровень UI”


    🧠 2. Сложность разработки

    Задача TUI Slint
    Нарисовать окно вручную готово
    Обработать клавиши вручную автоматически
    Layout (панели) сложно просто
    Состояние UI вручную встроено
    Список/таблица средне легко

    🔥 3. Где TUI сложнее

    TUI требует от вас:

    ❗ ручного контроля:

    • перерисовки экрана
    • фокуса элементов
    • состояния UI
    • оптимизации “мигания”

    👉 вы буквально пишете “мини-движок UI”


    🚀 4. Где Slint сложнее

    Slint может быть сложнее в другом:

    • нужно учить DSL (.slint файлы)
    • интеграция с Rust (binding model)
    • ограничения платформы (особенно Android)
    • не такой “низкоуровневый контроль”

    🧩 5. Важный вывод

    ✔ TUI:

    • сложнее писать
    • больше контроля
    • ближе к системному программированию
    • как “Midnight Commander внутри терминала”

    ✔ Slint:

    • быстрее разработка UI
    • проще архитектура
    • лучше для приложений
    • ближе к “GUI фреймворку”

    🚀 Итог

    ✔ да — TUI сложнее
    ✔ Slint быстрее и проще
    ✔ TUI даёт контроль, Slint — продуктивность