built more of the editor + tui parts

This commit is contained in:
Maddie H 2022-11-06 18:35:05 +00:00
parent 09d26ec97e
commit a8a978d86e
No known key found for this signature in database
GPG Key ID: 64FAA9959751687D
6 changed files with 240 additions and 52 deletions

61
Cargo.lock generated
View File

@ -2,6 +2,17 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -20,6 +31,17 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]] [[package]]
name = "crossterm" name = "crossterm"
version = "0.25.0" version = "0.25.0"
@ -45,13 +67,40 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "ctrlc"
version = "3.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173"
dependencies = [
"nix",
"winapi",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "lambda" name = "lambda"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"colored",
"crossterm", "crossterm",
"ctrlc",
] ]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.137" version = "0.2.137"
@ -89,6 +138,18 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "nix"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
dependencies = [
"autocfg",
"bitflags",
"cfg-if",
"libc",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"

View File

@ -5,3 +5,5 @@ edition = "2021"
[dependencies] [dependencies]
crossterm = "0.25" crossterm = "0.25"
colored = "2"
ctrlc = "3.2.3"

View File

@ -1,7 +1,11 @@
enum Mode { pub struct Config<'a> {
Normal, pub logo: &'a str,
Insert, }
Select
impl<'a> Config<'a> {
pub fn new() -> Self {
Self { logo: "λ" }
}
} }
pub struct Buffer<'a> { pub struct Buffer<'a> {
@ -10,21 +14,41 @@ pub struct Buffer<'a> {
pub path: &'a str, pub path: &'a str,
} }
pub enum Mode {
Normal,
Insert,
Select,
Command,
}
impl Mode {
pub fn as_str(&self) -> &str {
match self {
Mode::Normal => "NORMAL",
Mode::Insert => "INSERT",
Mode::Select => "SELECT",
Mode::Command => "COMMAND",
}
}
}
pub struct Editor<'a> { pub struct Editor<'a> {
pub config: Config<'a>,
pub buffer: Buffer<'a>, pub buffer: Buffer<'a>,
pub cursor: [i32; 2], pub cursors: Vec<i32>,
mode: Mode, pub mode: Mode,
} }
impl<'a> Editor<'a> { impl<'a> Editor<'a> {
pub fn new() -> Self { pub fn new() -> Self {
Editor { Editor {
config: Config::new(),
buffer: Buffer { buffer: Buffer {
data: Vec::from([String::from("Hello"), String::from("World")]), data: Vec::from([String::from("Hello"), String::from("World")]),
name: "[No Name]", name: "[No Name]",
path: "/home/spy", path: "/home/spy",
}, },
cursor: [0, 0], cursors: Vec::from([0]),
mode: Mode::Normal, mode: Mode::Normal,
} }
} }

View File

@ -1,18 +1,9 @@
use std::time::Duration;
mod terminal;
mod editor; mod editor;
mod terminal;
mod tui;
fn main() { fn main() {
let lambda = editor::Editor::new(); let lambda = editor::Editor::new();
let mut term = terminal::Terminal::new().unwrap(); let mut screen = terminal::Screen::new().unwrap();
loop { tui::start(&mut screen, lambda);
for line in lambda.buffer.data {
terminal::Terminal::write(format!("{line}"));
mut term.cursor.move_to(0, 1);
};
std::thread::sleep(Duration::from_secs(3));
break;
};
terminal::Terminal::exit();
} }

View File

@ -1,76 +1,124 @@
use crossterm::cursor::{Hide, MoveTo, Show};
use crossterm::style::Print;
use crossterm::terminal; use crossterm::terminal;
use crossterm::{execute, ErrorKind}; use crossterm::{execute, ErrorKind};
use crossterm::style::Print; use std::io::stdout;
use crossterm::cursor::{CursorShape, MoveTo};
use std::io::{stdout, Write};
pub struct Size {
pub width: usize,
pub height: usize,
}
// Struct for holding coordinates
#[derive(Copy, Clone)]
pub struct Coords { pub struct Coords {
pub x: usize, pub x: usize,
pub y: usize, pub y: usize,
} }
// Creating a coordinates from two values
impl Coords { impl Coords {
pub fn from(x: usize, y: usize) -> Self { pub fn from(x: usize, y: usize) -> Self {
Self { Self { x, y }
x: 0,
y: 0,
}
} }
} }
// A cursor for writing to the terminal screen
#[derive(Copy, Clone)]
pub struct Cursor { pub struct Cursor {
pub position: Coords, pub position: Coords,
pub shape: CursorShape, pub hidden: bool,
} }
// When a cursor is created
impl Cursor { impl Cursor {
pub fn new() -> Result<Self, ErrorKind> { pub fn new() -> Result<Self, ErrorKind> {
let cursor = Self { let mut cursor = Self {
position: Coords::from(0, 0), position: Coords::from(0, 0),
shape: CursorShape::Block, hidden: true,
}; };
Cursor::move_to(&mut cursor, 0, 0); Cursor::move_to(&mut cursor, Coords::from(0, 0));
Cursor::hide(&mut cursor);
Ok(cursor) Ok(cursor)
} }
pub fn move_to(&mut self, x: u16, y: u16) {
self.position = Coords::from(x as usize, y as usize);
execute!(stdout(), MoveTo(x, y)).unwrap()
}
} }
pub struct Terminal { // Cursor methods
impl Cursor {
pub fn move_to(&mut self, position: Coords) {
// Set the new position of the cursor
self.position = position;
// Move the cursor to the desired posiition in the terminal
execute!(stdout(), MoveTo(position.x as u16, position.y as u16)).unwrap();
}
pub fn hide(&mut self) {
// Remember that the cursor is hidden
self.hidden = true;
// Hide the cursor from the terminal screen
execute!(stdout(), Hide).unwrap();
}
pub fn show(&mut self) {
// Remember that the cursor isn't hidden
self.hidden = false;
// Show the cursor to the terminal screen
execute!(stdout(), Show).unwrap();
}
}
// A struct for holding the size of the terminal
pub struct Size {
pub width: usize,
pub height: usize,
}
// The terminal screen
pub struct Screen {
pub size: Size, pub size: Size,
pub cursor: Cursor, pub cursor: Cursor,
} }
impl Terminal { // For when a new terminal screen is created
impl Screen {
pub fn new() -> Result<Self, ErrorKind> { pub fn new() -> Result<Self, ErrorKind> {
// Get the size of the terminal
let size = terminal::size()?; let size = terminal::size()?;
Terminal::clear();
Terminal::enter(); // Define a new terminal screen struct
Ok(Self { let mut screen = Self {
size: Size { size: Size {
width: size.0 as usize, width: size.0 as usize,
height: size.1 as usize, height: size.1 as usize,
}, },
cursor: Cursor::new().unwrap(), cursor: Cursor::new().unwrap(),
}) };
}
pub fn enter() { // Empty the terminal screen
// Enter the current terminal Screen::clear();
// Enter the terminal screen
screen.enter();
// Return a result containing the terminal
Ok(screen)
}
}
// Terminal functions and methods for managing the terminal
impl Screen {
pub fn enter(&mut self) {
// Hide the cursor
self.cursor.hide();
// Enter the terminal screen
terminal::enable_raw_mode().unwrap(); terminal::enable_raw_mode().unwrap();
execute!(stdout(), terminal::EnterAlternateScreen).unwrap(); execute!(stdout(), terminal::EnterAlternateScreen).unwrap();
} }
pub fn exit() { pub fn exit(&mut self) {
// Exit the current terminal // Show the cursor
self.cursor.show();
// Exit the terminal screen
execute!(stdout(), terminal::LeaveAlternateScreen).unwrap(); execute!(stdout(), terminal::LeaveAlternateScreen).unwrap();
terminal::disable_raw_mode().unwrap(); terminal::disable_raw_mode().unwrap();
} }
@ -84,4 +132,10 @@ impl Terminal {
// Clears the terminal screen // Clears the terminal screen
execute!(stdout(), terminal::Clear(terminal::ClearType::All)).unwrap(); execute!(stdout(), terminal::Clear(terminal::ClearType::All)).unwrap();
} }
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);
}
} }

