built more of the editor + tui parts
This commit is contained in:
parent
09d26ec97e
commit
a8a978d86e
61
Cargo.lock
generated
61
Cargo.lock
generated
@ -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"
|
||||||
|
@ -5,3 +5,5 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = "0.25"
|
crossterm = "0.25"
|
||||||
|
colored = "2"
|
||||||
|
ctrlc = "3.2.3"
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/main.rs
17
src/main.rs
@ -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();
|
|
||||||
}
|
}
|
||||||
|
118
src/terminal.rs
118
src/terminal.rs
@ -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
56
src/tui.rs
Normal 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();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user