Fix backspace, fix add text

This commit is contained in:
Adrian Wozniak 2019-01-04 14:43:15 +01:00
parent c25fe0a4f5
commit 9460b6931a
No known key found for this signature in database
GPG Key ID: 3B441F7808FC43C7
16 changed files with 369 additions and 396 deletions

154
assets/test.rs Normal file
View File

@ -0,0 +1,154 @@
use std::ops::Deref;
pub mod plain;
pub mod rust_lang;
#[derive(Debug, Clone)]
pub enum Language {
PlainText,
}
#[derive(Debug, Clone)]
pub enum TokenType {
Whitespace { token: Token },
Keyword { token: Token },
String { token: Token },
Number { token: Token },
Identifier { token: Token },
Literal { token: Token },
Comment { token: Token },
Operator { token: Token },
Separator { token: Token },
}
impl TokenType {
pub fn move_to(&self, line: usize, character: usize, start: usize, end: usize) -> Self {
match self {
TokenType::Whitespace { token } => TokenType::Whitespace {
token: token.move_to(line, character, start, end),
},
TokenType::Keyword { token } => TokenType::Keyword {
token: token.move_to(line, character, start, end),
},
TokenType::String { token } => TokenType::String {
token: token.move_to(line, character, start, end),
},
TokenType::Number { token } => TokenType::Number {
token: token.move_to(line, character, start, end),
},
TokenType::Identifier { token } => TokenType::Identifier {
token: token.move_to(line, character, start, end),
},
TokenType::Literal { token } => TokenType::Literal {
token: token.move_to(line, character, start, end),
},
TokenType::Comment { token } => TokenType::Comment {
token: token.move_to(line, character, start, end),
},
TokenType::Operator { token } => TokenType::Operator {
token: token.move_to(line, character, start, end),
},
TokenType::Separator { token } => TokenType::Separator {
token: token.move_to(line, character, start, end),
},
}
}
pub fn is_new_line(&self) -> bool {
match self {
TokenType::Whitespace { token } => token.text().as_str() == "\n",
_ => false,
}
}
pub fn is_space(&self) -> bool {
match self {
TokenType::Whitespace { token } => token.text().as_str() == " ",
_ => false,
}
}
}
impl Deref for TokenType {
type Target = Token;
fn deref(&self) -> &<Self as Deref>::Target {
match self {
TokenType::Whitespace { token } => token,
TokenType::Keyword { token } => token,
TokenType::String { token } => token,
TokenType::Number { token } => token,
TokenType::Identifier { token } => token,
TokenType::Literal { token } => token,
TokenType::Comment { token } => token,
TokenType::Operator { token } => token,
TokenType::Separator { token } => token,
}
}
}
#[derive(Debug, Clone)]
pub struct Token {
line: usize,
character: usize,
start: usize,
end: usize,
text: String,
}
#[derive(Debug, Clone, Copy)]
pub struct Span {
pub lo: usize,
pub hi: usize,
}
impl Token {
pub fn new(text: String, line: usize, character: usize, start: usize, end: usize) -> Self {
Self {
text,
line,
character,
start,
end,
}
}
pub fn text(&self) -> &String {
&self.text
}
pub fn line(&self) -> usize {
self.line.clone()
}
pub fn character(&self) -> usize {
self.character.clone()
}
pub fn start(&self) -> usize {
self.start.clone()
}
pub fn end(&self) -> usize {
self.end.clone()
}
pub fn move_to(&self, line: usize, character: usize, start: usize, end: usize) -> Self {
Self {
text: self.text.clone(),
line,
character,
start,
end,
}
}
}
pub fn parse(text: String, language: Language) -> Vec<TokenType> {
match language {
Language::PlainText => plain::lexer::Lexer::new(text.as_str())
// .inspect(|tok| println!("tok: {:?}", tok))
.map(|t| t.0)
.collect(),
}
}

View File

