Compare commits

..

3 Commits

  1. 1
      Cargo.toml
  2. 37
      TODO.org
  3. 4
      src/editor_render.rs
  4. 161
      src/main.rs

@ -9,4 +9,5 @@ opt-level = 3
[dependencies] [dependencies]
clipboard = "0.5.0" clipboard = "0.5.0"
num-format = "0.4.4"
sdl2 = { version = "0.35.2" } sdl2 = { version = "0.35.2" }

@ -11,8 +11,8 @@
* [ ] Confine to line unless CTRL is pressed * [ ] Confine to line unless CTRL is pressed
- [ ] Mouse input - [ ] Mouse input
* Editing [0/5] * Editing [2/7]
- [ ] Type text - [X] Type text
- [-] Remove text [3/6] - [-] Remove text [3/6]
* [X] Character backspace * [X] Character backspace
* [X] Character delete * [X] Character delete
@ -21,29 +21,36 @@
* [ ] Sentence backspace * [ ] Sentence backspace
* [ ] Sentence delete * [ ] Sentence delete
- [ ] Select text - [ ] Select text
- [ ] Cut, Copy, & Paste - [-] Cut
- [ ] Undo / Redo - [-] Copy
- [X] Paste
- [-] Undo / Redo
* (Creates a copy of the buffer after a period of inactivity, does not switch said buffer out yet, however)
* Rendering [1/6] * Rendering [1/8]
- [-] Text [1/3] - [-] Text [1/3]
* [X] Redneck bitmap * [X] Redneck bitmap
* [ ] Refined bitmap (.otb format) * [ ] Refined bitmap (.otb format)
* [ ] Vector (.ttf, .otf, etc) * [ ] Vector (.ttf, .otf, etc)
- [X] Cursor - [X] Cursor
- [ ] Multi-panel
- [ ] Selection - [ ] Selection
- [ ] Scaling/Zoom - [ ] Scaling/Zoom
- [ ] Scrolling - [ ] Scrolling
- [ ] Syntax Highlighting [/] - [ ] Syntax Highlighting [0/3]
- [ ] Built-in basic Rust highlighting * [ ] Built-in basic Rust highlighting
* [ ] Built-in basic RON highlighting
* [ ] Built-in basic Lua highlighting
- [-] Status bar
* Misc [0/3] * Misc [0/4]
- [ ] Search [0/1] - [ ] Search [0/1]
- [ ] Regex support * [ ] Regex support
- [ ] Replace [0/2] - [ ] Replace [0/2]
- [ ] Regex support * [ ] Regex support
- [ ] Sed style * [ ] Sed style
- [ ] File handling [0/3] - [ ] File handling [0/3]
- [ ] Open files * [ ] Open files
- [ ] Save files * [ ] Save files
- [ ] Save files as * [ ] Folder handling (for projects)
- [ ] Folder handling (for projects) - [ ] Configuration file

