vak: (Default)
[personal profile] vak
Программировать с помощью ИИ становится прикольно. Зашёл на x.ai и попросил написать простой текстовый редактор типа emacs. Вполне неплохой код получился. Создаём файл src/main.rs:
use crossterm::{
    event::{self, Event, KeyCode, KeyEventKind},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
    backend::CrosstermBackend,
    layout::{Constraint, Layout},
    style::{Color, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Paragraph},
    Terminal,
};
use std::io;

fn main() -> Result<(), io::Error> {
    // Set up terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // Run the editor
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // Clean up terminal
    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{:?}", err);
    }

    Ok(())
}

struct App {
    text: Vec<String>, // Lines of text
    cursor_x: usize,   // Cursor position in current line
    cursor_y: usize,   // Current line number
}

impl App {
    fn new() -> App {
        App {
            text: vec![String::new()], // Start with one empty line
            cursor_x: 0,
            cursor_y: 0,
        }
    }

    fn move_cursor_left(&mut self) {
        if self.cursor_x > 0 {
            self.cursor_x -= 1;
        }
    }

    fn move_cursor_right(&mut self) {
        let line_len = self.text[self.cursor_y].len();
        if self.cursor_x < line_len {
            self.cursor_x += 1;
        }
    }

    fn move_cursor_up(&mut self) {
        if self.cursor_y > 0 {
            self.cursor_y -= 1;
            self.cursor_x = self.cursor_x.min(self.text[self.cursor_y].len());
        }
    }

    fn move_cursor_down(&mut self) {
        if self.cursor_y < self.text.len() - 1 {
            self.cursor_y += 1;
            self.cursor_x = self.cursor_x.min(self.text[self.cursor_y].len());
        }
    }

    fn insert_char(&mut self, c: char) {
        let line = &mut self.text[self.cursor_y];
        line.insert(self.cursor_x, c);
        self.cursor_x += 1;
    }

    fn insert_newline(&mut self) {
        let current_line = &mut self.text[self.cursor_y];
        let remainder = current_line.split_off(self.cursor_x);
        self.text.insert(self.cursor_y + 1, remainder);
        self.cursor_y += 1;
        self.cursor_x = 0;
    }

    fn delete_char(&mut self) {
        if self.cursor_x > 0 {
            let line = &mut self.text[self.cursor_y];
            line.remove(self.cursor_x - 1);
            self.cursor_x -= 1;
        } else if self.cursor_y > 0 {
            let current_line = self.text.remove(self.cursor_y);
            self.cursor_y -= 1;
            self.cursor_x = self.text[self.cursor_y].len();
            self.text[self.cursor_y].push_str(¤t_line);
        }
    }
}

fn run_app<B: ratatui::backend::Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
    loop {
        terminal.draw(|f| {
            let chunks = Layout::vertical([Constraint::Min(0)]).split(f.size());
            let text: Vec<Line> = app
                .text
                .iter()
                .map(|line| Line::from(Span::raw(line)))
                .collect();

            let paragraph = Paragraph::new(text)
                .block(Block::default().title("Simple Text Editor").borders(Borders::ALL))
                .style(Style::default().fg(Color::White));
            f.render_widget(paragraph, chunks[0]);

            // Set cursor position
            f.set_cursor(
                chunks[0].x + 1 + app.cursor_x as u16,
                chunks[0].y + 1 + app.cursor_y as u16,
            );
        })?;

        if let Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press {
                match key.code {
                    KeyCode::Char('c') if key.modifiers.contains(event::KeyModifiers::CONTROL) => {
                        return Ok(());
                    }
                    KeyCode::Char(c) => app.insert_char(c),
                    KeyCode::Enter => app.insert_newline(),
                    KeyCode::Backspace => app.delete_char(),
                    KeyCode::Left => app.move_cursor_left(),
                    KeyCode::Right => app.move_cursor_right(),
                    KeyCode::Up => app.move_cursor_up(),
                    KeyCode::Down => app.move_cursor_down(),
                    _ => {}
                }
            }
        }
    }
}
Добавляем Cargo.toml:
[package]
name = "xedit"
version = "0.1.0"
edition = "2024"

[dependencies]
ratatui = "0.27"
crossterm = "0.27"
Компилируем, запускаем - работает!
cargo run

Это я туда некий текст скопипастил. Выход по ^C. С таким помощником удобно язык изучать.
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at [email protected]

OSZAR »