@ -1,15 +1,16 @@
use crate::app::{UpdateResult, WindowCanvas}; use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config; use crate::config::Config;
use crate::ui::file::*;
use crate::ui::file::editor_file::EditorFile;
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*;
use crate::ui::caret::Caret; use crate::ui::caret::Caret;
use crate::ui::file::editor_file::EditorFile;
use crate::ui::file::*;
use crate::ui::menu_bar::MenuBar; use crate::ui::menu_bar::MenuBar;
use crate::ui::*;
use sdl2::rect::{Point, Rect};
use sdl2::VideoSubsystem;
use std::boxed::Box; use std::boxed::Box;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use sdl2::rect::{Rect, Point};
pub struct AppState { pub struct AppState {
menu_bar: MenuBar, menu_bar: MenuBar,
@ -55,23 +56,17 @@ impl AppState {
if position == 0 { if position == 0 {
return; return;
} }
buffer.remove(position); buffer.remove(position - 1);
match file.get_character_at(position - 1) { match file.get_character_at(position - 1) {
Some(character) => { Some(character) => {
let dest: &Rect = character.dest(); let dest: &Rect = character.dest();
caret.move_caret(position - 1, Point::new( caret.move_caret(position - 1, Point::new(dest.x(), dest.y()));
dest.x(), dest.y(),
));
} }
_ => { _ => {
caret.reset_caret(); caret.reset_caret();
} }
} }
let new_file = EditorFile::new( let new_file = EditorFile::new(file.path(), buffer, self.config.clone());
file.path(),
buffer,
self.config.clone(),
);
self.files[self.current_file] = new_file; self.files[self.current_file] = new_file;
} }
@ -88,15 +83,11 @@ impl AppState {
return; return;
} }
buffer.remove(position); buffer.remove(position);
let new_file = EditorFile::new( let new_file = EditorFile::new(file.path(), buffer, self.config.clone());
file.path(),
buffer,
self.config.clone(),
);
self.files[self.current_file] = new_file; self.files[self.current_file] = new_file;
} }
pub fn insert_character(&mut self, character: char, renderer: &mut Renderer) { pub fn insert_text(&mut self, text: String, renderer: &mut Renderer) {
let file: &mut EditorFile = if let Some(file) = self.files.get_mut(self.current_file) { let file: &mut EditorFile = if let Some(file) = self.files.get_mut(self.current_file) {
file file
} else { } else {
@ -104,30 +95,40 @@ impl AppState {
}; };
let mut buffer: String = file.buffer(); let mut buffer: String = file.buffer();
let caret: &mut Caret = &mut self.caret; let caret: &mut Caret = &mut self.caret;
let position: usize = caret.text_position();
buffer.insert(position, character.clone()); let current = match file.get_character_at(caret.text_position()) {
let new_file = EditorFile::new( Some(c) => c,
file.path(), _ => return,
buffer, };
self.config.clone(), let mut pos = Point::new(current.dest().x(), current.dest().y());
); let mut position: usize = caret.text_position();
for character in text.chars() {
buffer.insert(position, character);
if let Some(rect) = get_text_character_rect(character, renderer) { if let Some(rect) = get_text_character_rect(character, renderer) {
if let Some(current) = file.get_character_at(position) { pos = pos + Point::new(rect.width() as i32, 0);
caret.move_caret(position + 1, Point::new( position += 1;
current.dest().x() + rect.width() as i32, caret.move_caret(position, pos.clone());
current.dest().y(),
));
} }
} }
let new_file = EditorFile::new(file.path(), buffer, self.config.clone());
self.files[self.current_file] = new_file; self.files[self.current_file] = new_file;
} }
fn current_file(&mut self) -> Option<&mut EditorFile> { // fn current_file(&self) -> Option<&EditorFile> {
// self.files.get(self.current_file)
// }
fn current_file_mut(&mut self) -> Option<&mut EditorFile> {
self.files.get_mut(self.current_file) self.files.get_mut(self.current_file)
} }
fn on_editor_clicked(&mut self, point: &Point) -> UpdateResult { fn on_editor_clicked(
let current_file: &mut EditorFile = if let Some(current_file) = self.current_file() { &mut self,
point: &Point,
video_subsystem: &mut VideoSubsystem,
) -> UpdateResult {
let current_file: &mut EditorFile = if let Some(current_file) = self.current_file_mut() {
current_file current_file
} else { } else {
return UpdateResult::NoOp; return UpdateResult::NoOp;
@ -135,9 +136,11 @@ impl AppState {
if !current_file.is_left_click_target(point) { if !current_file.is_left_click_target(point) {
return UpdateResult::NoOp; return UpdateResult::NoOp;
} }
video_subsystem.text_input().start();
match current_file.on_left_click(point) { match current_file.on_left_click(point) {
UpdateResult::MoveCaret(rect, position) => { UpdateResult::MoveCaret(rect, position) => {
self.caret.move_caret(position, Point::new(rect.x(), rect.y())); self.caret
.move_caret(position, Point::new(rect.x(), rect.y()));
} }
_ => (), _ => (),
}; };
@ -149,7 +152,7 @@ impl AppState {
impl Render for AppState { impl Render for AppState {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult { fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
self.menu_bar.render(canvas, renderer); self.menu_bar.render(canvas, renderer);
if let Some(file) = self.files.get_mut(self.current_file) { if let Some(file) = self.current_file_mut() {
file.render(canvas, renderer); file.render(canvas, renderer);
} }
self.caret.render(canvas, renderer); self.caret.render(canvas, renderer);
@ -168,16 +171,21 @@ impl Update for AppState {
} }
} }
impl ClickHandler for AppState { impl AppState {
fn on_left_click(&mut self, point: &Point) -> UpdateResult { pub fn on_left_click(
&mut self,
point: &Point,
video_subsystem: &mut VideoSubsystem,
) -> UpdateResult {
if self.menu_bar.is_left_click_target(point) { if self.menu_bar.is_left_click_target(point) {
video_subsystem.text_input().stop();
return self.menu_bar.on_left_click(point); return self.menu_bar.on_left_click(point);
} }
self.on_editor_clicked(point); self.on_editor_clicked(point, video_subsystem);
UpdateResult::NoOp UpdateResult::NoOp
} }
fn is_left_click_target(&self, _point: &Point) -> bool { pub fn is_left_click_target(&self, _point: &Point) -> bool {
true true
} }
} }

View File

@ -1,281 +0,0 @@
use sdl2::keyboard::{Keycode, Scancode};
use sdl2::event::EventPollIterator;
use sdl2::EventPump;
use crate::app::UpdateResult;
pub fn resolve_action(key_code: Keycode, event_pump: &mut EventPump) -> UpdateResult {
match key_code {
Keycode::Backspace => return UpdateResult::DeleteFront,
Keycode::Delete => return UpdateResult::DeleteBack,
Keycode::Escape => return UpdateResult::NoOp,
Keycode::Space => {
let character: char = ' ';
return UpdateResult::Input(character);
}
Keycode::Exclaim => {
let character: char = '!';
return UpdateResult::Input(character);
}
Keycode::Quotedbl => {
let character: char = '"';
return UpdateResult::Input(character);
}
Keycode::Hash => {
let character: char = '#';
return UpdateResult::Input(character);
}
Keycode::Dollar => {
let character: char = '$';
return UpdateResult::Input(character);
}
Keycode::Percent => {
let character: char = '%';
return UpdateResult::Input(character);
}
Keycode::Ampersand => {
let character: char = '&';
return UpdateResult::Input(character);
}
Keycode::Quote => {
let character: char = '\'';
return UpdateResult::Input(character);
}
Keycode::LeftParen => {
let character: char = '{';
return UpdateResult::Input(character);
}
Keycode::RightParen => {
let character: char = '}';
return UpdateResult::Input(character);
}
Keycode::Asterisk => {
let character: char = '*';
return UpdateResult::Input(character);
}
Keycode::Plus => {
let character: char = '+';
return UpdateResult::Input(character);
}
Keycode::Comma => {
let character: char = ',';
return UpdateResult::Input(character);
}
Keycode::Minus => {
let character: char = '-';
return UpdateResult::Input(character);
}
Keycode::Period => {
let character: char = '.';
return UpdateResult::Input(character);
}
Keycode::Slash => {
let character: char = '/';
return UpdateResult::Input(character);
}
Keycode::Num0 => {
let character: char = '0';
return UpdateResult::Input(character);
}
Keycode::Num1 => {
let character: char = '1';
return UpdateResult::Input(character);
}
Keycode::Num2 => {
let character: char = '2';
return UpdateResult::Input(character);
}
Keycode::Num3 => {
let character: char = '3';
return UpdateResult::Input(character);
}
Keycode::Num4 => {
let character: char = '4';
return UpdateResult::Input(character);
}
Keycode::Num5 => {
let character: char = '5';
return UpdateResult::Input(character);
}
Keycode::Num6 => {
let character: char = '6';
return UpdateResult::Input(character);
}
Keycode::Num7 => {
let character: char = '7';
return UpdateResult::Input(character);
}
Keycode::Num8 => {
let character: char = '8';
return UpdateResult::Input(character);
}
Keycode::Num9 => {
let character: char = '9';
return UpdateResult::Input(character);
}
Keycode::Colon => {
let character: char = ':';
return UpdateResult::Input(character);
}
Keycode::Semicolon => {
let character: char = ';';
return UpdateResult::Input(character);
}
Keycode::Less => {
let character: char = '<';
return UpdateResult::Input(character);
}
Keycode::Equals => {
let character: char = '=';
return UpdateResult::Input(character);
}
Keycode::Greater => {
let character: char = '>';
return UpdateResult::Input(character);
}
Keycode::Question => {
let character: char = '?';
return UpdateResult::Input(character);
}
Keycode::At => {
let character: char = '@';
return UpdateResult::Input(character);
}
Keycode::LeftBracket => {
let character: char = '[';
return UpdateResult::Input(character);
}
Keycode::Backslash => {
let character: char = '\\';
return UpdateResult::Input(character);
}
Keycode::RightBracket => {
let character: char = ']';
return UpdateResult::Input(character);
}
Keycode::Caret => {
let character: char = '^';
return UpdateResult::Input(character);
}
Keycode::Underscore => {
let character: char = '_';
return UpdateResult::Input(character);
}
Keycode::Backquote => {
let character: char = '`';
return UpdateResult::Input(character);
}
Keycode::A => {
let character: char = if with_shift(event_pump) { 'A' } else { 'a' };
return UpdateResult::Input(character);
}
Keycode::B => {
let character: char = if with_shift(event_pump) { 'B' } else { 'b' };
return UpdateResult::Input(character);
}
Keycode::C => {
let character: char = if with_shift(event_pump) { 'C' } else { 'c' };
return UpdateResult::Input(character);
}
Keycode::D => {
let character: char = if with_shift(event_pump) { 'D' } else { 'd' };
return UpdateResult::Input(character);
}
Keycode::E => {
let character: char = if with_shift(event_pump) { 'E' } else { 'e' };
return UpdateResult::Input(character);
}
Keycode::F => {
let character: char = if with_shift(event_pump) { 'F' } else { 'f' };
return UpdateResult::Input(character);
}
Keycode::G => {
let character: char = if with_shift(event_pump) { 'G' } else { 'g' };
return UpdateResult::Input(character);
}
Keycode::H => {
let character: char = if with_shift(event_pump) { 'H' } else { 'h' };
return UpdateResult::Input(character);
}
Keycode::I => {
let character: char = if with_shift(event_pump) { 'I' } else { 'i' };
return UpdateResult::Input(character);
}
Keycode::J => {
let character: char = if with_shift(event_pump) { 'J' } else { 'j' };
return UpdateResult::Input(character);
}
Keycode::K => {
let character: char = if with_shift(event_pump) { 'K' } else { 'k' };
return UpdateResult::Input(character);
}
Keycode::L => {
let character: char = if with_shift(event_pump) { 'L' } else { 'l' };
return UpdateResult::Input(character);
}
Keycode::M => {
let character: char = if with_shift(event_pump) { 'M' } else { 'm' };
return UpdateResult::Input(character);
}
Keycode::N => {
let character: char = if with_shift(event_pump) { 'N' } else { 'n' };
return UpdateResult::Input(character);
}
Keycode::O => {
let character: char = if with_shift(event_pump) { 'O' } else { 'o' };
return UpdateResult::Input(character);
}
Keycode::P => {
let character: char = if with_shift(event_pump) { 'P' } else { 'p' };
return UpdateResult::Input(character);
}
Keycode::Q => {
let character: char = if with_shift(event_pump) { 'Q' } else { 'q' };
return UpdateResult::Input(character);
}
Keycode::R => {
let character: char = if with_shift(event_pump) { 'R' } else { 'r' };
return UpdateResult::Input(character);
}
Keycode::S => {
let character: char = if with_shift(event_pump) { 'S' } else { 's' };
return UpdateResult::Input(character);
}
Keycode::T => {
let character: char = if with_shift(event_pump) { 'T' } else { 't' };
return UpdateResult::Input(character);
}
Keycode::U => {
let character: char = if with_shift(event_pump) { 'U' } else { 'u' };
return UpdateResult::Input(character);
}
Keycode::V => {
let character: char = if with_shift(event_pump) { 'V' } else { 'v' };
return UpdateResult::Input(character);
}
Keycode::W => {
let character: char = if with_shift(event_pump) { 'W' } else { 'w' };
return UpdateResult::Input(character);
}
Keycode::X => {
let character: char = if with_shift(event_pump) { 'X' } else { 'x' };
return UpdateResult::Input(character);
}
Keycode::Y => {
let character: char = if with_shift(event_pump) { 'Y' } else { 'y' };
return UpdateResult::Input(character);
}
Keycode::Z => {
let character: char = if with_shift(event_pump) { 'Z' } else { 'z' };
return UpdateResult::Input(character);
}
_ => UpdateResult::NoOp
}
}
fn with_shift(event_pump: &mut EventPump) -> bool {
event_pump.keyboard_state().is_scancode_pressed(Scancode::LShift) ||
event_pump.keyboard_state().is_scancode_pressed(Scancode::RShift)
}

View File

@ -4,24 +4,23 @@ use crate::renderer::Renderer;
use crate::themes::*; use crate::themes::*;
use crate::ui::*; use crate::ui::*;
use std::rc::Rc;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use std::rc::Rc;
use sdl2::{Sdl, VideoSubsystem, TimerSubsystem};
use sdl2::event::Event; use sdl2::event::Event;
use sdl2::EventPump;
use sdl2::keyboard::{Keycode, Mod};
use sdl2::hint; use sdl2::hint;
use sdl2::keyboard::{Keycode, Mod};
use sdl2::mouse::MouseButton; use sdl2::mouse::MouseButton;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use sdl2::render::Canvas; use sdl2::render::Canvas;
use sdl2::video::Window;
use sdl2::ttf::Sdl2TtfContext; use sdl2::ttf::Sdl2TtfContext;
use sdl2::video::Window;
use sdl2::EventPump;
use sdl2::{Sdl, TimerSubsystem, VideoSubsystem};
pub mod app_state; pub mod app_state;
pub mod keyboard_handler;
pub type WindowCanvas = Canvas<Window>; pub type WindowCanvas = Canvas<Window>;
@ -34,7 +33,7 @@ pub enum UpdateResult {
MoveCaret(Rect, usize), MoveCaret(Rect, usize),
DeleteFront, DeleteFront,
DeleteBack, DeleteBack,
Input(char) Input(String),
} }
pub enum Task { pub enum Task {
@ -70,7 +69,6 @@ impl Application {
.unwrap(); .unwrap();
let canvas = window.into_canvas().accelerated().build().unwrap(); let canvas = window.into_canvas().accelerated().build().unwrap();
// let font_context = Rc::new(sdl2::ttf::init().unwrap());
Self { Self {
sdl_context, sdl_context,
@ -102,17 +100,18 @@ impl Application {
UpdateResult::NoOp => (), UpdateResult::NoOp => (),
UpdateResult::MoveCaret(_, _pos) => (), UpdateResult::MoveCaret(_, _pos) => (),
UpdateResult::MouseLeftClicked(point) => { UpdateResult::MouseLeftClicked(point) => {
app_state.on_left_click(&point); app_state.on_left_click(&point, &mut self.video_subsystem);
} }
UpdateResult::DeleteFront => { UpdateResult::DeleteFront => {
app_state.delete_front(); app_state.delete_front();
}, }
UpdateResult::DeleteBack => { UpdateResult::DeleteBack => {
app_state.delete_back(); app_state.delete_back();
}, }
UpdateResult::Input(text_character) => { UpdateResult::Input(text) => {
app_state.insert_character(text_character, &mut renderer); println!("text input: {}", text);
}, app_state.insert_text(text, &mut renderer);
}
} }
for task in self.tasks.iter() { for task in self.tasks.iter() {
match task { match task {
@ -163,10 +162,15 @@ impl Application {
} else { } else {
return UpdateResult::NoOp; return UpdateResult::NoOp;
}; };
return keyboard_handler::resolve_action( match keycode {
keycode, Keycode::Backspace => return UpdateResult::DeleteFront,
event_pump Keycode::Delete => return UpdateResult::DeleteBack,
); _ => UpdateResult::NoOp,
};
}
Event::TextInput { text, .. } => {
println!("text input: {}", text);
return UpdateResult::Input(text);
} }
_ => (), _ => (),
} }

View File

@ -1,6 +1,7 @@
use std::ops::Deref; use std::ops::Deref;
pub mod plain; pub mod plain;
pub mod rust_lang;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Language { pub enum Language {
@ -146,7 +147,7 @@ impl Token {
pub fn parse(text: String, language: Language) -> Vec<TokenType> { pub fn parse(text: String, language: Language) -> Vec<TokenType> {
match language { match language {
Language::PlainText => plain::lexer::Lexer::new(text.as_str()) Language::PlainText => plain::lexer::Lexer::new(text.as_str())
.inspect(|tok| println!("tok: {:?}", tok)) // .inspect(|tok| println!("tok: {:?}", tok))
.map(|t| t.0) .map(|t| t.0)
.collect(), .collect(),
} }

84
src/lexer/rust_lang.rs Normal file
View File

@ -0,0 +1,84 @@
use crate::lexer::{Token, TokenType};
pub mod lexer {
use crate::lexer::{Span, Token, TokenType};
use plex::lexer;
lexer! {
fn next_token(text: 'a) -> (TokenType, &'a str);
r"[ \t\r\n]" => (TokenType::Whitespace {
token: Token::new(text.to_string(), 0, 0, 0, 0)
}, text),
r"(let|fn|type|struct|pub|impl|for|self|Self)" => (TokenType::Keyword {
token: Token::new(text.to_string(), 0, 0, 0, 0)
}, text),
r"[^ \t\r\n]+" => (TokenType::Identifier {
token: Token::new(text.to_string(), 0, 0, 0, 0)
}, text),
}
pub struct Lexer<'a> {
original: &'a str,
remaining: &'a str,
line: usize,
character: usize,
}
impl<'a> Lexer<'a> {
pub fn new(s: &'a str) -> Self {
Self {
original: s,
remaining: s,
line: 0,
character: 0,
}
}
}
impl<'a> Iterator for Lexer<'a> {
type Item = (TokenType, Span);
fn next(&mut self) -> Option<(TokenType, Span)> {
loop {
let tok: (TokenType, &str) =
if let Some(((token_type, text), new_remaining)) = next_token(self.remaining) {
self.remaining = new_remaining;
if token_type.is_new_line() {
self.line += 1;
self.character = text.len();
} else {
self.character += text.len();
}
(token_type, text)
} else {
return None;
};
match tok {
(tok, text) => {
let span = self.span_in(text);
let token = tok.move_to(
self.line.clone(),
self.character - text.len(),
span.lo.clone(),
span.hi.clone(),
);
return Some((token, span));
}
}
}
}
}
impl<'a> Lexer<'a> {
fn span_in(&self, s: &str) -> Span {
let lo = s.as_ptr() as usize - self.original.as_ptr() as usize;
Span {
lo,
hi: lo + s.len(),
}
}
}
}

View File

@ -72,7 +72,7 @@ pub type FontManager<'l> = ResourceManager<'l, FontDetails, Font<'l, 'static>, S
#[derive(Clone)] #[derive(Clone)]
pub struct ResourceManager<'l, K, R, L> pub struct ResourceManager<'l, K, R, L>
where where
K: Hash + Eq, K: Hash + Eq,
L: 'l + ResourceLoader<'l, R>, L: 'l + ResourceLoader<'l, R>,
{ {
@ -81,7 +81,7 @@ pub struct ResourceManager<'l, K, R, L>
} }
impl<'l, K, R, L> ResourceManager<'l, K, R, L> impl<'l, K, R, L> ResourceManager<'l, K, R, L>
where where
K: Hash + Eq, K: Hash + Eq,
L: ResourceLoader<'l, R>, L: ResourceLoader<'l, R>,
{ {
@ -94,7 +94,7 @@ impl<'l, K, R, L> ResourceManager<'l, K, R, L>
pub fn load<D>(&mut self, details: &D) -> Result<Rc<R>, String> pub fn load<D>(&mut self, details: &D) -> Result<Rc<R>, String>
where where
L: ResourceLoader<'l, R, Args=D>, L: ResourceLoader<'l, R, Args = D>,
D: Eq + Hash + ?Sized, D: Eq + Hash + ?Sized,
K: Borrow<D> + for<'a> From<&'a D>, K: Borrow<D> + for<'a> From<&'a D>,
{ {

View File

@ -1,12 +1,12 @@
use crate::app::WindowCanvas; use crate::app::WindowCanvas;
use crate::config::Config; use crate::config::Config;
use crate::renderer::managers::{FontManager, TextureManager};
use crate::renderer::managers::TextDetails; use crate::renderer::managers::TextDetails;
use std::rc::Rc; use crate::renderer::managers::{FontManager, TextureManager};
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use sdl2::render::{Texture, TextureCreator}; use sdl2::render::{Texture, TextureCreator};
use sdl2::ttf::Sdl2TtfContext; use sdl2::ttf::Sdl2TtfContext;
use sdl2::video::WindowContext; use sdl2::video::WindowContext;
use std::rc::Rc;
pub mod managers; pub mod managers;

View File

@ -1,6 +1,6 @@
use crate::config::directories::*; use crate::config::directories::*;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use serde::ser::{Serialize, SerializeMap, Serializer, SerializeSeq}; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
use serde_json; use serde_json;
use std::env; use std::env;
use std::fs; use std::fs;

View File

@ -1,12 +1,12 @@
use crate::app::{UpdateResult, WindowCanvas}; use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config; use crate::config::Config;
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*;
use crate::ui::text_character::TextCharacter; use crate::ui::text_character::TextCharacter;
use std::rc::Rc; use crate::ui::*;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use sdl2::render::Texture; use sdl2::render::Texture;
use std::rc::Rc;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
enum CaretState { enum CaretState {
@ -14,11 +14,12 @@ enum CaretState {
Blur, Blur,
} }
#[derive(Clone, Debug, PartialEq)]
pub struct Caret { pub struct Caret {
pending: bool, pending: bool,
text_position: usize, text_position: usize,
blink_delay: u8, blink_delay: u8,
config: Rc<Config>, // config: Rc<Config>,
state: CaretState, state: CaretState,
dest: Rect, dest: Rect,
reset_position: Rect, reset_position: Rect,
@ -49,7 +50,7 @@ impl Caret {
blur_character_color, blur_character_color,
pending: true, pending: true,
text_position: 0, text_position: 0,
config, // config,
} }
} }
@ -96,10 +97,7 @@ impl Render for Caret {
self.pending = false; self.pending = false;
} }
let start = Point::new(self.dest.x(), self.dest.y()); let start = Point::new(self.dest.x(), self.dest.y());
let end = Point::new( let end = Point::new(self.dest.x(), self.dest.y() + self.dest.height() as i32);
self.dest.x(),
self.dest.y() + self.dest.height() as i32,
);
let color = match self.state { let color = match self.state {
CaretState::Bright => &self.bright_character_color, CaretState::Bright => &self.bright_character_color,
CaretState::Blur => &self.blur_character_color, CaretState::Blur => &self.blur_character_color,

View File

@ -1,12 +1,12 @@
use std::rc::Rc;
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use std::rc::Rc;
use crate::app::{UpdateResult, WindowCanvas}; use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config; use crate::config::Config;
use crate::ui::file::editor_file_section::EditorFileSection;
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*; use crate::ui::file::editor_file_section::EditorFileSection;
use crate::ui::text_character::TextCharacter; use crate::ui::text_character::TextCharacter;
use crate::ui::*;
#[derive(Clone)] #[derive(Clone)]
pub struct EditorFile { pub struct EditorFile {
@ -14,14 +14,12 @@ pub struct EditorFile {
sections: Vec<EditorFileSection>, sections: Vec<EditorFileSection>,
render_position: Rect, render_position: Rect,
buffer: String, buffer: String,
config: Rc<Config> config: Rc<Config>,
} }
impl EditorFile { impl EditorFile {
pub fn new(path: String, buffer: String, config: Rc<Config>) -> Self { pub fn new(path: String, buffer: String, config: Rc<Config>) -> Self {
let sections = vec![ let sections = vec![EditorFileSection::new(buffer.clone(), config.clone())];
EditorFileSection::new(buffer.clone(), config.clone())
];
let x = config.editor_left_margin(); let x = config.editor_left_margin();
let y = config.editor_top_margin(); let y = config.editor_top_margin();
Self { Self {
@ -29,7 +27,7 @@ impl EditorFile {
sections, sections,
render_position: Rect::new(x, y, 0, 0), render_position: Rect::new(x, y, 0, 0),
buffer, buffer,
config config,
} }
} }
@ -44,7 +42,7 @@ impl EditorFile {
pub fn get_character_at(&self, index: usize) -> Option<&TextCharacter> { pub fn get_character_at(&self, index: usize) -> Option<&TextCharacter> {
for section in self.sections.iter() { for section in self.sections.iter() {
if let Some(text_character) = section.get_character_at(index) { if let Some(text_character) = section.get_character_at(index) {
return Some(text_character) return Some(text_character);
} }
} }
None None

View File

@ -1,13 +1,13 @@
use std::rc::Rc;
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use std::rc::Rc;
use crate::app::{UpdateResult, WindowCanvas}; use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config; use crate::config::Config;
use crate::ui::file::editor_file_token::EditorFileToken;
use crate::lexer::Language; use crate::lexer::Language;
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*; use crate::ui::file::editor_file_token::EditorFileToken;
use crate::ui::text_character::TextCharacter; use crate::ui::text_character::TextCharacter;
use crate::ui::*;
#[derive(Clone)] #[derive(Clone)]
pub struct EditorFileSection { pub struct EditorFileSection {
@ -27,7 +27,11 @@ impl EditorFileSection {
tokens.push(token.clone()); tokens.push(token.clone());
} }
let language = Language::PlainText; let language = Language::PlainText;
Self { tokens, language, config } Self {
tokens,
language,
config,
}
} }
pub fn update_positions(&mut self, current: &mut Rect) { pub fn update_positions(&mut self, current: &mut Rect) {
@ -39,7 +43,7 @@ impl EditorFileSection {
pub fn get_character_at(&self, index: usize) -> Option<&TextCharacter> { pub fn get_character_at(&self, index: usize) -> Option<&TextCharacter> {
for token in self.tokens.iter() { for token in self.tokens.iter() {
if let Some(text_character) = token.get_character_at(index) { if let Some(text_character) = token.get_character_at(index) {
return Some(text_character) return Some(text_character);
} }
} }
None None

View File

@ -3,19 +3,19 @@ use crate::config::Config;
use crate::lexer::TokenType; use crate::lexer::TokenType;
use crate::renderer::managers::{FontDetails, TextDetails}; use crate::renderer::managers::{FontDetails, TextDetails};
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*;
use crate::ui::text_character::*; use crate::ui::text_character::*;
use std::rc::Rc; use crate::ui::*;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use sdl2::render::Texture; use sdl2::render::Texture;
use sdl2::ttf::Font; use sdl2::ttf::Font;
use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
pub struct EditorFileToken { pub struct EditorFileToken {
characters: Vec<TextCharacter>, characters: Vec<TextCharacter>,
token_type: TokenType, token_type: TokenType,
config: Rc<Config> config: Rc<Config>,
} }
impl EditorFileToken { impl EditorFileToken {
@ -23,7 +23,7 @@ impl EditorFileToken {
Self { Self {
characters: vec![], characters: vec![],
token_type, token_type,
config config,
} }
} }
@ -36,7 +36,7 @@ impl EditorFileToken {
pub fn get_character_at(&self, index: usize) -> Option<&TextCharacter> { pub fn get_character_at(&self, index: usize) -> Option<&TextCharacter> {
for character in self.characters.iter() { for character in self.characters.iter() {
if character.position() == index { if character.position() == index {
return Some(&character) return Some(&character);
} }
} }
None None
@ -61,7 +61,7 @@ impl EditorFileToken {
self.token_type.start() + index, self.token_type.start() + index,
self.token_type.line(), self.token_type.line(),
color.clone(), color.clone(),
self.config.clone() self.config.clone(),
); );
text_character.update_view(renderer); text_character.update_view(renderer);
self.characters.push(text_character); self.characters.push(text_character);

View File

@ -2,9 +2,9 @@ use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config; use crate::config::Config;
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*; use crate::ui::*;
use std::rc::Rc;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::{Rect, Point}; use sdl2::rect::{Point, Rect};
use std::rc::Rc;
pub struct MenuBar { pub struct MenuBar {
background_color: Color, background_color: Color,

View File

@ -2,13 +2,13 @@ use sdl2::rect::{Point, Rect};
use crate::app::{UpdateResult, WindowCanvas}; use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config; use crate::config::Config;
use crate::renderer::Renderer;
use crate::renderer::managers::FontDetails; use crate::renderer::managers::FontDetails;
use crate::renderer::Renderer;
pub mod caret; pub mod caret;
pub mod file;
pub mod menu_bar; pub mod menu_bar;
pub mod text_character; pub mod text_character;
pub mod file;
pub fn is_in_rect(point: &Point, rect: &Rect) -> bool { pub fn is_in_rect(point: &Point, rect: &Rect) -> bool {
let start = Point::new(rect.x(), rect.y()); let start = Point::new(rect.x(), rect.y());

View File

@ -6,11 +6,11 @@ use crate::renderer::managers::TextDetails;
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::ui::*; use crate::ui::*;
use std::rc::Rc;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::{Rect, Point}; use sdl2::rect::{Point, Rect};
use sdl2::render::Texture; use sdl2::render::Texture;
use sdl2::ttf::Font; use sdl2::ttf::Font;
use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
pub struct TextCharacter { pub struct TextCharacter {
@ -21,11 +21,17 @@ pub struct TextCharacter {
source: Rect, source: Rect,
dest: Rect, dest: Rect,
color: Color, color: Color,
config: Rc<Config> config: Rc<Config>,
} }
impl TextCharacter { impl TextCharacter {
pub fn new(text_character: char, position: usize, line: usize, color: Color, config: Rc<Config>) -> Self { pub fn new(
text_character: char,
position: usize,
line: usize,
color: Color,
config: Rc<Config>,
) -> Self {
Self { Self {
pending: true, pending: true,
text_character, text_character,
@ -34,7 +40,7 @@ impl TextCharacter {
source: Rect::new(0, 0, 0, 0), source: Rect::new(0, 0, 0, 0),
dest: Rect::new(0, 0, 0, 0), dest: Rect::new(0, 0, 0, 0),
color, color,
config config,
} }
} }
@ -148,10 +154,7 @@ impl Update for TextCharacter {
impl ClickHandler for TextCharacter { impl ClickHandler for TextCharacter {
fn on_left_click(&mut self, _point: &Point) -> UpdateResult { fn on_left_click(&mut self, _point: &Point) -> UpdateResult {
UpdateResult::MoveCaret( UpdateResult::MoveCaret(self.dest().clone(), self.position())
self.dest().clone(),
self.position()
)
} }
fn is_left_click_target(&self, point: &Point) -> bool { fn is_left_click_target(&self, point: &Point) -> bool {