rustfmt, renamed caret to txt_cursor

This commit is contained in:
Anton-4 2020-12-29 20:30:40 +01:00
parent 2b0a320734
commit bae3db0616
11 changed files with 430 additions and 509 deletions

View file

@ -87,7 +87,7 @@ pub struct RectBuffers {
pub fn create_rect_buffers( pub fn create_rect_buffers(
gpu_device: &wgpu::Device, gpu_device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
rects: &[Rect] rects: &[Rect],
) -> RectBuffers { ) -> RectBuffers {
let nr_of_rects = rects.len() as u64; let nr_of_rects = rects.len() as u64;
@ -113,9 +113,7 @@ pub fn create_rect_buffers(
quad_buffer_builder = quad_buffer_builder.push_rect(&rect); quad_buffer_builder = quad_buffer_builder.push_rect(&rect);
} }
let (stg_vertex, stg_index, num_indices) = quad_buffer_builder.build(&gpu_device);
let (stg_vertex, stg_index, num_indices) =
quad_buffer_builder.build(&gpu_device);
stg_vertex.copy_to_buffer(encoder, &vertex_buffer); stg_vertex.copy_to_buffer(encoder, &vertex_buffer);
stg_index.copy_to_buffer(encoder, &index_buffer); stg_index.copy_to_buffer(encoder, &index_buffer);

View file

@ -1,2 +1 @@
pub const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
pub const WHITE: [f32; 3] = [1.0, 1.0, 1.0];

View file

@ -1,5 +1,5 @@
use snafu::{Backtrace, Snafu, ErrorCompat};
use colored::*; use colored::*;
use snafu::{Backtrace, ErrorCompat, Snafu};
//import errors as follows: //import errors as follows:
// `use crate::error::OutOfBounds;` // `use crate::error::OutOfBounds;`
@ -14,18 +14,15 @@ pub enum EdError {
index, index,
vec_len vec_len
))] ))]
OutOfBounds { OutOfBounds {
index: usize, index: usize,
vec_len: usize, vec_len: usize,
backtrace: Backtrace backtrace: Backtrace,
}, },
#[snafu(display( #[snafu(display("InvalidSelection: {}", err_msg))]
"InvalidSelection: {}", InvalidSelection {
err_msg
))]
InvalidSelection {
err_msg: String, err_msg: String,
backtrace: Backtrace backtrace: Backtrace,
}, },
} }
@ -48,27 +45,23 @@ fn color_backtrace(backtrace: &snafu::Backtrace) -> String {
let mut prev_line_opt: Option<String> = None; let mut prev_line_opt: Option<String> = None;
for line in backtrace_split { for line in backtrace_split {
let new_line = if line.contains("src") {
let new_line = if !contains_one_of(&line, &irrelevant_src) {
if line.contains("src") { if let Some(prev_line) = prev_line_opt {
if !contains_one_of(&line, &irrelevant_src) { prev_line_opt = Some(format!("{}", prev_line.truecolor(255, 30, 30)));
if let Some(prev_line) = prev_line_opt {
prev_line_opt = Some(format!("{}", prev_line.truecolor(255, 30, 30)));
}
format!("{}\n", line.truecolor(255, 100, 100))
} else {
format!("{}\n", line)
} }
format!("{}\n", line.truecolor(255, 100, 100))
} else { } else {
format!("{}\n", line) format!("{}\n", line)
}; }
} else {
format!("{}\n", line)
};
if let Some(prev_line) = prev_line_opt { if let Some(prev_line) = prev_line_opt {
ret_str.push_str(&prev_line); ret_str.push_str(&prev_line);
} }
prev_line_opt = Some(new_line); prev_line_opt = Some(new_line);
} }
ret_str ret_str
@ -83,4 +76,3 @@ fn contains_one_of(main_str: &str, contain_slice: &[&str]) -> bool {
false false
} }

View file

