use crossterm::{ event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use ratatui::{ backend::{Backend, CrosstermBackend}, layout::{Constraint, Direction, Layout}, prelude::Alignment, style::Stylize, widgets::{Block, BorderType, Borders}, Frame, Terminal, }; use std::{error::Error, io}; use tui_vim_editor::{ editor::{theme::EditorTheme, view::ViewState}, input::Input, Buffer, Editor, }; type Result = std::result::Result>; fn main() -> Result<()> { let mut terminal = init_terminal()?; let app = App::new(); run_app(&mut terminal, app).unwrap(); reset_terminal()?; terminal.show_cursor()?; Ok(()) } /// Initializes the terminal. fn init_terminal() -> Result>> { crossterm::execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?; enable_raw_mode()?; let backend = CrosstermBackend::new(io::stdout()); let mut terminal = Terminal::new(backend)?; terminal.hide_cursor()?; // Shutdown gracefully let original_hook = std::panic::take_hook(); std::panic::set_hook(Box::new(move |panic| { reset_terminal().unwrap(); original_hook(panic); })); Ok(terminal) } /// Resets the terminal. fn reset_terminal() -> Result<()> { disable_raw_mode()?; crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?; Ok(()) } pub struct App { buffer: Buffer, state: ViewState, } impl App { pub fn new() -> App { let mut buffer = Buffer::new(); buffer.push("\"Hello\", world"); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("\"Hello\", world"); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("\"Hello\", world"); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("\"Hello\", world"); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("\"Hello\", world"); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); buffer.push("123 Boom."); // let clipboard: Box = Box::new(&CLIPBOARD); // buffer.set_clipboard(clipboard); let state = ViewState::default(); App { buffer, state } } } pub fn run_app(terminal: &mut Terminal, mut app: App) -> io::Result<()> { let mut input = Input::default(); loop { terminal.draw(|f| ui(f, &mut app))?; if let Event::Key(key) = event::read()? { if key.kind == KeyEventKind::Press { match key.code { KeyCode::Char('q') => return Ok(()), _ => input.on_key(key, &mut app.buffer), } } } } } pub fn ui(f: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Min(0)].as_ref()) .split(f.size()); let theme = EditorTheme::default() .block( Block::default() .borders(Borders::ALL) .border_type(BorderType::Thick) .title("Editor") .title_alignment(Alignment::Center), ) .base(EditorTheme::default().base.bold()); let editor = Editor::new(&app.buffer, &mut app.state).theme(theme); f.render_widget(editor, chunks[0]); }