miv_editor/app/
mod.rs

1pub mod command_line;
2pub mod editor;
3pub mod theme;
4
5use std::error;
6
7use strum_macros::{Display, EnumString};
8
9use crate::commands::Command;
10
11use self::{command_line::CommandLine, editor::EditorBuffer, theme::Theme};
12
13/// Application result type.
14pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>;
15
16/// The editing mode of the application
17#[derive(Display, Debug, EnumString, PartialEq, Clone, Copy)]
18pub enum InputMode {
19    Normal,
20    Insert,
21    Command,
22}
23
24/// Application.
25#[derive(Debug)]
26pub struct App {
27    /// Is the application running?
28    pub running: bool,
29    /// Editing mode of application
30    pub mode: InputMode,
31    /// Data for maintaining command input
32    pub command_line: CommandLine,
33    /// Colors for display
34    pub theme: Theme,
35    /// The buffer being edited
36    pub editor: EditorBuffer,
37}
38
39impl Default for App {
40    fn default() -> Self {
41        Self {
42            running: true,
43            mode: InputMode::Normal,
44            command_line: CommandLine::default(),
45            theme: Theme::default(),
46            editor: EditorBuffer::default(),
47        }
48    }
49}
50
51impl App {
52    /// Constructs a new instance of [`App`].
53    pub fn new(file: String) -> Self {
54        Self {
55            running: true,
56            mode: InputMode::Normal,
57            command_line: CommandLine::default(),
58            theme: Theme::default(),
59            editor: EditorBuffer::from_file(file),
60        }
61    }
62
63    /// Handles the tick event of the terminal.
64    pub fn tick(&self) {}
65
66    /// Execute collection of commands
67    pub fn execute(&mut self, commands: Vec<Command>) -> AppResult<()> {
68        for command in commands {
69            self.execute_single_command(command)?;
70        }
71        Ok(())
72    }
73
74    /// An internal function to run a single command
75    fn execute_single_command(&mut self, command: Command) -> AppResult<()> {
76        match command {
77            Command::Quit => self.quit(),
78            Command::CommandLineStop => self.command_line.deactivate(),
79            Command::CommandLineInsertChar(ch) => self.command_line.enter_char(ch),
80            Command::CommandLineDelete => self.command_line.delete_char(),
81            Command::CommandLineLeft => self.command_line.move_cursor_left(),
82            Command::CommandLineRight => self.command_line.move_cursor_right(),
83            Command::CommandLineEnter => {
84                self.execute(self.command_line.get_commands())?;
85            }
86            Command::ChangeInputMode(mode) => self.change_input_mode(mode),
87            Command::EditorInsert(to_insert) => self.editor.insert(to_insert, self.mode),
88            Command::EditorDelete(motion) => self.editor.delete(motion, self.mode),
89            Command::EditorMove(motion) => self.editor.move_cursor(&motion, self.mode),
90            Command::EditorSave => self.editor.save()?,
91        };
92        Ok(())
93    }
94
95    /// Set running to false to quit the application.
96    fn quit(&mut self) {
97        self.running = false;
98    }
99
100    /// Change input mode
101    fn change_input_mode(&mut self, input_mode: InputMode) {
102        self.mode = input_mode
103    }
104}