56
src/tui.rs Normal file
View File

@ -0,0 +1,56 @@
use crate::editor::Editor;
use crate::terminal::{Coords, Screen};
use colored::Colorize;
use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
pub fn draw_status(screen: &mut Screen, editor: &Editor) {
// Calculate where to draw the status bar
let status_height = screen.size.height - 2;
// Get the editor logo from the config
let editor_logo = &format!(" {} ", editor.config.logo) as &str;
// Write the editor logo
screen.write_at(
editor_logo.bright_yellow().bold().reversed().to_string(),
Coords::from(0, status_height),
);
// Get the current mode into a string
let mode_string = &format!(" {} ", editor.mode.as_str()) as &str;
// Calculate where to write the current mode
let x = editor_logo.len() - 1;
// Write the current mode
screen.write_at(
mode_string.green().bold().reversed().to_string(),
Coords::from(x, status_height),
);
// Get the current open file name
let file_name = &format!(" {} ", editor.buffer.name) as &str;
// Calculate where to write the file name
let x = editor_logo.len() + mode_string.len() - 1;
// Write the current file name
screen.write_at(
file_name.magenta().bold().reversed().to_string(),
Coords::from(x, status_height),
);
}
pub fn start(screen: &mut Screen, editor: Editor) {
loop {
// Draw the status bar
draw_status(screen, &editor);
// Check for any key presses
match read().unwrap() {
Event::Key(KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::CONTROL,
..
}) => break,
_ => (),
}
}
screen.exit();
}