Skip to content

Commit

Permalink
gap buffer p5
Browse files Browse the repository at this point in the history
  • Loading branch information
Kacperacy committed Jun 14, 2024
1 parent 53a36e4 commit a82b0df
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 24 deletions.
42 changes: 25 additions & 17 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use std::{cmp::min, error, fs};

use ratatui::layout::Rect;

use crate::gap_buffer::GapBuffer;

pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>;

const GAP_BUFFER_DEFAULT_SIZE: usize = 80;
const QUIT_TIMES: i8 = 2;
const DEFAULT_STATUS: &str = "Press Ctrl + C to quit, Ctrl + S to save.";

Expand All @@ -22,7 +25,7 @@ pub struct Position {
#[derive(Debug)]
pub struct App {
pub running: bool,
pub content: Vec<String>,
pub content: Vec<GapBuffer>,
pub cursor_position: Position,
pub cursor_offset: Position,
pub opened_filename: String,
Expand All @@ -40,7 +43,7 @@ impl Default for App {
fn default() -> Self {
Self {
running: true,
content: vec![String::new()],
content: vec![],
cursor_position: Position { x: 0, y: 0 },
cursor_offset: Position { x: 0, y: 0 },
opened_filename: String::new(),
Expand Down Expand Up @@ -103,12 +106,12 @@ impl App {
std::cmp::max((self.content.len() as f64).log10().ceil() as usize, 4);
}

fn push_to_content(&mut self, s: String) {
fn push_to_content(&mut self, s: GapBuffer) {
self.content.push(s);
self.update_line_numbers_width();
}

fn insert_to_content(&mut self, index: usize, s: String) {
fn insert_to_content(&mut self, index: usize, s: GapBuffer) {
self.content.insert(index, s);
self.update_line_numbers_width();
}
Expand All @@ -117,7 +120,7 @@ impl App {
let s = self.content.remove(index);
self.line_numbers_width =
std::cmp::max((self.content.len() as f64).log10().ceil() as usize, 4);
s
s.to_string()
}

pub fn enter_prompt(&mut self) {
Expand All @@ -144,7 +147,14 @@ impl App {

self.dirty = false;
self.status = format!("Saved to {}", self.opened_filename);
let _ = fs::write(&self.opened_filename, self.content.join("\n"));
let _ = fs::write(
&self.opened_filename,
self.content
.iter()
.map(|b| b.to_string())
.collect::<Vec<_>>()
.join("\n"),
);
}

pub fn insert_char(&mut self, c: char) {
Expand All @@ -155,11 +165,11 @@ impl App {
}

while self.cursor_position.y >= self.content.len() {
self.push_to_content(String::new());
self.push_to_content(GapBuffer::new(GAP_BUFFER_DEFAULT_SIZE));
}

self.content[self.cursor_position.y + self.cursor_offset.y]
.insert(self.cursor_position.x + self.cursor_offset.x, c);
.insert_at(self.cursor_position.x + self.cursor_offset.x, c);
self.move_cursor(Direction { x: 1, y: 0 });
}

Expand All @@ -172,22 +182,20 @@ impl App {
}

while self.cursor_position.y >= self.content.len() {
self.push_to_content(String::new());
self.push_to_content(GapBuffer::new(GAP_BUFFER_DEFAULT_SIZE));
}

let current_line = &self.content[self.cursor_position.y];
let current_line = &mut self.content[self.cursor_position.y];

if current_line.len() > 0 {
let new_line = self.content[self.cursor_position.y].split_off(self.cursor_position.x);
let new_line = current_line.split_off(self.cursor_position.x);
let index = self.cursor_position.y + self.cursor_offset.y + 1;

self.insert_to_content(
self.cursor_position.y + self.cursor_offset.y + 1,
String::from(new_line),
);
self.insert_to_content(index, new_line);
} else {
self.insert_to_content(
self.cursor_position.y + self.cursor_offset.y + 1,
String::new(),
GapBuffer::new(GAP_BUFFER_DEFAULT_SIZE),
);
}

Expand Down Expand Up @@ -224,7 +232,7 @@ impl App {

self.move_cursor(Direction { x: 0, y: 1 });
} else if !(self.cursor_position.x == 0 && self.cursor_position.y == 0) {
self.content[pos.y].remove(pos.x - 1);
self.content[pos.y].remove_at(pos.x - 1);

self.move_cursor(Direction { x: -1, y: 0 });
}
Expand Down
59 changes: 54 additions & 5 deletions src/gap_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
struct GapBuffer {
#[derive(Debug, Clone)]
pub struct GapBuffer {
buffer: Vec<char>,
gap_start: usize,
gap_end: usize,
}

impl GapBuffer {
fn new(capacity: usize) -> GapBuffer {
pub fn new(capacity: usize) -> GapBuffer {
GapBuffer {
buffer: vec![' '; capacity],
gap_start: 0,
gap_end: capacity,
}
}

fn insert(&mut self, c: char) {
pub fn push(&mut self, c: char) {
if self.gap_start == self.gap_end {
self.resize();
}
Expand All @@ -39,7 +40,7 @@ impl GapBuffer {
}
}

fn move_cursor(&mut self, index: usize) {
fn move_gap(&mut self, index: usize) {
if index < self.gap_start {
let move_size = self.gap_start - index;
self.buffer
Expand All @@ -55,11 +56,59 @@ impl GapBuffer {
}
}

fn to_string(&self) -> String {
pub fn to_string(&self) -> String {
let mut result: Vec<char> =
Vec::with_capacity(self.buffer.len() - (self.gap_end - self.gap_start));
result.extend_from_slice(&self.buffer[..self.gap_start]);
result.extend_from_slice(&self.buffer[self.gap_end..]);
result.into_iter().collect()
}

pub fn insert_at(&mut self, index: usize, c: char) {
if index > self.buffer.len() {
return;
}
self.move_gap(index);
self.push(c);
}

pub fn push_str(&mut self, s: &str) {
for c in s.chars() {
self.push(c);
}
}

pub fn remove_at(&mut self, index: usize) {
if index > self.buffer.len() - (self.gap_end - self.gap_start) {
return;
}
self.move_gap(index + 1);
self.delete();
}

pub fn len(&self) -> usize {
self.buffer.len() - (self.gap_end - self.gap_start)
}

pub fn split_off(&mut self, at: usize) -> GapBuffer {
if at > self.len() {
panic!("Index out of bounds");
}
self.move_gap(at);

let new_capacity = self.buffer.len() - self.gap_end;
let mut new_buffer = vec![' '; new_capacity];

new_buffer[..new_capacity].copy_from_slice(&self.buffer[self.gap_end..]);

let split_buffer = GapBuffer {
buffer: new_buffer,
gap_start: 0,
gap_end: new_capacity,
};

self.gap_end = self.buffer.len();

split_buffer
}
}
4 changes: 2 additions & 2 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ pub fn render(app: &mut App, frame: &mut Frame) {
.enumerate()
.map(|(i, s)| {
if i == pos.y {
Line::from(format!("{:<content_width$}", s))
Line::from(format!("{:<content_width$}", s.to_string()))
.style(Style::default().bg(Color::Rgb(64, 64, 96)))
} else {
Line::from(format!("{}", s))
Line::from(format!("{}", s.to_string()))
}
})
.collect();
Expand Down

0 comments on commit a82b0df

Please sign in to comment.