diff --git a/README.md b/README.md index 01dee9a..9ea8555 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,15 @@ rustup run nightly cargo build --all -rr rustup run nightly cargo run -p rider-editor ``` +## Keyboard mapping + +* `DELETE` - delete next character +* `BACKSPACE` - delete prev character +* `SHIFT + DELETE` - delete line +* `CTRL + O` - open file +* `CTRL + S` - save current file +* `ESCAPE` - close current modal + ## Road map ### v1.0 @@ -25,10 +34,9 @@ rustup run nightly cargo run -p rider-editor * [x] Open file menu * [x] `Save file` with button * [x] `Save file` with shortcut -* [ ] `Save file as...` with shortcut * [x] Theme based menu UI * [x] Lock scroll when no available content -* [ ] Config edit menu +* [x] Config edit menu * [x] Project tree * [x] Cover `rider` with tests at least 50% * [x] Handle resize window diff --git a/rider-config/src/config.rs b/rider-config/src/config.rs index 017873f..4586361 100644 --- a/rider-config/src/config.rs +++ b/rider-config/src/config.rs @@ -205,7 +205,7 @@ mod test_getters { fn assert_menu_height() { let config = Config::new(); let result = config.menu_height(); - let expected = 60; + let expected = 40; assert_eq!(result, expected); } diff --git a/rider-editor/src/app/app_state.rs b/rider-editor/src/app/app_state.rs index fcedc8b..9510549 100644 --- a/rider-editor/src/app/app_state.rs +++ b/rider-editor/src/app/app_state.rs @@ -16,7 +16,7 @@ pub struct AppState { files: Vec, config: Arc>, file_editor: FileEditor, - open_file_modal: Option, + modal: Option, } impl AppState { @@ -29,7 +29,7 @@ impl AppState { ), files: vec![], file_editor: FileEditor::new(Arc::clone(&config)), - open_file_modal: None, + modal: None, config, } } @@ -65,13 +65,35 @@ impl AppState { Ok(()) } + pub fn open_settings(&mut self, renderer: &mut R) -> Result<(), String> + where + R: Renderer + CharacterSizeManager, + { + println!("Open Settings..."); + match self.modal { + None => { + let mut settings = Settings::new(self.config.clone()); + settings.prepare_ui(renderer); + self.modal = Some(ModalType::Settings(settings)); + } + _ => return Ok(()), + } + Ok(()) + } + + pub fn close_modal(&mut self) -> Result<(), String> { + self.modal = None; + Ok(()) + } + pub fn open_directory(&mut self, dir_path: String, renderer: &mut R) where R: Renderer + CharacterSizeManager, { - match self.open_file_modal.as_mut() { - Some(modal) => modal.open_directory(dir_path, renderer), + match self.modal.as_mut() { + Some(ModalType::OpenFile(modal)) => modal.open_directory(dir_path, renderer), None => self.project_tree.open_directory(dir_path, renderer), + _ => (), }; } @@ -86,19 +108,33 @@ impl AppState { } pub fn set_open_file_modal(&mut self, modal: Option) { - self.open_file_modal = modal; + self.modal = if let Some(modal) = modal { + Some(ModalType::OpenFile(modal)) + } else { + None + }; } pub fn scroll_by(&mut self, x: i32, y: i32) { - if let Some(modal) = self.open_file_modal.as_mut() { - modal.scroll_by(x, y); - } else { - self.file_editor_mut().scroll_by(x, y); - } + match self.modal.as_mut() { + Some(ModalType::OpenFile(modal)) => modal.scroll_by(x, y), + Some(ModalType::Settings(modal)) => modal.scroll_by(x, y), + _ => self.file_editor_mut().scroll_by(x, y), + }; } pub fn open_file_modal(&self) -> Option<&OpenFile> { - self.open_file_modal.as_ref() + match self.modal { + Some(ModalType::OpenFile(ref m)) => Some(m), + _ => None, + } + } + + pub fn settings_modal(&self) -> Option<&Settings> { + match self.modal { + Some(ModalType::Settings(ref m)) => Some(m), + _ => None, + } } } @@ -119,9 +155,14 @@ impl AppState { // project tree self.project_tree.render(canvas, renderer); - // open file modal - match self.open_file_modal.as_ref() { - Some(modal) => modal.render(canvas, renderer, &RenderContext::Nothing), + // settings modal + match self.modal.as_ref() { + Some(ModalType::OpenFile(modal)) => { + return modal.render(canvas, renderer, &RenderContext::Nothing) + } + Some(ModalType::Settings(modal)) => { + return modal.render(canvas, renderer, &RenderContext::Nothing) + } _ => (), }; } @@ -136,10 +177,10 @@ impl AppState { } pub fn update(&mut self, ticks: i32, context: &UpdateContext) -> UpdateResult { - // open file modal - let res = match self.open_file_modal.as_mut() { - Some(modal) => modal.update(ticks, &UpdateContext::Nothing), - _ => UpdateResult::NoOp, + let res = match self.modal.as_mut() { + Some(ModalType::OpenFile(modal)) => modal.update(ticks, context.clone()), + Some(ModalType::Settings(modal)) => modal.update(ticks, context.clone()), + None => UpdateResult::NoOp, }; if res != UpdateResult::NoOp { return res; @@ -171,8 +212,13 @@ impl AppState { .project_tree .on_left_click(point, &UpdateContext::Nothing); } - match self.open_file_modal.as_mut() { - Some(modal) => return modal.on_left_click(point, &UpdateContext::Nothing), + match self.modal.as_mut() { + Some(ModalType::OpenFile(modal)) => { + return modal.on_left_click(point, &UpdateContext::Nothing) + } + Some(ModalType::Settings(modal)) => { + return modal.on_left_click(point, &UpdateContext::Nothing) + } _ => (), }; if self @@ -188,10 +234,10 @@ impl AppState { return UpdateResult::NoOp; } else { video_subsystem.text_input().start(); - self.file_editor + return self + .file_editor .on_left_click(point, &UpdateContext::Nothing); } - UpdateResult::NoOp } pub fn is_left_click_target(&self, _point: &Point) -> bool { diff --git a/rider-editor/src/app/application.rs b/rider-editor/src/app/application.rs index d2a2d6b..f384f96 100644 --- a/rider-editor/src/app/application.rs +++ b/rider-editor/src/app/application.rs @@ -3,6 +3,7 @@ pub use crate::renderer::CanvasRenderer; use crate::ui::caret::{CaretPosition, MoveDirection}; use crate::ui::*; pub use rider_config::{Config, ConfigAccess, ConfigHolder}; + use sdl2::event::*; use sdl2::hint; use sdl2::keyboard::Keycode; @@ -24,7 +25,7 @@ use std::time::Duration; pub type WindowCanvas = Canvas; -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Debug)] pub enum UpdateResult { NoOp, Stop, @@ -35,6 +36,7 @@ pub enum UpdateResult { MoveCaret(Rect, CaretPosition), DeleteFront, DeleteBack, + DeleteLine, Input(String), InsertNewLine, MoveCaretLeft, @@ -49,6 +51,8 @@ pub enum UpdateResult { OpenFileModal, FileDropped(String), SaveCurrentFile, + OpenSettings, + CloseModal, } #[cfg_attr(tarpaulin, skip)] @@ -137,6 +141,7 @@ impl Application { let res = app_state.on_left_click(&point, &mut self.video_subsystem); match res { UpdateResult::OpenDirectory(_) => new_tasks.push(res), + UpdateResult::OpenSettings => new_tasks.push(res), UpdateResult::OpenFile(_) => { new_tasks.push(res); app_state.set_open_file_modal(None); @@ -154,9 +159,14 @@ impl Application { UpdateResult::Input(text) => app_state .file_editor_mut() .insert_text(text.clone(), &mut renderer), - UpdateResult::InsertNewLine => { - app_state.file_editor_mut().insert_new_line(&mut renderer); - } + UpdateResult::InsertNewLine => app_state + .file_editor_mut() + .insert_new_line(&mut renderer) + .unwrap_or_else(|e| eprintln!("Failed to delete line {:?}", e)), + UpdateResult::DeleteLine => app_state + .file_editor_mut() + .delete_current_line(&mut renderer) + .unwrap_or_else(|e| eprintln!("Failed to delete line {:?}", e)), UpdateResult::MoveCaretLeft => { app_state.file_editor_mut().move_caret(MoveDirection::Left); } @@ -205,6 +215,12 @@ impl Application { UpdateResult::SaveCurrentFile => app_state .save_file() .unwrap_or_else(|e| eprintln!("Failed to save {:?}", e)), + UpdateResult::OpenSettings => app_state + .open_settings(&mut renderer) + .unwrap_or_else(|e| eprintln!("Failed to open settings {:?}", e)), + UpdateResult::CloseModal => app_state + .close_modal() + .unwrap_or_else(|e| eprintln!("Failed to close modal {:?}", e)), } } self.tasks = new_tasks; @@ -266,12 +282,18 @@ impl Application { .tasks .push(UpdateResult::MouseDragStart(Point::new(x, y))), Event::KeyDown { keycode, .. } if keycode.is_some() => match keycode.unwrap() { + Keycode::Escape => { + self.tasks.push(UpdateResult::CloseModal); + } Keycode::Backspace => { self.tasks.push(UpdateResult::DeleteFront); } - Keycode::Delete => { + Keycode::Delete if !shift_pressed => { self.tasks.push(UpdateResult::DeleteBack); } + Keycode::Delete if shift_pressed => { + self.tasks.push(UpdateResult::DeleteLine); + } Keycode::KpEnter | Keycode::Return => { self.tasks.push(UpdateResult::InsertNewLine); } @@ -307,9 +329,7 @@ impl Application { MouseWheelDirection::Flipped => { self.tasks.push(UpdateResult::Scroll { x, y: -y }); } - _ => { - // ignore - } + _ => (), }, Event::Window { win_event: WindowEvent::Resized(w, h), @@ -318,7 +338,7 @@ impl Application { width: w, height: h, }), - _ => {} + _ => (), } } } diff --git a/rider-editor/src/app/file_content_manager.rs b/rider-editor/src/app/file_content_manager.rs index 49c7878..1dca640 100644 --- a/rider-editor/src/app/file_content_manager.rs +++ b/rider-editor/src/app/file_content_manager.rs @@ -104,14 +104,14 @@ where file_editor.replace_current_file(new_file); } -pub fn insert_new_line(file_editor: &mut FileEditor, renderer: &mut R) +pub fn insert_new_line(file_editor: &mut FileEditor, renderer: &mut R) -> Result<(), String> where R: ConfigHolder + CharacterSizeManager + Renderer, { - let mut buffer: String = match file_editor.file() { - Some(file) => file.buffer(), - None => return, - }; + let mut buffer: String = file_editor + .file() + .map(|file| file.buffer()) + .ok_or_else(|| "No file is open".to_string())?; let maybe_character = file_editor .file() @@ -134,6 +134,36 @@ where ); new_file.prepare_ui(renderer); file_editor.replace_current_file(new_file); + Ok(()) +} + +pub fn delete_current_line(file_editor: &mut FileEditor, renderer: &mut R) -> Result<(), String> +where + R: ConfigHolder + CharacterSizeManager + Renderer, +{ + let file: &EditorFile = file_editor + .file() + .ok_or_else(|| "No file is open".to_string())?; + let mut new_buffer = String::new(); + let target_line = file_editor.caret().line_number(); + let mut current_line = 0; + for c in file.buffer_ref().chars() { + match c { + '\n' if current_line == target_line => { + current_line += 1; + } + '\n' => { + current_line += 1; + new_buffer.push(c); + } + _ if current_line == target_line => (), + _ => new_buffer.push(c), + } + } + let mut new_file = EditorFile::new(file.path(), new_buffer, file_editor.config().clone()); + new_file.prepare_ui(renderer); + file_editor.replace_current_file(new_file); + Ok(()) } #[cfg(test)] @@ -309,7 +339,8 @@ mod tests { let mut renderer = RendererMock::new(config.clone()); let mut widget = FileEditor::new(config.clone()); widget.prepare_ui(&mut renderer); - widget.insert_new_line(&mut renderer); + let res: Result<(), String> = widget.insert_new_line(&mut renderer); + assert_eq!(res.is_ok(), false); let expected = CaretPosition::new(0, 0, 0); assert_eq!(widget.caret().position(), &expected); let expected = Rect::new(0, 0, 6, 15); @@ -324,7 +355,8 @@ mod tests { let file = EditorFile::new("".to_owned(), "".to_owned(), config.clone()); widget.open_file(file); widget.prepare_ui(&mut renderer); - widget.insert_new_line(&mut renderer); + let res: Result<(), String> = widget.insert_new_line(&mut renderer); + assert_eq!(res.is_ok(), true); let expected = CaretPosition::new(1, 1, 0); assert_eq!(widget.caret().position(), &expected); let expected = Rect::new(0, 13, 6, 15); @@ -339,7 +371,8 @@ mod tests { let file = EditorFile::new("".to_owned(), "foo".to_owned(), config.clone()); widget.open_file(file); widget.prepare_ui(&mut renderer); - widget.insert_new_line(&mut renderer); + let res: Result<(), String> = widget.insert_new_line(&mut renderer); + assert_eq!(res.is_ok(), true); let expected = CaretPosition::new(1, 1, 0); assert_eq!(widget.caret().position(), &expected); let expected = Rect::new(0, 13, 6, 15); @@ -359,7 +392,8 @@ mod tests { widget.prepare_ui(&mut renderer); widget.move_caret(MoveDirection::Right); widget.move_caret(MoveDirection::Right); - widget.insert_new_line(&mut renderer); + let res: Result<(), String> = widget.insert_new_line(&mut renderer); + assert_eq!(res.is_ok(), true); let expected = CaretPosition::new(3, 1, 0); assert_eq!(widget.caret().position(), &expected); let expected = Rect::new(0, 13, 6, 15); diff --git a/rider-editor/src/ui/buttons/mod.rs b/rider-editor/src/ui/buttons/mod.rs new file mode 100644 index 0000000..f342a23 --- /dev/null +++ b/rider-editor/src/ui/buttons/mod.rs @@ -0,0 +1,5 @@ +pub mod save_button; +pub mod settings_button; + +pub use self::save_button::*; +pub use self::settings_button::*; diff --git a/rider-editor/src/ui/save_button.rs b/rider-editor/src/ui/buttons/save_button.rs similarity index 93% rename from rider-editor/src/ui/save_button.rs rename to rider-editor/src/ui/buttons/save_button.rs index e4079c6..395af1a 100644 --- a/rider-editor/src/ui/save_button.rs +++ b/rider-editor/src/ui/buttons/save_button.rs @@ -32,7 +32,7 @@ impl SaveButton { { use std::borrow::*; let mut dest = match context { - &RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest), + &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), _ => self.dest.clone(), }; @@ -78,8 +78,6 @@ impl SaveButton { impl Update for SaveButton { fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR { - let config = self.config.read().unwrap(); - self.dest.set_width(config.width()); UR::NoOp } } @@ -92,7 +90,7 @@ impl ClickHandler for SaveButton { fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool { match *context { UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest(), + _ => self.dest, } .contains_point(point.clone()) } diff --git a/rider-editor/src/ui/settings_button.rs b/rider-editor/src/ui/buttons/settings_button.rs similarity index 92% rename from rider-editor/src/ui/settings_button.rs rename to rider-editor/src/ui/buttons/settings_button.rs index c230ca3..8d5b578 100644 --- a/rider-editor/src/ui/settings_button.rs +++ b/rider-editor/src/ui/buttons/settings_button.rs @@ -32,7 +32,7 @@ impl SettingsButton { { use std::borrow::*; let mut dest = match context { - &RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest), + &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), _ => self.dest.clone(), }; @@ -78,21 +78,19 @@ impl SettingsButton { impl Update for SettingsButton { fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR { - let config = self.config.read().unwrap(); - self.dest.set_width(config.width()); UR::NoOp } } impl ClickHandler for SettingsButton { fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR { - UR::NoOp + UR::OpenSettings } fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool { match *context { UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest(), + _ => self.dest, } .contains_point(point.clone()) } diff --git a/rider-editor/src/ui/caret/caret.rs b/rider-editor/src/ui/caret/caret.rs index 192c687..d2529c6 100644 --- a/rider-editor/src/ui/caret/caret.rs +++ b/rider-editor/src/ui/caret/caret.rs @@ -72,7 +72,7 @@ impl Caret { use std::borrow::*; let dest = match context.borrow() { - RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest), + RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), _ => self.dest().clone(), }; let start = Point::new(dest.x(), dest.y()); @@ -368,7 +368,7 @@ mod test_render { #[test] fn assert_render_line() { let config = build_config(); - let context = RenderContext::RelativePosition(Point::new(10, 14)); + let context = RenderContext::ParentPosition(Point::new(10, 14)); let mut canvas = CanvasMock { start: Point::new(0, 0), end: Point::new(0, 0), diff --git a/rider-editor/src/ui/file/editor_file.rs b/rider-editor/src/ui/file/editor_file.rs index e03c21a..823698c 100644 --- a/rider-editor/src/ui/file/editor_file.rs +++ b/rider-editor/src/ui/file/editor_file.rs @@ -47,6 +47,10 @@ impl EditorFile { self.buffer.clone() } + pub fn buffer_ref(&self) -> &String { + &self.buffer + } + pub fn path(&self) -> String { self.path.clone() } diff --git a/rider-editor/src/ui/file/editor_file_section.rs b/rider-editor/src/ui/file/editor_file_section.rs index 1d7fc52..35aef2a 100644 --- a/rider-editor/src/ui/file/editor_file_section.rs +++ b/rider-editor/src/ui/file/editor_file_section.rs @@ -80,7 +80,8 @@ impl EditorFileSection { } } - fn iter_char(&self) -> EditorFileSectionIterator { + #[inline] + pub fn iter_char(&self) -> EditorFileSectionIterator { EditorFileSectionIterator::new(self) } diff --git a/rider-editor/src/ui/file/editor_file_token.rs b/rider-editor/src/ui/file/editor_file_token.rs index 4ac4aae..5290403 100644 --- a/rider-editor/src/ui/file/editor_file_token.rs +++ b/rider-editor/src/ui/file/editor_file_token.rs @@ -40,6 +40,7 @@ impl EditorFileToken { } } + #[inline] pub fn characters(&self) -> &Vec { &self.characters } @@ -59,7 +60,8 @@ impl EditorFileToken { } } - fn iter_char(&self) -> EditorFileTokenIterator { + #[inline] + pub fn iter_char(&self) -> EditorFileTokenIterator { EditorFileTokenIterator::new(self) } } @@ -82,12 +84,10 @@ impl TextWidget for EditorFileToken { impl TextCollection for EditorFileToken { fn get_character_at(&self, index: usize) -> Option { - for character in self.characters.iter() { - if character.position() == index { - return Some(character.clone()); - } - } - None + self.characters + .iter() + .find(|character| character.position() == index) + .cloned() } fn get_line(&self, line: &usize) -> Option> { diff --git a/rider-editor/src/ui/file_editor/mod.rs b/rider-editor/src/ui/file_editor/mod.rs index 209d019..4ddc1dc 100644 --- a/rider-editor/src/ui/file_editor/mod.rs +++ b/rider-editor/src/ui/file_editor/mod.rs @@ -106,11 +106,18 @@ impl FileEditor { file_content_manager::insert_text(self, text, renderer); } - pub fn insert_new_line(&mut self, renderer: &mut R) + pub fn insert_new_line(&mut self, renderer: &mut R) -> Result<(), String> where R: ConfigHolder + CharacterSizeManager + Renderer, { - file_content_manager::insert_new_line(self, renderer); + file_content_manager::insert_new_line(self, renderer) + } + + pub fn delete_current_line(&mut self, renderer: &mut R) -> Result<(), String> + where + R: ConfigHolder + CharacterSizeManager + Renderer, + { + file_content_manager::delete_current_line(self, renderer) } fn is_text_character_clicked(&self, point: &Point) -> bool { @@ -264,22 +271,18 @@ impl FileEditor { Some(file) => file.render( canvas, renderer, - &RenderContext::RelativePosition(self.render_start_point()), + &RenderContext::ParentPosition(self.render_start_point()), ), _ => (), }; self.caret.render( canvas, - &RenderContext::RelativePosition(self.render_start_point()), - ); - self.vertical_scroll_bar.render( - canvas, - &RenderContext::RelativePosition(self.dest.top_left()), - ); - self.horizontal_scroll_bar.render( - canvas, - &RenderContext::RelativePosition(self.dest.top_left()), + &RenderContext::ParentPosition(self.render_start_point()), ); + self.vertical_scroll_bar + .render(canvas, &RenderContext::ParentPosition(self.dest.top_left())); + self.horizontal_scroll_bar + .render(canvas, &RenderContext::ParentPosition(self.dest.top_left())); } pub fn prepare_ui(&mut self, renderer: &mut T) diff --git a/rider-editor/src/ui/filesystem/directory.rs b/rider-editor/src/ui/filesystem/directory.rs index 4ff9f6d..cff6f88 100644 --- a/rider-editor/src/ui/filesystem/directory.rs +++ b/rider-editor/src/ui/filesystem/directory.rs @@ -252,12 +252,12 @@ impl DirectoryView { self.icon_height as i32 + CHILD_MARGIN, ); for dir in self.directories.iter() { - let context = RenderContext::RelativePosition(point.clone()); + let context = RenderContext::ParentPosition(point.clone()); dir.render(canvas, renderer, &context); point = point + Point::new(0, dir.height() as i32 + CHILD_MARGIN as i32); } for file in self.files.iter() { - let context = RenderContext::RelativePosition(point.clone()); + let context = RenderContext::ParentPosition(point.clone()); file.render(canvas, renderer, &context); point = point + Point::new(0, file.height() as i32 + CHILD_MARGIN as i32); } @@ -302,7 +302,7 @@ impl DirectoryView { { let dest = self.dest(); let move_point = match context { - &RenderContext::RelativePosition(p) => p.clone(), + &RenderContext::ParentPosition(p) => p.clone(), _ => Point::new(0, 0), }; let mut dest = move_render_point(move_point, &dest); diff --git a/rider-editor/src/ui/filesystem/file.rs b/rider-editor/src/ui/filesystem/file.rs index 5513736..f78e2ac 100644 --- a/rider-editor/src/ui/filesystem/file.rs +++ b/rider-editor/src/ui/filesystem/file.rs @@ -139,7 +139,7 @@ impl FileEntry { R: Renderer, { let mut dest = match context { - &RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest), + &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), _ => self.dest.clone(), }; self.render_icon(canvas, renderer, &mut dest); diff --git a/rider-editor/src/ui/label.rs b/rider-editor/src/ui/label.rs new file mode 100644 index 0000000..ff609a3 --- /dev/null +++ b/rider-editor/src/ui/label.rs @@ -0,0 +1,121 @@ +use crate::app::*; +use crate::renderer::*; +use crate::ui::*; +use sdl2::pixels::Color; +use sdl2::rect::{Point, Rect}; +use std::collections::HashMap; + +const DEST_WIDTH: u32 = 16; +const DEST_HEIGHT: u32 = 16; +const SRC_WIDTH: u32 = 64; +const SRC_HEIGHT: u32 = 64; + +pub struct Label { + name_width: u32, + height: u32, + name: String, + source: Rect, + dest: Rect, + char_sizes: HashMap, + config: ConfigAccess, +} + +impl Label { + pub fn new(name: String, config: ConfigAccess) -> Self { + Self { + name, + name_width: 0, + height: 0, + dest: Rect::new(0, 0, DEST_WIDTH, DEST_HEIGHT), + source: Rect::new(0, 0, SRC_WIDTH, SRC_HEIGHT), + config, + char_sizes: HashMap::new(), + } + } + + pub fn name_width(&self) -> u32 { + self.name_width + } + + pub fn name(&self) -> String { + self.name.clone() + } + + pub fn render(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext) + where + C: CanvasAccess, + R: Renderer, + { + let dest = match context { + &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), + _ => self.dest.clone(), + }; + let mut d = dest.clone(); + d.set_x(dest.x() + NAME_MARGIN); + + let font_details = build_font_details(self); + for c in self.name.chars() { + let size = self + .char_sizes + .get(&c) + .unwrap_or(&Rect::new(0, 0, 0, 0)) + .clone(); + let mut text_details = TextDetails { + color: Color::RGBA(255, 255, 255, 0), + text: c.to_string(), + font: font_details.clone(), + }; + let maybe_texture = renderer.load_text_tex(&mut text_details, font_details.clone()); + + if let Ok(texture) = maybe_texture { + d.set_width(size.width()); + d.set_height(size.height()); + + canvas + .render_image(texture, self.source.clone(), d.clone()) + .unwrap_or_else(|_| panic!("Failed to draw directory entry texture")); + d.set_x(d.x() + size.width() as i32); + } + } + } + + pub fn prepare_ui(&mut self, renderer: &mut R) + where + R: Renderer + CharacterSizeManager, + { + let w_rect = renderer.load_character_size('W'); + self.char_sizes.insert('W', w_rect.clone()); + self.height = w_rect.height(); + self.name_width = 0; + + for c in self.name().chars() { + let size = { renderer.load_character_size(c.clone()) }; + self.char_sizes.insert(c, size); + self.name_width += size.width(); + } + self.dest.set_width(w_rect.height()); + self.dest.set_height(w_rect.height()); + } +} + +impl RenderBox for Label { + fn render_start_point(&self) -> Point { + self.dest.top_left() + } + + fn dest(&self) -> Rect { + self.dest.clone() + } +} + +impl Update for Label { + fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UpdateResult { + UpdateResult::NoOp + } +} + +impl ConfigHolder for Label { + fn config(&self) -> &ConfigAccess { + &self.config + } +} diff --git a/rider-editor/src/ui/menu_bar.rs b/rider-editor/src/ui/menu_bar.rs index 36376ec..ab15b0a 100644 --- a/rider-editor/src/ui/menu_bar.rs +++ b/rider-editor/src/ui/menu_bar.rs @@ -50,7 +50,7 @@ impl MenuBar { use std::borrow::*; let relative_position = match context.borrow() { - RenderContext::RelativePosition(p) => p.clone(), + RenderContext::ParentPosition(p) => p.clone(), _ => Point::new(0, 0), }; @@ -64,21 +64,19 @@ impl MenuBar { canvas .render_border( match context.borrow() { - RenderContext::RelativePosition(p) => { - move_render_point((*p).clone(), &self.dest) - } + RenderContext::ParentPosition(p) => move_render_point((*p).clone(), &self.dest), _ => self.dest(), }, self.border_color.clone(), ) .unwrap_or_else(|_| panic!("Failed to draw main menu background")); - let context = RenderContext::RelativePosition( + let context = RenderContext::ParentPosition( relative_position.offset(SAVE_BUTTON_OFFSET_LEFT, SAVE_BUTTON_OFFSET_TOP), ); self.save_button.render(canvas, renderer, &context); - let context = RenderContext::RelativePosition( + let context = RenderContext::ParentPosition( relative_position.offset(SAVE_BUTTON_OFFSET_LEFT * 2, SAVE_BUTTON_OFFSET_TOP), ); self.settings_button.render(canvas, renderer, &context); @@ -324,12 +322,12 @@ mod test_render { let mut widget = MenuBar::new(Arc::clone(&config)); widget.prepare_ui(); widget.render(&mut canvas, &mut renderer, &context); - assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 60)); + assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 40)); let expected = CanvasMock { - clipping: Rect::new(0, 0, 1024, 60), - background_rect: Rect::new(0, 0, 1024, 60), + clipping: Rect::new(32, 10, 32, 32), + background_rect: Rect::new(0, 0, 1024, 40), background_color: Color::RGBA(18, 18, 18, 0), - border_rect: Rect::new(0, 0, 1024, 60), + border_rect: Rect::new(0, 0, 1024, 40), border_color: Color::RGBA(200, 200, 200, 0), }; assert_eq!(canvas, expected); @@ -340,6 +338,6 @@ mod test_render { let config = support::build_config(); let mut widget = MenuBar::new(Arc::clone(&config)); widget.prepare_ui(); - assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 60)); + assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 40)); } } diff --git a/rider-editor/src/ui/mod.rs b/rider-editor/src/ui/mod.rs index 92c5964..efc9d1d 100644 --- a/rider-editor/src/ui/mod.rs +++ b/rider-editor/src/ui/mod.rs @@ -8,29 +8,29 @@ use crate::app::UpdateResult as UR; use crate::renderer::managers::*; use rider_config::*; +pub mod buttons; pub mod caret; pub mod file; pub mod file_editor; pub mod filesystem; +pub mod label; pub mod menu_bar; pub mod modal; pub mod project_tree; -pub mod save_button; pub mod scroll_bar; -pub mod settings_button; pub mod text_character; -pub use crate::ui::caret::*; -pub use crate::ui::file::*; -pub use crate::ui::file_editor::*; -pub use crate::ui::filesystem::*; -pub use crate::ui::menu_bar::*; -pub use crate::ui::modal::*; -pub use crate::ui::project_tree::*; -pub use crate::ui::save_button::*; -pub use crate::ui::scroll_bar::*; -pub use crate::ui::settings_button::*; -pub use crate::ui::text_character::*; +pub use self::buttons::*; +pub use self::caret::*; +pub use self::file::*; +pub use self::file_editor::*; +pub use self::filesystem::*; +pub use self::label::*; +pub use self::menu_bar::*; +pub use self::modal::*; +pub use self::project_tree::*; +pub use self::scroll_bar::*; +pub use self::text_character::*; #[derive(Debug)] pub enum UpdateContext<'l> { @@ -42,7 +42,7 @@ pub enum UpdateContext<'l> { #[derive(Clone, PartialEq, Debug)] pub enum RenderContext { Nothing, - RelativePosition(Point), + ParentPosition(Point), } pub trait CanvasAccess { diff --git a/rider-editor/src/ui/modal/mod.rs b/rider-editor/src/ui/modal/mod.rs index f8712d5..50ae674 100644 --- a/rider-editor/src/ui/modal/mod.rs +++ b/rider-editor/src/ui/modal/mod.rs @@ -1,3 +1,30 @@ pub mod open_file; +pub mod settings; -pub use crate::ui::modal::open_file::OpenFile; +pub use self::open_file::*; +pub use self::settings::*; + +pub enum ModalType { + OpenFile(OpenFile), + Settings(Settings), +} + +impl PartialEq for ModalType { + fn eq(&self, other: &ModalType) -> bool { + match (self, other) { + (ModalType::OpenFile { .. }, ModalType::OpenFile { .. }) => true, + (ModalType::Settings { .. }, ModalType::Settings { .. }) => true, + _ => false, + } + } +} + +impl std::fmt::Debug for ModalType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + let name = match self { + ModalType::OpenFile(_) => "OpenFile", + ModalType::Settings(_) => "Settings", + }; + write!(f, " move_render_point(p.clone(), &self.dest), + RC::ParentPosition(p) => move_render_point(p.clone(), &self.dest), _ => self.dest.clone(), }; @@ -164,7 +165,7 @@ impl OpenFile { .render_border(dest, self.border_color) .unwrap_or_else(|_| panic!("Failed to render open file modal border!")); - let context = RC::RelativePosition( + let context = RC::ParentPosition( dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(), ); @@ -172,14 +173,10 @@ impl OpenFile { self.directory_view.render(canvas, renderer, &context); // Scroll bars - self.vertical_scroll_bar.render( - canvas, - &RenderContext::RelativePosition(self.dest.top_left()), - ); - self.horizontal_scroll_bar.render( - canvas, - &RenderContext::RelativePosition(self.dest.top_left()), - ); + self.vertical_scroll_bar + .render(canvas, &RenderContext::ParentPosition(self.dest.top_left())); + self.horizontal_scroll_bar + .render(canvas, &RenderContext::ParentPosition(self.dest.top_left())); } pub fn prepare_ui(&mut self, renderer: &mut R) @@ -397,7 +394,7 @@ mod tests { let mut canvas = CanvasMock::new(); let widget = OpenFile::new(path.to_owned(), 100, 100, config); let p = Point::new(100, 100); - let context = RenderContext::RelativePosition(p); + let context = RenderContext::ParentPosition(p); widget.render(&mut canvas, &mut renderer, &context); } diff --git a/rider-editor/src/ui/modal/settings.rs b/rider-editor/src/ui/modal/settings.rs new file mode 100644 index 0000000..f68ac18 --- /dev/null +++ b/rider-editor/src/ui/modal/settings.rs @@ -0,0 +1,238 @@ +use crate::app::UpdateResult as UR; +use crate::renderer::renderer::Renderer; +use crate::ui::*; +use crate::ui::{RenderContext as RC, UpdateContext as UC}; +use rider_config::ConfigAccess; +use rider_config::ConfigHolder; +use sdl2::pixels::Color; +use sdl2::rect::{Point, Rect}; +use std::sync::Arc; + +const CONTENT_MARGIN_LEFT: i32 = 16; +const CONTENT_MARGIN_TOP: i32 = 24; +const DEFAULT_ICON_SIZE: u32 = 16; + +pub struct Settings { + vertical_scroll_bar: VerticalScrollBar, + horizontal_scroll_bar: HorizontalScrollBar, + dest: Rect, + full_dest: Rect, + background_color: Color, + border_color: Color, + config: ConfigAccess, + font_label: Label, + font_value: Label, +} + +impl Settings { + pub fn new(config: ConfigAccess) -> Self { + // let (window_width, window_height, background_color, border_color) = { + let c = config + .read() + .unwrap_or_else(|_| panic!("Failed to read config")); + let theme = c.theme(); + let window_width = c.width(); + let window_height = c.height(); + let background_color = theme.background().into(); + let border_color = theme.border_color().into(); + // }; + Self { + vertical_scroll_bar: VerticalScrollBar::new(Arc::clone(&config)), + horizontal_scroll_bar: HorizontalScrollBar::new(Arc::clone(&config)), + dest: Rect::new( + CONTENT_MARGIN_LEFT, + CONTENT_MARGIN_TOP, + window_width - (CONTENT_MARGIN_LEFT * 2) as u32, + window_height - (CONTENT_MARGIN_TOP * 2) as u32, + ), + full_dest: Rect::new(0, 0, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE), + background_color, + border_color, + font_label: Label::new("Font path".into(), config.clone()), + font_value: Label::new(c.editor_config().font_path().clone(), config.clone()), + config: config.clone(), + } + } + + pub fn full_rect(&self) -> &Rect { + &self.full_dest + } + + pub fn scroll_by(&mut self, x: i32, y: i32) { + let read_config = self.config.read().unwrap(); + + let value_x = read_config.scroll().speed() * x; + let value_y = read_config.scroll().speed() * y; + let old_x = self.horizontal_scroll_bar.scroll_value(); + let old_y = self.vertical_scroll_bar.scroll_value(); + + if value_x + old_x >= 0 { + self.horizontal_scroll_bar.scroll_to(value_x + old_x); + if self.horizontal_scroll_bar.scrolled_part() > 1.0 { + self.horizontal_scroll_bar.scroll_to(old_x); + } + } + if value_y + old_y >= 0 { + self.vertical_scroll_bar.scroll_to(value_y + old_y); + if self.vertical_scroll_bar.scrolled_part() > 1.0 { + self.vertical_scroll_bar.scroll_to(old_y); + } + } + } + + pub fn scroll(&self) -> Point { + Point::new( + -self.horizontal_scroll_bar.scroll_value(), + -self.vertical_scroll_bar.scroll_value(), + ) + } + + pub fn render(&self, canvas: &mut C, renderer: &mut R, context: &RC) + where + C: CanvasAccess, + R: Renderer + CharacterSizeManager + ConfigHolder, + { + let dest = match context { + RC::ParentPosition(p) => move_render_point(p.clone(), &self.dest), + _ => self.dest.clone(), + }; + + // Background + canvas.set_clipping(dest.clone()); + canvas + .render_rect(dest, self.background_color) + .unwrap_or_else(|_| panic!("Failed to render open file modal background!")); + canvas + .render_border(dest, self.border_color) + .unwrap_or_else(|_| panic!("Failed to render open file modal border!")); + + self.font_label.render( + canvas, + renderer, + &RC::ParentPosition( + self.render_start_point() + + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + + self.scroll(), + ), + ); + self.font_value.render( + canvas, + renderer, + &RC::ParentPosition( + self.render_start_point() + + Point::new( + (CONTENT_MARGIN_LEFT * 2) + self.font_label.name_width() as i32, + CONTENT_MARGIN_TOP, + ) + + self.scroll(), + ), + ); + + // Scroll bars + self.vertical_scroll_bar + .render(canvas, &RenderContext::ParentPosition(self.dest.top_left())); + self.horizontal_scroll_bar + .render(canvas, &RenderContext::ParentPosition(self.dest.top_left())); + } + + pub fn prepare_ui(&mut self, renderer: &mut R) + where + R: Renderer + CharacterSizeManager, + { + self.font_label.prepare_ui(renderer); + self.font_value.prepare_ui(renderer); + } +} + +impl ClickHandler for Settings { + fn on_left_click(&mut self, _point: &Point, context: &UpdateContext) -> UR { + let dest = match context { + UC::ParentPosition(p) => move_render_point(*p, &self.dest), + _ => self.dest, + }; + let _context = UC::ParentPosition( + dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(), + ); + // let res = self.directory_view.on_left_click(point, &context); + // { + // let dest = self.directory_view.dest(); + // let full_dest = Rect::new( + // dest.x(), + // dest.y(), + // dest.width() + (2 * CONTENT_MARGIN_LEFT as u32), + // dest.height() + (2 * CONTENT_MARGIN_TOP as u32), + // ); + // self.full_dest = full_dest; + // } + // res + UR::NoOp + } + + fn is_left_click_target(&self, _point: &Point, context: &UpdateContext) -> bool { + let dest = match *context { + UC::ParentPosition(p) => move_render_point(p.clone(), &self.dest), + _ => self.dest.clone(), + }; + let p = + dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(); + let _context = UC::ParentPosition(p); + // if self.directory_view.is_left_click_target(point, &context) { + // true + // } else { + // Rect::new(p.x(), p.y(), dest.width(), dest.height()).contains_point(point.clone()) + // } + false + } +} + +impl RenderBox for Settings { + fn render_start_point(&self) -> Point { + self.dest.top_left() + } + + fn dest(&self) -> Rect { + self.dest.clone() + } +} + +impl Update for Settings { + fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR { + let (window_width, window_height, color, scroll_width, scroll_margin) = { + let c = self.config.read().unwrap(); + ( + c.width(), + c.height(), + c.theme().background().into(), + c.scroll().width(), + c.scroll().margin_right(), + ) + }; + + self.dest.set_x(CONTENT_MARGIN_LEFT); + self.dest + .set_width(window_width - (CONTENT_MARGIN_LEFT * 2) as u32); + self.dest.set_y(CONTENT_MARGIN_TOP); + self.dest + .set_height(window_height - (CONTENT_MARGIN_TOP * 2) as u32); + + self.background_color = color; + + // Scroll bars + self.vertical_scroll_bar + .set_full_size(self.full_dest.height()); // full dest + self.vertical_scroll_bar.set_viewport(self.dest.height()); + self.vertical_scroll_bar + .set_location(self.dest.width() as i32 - (scroll_width as i32 + scroll_margin)); + self.vertical_scroll_bar.update(ticks, context); + + self.horizontal_scroll_bar + .set_full_size(self.full_dest.width()); // full dest + self.horizontal_scroll_bar.set_viewport(self.dest.width()); + self.horizontal_scroll_bar + .set_location(self.dest.height() as i32 - (scroll_width as i32 + scroll_margin)); + self.horizontal_scroll_bar.update(ticks, context); + + // End + UR::NoOp + } +} diff --git a/rider-editor/src/ui/project_tree/mod.rs b/rider-editor/src/ui/project_tree/mod.rs index 384e1cd..b0f0307 100644 --- a/rider-editor/src/ui/project_tree/mod.rs +++ b/rider-editor/src/ui/project_tree/mod.rs @@ -98,7 +98,7 @@ impl ProjectTreeSidebar { .unwrap(); // dir view - let context = RenderContext::RelativePosition( + let context = RenderContext::ParentPosition( self.dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP), ); self.dir_view.render(canvas, renderer, &context); @@ -271,7 +271,7 @@ mod tests { let mut renderer = RendererMock::new(config.clone()); let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config); widget.prepare_ui(&mut renderer); - assert_eq!(widget.full_rect(), Rect::new(0, 60, 200, 860)); + assert_eq!(widget.full_rect(), Rect::new(0, 40, 200, 860)); } #[test] @@ -279,7 +279,7 @@ mod tests { let config = build_config(); let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config); widget.update(0); - assert_eq!(widget.full_rect(), Rect::new(0, 60, 200, 800)); + assert_eq!(widget.full_rect(), Rect::new(0, 40, 200, 820)); } #[test] @@ -288,7 +288,7 @@ mod tests { let mut renderer = RendererMock::new(config.clone()); let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config); widget.prepare_ui(&mut renderer); - assert_eq!(widget.full_rect(), Rect::new(0, 60, 200, 860)); + assert_eq!(widget.full_rect(), Rect::new(0, 40, 200, 860)); } #[test] diff --git a/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs b/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs index cd00887..9bdf7a0 100644 --- a/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs +++ b/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs @@ -66,7 +66,7 @@ impl HorizontalScrollBar { canvas .render_rect( match context { - RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.rect), + RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.rect), _ => self.rect.clone(), }, Color::RGBA(255, 255, 255, 0), diff --git a/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs b/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs index 340bc2a..73372b7 100644 --- a/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs +++ b/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs @@ -66,7 +66,7 @@ impl VerticalScrollBar { canvas .render_border( match context { - RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.rect), + RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.rect), _ => self.rect.clone(), }, Color::RGBA(255, 255, 255, 0), diff --git a/rider-editor/src/ui/text_character.rs b/rider-editor/src/ui/text_character.rs index d411cd3..f70744e 100644 --- a/rider-editor/src/ui/text_character.rs +++ b/rider-editor/src/ui/text_character.rs @@ -124,7 +124,7 @@ impl TextCharacter { font: font_details.clone(), }; let dest = match context { - RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest), + RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), _ => self.dest(), }; diff --git a/rider-generator/src/main.rs b/rider-generator/src/main.rs index 906c4ac..a770793 100644 --- a/rider-generator/src/main.rs +++ b/rider-generator/src/main.rs @@ -28,7 +28,7 @@ fn main() -> std::io::Result<()> { mod tests { use super::*; use std::env::set_var; - use std::fs::create_dir_all; + use std::fs::{create_dir_all, remove_dir_all}; use std::path::Path; use uuid::Uuid; @@ -48,73 +48,130 @@ mod tests { let uniq = Uuid::new_v4(); let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string()); let test_path = joined.as_str(); + remove_dir_all(joined.clone()).unwrap_or_else(|_| ()); create_dir_all(test_path.to_owned()).unwrap(); set_var("XDG_CONFIG_HOME", test_path); set_var("XDG_RUNTIME_DIR", test_path); - assert_eq!(exists(&test_path.to_owned(), ".rider"), false); - assert_eq!(main().is_ok(), true); - assert_eq!(exists(&test_path.to_owned(), ".rider"), true); + debug_assert!( + !exists(&test_path.to_owned(), ".rider"), + "rider config dir should not exists before generator run" + ); + debug_assert!(main().is_ok(), "generator should not failed"); + debug_assert!( + exists(&test_path.to_owned(), ".rider"), + "rider config dir should exists after generator run" + ); } #[test] fn assert_fonts_dir() { let uniq = Uuid::new_v4(); let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string()); + + remove_dir_all(joined.clone()).unwrap_or_else(|_| ()); create_dir_all(joined.clone()).unwrap(); + set_var("XDG_CONFIG_HOME", joined.as_str().clone()); set_var("XDG_RUNTIME_HOME", joined.as_str().clone()); - assert_eq!(exists(&joined, "rider/fonts"), false); - assert_eq!(main().is_ok(), true); - assert_eq!(exists(&joined, "rider/fonts"), true); + + debug_assert!( + !exists(&joined, "rider/fonts"), + "fonts director should not exists before run generator" + ); + debug_assert!(main().is_ok(), "generator should not failed"); + debug_assert!( + exists(&joined, "rider/fonts"), + "fonts director should exists after run generator" + ); } #[test] fn assert_log_dir() { let uniq = Uuid::new_v4(); let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string()); + + remove_dir_all(joined.clone()).unwrap_or_else(|_| ()); create_dir_all(joined.clone()).unwrap(); + set_var("XDG_CONFIG_HOME", joined.as_str().clone()); set_var("XDG_RUNTIME_HOME", joined.as_str().clone()); - assert_eq!(exists(&joined, "rider/log"), false); - assert_eq!(main().is_ok(), true); - assert_eq!(exists(&joined, "rider/log"), true); + + debug_assert!( + !exists(&joined, "rider/log"), + "log should not exists before run generator" + ); + debug_assert!(main().is_ok(), "generator should not failed"); + debug_assert!( + exists(&joined, "rider/log"), + "log should exists after run generator" + ); } #[test] fn assert_themes_dir() { let uniq = Uuid::new_v4(); let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string()); + + remove_dir_all(joined.clone()).unwrap_or_else(|_| ()); create_dir_all(joined.clone()).unwrap(); + set_var("XDG_CONFIG_HOME", joined.as_str().clone()); set_var("XDG_RUNTIME_HOME", joined.as_str().clone()); - assert_eq!(exists(&joined, "rider/themes"), false); - assert_eq!(main().is_ok(), true); - assert_eq!(exists(&joined, "rider/themes"), true); + + debug_assert!( + !exists(&joined, "rider/themes"), + "themes should not exists before run generator" + ); + debug_assert!(main().is_ok(), "generator should not failed"); + debug_assert!( + exists(&joined, "rider/themes"), + "themes should exists after run generator" + ); } #[test] fn assert_default_json() { let uniq = Uuid::new_v4(); let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string()); + + remove_dir_all(joined.clone()).unwrap_or_else(|_| ()); create_dir_all(joined.clone()).unwrap(); + set_var("XDG_CONFIG_HOME", joined.as_str().clone()); set_var("XDG_RUNTIME_HOME", joined.as_str().clone()); - assert_eq!(exists(&joined, "rider/themes/default.json"), false); - assert_eq!(main().is_ok(), true); - assert_eq!(exists(&joined, "rider/themes/default.json"), true); + + debug_assert!( + !exists(&joined, "rider/themes/default.json"), + "default theme should not exists before run generator" + ); + debug_assert!(main().is_ok(), "generator should not failed"); + debug_assert!( + exists(&joined, "rider/themes/default.json"), + "default theme should exists after run generator" + ); } #[test] fn assert_railscasts_json() { let uniq = Uuid::new_v4(); let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string()); + + remove_dir_all(joined.clone()).unwrap_or_else(|_| ()); create_dir_all(joined.clone()).unwrap(); + set_var("XDG_CONFIG_HOME", joined.as_str().clone()); set_var("XDG_RUNTIME_HOME", joined.as_str().clone()); - assert_eq!(exists(&joined, "rider/themes/railscasts.json"), false); - assert_eq!(main().is_ok(), true); - assert_eq!(exists(&joined, "rider/themes/railscasts.json"), true); + + debug_assert!( + !exists(&joined, "rider/themes/railscasts.json"), + "railscasts theme should not exists before run generator" + ); + debug_assert!(main().is_ok(), "generator should not failed"); + debug_assert!( + exists(&joined, "rider/themes/railscasts.json"), + "railscasts theme should exists after run generator" + ); } }