diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4ae05f6..08c7190 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,9 +3,6 @@ name: Deploy on: release: types: [ published ] - push: - branches: - - master jobs: build: @@ -13,7 +10,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v3 - name: Install latest rust toolchain uses: actions-rs/toolchain@v1 @@ -39,7 +36,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v3 - name: Install latest rust toolchain uses: actions-rs/toolchain@v1 @@ -64,7 +61,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v3 - name: Install latest rust toolchain uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f7c2f78 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +name: Test + +on: + pull_request: + types: [opened, reopened] + push: + branches: + - master + - development + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install latest rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + default: true + override: true + + - name: Check code formatting + run: cargo fmt --all -- --check + + - name: Test code + run: cargo test --verbose --all diff --git a/Cargo.lock b/Cargo.lock index 49b5993..1bb1924 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1084,8 +1084,7 @@ dependencies = [ [[package]] name = "native-dialog" version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab637f328b31bd0855c43bd38a4a4455e74324d9e74e0aac6a803422f43abc6" +source = "git+https://github.com/CodeDead/native-dialog-rs#bf41d3b80351f8a16c178fbbf3c81e4354069888" dependencies = [ "block", "cocoa", @@ -1524,20 +1523,6 @@ name = "serde" version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "serde_json" @@ -1656,7 +1641,7 @@ dependencies = [ [[package]] name = "text-diff" -version = "0.1.0" +version = "0.1.1" dependencies = [ "iced", "native-dialog", diff --git a/Cargo.toml b/Cargo.toml index eb61da8..dd189a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "text-diff" -version = "0.1.0" +version = "0.1.1" edition = "2021" authors = ["CodeDead "] description = "A cross-platform GUI for comparing two text files" readme = "README.md" repository = "https://github.com/CodeDead/text-diff-rs" +license = "GPL-3.0" license-file = "LICENSE" keywords = ["gui", "ui", "text-diff", "interface", "codedead", "diff", "difference"] @@ -13,8 +14,8 @@ keywords = ["gui", "ui", "text-diff", "interface", "codedead", "diff", "differen [dependencies] iced = { git = "https://github.com/iced-rs/iced" } -native-dialog = "0.6.3" -serde = { version = "1.0", features = ["derive"] } +native-dialog = { git = "https://github.com/CodeDead/native-dialog-rs" } +serde = { version = "1.0" } serde_json = "1.0" [profile.release] diff --git a/README.md b/README.md index f2223a5..297208f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ ![GitHub](https://img.shields.io/badge/language-Rust-green) ![GitHub](https://img.shields.io/github/license/CodeDead/text-diff-rs) [![Deploy](https://github.com/CodeDead/text-diff-rs/actions/workflows/rust.yml/badge.svg)](https://github.com/CodeDead/text-diff-rs/actions/workflows/rust.yml) +[![Test](https://github.com/CodeDead/text-diff-rs/actions/workflows/test.yml/badge.svg)](https://github.com/CodeDead/text-diff-rs/actions/workflows/test.yml) ![text-diff](https://i.imgur.com/VrcSyMD.png) diff --git a/src/filereader.rs b/src/file_reader.rs similarity index 100% rename from src/filereader.rs rename to src/file_reader.rs diff --git a/src/main.rs b/src/main.rs index aa5eac6..b31f161 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use iced::window; use iced::{Sandbox, Settings}; -mod filereader; +mod file_reader; mod style; mod vector_comparer; mod vector_exporter; @@ -11,7 +11,7 @@ pub fn main() -> iced::Result { view::ApplicationContext::run(Settings { id: Some(String::from("text-diff")), window: window::Settings { - size: (800, 800), + size: (800, 720), position: window::Position::Centered, ..window::Settings::default() }, diff --git a/src/style.rs b/src/style.rs index 2b86134..d526a66 100644 --- a/src/style.rs +++ b/src/style.rs @@ -383,7 +383,7 @@ mod dark { a: 0.8, ..if is_checked { ACTIVE } else { SURFACE } } - .into(), + .into(), ..self.active(is_checked) } } diff --git a/src/view.rs b/src/view.rs index d832377..e9d6415 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,7 +1,7 @@ -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::path::Path; -use crate::filereader::FileReader; +use crate::file_reader::FileReader; use crate::style; use crate::vector_comparer::{IVectorComparer, VectorComparer}; use crate::vector_exporter::{ExportType, IVectorExporter, VectorExporter}; @@ -41,6 +41,59 @@ pub struct ApplicationContext { pub has_compared: bool, } +impl ApplicationContext { + /// Display a native alert + /// + /// # Example + /// + /// ```rust + /// display_alert("hello", "world", MessageType::Info) + /// ``` + /// + /// # Arguments + /// + /// * `title` - The alert title + /// * `content` - the content of the alert + /// * `message_type` - The `MessageType` for the alert + fn display_alert(&self, title: &str, content: &str, message_type: MessageType) { + MessageDialog::new() + .set_type(message_type) + .set_title(title) + .set_text(content) + .show_alert() + .unwrap(); + } + + /// Open the file dialog to select a file + /// + /// # Example + /// + /// ```rust + /// let selected_file_result: Result, OsString> = open_file_dialog() + /// ``` + /// + /// # Returns + /// + /// The optional `String` that contains the path of the selected file or an `OsString` error + fn open_file_dialog() -> Result, OsString> { + let path = FileDialog::new() + .add_filter("Text file", &["txt"]) + .add_filter("All files", &["*"]) + .show_open_single_file() + .unwrap(); + + let path = match path { + Some(path) => path, + None => return Ok(None), + }; + + match path.into_os_string().into_string() { + Ok(d) => Ok(Some(d)), + Err(e) => Err(e), + } + } +} + impl Sandbox for ApplicationContext { type Message = Message; @@ -57,41 +110,51 @@ impl Sandbox for ApplicationContext { Message::FirstFileInputChanged(d) => self.first_file = d, Message::SecondFileInputChanged(d) => self.second_file = d, Message::SelectFirstFilePressed => { - let path = FileDialog::new() - .add_filter("Text file", &["txt"]) - .add_filter("All files", &["*"]) - .show_open_single_file() - .unwrap(); - - let path = match path { - Some(path) => path, - None => return, + let path = match ApplicationContext::open_file_dialog() { + Ok(res) => match res { + Some(d) => d, + None => return, + }, + Err(e) => { + ApplicationContext::display_alert( + &self, + "text-diff", + &format!("Error while selecting file!\n{:?}", e), + MessageType::Error, + ); + return; + } }; - self.first_file = path.into_os_string().into_string().unwrap(); + self.first_file = path; } Message::SelectSecondFilePressed => { - let path = FileDialog::new() - .add_filter("Text file", &["txt"]) - .add_filter("All files", &["*"]) - .show_open_single_file() - .unwrap(); - - let path = match path { - Some(path) => path, - None => return, + let path = match ApplicationContext::open_file_dialog() { + Ok(res) => match res { + Some(d) => d, + None => return, + }, + Err(e) => { + ApplicationContext::display_alert( + &self, + "text-diff", + &format!("Error while selecting file!\n{:?}", e), + MessageType::Error, + ); + return; + } }; - self.second_file = path.into_os_string().into_string().unwrap(); + self.second_file = path; } Message::ComparePressed => { if self.first_file.is_empty() || self.second_file.is_empty() { - MessageDialog::new() - .set_type(MessageType::Warning) - .set_title("text-diff") - .set_text("Please select two files first!") - .show_alert() - .unwrap(); + ApplicationContext::display_alert( + &self, + "text-diff", + "Please select two files first!", + MessageType::Warning, + ); return; } @@ -103,15 +166,12 @@ impl Sandbox for ApplicationContext { let lines_first_file = match lines_first_file { Ok(d) => d, Err(e) => { - MessageDialog::new() - .set_type(MessageType::Error) - .set_title("text-diff") - .set_text(&format!( - "Error while reading file {}!\n{}", - &self.first_file, e - )) - .show_alert() - .unwrap(); + ApplicationContext::display_alert( + &self, + "text-diff", + &format!("Error while reading file {}!\n{}", &self.first_file, e), + MessageType::Error, + ); return; } }; @@ -119,15 +179,12 @@ impl Sandbox for ApplicationContext { let lines_second_file = match lines_second_file { Ok(d) => d, Err(e) => { - MessageDialog::new() - .set_type(MessageType::Error) - .set_title("text-diff") - .set_text(&format!( - "Error while reading file {}!\n{}", - &self.second_file, e - )) - .show_alert() - .unwrap(); + ApplicationContext::display_alert( + &self, + "text-diff", + &format!("Error while reading file {}!\n{}", &self.second_file, e), + MessageType::Error, + ); return; } }; @@ -179,23 +236,20 @@ impl Sandbox for ApplicationContext { Ok(_) => return, Err(e) => match e { crate::vector_exporter::ExportError::IoError(e) => { - MessageDialog::new() - .set_type(MessageType::Error) - .set_title("text-diff") - .set_text(&format!("Error while writing to file {}!\n{}", &path, e)) - .show_alert() - .unwrap(); + ApplicationContext::display_alert( + &self, + "text-diff", + &format!("Error while writing to file {}!\n{}", &path, e), + MessageType::Error, + ); } crate::vector_exporter::ExportError::JsonError(e) => { - MessageDialog::new() - .set_type(MessageType::Error) - .set_title("text-diff") - .set_text(&format!( - "Error while creating JSON for file {}!\n{}", - &path, e - )) - .show_alert() - .unwrap(); + ApplicationContext::display_alert( + &self, + "text-diff", + &format!("Error while creating JSON for file {}!\n{}", &path, e), + MessageType::Error, + ); } }, }; @@ -206,15 +260,11 @@ impl Sandbox for ApplicationContext { fn view(&mut self) -> Element<'_, Self::Message> { let title = Text::new("text-diff") .width(Length::Fill) - .size(85) - .color([0.5, 0.5, 0.5]) + .size(80) .horizontal_alignment(alignment::Horizontal::Center); let choose_theme = style::Theme::ALL.iter().fold( - Row::new() - .width(Length::Fill) - .align_items(Alignment::Center) - .spacing(10), + Row::new().width(Length::Fill).spacing(10), |row, theme| { row.push( Radio::new( @@ -330,15 +380,16 @@ impl Sandbox for ApplicationContext { diff_text = Text::new("No differences detected!") } - let diff_column = self.differences.iter().fold( - Column::new().spacing(10), - |column, theme| column.push(Text::new(format!("- {}", theme))), - ); + let diff_column = self + .differences + .iter() + .fold(Column::new().spacing(10), |column, theme| { + column.push(Text::new(format!("- {}", theme))) + }); let scroll_container = Column::new().width(Length::Fill).push(diff_column); let scroll = Scrollable::new(&mut self.scrollable) - .push(Container::new(scroll_container) - .width(Length::Fill)) + .push(Container::new(scroll_container).width(Length::Fill)) .max_height(150) .style(self.theme); @@ -357,19 +408,19 @@ impl Sandbox for ApplicationContext { .on_press(Message::ExportPressed) .style(self.theme); - content = content.push( - Column::new() - .width(Length::Fill) - .align_items(Alignment::End) - .spacing(20) - .push(btn_export), - ); + content = content + .push( + Column::new() + .width(Length::Fill) + .align_items(Alignment::End) + .spacing(20) + .push(btn_export), + ) + .push(Rule::horizontal(20).style(self.theme)); } } - content = content - .push(Rule::horizontal(20).style(self.theme)) - .push(choose_theme); + content = content.push(choose_theme); Container::new(content) .width(Length::Fill)