reverted oop changes

This commit is contained in:
Maddie 2022-11-11 11:15:33 +00:00
parent a8c7733c0a
commit 1d18cd1715
10 changed files with 135 additions and 238 deletions

View File

@ -1,9 +1,8 @@
mod core;
mod terminal;
mod tui;
fn main() {
let lambda = core::editor::Editor::new();
let mut screen = terminal::screen::Screen::new().unwrap();
tui::ui::Ui::run(&mut screen, lambda);
terminal::tui::start(&mut screen, lambda);
}

View File

@ -1 +1,2 @@
pub mod screen;
pub mod tui;

View File

@ -11,7 +11,7 @@ pub struct Coords {
pub y: usize,
}
// Creating a set of coordinates from two values
// Creating a coordinates from two values
impl Coords {
pub fn from(x: usize, y: usize) -> Self {
Self { x, y }
@ -146,7 +146,7 @@ impl Screen {
execute!(stdout(), Print(text)).unwrap();
}
pub fn write_at(&mut self, text: &String, position: Coords) {
pub fn write_at(&mut self, text: String, position: Coords) {
// Writes a line at a set of coordinates
self.cursor.move_to(position);
Screen::write(&text);

131
src/terminal/tui.rs Normal file
View File

@ -0,0 +1,131 @@
use crate::core::editor::Editor;
use crate::terminal::screen::{Coords, Screen};
use crossterm::style::Stylize;
use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
// Utils
fn with_spaces(text: &str) -> String {
format!(" {} ", text)
}
fn calc_x(screen_width: usize, item_length: usize) -> usize {
(screen_width / 2) - (item_length / 2)
}
fn longest_element_in_array(elements: Vec<&str>) -> usize {
elements.iter().max_by_key(|x: &&&str| x.len()).unwrap().len()
}
pub fn draw_status(screen: &mut Screen, editor: &Editor) -> Result<(), ()> {
// Calculate where to draw the status bar
let status_height = screen.size.height - 2;
// Get the editor logo from the config
let editor_logo = &with_spaces(editor.config.logo) as &str;
// Get the current mode into a string
let mode_string = &with_spaces(editor.mode.as_str()) as &str;
// Get the current open file name
let file_name = &with_spaces(editor.buffer.name) as &str;
// Calculate the total length of all the status bar components
let total_length = editor_logo.len() + mode_string.len() + file_name.len() + 1;
// If the screen isn't wide enough, panic as we can't draw the status bar
if screen.size.width < total_length {
Err(())
} else {
// Write the editor logo
screen.write_at(
editor_logo.yellow().bold().reverse().to_string(),
Coords::from(0, status_height),
);
// Calculate where to write the current mode
let x = editor_logo.len() - 1;
// Write the current mode
screen.write_at(
mode_string.green().bold().reverse().to_string(),
Coords::from(x, status_height),
);
// Calculate where to write the file name
let x = x + mode_string.len();
// Write the current file name
screen.write_at(
file_name.magenta().bold().reverse().to_string(),
Coords::from(x, status_height),
);
// Draw the rest of the status bar
let x = x + file_name.len();
screen.write_at(
" ".repeat(screen.size.width - x).reverse().to_string(),
Coords::from(x, status_height),
);
Ok(())
}
}
pub fn draw_welcome(screen: &mut Screen, editor: &Editor) {
// The welcome message
let title = format!("{} {}", editor.config.logo, editor.config.friendly_name);
let message: [&str; 5] = [
"Hackable text editor for nerds",
"",
"Type :help to open the README.md document",
"Type :o <file> to open a file and edit",
"Type :q! or <C-c> to quit lambda",
];
// If the screen is big enough, we can draw
if screen.size.width > longest_element_in_array(message.to_vec()) && screen.size.height > message.len() + 4 {
// The starting y position in the centre of the screen
let mut y = (screen.size.height / 2) - (message.len() / 2) - 2;
// Calculate where to place the title
let x = calc_x(screen.size.width, title.len());
// Write the title to the screen
screen.write_at(title.yellow().to_string(), Coords::from(x, y));
for line in message {
// Each line has different width so requires a different x position to center it
let x = calc_x(screen.size.width, line.len()) ;
// For each line we move downwards so increment y
y += 1;
// Write the line to the screen at position (x, y)
screen.write_at(line.to_string(), Coords::from(x, y));
}
}
}
pub fn start(screen: &mut Screen, editor: Editor) {
loop {
// Refresh the screen
screen.refresh().unwrap();
// Draw the welcome message
draw_welcome(screen, &editor);
// Draw the status bar
draw_status(screen, &editor).unwrap();
// Check for any key presses
match read().unwrap() {
Event::Key(KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::CONTROL,
..
}) => break,
Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
..
}) => break,
_ => (),
}
}
screen.exit();
}

View File

@ -1,2 +0,0 @@
pub mod statusbar;
pub mod welcome;

View File

@ -1,74 +0,0 @@
use crate::tui::utils::with_spaces;
use crate::tui::ui::Component;
use crate::core::editor::Editor;
use crate::terminal::screen::{Coords, Screen};
use crossterm::style::Stylize;
pub struct StatusBar<'a> {
logo: &'a str,
mode: &'a str,
file_name: &'a str,
}
impl<'a> StatusBar<'a> {
pub fn new(editor: &'a Editor<'a>) -> Self {
Self {
logo: editor.config.logo,
mode: editor.mode.as_str(),
file_name: editor.buffer.name,
}
}
}
impl<'a> Component for StatusBar<'a> {
fn draw(&self, screen: &mut Screen, editor: &Editor) -> Result<(), ()> {
// Calculate where to draw the status bar
let status_height = screen.size.height - 2;
// Get the editor logo from the config
let editor_logo = &with_spaces(editor.config.logo) as &str;
// Get the current mode into a string
let mode_string = &with_spaces(editor.mode.as_str()) as &str;
// Get the current open file name
let file_name = &with_spaces(editor.buffer.name) as &str;
// Calculate the total length of all the status bar components
let total_length = editor_logo.len() + mode_string.len() + file_name.len() + 1;
// If the screen isn't wide enough, panic as we can't draw the status bar
if screen.size.width < total_length {
Err(())
} else {
// Write the editor logo
screen.write_at(
&editor_logo.yellow().bold().reverse().to_string(),
Coords::from(0, status_height),
);
// Calculate where to write the current mode
let x = editor_logo.len() - 1;
// Write the current mode
screen.write_at(
&mode_string.green().bold().reverse().to_string(),
Coords::from(x, status_height),
);
// Calculate where to write the file name
let x = x + mode_string.len();
// Write the current file name
screen.write_at(
&file_name.magenta().bold().reverse().to_string(),
Coords::from(x, status_height),
);
// Draw the rest of the status bar
let x = x + file_name.len();
screen.write_at(
&" ".repeat(screen.size.width - x).reverse().to_string(),
Coords::from(x, status_height),
);
Ok(())
}
}
}