@ -8,8 +8,8 @@ use std::{fs::File, path::Path, io::Read};
use sdl2::rect::Point; use sdl2::rect::Point;
pub struct GlyphMetrics { pub struct GlyphMetrics {
width: usize, pub width: usize,
height: usize, pub height: usize,
} }
impl GlyphMetrics { impl GlyphMetrics {

@ -1,15 +1,23 @@
extern crate sdl2; extern crate sdl2;
use clipboard::{ClipboardProvider, ClipboardContext}; use clipboard::{ClipboardProvider, ClipboardContext};
use sdl2::event::Event; use num_format::{Locale, ToFormattedString};
use sdl2::event::{Event, WindowEvent};
use sdl2::keyboard::Keycode; use sdl2::keyboard::Keycode;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::Point; use sdl2::rect::{Point, Rect};
mod editor_render; mod editor_render;
static SCREEN_WIDTH: u32 = 1680; static SCREEN_WIDTH: u32 = 1280;
static SCREEN_HEIGHT: u32 = 945; static SCREEN_HEIGHT: u32 = 720;
// TODO: Make this configurable
static REFRESH_RATE: u32 = 50;
// TODO: Make this configurable
static UNDO_TIME: u32 = 500;
static UNDO_TIME_COUNT: u32 = (REFRESH_RATE as f32 * (UNDO_TIME as f32 / 1000.0)) as u32;
struct ModifierKeys { struct ModifierKeys {
alt: bool, alt: bool,
@ -18,8 +26,9 @@ struct ModifierKeys {
} }
pub fn main() -> Result<(), String> { pub fn main() -> Result<(), String> {
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false};
let mut clipboard_context: ClipboardContext = ClipboardProvider::new().unwrap(); let mut clipboard_context: ClipboardContext = ClipboardProvider::new().unwrap();
let (glyph_atlas, glyph_metrics) = editor_render::generate_glyph_data();
let sdl_context = sdl2::init()?; let sdl_context = sdl2::init()?;
let video_subsys = sdl_context.video()?; let video_subsys = sdl_context.video()?;
@ -27,19 +36,28 @@ pub fn main() -> Result<(), String> {
let window = video_subsys let window = video_subsys
.window("Rude", SCREEN_WIDTH, SCREEN_HEIGHT) .window("Rude", SCREEN_WIDTH, SCREEN_HEIGHT)
.position_centered() .position_centered()
.resizable()
.opengl() .opengl()
.build() .build()
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
let mut window_size = canvas.output_size()?;
let mut buffer = String::new(); let mut buffer = String::new();
let mut cursor_position = 0; let mut cursor_position = 0;
let mut selection_anchor: Option<usize> = None; let mut selection_anchor: Option<usize> = None;
let mut undo_history: Vec<(String, usize)> = vec![];
let mut undo_position: usize = 0;
let mut undo_timer: u32 = UNDO_TIME_COUNT;
let pad_offset = Point::new(10, 10); let pad_offset = Point::new(10, 10);
let mut draw_text = |text: &str, pos: usize| -> Result<(), String> { let (glyph_atlas, glyph_metrics) = editor_render::generate_glyph_data();
let mut draw = |window_size: (u32, u32), text: &str, pos: usize| -> Result<(), String> {
// Draw background // Draw background
canvas.set_draw_color(Color::RGB(32, 32, 32)); canvas.set_draw_color(Color::RGB(32, 32, 32));
canvas.clear(); canvas.clear();
@ -54,6 +72,29 @@ pub fn main() -> Result<(), String> {
); );
canvas.draw_points(&fb_text[..])?; canvas.draw_points(&fb_text[..])?;
// Draw info
let status = text.len().to_formatted_string(&Locale::en);
let status_position = Point::new(
pad_offset.x,
window_size.1 as i32 - glyph_metrics.height as i32 * 2
);
canvas.set_draw_color(Color::RGB(16, 64, 64));
canvas.fill_rect(Rect::new(0,
status_position.y - 5,
window_size.0,
glyph_metrics.height as u32 + 10
))?;
canvas.set_draw_color(Color::RGB(127, 240, 240));
let status_bar = editor_render::draw_text(
&glyph_atlas,
&glyph_metrics,
&status,
status_position
);
canvas.draw_points(&status_bar[..])?;
// Draw cursor // Draw cursor
canvas.set_draw_color(Color::RGB(64, 240, 240)); canvas.set_draw_color(Color::RGB(64, 240, 240));
let fb_cursor = editor_render::draw_cursor( let fb_cursor = editor_render::draw_cursor(
@ -69,16 +110,20 @@ pub fn main() -> Result<(), String> {
Ok(()) Ok(())
}; };
draw_text("", cursor_position)?; draw(window_size, "", cursor_position)?;
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false};
'mainloop: loop { 'mainloop: loop {
// TODO: Make this completely user-configurable instead of hardcoded // TODO: Make this completely user-configurable instead of hardcoded
for event in sdl_context.event_pump()?.poll_iter() { for event in sdl_context.event_pump()?.poll_iter() {
match event { match event {
Event::Window { win_event, .. } => {
if let WindowEvent::Resized(w, h) = win_event {
window_size = (w as u32, h as u32);
draw(window_size, &buffer, cursor_position)?
}
}
// ESC or SIGKILL // ESC or SIGKILL
Event::KeyDown { keycode: Some(Keycode::Escape), .. } | // Event::KeyDown { keycode: Some(Keycode::Escape), .. } |
Event::Quit { .. } => break 'mainloop, Event::Quit { .. } => break 'mainloop,
Event::KeyUp { keycode, .. } => { Event::KeyUp { keycode, .. } => {
@ -123,53 +168,68 @@ pub fn main() -> Result<(), String> {
// DELETE key // DELETE key
Some(Keycode::Delete) => { Some(Keycode::Delete) => {
if buffer.len() > 0 && cursor_position < buffer.len() { if buffer.len() > 0 && cursor_position < buffer.len() {
undo_timer = 0;
selection_anchor = None;
buffer.remove(cursor_position); buffer.remove(cursor_position);
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
} }
}, },
// ENTER key // ENTER key
Some(Keycode::Return) => { Some(Keycode::Return) => {
undo_timer = 0;
selection_anchor = None;
let key = '\n'; let key = '\n';
buffer.insert(cursor_position, key); buffer.insert(cursor_position, key);
cursor_position += 1; cursor_position += 1;
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
}, },
// HOME key // HOME key
Some(Keycode::Home) => { Some(Keycode::Home) => {
selection_anchor = None;
cursor_position = 0; cursor_position = 0;
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
}, },
// END key // END key
Some(Keycode::End) => { Some(Keycode::End) => {
selection_anchor = None;
cursor_position = buffer.len(); cursor_position = buffer.len();
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
}, },
// Left/Back arrow // Left/Back arrow
Some(Keycode::Left) => { Some(Keycode::Left) => {
selection_anchor = None; selection_anchor = None;
cursor_position = usize::checked_sub(cursor_position, 1) cursor_position = usize::checked_sub(cursor_position, 1)
.unwrap_or(0); .unwrap_or(0);
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
}, },
// Right/Forward arrow // Right/Forward arrow
Some(Keycode::Right) => { Some(Keycode::Right) => {
selection_anchor = None; selection_anchor = None;
cursor_position = (cursor_position + 1).min(buffer.len()); cursor_position = (cursor_position + 1).min(buffer.len());
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
}, },
// BACKSPACE key // BACKSPACE key
// Character backspace
Some(Keycode::Backspace) => { Some(Keycode::Backspace) => {
if buffer.len() > 0 { if buffer.len() > 0 {
// Character backspace; regular undo_timer = 0;
selection_anchor = None;
buffer.remove(cursor_position - 1); buffer.remove(cursor_position - 1);
cursor_position -= 1; cursor_position -= 1;
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
} }
}, },
@ -180,18 +240,42 @@ pub fn main() -> Result<(), String> {
// CTRL down // CTRL down
(false, true, false) => { (false, true, false) => {
match keycode { match keycode {
Some(Keycode::Z) => println!("Undo"), Some(Keycode::Z) => {
if undo_position > 1 {
undo_position -= 1;
let last_undo = undo_history[undo_position - 1].clone();
buffer = last_undo.0;
cursor_position = last_undo.1;
draw(window_size, &buffer, cursor_position)?
}
},
Some(Keycode::X) => println!("Cut"), Some(Keycode::X) => println!("Cut"),
Some(Keycode::C) => { Some(Keycode::C) => {
clipboard_context.set_contents(buffer.clone()).unwrap() clipboard_context.set_contents(buffer.clone()).unwrap()
}, },
Some(Keycode::V) => println!("Paste"), Some(Keycode::V) => {
let paste = clipboard_context.get_contents().unwrap();
for character in paste.chars() {
buffer.insert(cursor_position, character);
cursor_position += 1;
undo_timer = UNDO_TIME_COUNT;
}
draw(window_size, &buffer, cursor_position)?
},
// BACKSPACE key // BACKSPACE key
// Word backspace // Word backspace
// TODO: Clean up this cursed expression // TODO: Clean up this cursed expression
Some(Keycode::Backspace) => { Some(Keycode::Backspace) => {
if buffer.len() > 0 { if buffer.len() > 0 {
undo_timer = 0;
selection_anchor = None;
let buffer_chars: Vec<char> = buffer.chars() let buffer_chars: Vec<char> = buffer.chars()
.collect(); .collect();
while !(buffer_chars[cursor_position - 1] == ' ' || while !(buffer_chars[cursor_position - 1] == ' ' ||
@ -203,7 +287,7 @@ pub fn main() -> Result<(), String> {
buffer.remove(cursor_position - 1); buffer.remove(cursor_position - 1);
cursor_position -= 1; cursor_position -= 1;
draw_text(&buffer, cursor_position)? draw(window_size, &buffer, cursor_position)?
} }
}, },
_ => (), _ => (),
@ -212,8 +296,19 @@ pub fn main() -> Result<(), String> {
(true, true, false) => { (true, true, false) => {
match keycode { match keycode {
Some(Keycode::Z) => println!("Redo"), Some(Keycode::Z) => {
if undo_position < undo_history.len() {
undo_position += 1;
let last_redo = undo_history[undo_position - 1].clone();
buffer = last_redo.0;
cursor_position = last_redo.1;
draw(window_size, &buffer, cursor_position)?
}
},
Some(Keycode::X) => println!("Cut line(s)"), Some(Keycode::X) => println!("Cut line(s)"),
Some(Keycode::C) => println!("Copy line(s)"), Some(Keycode::C) => println!("Copy line(s)"),
_ => (), _ => (),
} }
@ -224,16 +319,36 @@ pub fn main() -> Result<(), String> {
}, },
Event::TextInput { text, .. } => { Event::TextInput { text, .. } => {
undo_timer = 0;
selection_anchor = None;
let input_char = text.chars().nth(0).expect("Empty"); let input_char = text.chars().nth(0).expect("Empty");
buffer.insert(cursor_position, input_char); buffer.insert(cursor_position, input_char);
cursor_position += 1; cursor_position += 1;
draw_text(&buffer, cursor_position)?; draw(window_size, &buffer, cursor_position)?;
}, },
_ => {} _ => {}
} }
} }
// Wait for pause in input to snapshot buffer for undoing/redoing
if undo_timer < UNDO_TIME_COUNT {
undo_timer += 1;
} else if undo_timer == UNDO_TIME_COUNT {
// println!("Saving undo step.");
if undo_position < undo_history.len() {
undo_history.truncate(undo_position);
}
undo_history.push((buffer.clone(), cursor_position));
undo_timer += 1;
undo_position += 1;
//println!("Undo data: {undo_history:?}");
}
::std::thread::sleep(std::time::Duration::new(0, 1_000_000_000 / REFRESH_RATE));
} }
format!("{selection_anchor:?}"); format!("{selection_anchor:?}");
println!("{buffer}"); println!("{buffer}");

Loading…
Cancel
Save