@ -1,6 +1,8 @@
use crate::tea::model::Model;
use crate::tea::update::{
move_txt_cursor_down, move_txt_cursor_left, move_txt_cursor_right, move_txt_cursor_up,
};
use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; use winit::event::{ElementState, ModifiersState, VirtualKeyCode};
use crate::tea::model::{Model};
use crate::tea::update::{move_caret_left, move_caret_right, move_caret_down, move_caret_up};
pub fn handle_keydown( pub fn handle_keydown(
elem_state: ElementState, elem_state: ElementState,
@ -16,25 +18,45 @@ pub fn handle_keydown(
match virtual_keycode { match virtual_keycode {
Left => { Left => {
let (new_caret_pos, new_selection_opt) = move_caret_left(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); let (new_txt_cursor_pos, new_selection_opt) = move_txt_cursor_left(
model.caret_pos = new_caret_pos; model.txt_cursor_pos,
model.selection_opt,
modifiers.shift(),
&model.lines,
);
model.txt_cursor_pos = new_txt_cursor_pos;
model.selection_opt = new_selection_opt; model.selection_opt = new_selection_opt;
}, }
Up => { Up => {
let (new_caret_pos, new_selection_opt) = move_caret_up(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); let (new_txt_cursor_pos, new_selection_opt) = move_txt_cursor_up(
model.caret_pos = new_caret_pos; model.txt_cursor_pos,
model.selection_opt,
modifiers.shift(),
&model.lines,
);
model.txt_cursor_pos = new_txt_cursor_pos;
model.selection_opt = new_selection_opt; model.selection_opt = new_selection_opt;
}, }
Right => { Right => {
let (new_caret_pos, new_selection_opt) = move_caret_right(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); let (new_txt_cursor_pos, new_selection_opt) = move_txt_cursor_right(
model.caret_pos = new_caret_pos; model.txt_cursor_pos,
model.selection_opt,
modifiers.shift(),
&model.lines,
);
model.txt_cursor_pos = new_txt_cursor_pos;
model.selection_opt = new_selection_opt; model.selection_opt = new_selection_opt;
}, }
Down => { Down => {
let (new_caret_pos, new_selection_opt) = move_caret_down(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); let (new_txt_cursor_pos, new_selection_opt) = move_txt_cursor_down(
model.caret_pos = new_caret_pos; model.txt_cursor_pos,
model.selection_opt,
modifiers.shift(),
&model.lines,
);
model.txt_cursor_pos = new_txt_cursor_pos;
model.selection_opt = new_selection_opt; model.selection_opt = new_selection_opt;
}, }
Copy => { Copy => {
todo!("copy"); todo!("copy");
} }
@ -100,7 +122,7 @@ pub fn handle_keydown(
// Escape | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15 // Escape | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15
// | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23 | F24 | Snapshot | Scroll | Pause // | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23 | F24 | Snapshot | Scroll | Pause
// | Insert | Home | Delete | End | PageDown | PageUp | Left | Up | Right | Down | Compose // | Insert | Home | Delete | End | PageDown | PageUp | Left | Up | Right | Down | Compose
// | Caret | Numlock | AbntC1 | AbntC2 | Ax | Calculator | Capital | Convert | Kana // | txt_cursor | Numlock | AbntC1 | AbntC2 | Ax | Calculator | Capital | Convert | Kana
// | Kanji | LAlt | LBracket | LControl | LShift | LWin | Mail | MediaSelect | PlayPause // | Kanji | LAlt | LBracket | LControl | LShift | LWin | Mail | MediaSelect | PlayPause
// | Power | PrevTrack | MediaStop | Mute | MyComputer | NavigateForward // | Power | PrevTrack | MediaStop | Mute | MyComputer | NavigateForward
// | NavigateBackward | NextTrack | NoConvert | OEM102 | RAlt | Sysrq | RBracket // | NavigateBackward | NextTrack | NoConvert | OEM102 | RAlt | Sysrq | RBracket

View file

@ -9,25 +9,26 @@
// See this link to learn wgpu: https://sotrh.github.io/learn-wgpu/ // See this link to learn wgpu: https://sotrh.github.io/learn-wgpu/
use crate::buffer::create_rect_buffers; use crate::buffer::create_rect_buffers;
use crate::text::{build_glyph_brush, Text, is_newline}; use crate::error::print_err;
use crate::vertex::Vertex;
use crate::rect::{Rect};
use crate::error::{print_err};
use crate::ortho::{init_ortho, update_ortho_buffer, OrthoResources}; use crate::ortho::{init_ortho, update_ortho_buffer, OrthoResources};
use crate::selection::{create_selection_rects}; use crate::rect::Rect;
use crate::selection::create_selection_rects;
use crate::tea::{model, update}; use crate::tea::{model, update};
use model::{Position}; use crate::text::{build_glyph_brush, is_newline, Text};
use crate::vertex::Vertex;
use model::Position;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use wgpu::{CommandEncoder, RenderPass, TextureView};
use winit::event; use winit::event;
use winit::event::{Event, ModifiersState}; use winit::event::{Event, ModifiersState};
use winit::event_loop::ControlFlow; use winit::event_loop::ControlFlow;
use wgpu::{TextureView, CommandEncoder, RenderPass};
pub mod ast; pub mod ast;
mod buffer; mod buffer;
mod colors;
pub mod error;
pub mod expr; pub mod expr;
pub mod file; pub mod file;
mod keyboard_input; mod keyboard_input;
@ -36,15 +37,13 @@ mod pattern;
pub mod pool; pub mod pool;
mod rect; mod rect;
mod scope; mod scope;
mod selection;
mod tea;
pub mod text; pub mod text;
mod types; mod types;
mod util; mod util;
mod vertex;
mod colors;
pub mod error;
mod vec_result; mod vec_result;
mod selection; mod vertex;
mod tea;
/// The editor is actually launched from the CLI if you pass it zero arguments, /// The editor is actually launched from the CLI if you pass it zero arguments,
/// or if you provide it 1 or more files or directories to open on launch. /// or if you provide it 1 or more files or directories to open on launch.
@ -183,7 +182,7 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
input.state, input.state,
virtual_keycode, virtual_keycode,
keyboard_modifiers, keyboard_modifiers,
&mut ed_model &mut ed_model,
); );
} }
} }
@ -202,7 +201,7 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
label: Some("Redraw"), label: Some("Redraw"),
}); });
let frame = swap_chain let frame = swap_chain
.get_current_frame() .get_current_frame()
.expect("Failed to acquire next SwapChainFrame") .expect("Failed to acquire next SwapChainFrame")
.output; .output;
@ -210,30 +209,33 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
let glyph_bounds_rects = queue_all_text( let glyph_bounds_rects = queue_all_text(
&size, &size,
&ed_model.lines, &ed_model.lines,
ed_model.caret_pos, ed_model.txt_cursor_pos,
&mut glyph_brush, &mut glyph_brush,
); );
if let Some(selection) = ed_model.selection_opt { if let Some(selection) = ed_model.selection_opt {
let selection_rects_res = create_selection_rects(selection, &glyph_bounds_rects); let selection_rects_res =
create_selection_rects(selection, &glyph_bounds_rects);
match selection_rects_res { match selection_rects_res {
Ok(selection_rects) => Ok(selection_rects) => {
if !selection_rects.is_empty() { if !selection_rects.is_empty() {
let rect_buffers = create_rect_buffers( let rect_buffers = create_rect_buffers(
&gpu_device, &gpu_device,
&mut encoder, &mut encoder,
&selection_rects, &selection_rects,
); );
let mut render_pass = begin_render_pass(&mut encoder, &frame.view); let mut render_pass = begin_render_pass(&mut encoder, &frame.view);
render_pass.set_pipeline(&rect_pipeline); render_pass.set_pipeline(&rect_pipeline);
render_pass.set_bind_group(0, &ortho.bind_group, &[]); render_pass.set_bind_group(0, &ortho.bind_group, &[]);
render_pass.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..)); render_pass
.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..));
render_pass.set_index_buffer(rect_buffers.index_buffer.slice(..)); render_pass.set_index_buffer(rect_buffers.index_buffer.slice(..));
render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1); render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1);
}, }
}
Err(e) => { Err(e) => {
begin_render_pass(&mut encoder, &frame.view); begin_render_pass(&mut encoder, &frame.view);
print_err(&e) //TODO draw error text on screen print_err(&e) //TODO draw error text on screen
@ -245,15 +247,15 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
// draw all text // draw all text
glyph_brush glyph_brush
.draw_queued( .draw_queued(
&gpu_device, &gpu_device,
&mut staging_belt, &mut staging_belt,
&mut encoder, &mut encoder,
&frame.view, &frame.view,
size.width, size.width,
size.height, size.height,
) )
.expect("Draw queued"); .expect("Draw queued");
staging_belt.finish(); staging_belt.finish();
cmd_queue.submit(Some(encoder.finish())); cmd_queue.submit(Some(encoder.finish()));
@ -274,10 +276,9 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
}) })
} }
fn begin_render_pass<'a>( fn begin_render_pass<'a>(
encoder: &'a mut CommandEncoder, encoder: &'a mut CommandEncoder,
texture_view: &'a TextureView texture_view: &'a TextureView,
) -> RenderPass<'a> { ) -> RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor { encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
@ -365,7 +366,7 @@ fn create_render_pipeline(
fn queue_all_text( fn queue_all_text(
size: &winit::dpi::PhysicalSize<u32>, size: &winit::dpi::PhysicalSize<u32>,
lines: &[String], lines: &[String],
caret_pos: Position, txt_cursor_pos: Position,
glyph_brush: &mut wgpu_glyph::GlyphBrush<()>, glyph_brush: &mut wgpu_glyph::GlyphBrush<()>,
) -> Vec<Vec<Rect>> { ) -> Vec<Vec<Rect>> {
let area_bounds = (size.width as f32, size.height as f32).into(); let area_bounds = (size.width as f32, size.height as f32).into();
@ -388,18 +389,18 @@ fn queue_all_text(
..Default::default() ..Default::default()
}; };
let caret_pos_label = Text { let txt_cursor_pos_label = Text {
position: (30.0, 530.0).into(), position: (30.0, 530.0).into(),
area_bounds, area_bounds,
color: (0.4666, 0.2, 1.0, 1.0).into(), color: (0.4666, 0.2, 1.0, 1.0).into(),
text: format!("Ln {}, Col {}", caret_pos.line, caret_pos.column), text: format!("Ln {}, Col {}", txt_cursor_pos.line, txt_cursor_pos.column),
size: 30.0, size: 30.0,
..Default::default() ..Default::default()
}; };
text::queue_text_draw(&main_label, glyph_brush); text::queue_text_draw(&main_label, glyph_brush);
text::queue_text_draw(&caret_pos_label, glyph_brush); text::queue_text_draw(&txt_cursor_pos_label, glyph_brush);
text::queue_text_draw(&code_text, glyph_brush) text::queue_text_draw(&code_text, glyph_brush)
} }
@ -417,23 +418,28 @@ fn update_text_state(ed_model: &mut model::Model, received_char: &char) {
} else if ed_model.lines.len() > 1 { } else if ed_model.lines.len() > 1 {
ed_model.lines.pop(); ed_model.lines.pop();
} }
ed_model.caret_pos = update::move_caret_left(ed_model.caret_pos, None, false, &ed_model.lines).0; ed_model.txt_cursor_pos = update::move_txt_cursor_left(
ed_model.txt_cursor_pos,
None,
false,
&ed_model.lines,
)
.0;
} }
} }
'\u{e000}'..='\u{f8ff}' | '\u{f0000}'..='\u{ffffd}' | '\u{100000}'..='\u{10fffd}' => { '\u{e000}'..='\u{f8ff}' | '\u{f0000}'..='\u{ffffd}' | '\u{100000}'..='\u{10fffd}' => {
// These are private use characters; ignore them. // These are private use characters; ignore them.
// See http://www.unicode.org/faq/private_use.html // See http://www.unicode.org/faq/private_use.html
} }
ch if is_newline(ch) => { ch if is_newline(ch) => {
if let Some(last_line) = ed_model.lines.last_mut() { if let Some(last_line) = ed_model.lines.last_mut() {
last_line.push(*received_char) last_line.push(*received_char)
} }
ed_model.lines.push(String::new()); ed_model.lines.push(String::new());
ed_model.caret_pos = ed_model.txt_cursor_pos = Position {
Position { line: ed_model.txt_cursor_pos.line + 1,
line: ed_model.caret_pos.line + 1, column: 0,
column: 0 };
};
ed_model.selection_opt = None; ed_model.selection_opt = None;
} }
@ -442,11 +448,10 @@ fn update_text_state(ed_model: &mut model::Model, received_char: &char) {
if let Some(last_line) = ed_model.lines.last_mut() { if let Some(last_line) = ed_model.lines.last_mut() {
last_line.push(*received_char); last_line.push(*received_char);
ed_model.caret_pos = ed_model.txt_cursor_pos = Position {
Position {
line: nr_lines - 1, line: nr_lines - 1,
column: last_line.len() column: last_line.len(),
}; };
ed_model.selection_opt = None; ed_model.selection_opt = None;

View file

@ -1,34 +1,32 @@
use crate::rect::{Rect};
use crate::vec_result::{get_res};
use crate::error::{EdResult, InvalidSelection};
use crate::colors; use crate::colors;
use crate::tea::model::{RawSelection}; use crate::error::{EdResult, InvalidSelection};
use crate::rect::Rect;
use crate::tea::model::RawSelection;
use crate::vec_result::get_res;
use snafu::ensure; use snafu::ensure;
//using the "parse don't validate" pattern //using the "parse don't validate" pattern
struct ValidSelection { struct ValidSelection {
selection: RawSelection selection: RawSelection,
} }
fn validate_selection( selection: RawSelection) -> EdResult<ValidSelection> { fn validate_selection(selection: RawSelection) -> EdResult<ValidSelection> {
let RawSelection {start_pos, end_pos} = selection; let RawSelection { start_pos, end_pos } = selection;
ensure!( ensure!(
start_pos.line <= end_pos.line, start_pos.line <= end_pos.line,
InvalidSelection { err_msg: InvalidSelection {
format!( err_msg: format!(
"start_pos.line ({}) should be smaller than or equal to end_pos.line ({})", "start_pos.line ({}) should be smaller than or equal to end_pos.line ({})",
start_pos.line, start_pos.line, end_pos.line
end_pos.line
) )
} }
); );
ensure!( ensure!(
!(start_pos.line == end_pos.line && start_pos.column > end_pos.column), !(start_pos.line == end_pos.line && start_pos.column > end_pos.column),
InvalidSelection { err_msg: InvalidSelection {
format!( err_msg: format!(
"start_pos.column ({}) should be smaller than or equal to end_pos.column ({}) when start_pos.line equals end_pos.line", "start_pos.column ({}) should be smaller than or equal to end_pos.column ({}) when start_pos.line equals end_pos.line",
start_pos.column, start_pos.column,
end_pos.column end_pos.column
@ -36,150 +34,116 @@ fn validate_selection( selection: RawSelection) -> EdResult<ValidSelection> {
} }
); );
Ok( Ok(ValidSelection {
ValidSelection { selection: RawSelection { start_pos, end_pos },
selection: RawSelection {start_pos, end_pos} })
}
)
} }
pub fn create_selection_rects( pub fn create_selection_rects(
raw_sel: RawSelection, raw_sel: RawSelection,
glyph_bound_rects: &Vec<Vec<Rect>> glyph_bound_rects: &Vec<Vec<Rect>>,
) -> EdResult<Vec<Rect>> { ) -> EdResult<Vec<Rect>> {
let valid_sel = validate_selection(raw_sel)?; let valid_sel = validate_selection(raw_sel)?;
let RawSelection {start_pos, end_pos} = valid_sel.selection; let RawSelection { start_pos, end_pos } = valid_sel.selection;
let mut all_rects = Vec::new(); let mut all_rects = Vec::new();
if start_pos.line == end_pos.line { if start_pos.line == end_pos.line {
let start_glyph_rect = let start_glyph_rect = get_res(
get_res( start_pos.column,
start_pos.column, get_res(start_pos.line, glyph_bound_rects)?,
get_res(start_pos.line, glyph_bound_rects)?, )?;
)?;
let stop_glyph_rect = let stop_glyph_rect = get_res(
get_res( end_pos.column - 1,
end_pos.column - 1, get_res(end_pos.line, glyph_bound_rects)?,
get_res(end_pos.line, glyph_bound_rects)? )?;
)?;
let top_left_coords = let top_left_coords = start_glyph_rect.top_left_coords;
start_glyph_rect.top_left_coords;
let height = start_glyph_rect.height; let height = start_glyph_rect.height;
let width = (stop_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x) + stop_glyph_rect.width; let width = (stop_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x)
+ stop_glyph_rect.width;
all_rects.push( all_rects.push(Rect {
Rect { top_left_coords,
top_left_coords, width,
width, height,
height, color: colors::WHITE,
color: colors::WHITE });
}
);
Ok(all_rects) Ok(all_rects)
} else { } else {
// first line // first line
let start_line = get_res(start_pos.line, glyph_bound_rects)?; let start_line = get_res(start_pos.line, glyph_bound_rects)?;
let start_glyph_rect = let start_glyph_rect = get_res(start_pos.column, start_line)?;
get_res(
start_pos.column,
start_line
)?;
let start_line_last_glyph_rect = let start_line_last_glyph_rect = get_res(start_line.len() - 1, start_line)?;
get_res(
start_line.len() - 1,
start_line
)?;
let top_left_coords = let top_left_coords = start_glyph_rect.top_left_coords;
start_glyph_rect.top_left_coords;
let height = start_glyph_rect.height; let height = start_glyph_rect.height;
let width = (start_line_last_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x) + start_line_last_glyph_rect.width; let width = (start_line_last_glyph_rect.top_left_coords.x
- start_glyph_rect.top_left_coords.x)
+ start_line_last_glyph_rect.width;
all_rects.push( all_rects.push(Rect {
Rect { top_left_coords,
top_left_coords, width,
width, height,
height, color: colors::WHITE,
color: colors::WHITE });
}
);
//middle lines //middle lines
let nr_mid_lines = (end_pos.line - start_pos.line) - 1; let nr_mid_lines = (end_pos.line - start_pos.line) - 1;
let first_mid_line = start_pos.line + 1; let first_mid_line = start_pos.line + 1;
for i in first_mid_line..(first_mid_line + nr_mid_lines) { for i in first_mid_line..(first_mid_line + nr_mid_lines) {
let mid_line = get_res(i, glyph_bound_rects)?; let mid_line = get_res(i, glyph_bound_rects)?;
let mid_line_first_glyph_rect = let mid_line_first_glyph_rect = get_res(0, mid_line)?;
get_res(
0,
mid_line
)?;
let mid_line_last_glyph_rect = let mid_line_last_glyph_rect = get_res(mid_line.len() - 1, mid_line)?;
get_res(
mid_line.len() - 1,
mid_line
)?;
let top_left_coords = let top_left_coords = mid_line_first_glyph_rect.top_left_coords;
mid_line_first_glyph_rect.top_left_coords;
let height = mid_line_first_glyph_rect.height; let height = mid_line_first_glyph_rect.height;
let width = (mid_line_last_glyph_rect.top_left_coords.x - mid_line_first_glyph_rect.top_left_coords.x) + mid_line_last_glyph_rect.width; let width = (mid_line_last_glyph_rect.top_left_coords.x
- mid_line_first_glyph_rect.top_left_coords.x)
+ mid_line_last_glyph_rect.width;
all_rects.push( all_rects.push(Rect {
Rect { top_left_coords,
top_left_coords, width,
width, height,
height, color: colors::WHITE,
color: colors::WHITE });
}
);
} }
//last line //last line
if end_pos.column > 0 { if end_pos.column > 0 {
let stop_line = get_res(end_pos.line, glyph_bound_rects)?; let stop_line = get_res(end_pos.line, glyph_bound_rects)?;
let stop_line_first_glyph_rect = let stop_line_first_glyph_rect = get_res(0, stop_line)?;
get_res(
0,
stop_line
)?;
let stop_glyph_rect = let stop_glyph_rect = get_res(end_pos.column - 1, stop_line)?;
get_res(
end_pos.column - 1,
stop_line
)?;
let top_left_coords = let top_left_coords = stop_line_first_glyph_rect.top_left_coords;
stop_line_first_glyph_rect.top_left_coords;
let height = stop_glyph_rect.height; let height = stop_glyph_rect.height;
let width = (stop_glyph_rect.top_left_coords.x - stop_line_first_glyph_rect.top_left_coords.x) + stop_glyph_rect.width; let width = (stop_glyph_rect.top_left_coords.x
- stop_line_first_glyph_rect.top_left_coords.x)
+ stop_glyph_rect.width;
all_rects.push( all_rects.push(Rect {
Rect { top_left_coords,
top_left_coords, width,
width, height,
height, color: colors::WHITE,
color: colors::WHITE });
}
);
} }
Ok(all_rects) Ok(all_rects)
} }
} }

View file

@ -1,3 +1,2 @@
pub mod model; pub mod model;
pub mod update; pub mod update;

View file

@ -1,23 +1,17 @@
use std::cmp::Ordering;
use std::cmp::{Ordering};
#[derive(Debug)] #[derive(Debug)]
pub struct Model { pub struct Model {
pub lines: Vec<String>, pub lines: Vec<String>,
pub caret_pos: Position, pub txt_cursor_pos: Position,
pub selection_opt: Option<RawSelection> pub selection_opt: Option<RawSelection>,
} }
pub fn init_model() -> Model { pub fn init_model() -> Model {
Model { Model {
lines: lines: vec![String::new()],
vec![String::new()], txt_cursor_pos: Position { line: 0, column: 0 },
caret_pos: selection_opt: None,
Position {
line: 0, column: 0
},
selection_opt:
None
} }
} }
@ -25,7 +19,7 @@ pub fn init_model() -> Model {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Position { pub struct Position {
pub line: usize, pub line: usize,
pub column: usize pub column: usize,
} }
impl Ord for Position { impl Ord for Position {
@ -46,10 +40,10 @@ impl PartialEq for Position {
} }
} }
impl Eq for Position { } impl Eq for Position {}
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct RawSelection { pub struct RawSelection {
pub start_pos: Position, pub start_pos: Position,
pub end_pos: Position pub end_pos: Position,
} }

View file

@ -1,280 +1,225 @@
use crate::tea::model::{Position, RawSelection}; use crate::tea::model::{Position, RawSelection};
use crate::text::{is_newline}; use crate::text::is_newline;
use std::cmp::{min, max}; use std::cmp::{max, min};
pub fn move_caret_left(old_caret_pos: Position, old_selection_opt: Option<RawSelection>, shift_pressed: bool, lines: &[String]) -> (Position, Option<RawSelection>) { pub fn move_txt_cursor_left(
let old_line_nr = old_caret_pos.line; old_txt_cursor_pos: Position,
let old_col_nr = old_caret_pos.column; old_selection_opt: Option<RawSelection>,
shift_pressed: bool,
lines: &[String],
) -> (Position, Option<RawSelection>) {
let old_line_nr = old_txt_cursor_pos.line;
let old_col_nr = old_txt_cursor_pos.column;
let (line_nr, col_nr) = let (line_nr, col_nr) = if old_txt_cursor_pos.column == 0 {
if old_caret_pos.column == 0 { if old_txt_cursor_pos.line == 0 {
if old_caret_pos.line == 0 { (0, 0)
(0, 0) } else if let Some(curr_line) = lines.get(old_line_nr - 1) {
} else if let Some(curr_line) = lines.get(old_line_nr - 1) { (old_line_nr - 1, curr_line.len() - 1)
(old_line_nr - 1, curr_line.len() - 1)
} else {
(0, 0) // this should never happen, should this method return Result?
}
} else { } else {
(old_line_nr, old_col_nr - 1) (0, 0) // this should never happen, should this method return Result?
}; }
} else {
let new_caret_pos = Position { (old_line_nr, old_col_nr - 1)
line: line_nr,
column: col_nr
}; };
let new_selection_opt = let new_txt_cursor_pos = Position {
if shift_pressed { line: line_nr,
if let Some(old_selection) = old_selection_opt { column: col_nr,
Some( };
RawSelection {
start_pos: let new_selection_opt = if shift_pressed {
Position { if let Some(old_selection) = old_selection_opt {
line: line_nr, Some(RawSelection {
column: col_nr start_pos: Position {
} line: line_nr,
, column: col_nr,
end_pos: },
old_selection.end_pos end_pos: old_selection.end_pos,
, })
} } else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
) Some(RawSelection {
} else if !(old_line_nr == line_nr && old_col_nr == col_nr){ start_pos: Position {
Some( line: line_nr,
RawSelection { column: col_nr,
start_pos: },
Position { end_pos: Position {
line: line_nr, line: old_line_nr,
column: col_nr column: old_col_nr,
} },
, })
end_pos:
Position {
line: old_line_nr,
column: old_col_nr
}
,
}
)
} else {
None
}
} else { } else {
None None
}; }
} else {
None
};
(new_txt_cursor_pos, new_selection_opt)
(
new_caret_pos,
new_selection_opt
)
} }
pub fn move_caret_right(old_caret_pos: Position, old_selection_opt: Option<RawSelection>, shift_pressed: bool, lines: &[String]) -> (Position, Option<RawSelection>) { pub fn move_txt_cursor_right(
let old_line_nr = old_caret_pos.line; old_txt_cursor_pos: Position,
let old_col_nr = old_caret_pos.column; old_selection_opt: Option<RawSelection>,
shift_pressed: bool,
lines: &[String],
) -> (Position, Option<RawSelection>) {
let old_line_nr = old_txt_cursor_pos.line;
let old_col_nr = old_txt_cursor_pos.column;
let (line_nr, col_nr) = let (line_nr, col_nr) = if let Some(curr_line) = lines.get(old_line_nr) {
if let Some(curr_line) = lines.get(old_line_nr) { if let Some(last_char) = curr_line.chars().last() {
if let Some(last_char) = curr_line.chars().last() { if is_newline(&last_char) {
if is_newline(&last_char) { if old_col_nr + 1 > curr_line.len() - 1 {
if old_col_nr + 1 > curr_line.len() - 1 { (old_line_nr + 1, 0)
(old_line_nr + 1, 0)
} else {
(old_line_nr, old_col_nr + 1)
}
} else if old_col_nr < curr_line.len() {
(old_line_nr, old_col_nr + 1)
} else { } else {
(old_line_nr, old_col_nr) (old_line_nr, old_col_nr + 1)
} }
} else if old_col_nr < curr_line.len() {
(old_line_nr, old_col_nr + 1)
} else { } else {
(old_line_nr, old_col_nr) (old_line_nr, old_col_nr)
} }
} else { } else {
(0, 0) // this should never happen, should this method return Result? (old_line_nr, old_col_nr)
}; }
} else {
let new_caret_pos = Position { (0, 0) // this should never happen, should this method return Result?
line: line_nr,
column: col_nr
}; };
let new_selection_opt = let new_txt_cursor_pos = Position {
if shift_pressed {
if let Some(old_selection) = old_selection_opt {
Some(
RawSelection {
start_pos:
old_selection.start_pos
,
end_pos:
Position {
line: line_nr,
column: col_nr
}
,
}
)
} else if !(old_line_nr == line_nr && old_col_nr == col_nr){
Some(
RawSelection {
start_pos:
Position {
line: old_line_nr,
column: old_col_nr
}
,
end_pos:
Position {
line: line_nr,
column: col_nr
}
,
}
)
} else {
None
}
} else {
None
};
(
new_caret_pos,
new_selection_opt
)
}
pub fn move_caret_up(old_caret_pos: Position, old_selection_opt: Option<RawSelection>, shift_pressed: bool, lines: &[String]) -> (Position, Option<RawSelection>) {
let old_line_nr = old_caret_pos.line;
let old_col_nr = old_caret_pos.column;
let (line_nr, col_nr) =
if old_line_nr == 0 {
(old_line_nr, old_col_nr)
} else if let Some(prev_line) = lines.get(old_line_nr - 1) {
if prev_line.len() < old_col_nr {
(old_line_nr - 1, prev_line.len() - 1)
} else {
(old_line_nr - 1, old_col_nr)
}
} else {
(0, 0) // this should never happen, should this method return Result?
};
let new_caret_pos = Position {
line: line_nr,
column: col_nr
};
let new_selection_opt =
if shift_pressed {
if let Some(old_selection) = old_selection_opt {
Some(
RawSelection {
start_pos:
new_caret_pos
,
end_pos:
old_selection.end_pos
,
}
)
} else if !(old_line_nr == line_nr && old_col_nr == col_nr){
Some(
RawSelection {
start_pos:
min(old_caret_pos, new_caret_pos)
,
end_pos:
max(old_caret_pos, new_caret_pos)
,
}
)
} else {
None
}
} else {
None
};
(
new_caret_pos,
new_selection_opt
)
}
pub fn move_caret_down(old_caret_pos: Position, old_selection_opt: Option<RawSelection>, shift_pressed: bool, lines: &[String]) -> (Position, Option<RawSelection>) {
let old_line_nr = old_caret_pos.line;
let old_col_nr = old_caret_pos.column;
let (line_nr, col_nr) =
if old_line_nr + 1 >= lines.len() {
(old_line_nr, old_col_nr)
} else if let Some(next_line) = lines.get(old_line_nr + 1) {
if next_line.len() < old_col_nr {
if let Some(last_char) = next_line.chars().last() {
if is_newline(&last_char) {
(old_line_nr + 1, next_line.len() - 1)
} else {
(old_line_nr + 1, next_line.len())
}
} else {
(old_line_nr + 1, 0)
}
} else {
(old_line_nr + 1, old_col_nr)
}
} else {
(0, 0) // this should never happen, should this method return Result?
};
let new_caret_pos = Position {
line: line_nr, line: line_nr,
column: col_nr column: col_nr,
}; };
let new_selection_opt = let new_selection_opt = if shift_pressed {
if shift_pressed { if let Some(old_selection) = old_selection_opt {
if let Some(old_selection) = old_selection_opt { Some(RawSelection {
Some( start_pos: old_selection.start_pos,
RawSelection { end_pos: Position {
start_pos: line: line_nr,
old_selection.start_pos column: col_nr,
, },
end_pos: })
new_caret_pos } else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
, Some(RawSelection {
} start_pos: Position {
) line: old_line_nr,
} else if !(old_line_nr == line_nr && old_col_nr == col_nr){ column: old_col_nr,
Some( },
RawSelection { end_pos: Position {
start_pos: line: line_nr,
min(old_caret_pos, new_caret_pos) column: col_nr,
, },
end_pos: })
max(old_caret_pos, new_caret_pos)
,
}
)
} else {
None
}
} else { } else {
None None
}; }
} else {
None
};
( (new_txt_cursor_pos, new_selection_opt)
new_caret_pos, }
new_selection_opt
) pub fn move_txt_cursor_up(
} old_txt_cursor_pos: Position,
old_selection_opt: Option<RawSelection>,
shift_pressed: bool,
lines: &[String],
) -> (Position, Option<RawSelection>) {
let old_line_nr = old_txt_cursor_pos.line;
let old_col_nr = old_txt_cursor_pos.column;
let (line_nr, col_nr) = if old_line_nr == 0 {
(old_line_nr, old_col_nr)
} else if let Some(prev_line) = lines.get(old_line_nr - 1) {
if prev_line.len() < old_col_nr {
(old_line_nr - 1, prev_line.len() - 1)
} else {
(old_line_nr - 1, old_col_nr)
}
} else {
(0, 0) // this should never happen, should this method return Result?
};
let new_txt_cursor_pos = Position {
line: line_nr,
column: col_nr,
};
let new_selection_opt = if shift_pressed {
if let Some(old_selection) = old_selection_opt {
Some(RawSelection {
start_pos: new_txt_cursor_pos,
end_pos: old_selection.end_pos,
})
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
Some(RawSelection {
start_pos: min(old_txt_cursor_pos, new_txt_cursor_pos),
end_pos: max(old_txt_cursor_pos, new_txt_cursor_pos),
})
} else {
None
}
} else {
None
};
(new_txt_cursor_pos, new_selection_opt)
}
pub fn move_txt_cursor_down(
old_txt_cursor_pos: Position,
old_selection_opt: Option<RawSelection>,
shift_pressed: bool,
lines: &[String],
) -> (Position, Option<RawSelection>) {
let old_line_nr = old_txt_cursor_pos.line;
let old_col_nr = old_txt_cursor_pos.column;
let (line_nr, col_nr) = if old_line_nr + 1 >= lines.len() {
(old_line_nr, old_col_nr)
} else if let Some(next_line) = lines.get(old_line_nr + 1) {
if next_line.len() < old_col_nr {
if let Some(last_char) = next_line.chars().last() {
if is_newline(&last_char) {
(old_line_nr + 1, next_line.len() - 1)
} else {
(old_line_nr + 1, next_line.len())
}
} else {
(old_line_nr + 1, 0)
}
} else {
(old_line_nr + 1, old_col_nr)
}
} else {
(0, 0) // this should never happen, should this method return Result?
};
let new_txt_cursor_pos = Position {
line: line_nr,
column: col_nr,
};
let new_selection_opt = if shift_pressed {
if let Some(old_selection) = old_selection_opt {
Some(RawSelection {
start_pos: old_selection.start_pos,
end_pos: new_txt_cursor_pos,
})
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
Some(RawSelection {
start_pos: min(old_txt_cursor_pos, new_txt_cursor_pos),
end_pos: max(old_txt_cursor_pos, new_txt_cursor_pos),
})
} else {
None
}
} else {
None
};
(new_txt_cursor_pos, new_selection_opt)
}

View file

@ -1,11 +1,11 @@
// Adapted from https://github.com/sotrh/learn-wgpu // Adapted from https://github.com/sotrh/learn-wgpu
// by Benjamin Hansen, licensed under the MIT license // by Benjamin Hansen, licensed under the MIT license
use ab_glyph::{FontArc, InvalidFont, Glyph};
use cgmath::{Vector2, Vector4};
use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section};
use crate::rect::Rect; use crate::rect::Rect;
use ab_glyph::{FontArc, Glyph, InvalidFont};
use cgmath::{Vector2, Vector4};
use itertools::Itertools; use itertools::Itertools;
use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section};
#[derive(Debug)] #[derive(Debug)]
pub struct Text { pub struct Text {
@ -45,7 +45,8 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Vec<Vec
bounds: text.area_bounds.into(), bounds: text.area_bounds.into(),
layout, layout,
..Section::default() ..Section::default()
}.add_text( }
.add_text(
wgpu_glyph::Text::new(&text.text) wgpu_glyph::Text::new(&text.text)
.with_color(text.color) .with_color(text.color)
.with_scale(text.size), .with_scale(text.size),
@ -55,8 +56,8 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Vec<Vec
let glyph_section_iter = glyph_brush.glyphs_custom_layout(section, &layout); let glyph_section_iter = glyph_brush.glyphs_custom_layout(section, &layout);
glyph_section_iter.map(|section_glyph| glyph_section_iter
{ .map(|section_glyph| {
let position = section_glyph.glyph.position; let position = section_glyph.glyph.position;
let px_scale = section_glyph.glyph.scale; let px_scale = section_glyph.glyph.scale;
let width = glyph_width(&section_glyph.glyph); let width = glyph_width(&section_glyph.glyph);
@ -67,31 +68,35 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Vec<Vec
top_left_coords: [position.x, top_y].into(), top_left_coords: [position.x, top_y].into(),
width, width,
height, height,
color: [1.0, 1.0, 1.0] color: [1.0, 1.0, 1.0],
} }
} })
).group_by(|rect| rect.top_left_coords.y) .group_by(|rect| rect.top_left_coords.y)
.into_iter() .into_iter()
.map(|(_y_coord, rect_group)| { .map(|(_y_coord, rect_group)| {
let mut rects_vec = rect_group.collect::<Vec<Rect>>(); let mut rects_vec = rect_group.collect::<Vec<Rect>>();
let last_rect_opt = rects_vec.last().cloned(); let last_rect_opt = rects_vec.last().cloned();
// add extra rect to make it easy to highlight the newline character // add extra rect to make it easy to highlight the newline character
if let Some(last_rect) = last_rect_opt { if let Some(last_rect) = last_rect_opt {
rects_vec.push(Rect { rects_vec.push(Rect {
top_left_coords: [last_rect.top_left_coords.x + last_rect.width, last_rect.top_left_coords.y].into(), top_left_coords: [
width: last_rect.width, last_rect.top_left_coords.x + last_rect.width,
height: last_rect.height, last_rect.top_left_coords.y,
color: last_rect.color ]
}); .into(),
} width: last_rect.width,
rects_vec height: last_rect.height,
}) color: last_rect.color,
.collect() });
}
rects_vec
})
.collect()
} }
pub fn glyph_top_y(glyph: &Glyph) -> f32 { pub fn glyph_top_y(glyph: &Glyph) -> f32 {
let height = glyph.scale.y; let height = glyph.scale.y;
glyph.position.y - height * 0.75 glyph.position.y - height * 0.75
} }
@ -112,4 +117,4 @@ pub fn is_newline(char_ref: &char) -> bool {
let newline_codes = vec!['\u{d}']; let newline_codes = vec!['\u{d}'];
newline_codes.contains(char_ref) newline_codes.contains(char_ref)
} }

View file

@ -1,17 +1,15 @@
use crate::error::EdResult;
use crate::error::OutOfBounds; use crate::error::OutOfBounds;
use crate::error::{EdResult}; use snafu::OptionExt;
use std::slice::SliceIndex; use std::slice::SliceIndex;
use snafu::{OptionExt};
// replace vec methods that return Option with ones that return Result and proper Error // replace vec methods that return Option with ones that return Result and proper Error
pub fn get_res<T>(index: usize, vec: &[T]) -> EdResult<&<usize as SliceIndex<[T]>>::Output> { pub fn get_res<T>(index: usize, vec: &[T]) -> EdResult<&<usize as SliceIndex<[T]>>::Output> {
let elt_ref = vec.get(index).context(OutOfBounds { let elt_ref = vec.get(index).context(OutOfBounds {
index, index,
vec_len: vec.len() vec_len: vec.len(),
})?; })?;
Ok(elt_ref) Ok(elt_ref)
} }