View File

@ -1,62 +0,0 @@
use crate::tui::utils;
use crate::tui::ui::Component;
use crate::core::editor::Editor;
use crate::terminal::screen::{Coords, Screen};
use crossterm::style::Stylize;
pub struct WelcomeMessage<'a> {
title: String,
message: [&'a str; 5],
}
impl<'a> WelcomeMessage<'a> {
pub fn new(editor: &'a Editor<'a>) -> Self {
// The title message
let title = format!("{} {}", editor.config.logo, editor.config.friendly_name);
// The welcome message
let message: [&str; 5] = [
"Hackable text editor for nerds",
"",
"Type :help to open the README.md document",
"Type :o <file> to open a file and edit",
"Type :q! or <C-c> to quit lambda",
];
Self {
title,
message,
}
}
}
impl<'a> Component for WelcomeMessage<'a> {
fn draw(&self, screen: &mut Screen, _editor: &Editor) -> Result<(), ()> {
// If the screen is big enough, we can draw
if screen.size.width > utils::longest_element_in_vec(self.message.to_vec()) && screen.size.height > self.message.len() + 4 {
// The starting y position in the centre of the screen
let mut y = (screen.size.height / 2) - (self.message.len() / 2) - 2;
// Calculate where to place the title
let x = utils::calc_centered_x(screen.size.width, self.title.len());
// Write the title to the screen
screen.write_at(&self.title.clone().yellow().to_string(), Coords::from(x, y));
for line in &self.message {
// Each line has different width so requires a different x position to center it
let x = utils::calc_centered_x(screen.size.width, line.len()) ;
// For each line we move downwards so increment y
y += 1;
// Write the line to the screen at position (x, y)
screen.write_at(&line.to_string(), Coords::from(x, y));
};
Ok(())
} else {
Err(())
}
}
}

View File

@ -1,3 +0,0 @@
pub mod ui;
pub mod components;
mod utils;

View File

@ -1,79 +0,0 @@
use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
use crate::core::editor::Editor;
use crate::terminal::screen::Screen;
use crate::tui::components;
pub trait Component {
fn draw(&self, screen: &mut Screen, editor: &Editor) -> Result<(), ()>;
}
struct Components<'a> {
bottom: Vec<Box<dyn Component + 'a>>,
centre: Vec<Box<dyn Component + 'a>>,
}
pub struct Ui<'a> {
components: Components<'a>,
}
impl<'a> Ui<'a> {
pub fn new(editor: &'a Editor<'a>) -> Self {
let status_bar = components::statusbar::StatusBar::new(editor);
let welcome_msg = components::welcome::WelcomeMessage::new(editor);
Self {
components: Components {
bottom: vec![Box::new(status_bar)],
centre: vec![Box::new(welcome_msg)],
},
}
}
pub fn draw(&self, screen: &mut Screen, editor: &Editor) {
// Dereference the box
let _ = &*self.components.bottom;
// Draw all components on the bottom
for component in &self.components.bottom {
component.draw(screen, &editor).unwrap();
};
// Dereference the box
let _ = &*self.components.centre;
// Draw all components in the center
for component in &self.components.centre {
component.draw(screen, &editor).unwrap();
}
}
pub fn run(screen: &mut Screen, editor: Editor) {
loop {
// Refresh the screen
screen.refresh().unwrap();
// Generate all the UI elements
let components = Ui::new(&editor);
// Draw all UI elements
components.draw(screen, &editor);
// Check for any key presses
match read().unwrap() {
Event::Key(KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::CONTROL,
..
}) => break,
Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
..
}) => break,
_ => (),
}
}
screen.exit();
}
}

View File

@ -1,14 +0,0 @@
// Surrounds a &str with spaces
pub fn with_spaces(text: &str) -> String {
format!(" {} ", text)
}
// Calculates the x coordinate for centered text
pub fn calc_centered_x(screen_width: usize, item_length: usize) -> usize {
(screen_width / 2) - (item_length / 2)
}
// Finds and returns the longest element in a vector
pub fn longest_element_in_vec(elements: Vec<&str>) -> usize {
elements.iter().max_by_key(|x: &&&str| x.len()).unwrap().len()
}