summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock14
-rw-r--r--src/config.rs3
-rw-r--r--src/dialogs.rs19
-rw-r--r--src/environment.rs3
-rw-r--r--src/error.rs6
-rw-r--r--src/main.rs101
-rw-r--r--src/types/project.rs7
7 files changed, 102 insertions, 51 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 26a20ef..a4992bb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2078,10 +2078,11 @@ dependencies = [
[[package]]
name = "iced_custom_highlighter"
version = "0.1.0"
-source = "git+https://github.com/pml68/iced_custom_highlighter?branch=master#e4708bdb31a792918a4bc162aebbc296fce9ce85"
+source = "git+https://github.com/pml68/iced_custom_highlighter?branch=master#aa5e7e024061a759fb89947185bb4969c3e21e66"
dependencies = [
"iced_core",
"syntect",
+ "two-face",
]
[[package]]
@@ -4867,6 +4868,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
[[package]]
+name = "two-face"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384eda438ddf62e2c6f39a174452d952d9d9df5a8ad5ade22198609f8dcaf852"
+dependencies = [
+ "once_cell",
+ "serde",
+ "syntect",
+]
+
+[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/config.rs b/src/config.rs
index 975437f..1da1239 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,3 +1,6 @@
+// (c) 2022-2024 Cory Forsstrom, Casper Rogild Storm, Calvin Lee, Andrew Baldwin, Reza Alizadeh Majd
+// (c) 2024-2025 Polesznyák Márk László
+
use std::path::PathBuf;
use serde::Deserialize;
diff --git a/src/dialogs.rs b/src/dialogs.rs
index 2d916b1..5954ff5 100644
--- a/src/dialogs.rs
+++ b/src/dialogs.rs
@@ -1,21 +1,26 @@
-use rfd::{MessageButtons, MessageDialog, MessageDialogResult, MessageLevel};
+use rfd::{
+ AsyncMessageDialog, MessageButtons, MessageDialog, MessageDialogResult,
+ MessageLevel,
+};
-pub fn error_dialog(description: impl Into<String>) {
- let _ = MessageDialog::new()
+pub async fn error_dialog(description: impl Into<String>) {
+ let _ = AsyncMessageDialog::new()
.set_level(MessageLevel::Error)
.set_buttons(MessageButtons::Ok)
.set_title("Oops! Something went wrong.")
.set_description(description)
- .show();
+ .show()
+ .await;
}
-pub fn warning_dialog(description: impl Into<String>) {
- let _ = MessageDialog::new()
+pub async fn warning_dialog(description: impl Into<String>) {
+ let _ = AsyncMessageDialog::new()
.set_level(MessageLevel::Warning)
.set_buttons(MessageButtons::Ok)
.set_title("Heads up!")
.set_description(description)
- .show();
+ .show()
+ .await;
}
pub fn unsaved_changes_dialog(description: impl Into<String>) -> bool {
diff --git a/src/environment.rs b/src/environment.rs
index 70953a0..8efc425 100644
--- a/src/environment.rs
+++ b/src/environment.rs
@@ -1,3 +1,6 @@
+// (c) 2023-2025 Cory Forsstrom, Casper Rogild Storm
+// (c) 2024-2025 Polesznyák Márk László
+
use std::env;
use std::path::PathBuf;
diff --git a/src/error.rs b/src/error.rs
index 002a1fc..9e1ee9d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -7,16 +7,16 @@ use thiserror::Error;
#[error(transparent)]
pub enum Error {
IO(Arc<io::Error>),
- #[error("config does not exist")]
+ #[error("Config does not exist")]
ConfigMissing,
#[error("JSON parsing error: {0}")]
SerdeJSON(Arc<serde_json::Error>),
#[error("TOML parsing error: {0}")]
SerdeTOML(#[from] toml::de::Error),
RustFmt(Arc<rust_format::Error>),
- #[error("the element tree contains no matching element")]
+ #[error("The element tree contains no matching element")]
NonExistentElement,
- #[error("the file dialog has been closed without selecting a valid option")]
+ #[error("The file dialog has been closed without selecting a valid option")]
DialogClosed,
#[error("{0}")]
Other(String),
diff --git a/src/main.rs b/src/main.rs
index e7faea1..b645e80 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,6 +12,7 @@ mod values;
mod widget;
use std::path::PathBuf;
+use std::sync::Arc;
use config::Config;
use dialogs::{error_dialog, unsaved_changes_dialog, warning_dialog};
@@ -60,7 +61,7 @@ struct App {
is_loading: bool,
project_path: Option<PathBuf>,
project: Project,
- config: Config,
+ config: Arc<Config>,
theme: Animated<Theme>,
pane_state: pane_grid::State<Panes>,
focus: Option<pane_grid::Pane>,
@@ -86,24 +87,25 @@ impl App {
},
);
- let config = config_load.unwrap_or_default();
+ let config = Arc::new(config_load.unwrap_or_default());
let theme = config.selected_theme();
- let mut task = Task::none();
-
- if let Some(path) = config.last_project.clone() {
+ let task = if let Some(path) = config.last_project.clone() {
if path.exists() && path.is_file() {
- task = Task::perform(
+ Task::perform(
Project::from_path(path, config.clone()),
Message::FileOpened,
- );
+ )
} else {
- warning_dialog(format!(
+ Task::future(warning_dialog(format!(
"The file {} does not exist, or isn't a file.",
path.to_string_lossy()
- ));
+ )))
+ .discard()
}
- }
+ } else {
+ Task::none()
+ };
(
Self {
@@ -147,32 +149,37 @@ impl App {
match message {
Message::SwitchTheme(event) => {
self.theme.update(event);
+
+ Task::none()
}
- Message::CopyCode => {
- return clipboard::write(self.editor_content.text());
+ Message::CopyCode => clipboard::write(self.editor_content.text()),
+ Message::SwitchPage(page) => {
+ self.designer_page = page;
+ Task::none()
}
- Message::SwitchPage(page) => self.designer_page = page,
Message::EditorAction(action) => {
if let text_editor::Action::Scroll { lines: _ } = action {
self.editor_content.perform(action);
}
+ Task::none()
}
Message::RefreshEditorContent => {
match self.project.app_code(&self.config) {
Ok(code) => {
self.editor_content =
text_editor::Content::with_text(&code);
+ Task::none()
}
- Err(error) => error_dialog(error),
+ Err(error) => Task::future(error_dialog(error)).discard(),
}
}
Message::DropNewElement(name, point, _) => {
- return iced_drop::zones_on_point(
+ iced_drop::zones_on_point(
move |zones| Message::HandleNew(name.clone(), zones),
point,
None,
None,
- );
+ )
}
Message::HandleNew(name, zones) => {
let ids: Vec<Id> = zones.into_iter().map(|z| z.0).collect();
@@ -183,25 +190,29 @@ impl App {
self.project.element_tree.as_mut(),
action,
);
+ self.is_dirty = true;
match result {
Ok(Some(ref element)) => {
self.project.element_tree = Some(element.clone());
}
- Err(error) => error_dialog(error),
+ Err(error) => {
+ return Task::future(error_dialog(error))
+ .map(|_| Message::RefreshEditorContent);
+ }
_ => {}
}
-
- self.is_dirty = true;
- return Task::done(Message::RefreshEditorContent);
+ Task::done(Message::RefreshEditorContent)
+ } else {
+ Task::none()
}
}
Message::MoveElement(element, point, _) => {
- return iced_drop::zones_on_point(
+ iced_drop::zones_on_point(
move |zones| Message::HandleMove(element.clone(), zones),
point,
None,
None,
- );
+ )
}
Message::HandleMove(element, zones) => {
let ids: Vec<Id> = zones.into_iter().map(|z| z.0).collect();
@@ -217,26 +228,31 @@ impl App {
action,
);
if let Err(error) = result {
- error_dialog(error);
+ return Task::future(error_dialog(error)).discard();
}
self.is_dirty = true;
- return Task::done(Message::RefreshEditorContent);
+ Task::done(Message::RefreshEditorContent)
+ } else {
+ Task::none()
}
}
Message::PaneResized(pane_grid::ResizeEvent { split, ratio }) => {
self.pane_state.resize(split, ratio);
+ Task::none()
}
Message::PaneClicked(pane) => {
self.focus = Some(pane);
+ Task::none()
}
Message::PaneDragged(pane_grid::DragEvent::Dropped {
pane,
target,
}) => {
self.pane_state.drop(pane, target);
+ Task::none()
}
- Message::PaneDragged(_) => {}
+ Message::PaneDragged(_) => Task::none(),
Message::NewFile => {
if !self.is_loading {
if !self.is_dirty {
@@ -252,26 +268,32 @@ impl App {
self.editor_content = text_editor::Content::new();
}
}
+
+ Task::none()
}
Message::OpenFile => {
if !self.is_loading {
if !self.is_dirty {
self.is_loading = true;
- return Task::perform(
+ Task::perform(
Project::from_file(self.config.clone()),
Message::FileOpened,
- );
+ )
} else if unsaved_changes_dialog(
"You have unsaved changes. Do you wish to discard these and open another project?",
) {
self.is_dirty = false;
self.is_loading = true;
- return Task::perform(
+ Task::perform(
Project::from_file(self.config.clone()),
Message::FileOpened,
- );
+ )
+ } else {
+ Task::none()
}
+ } else {
+ Task::none()
}
}
Message::FileOpened(result) => {
@@ -282,31 +304,35 @@ impl App {
Ok((path, project)) => {
self.project = project;
self.project_path = Some(path);
- return Task::done(Message::RefreshEditorContent);
+ Task::done(Message::RefreshEditorContent)
}
- Err(error) => error_dialog(error),
+ Err(error) => Task::future(error_dialog(error)).discard(),
}
}
Message::SaveFile => {
if !self.is_loading {
self.is_loading = true;
- return Task::perform(
+ Task::perform(
self.project
.clone()
.write_to_file(self.project_path.clone()),
Message::FileSaved,
- );
+ )
+ } else {
+ Task::none()
}
}
Message::SaveFileAs => {
if !self.is_loading {
self.is_loading = true;
- return Task::perform(
+ Task::perform(
self.project.clone().write_to_file(None),
Message::FileSaved,
- );
+ )
+ } else {
+ Task::none()
}
}
Message::FileSaved(result) => {
@@ -316,13 +342,12 @@ impl App {
Ok(path) => {
self.project_path = Some(path);
self.is_dirty = false;
+ Task::none()
}
- Err(error) => error_dialog(error),
+ Err(error) => Task::future(error_dialog(error)).discard(),
}
}
}
-
- Task::none()
}
fn subscription(&self) -> iced::Subscription<Message> {
diff --git a/src/types/project.rs b/src/types/project.rs
index e665d5e..721783e 100644
--- a/src/types/project.rs
+++ b/src/types/project.rs
@@ -1,4 +1,5 @@
use std::path::{Path, PathBuf};
+use std::sync::Arc;
extern crate fxhash;
use fxhash::FxHashMap;
@@ -58,7 +59,7 @@ impl Project {
pub async fn from_path(
path: PathBuf,
- config: Config,
+ config: Arc<Config>,
) -> Result<(PathBuf, Self), Error> {
let contents = tokio::fs::read_to_string(&path).await?;
let mut project: Self = serde_json::from_str(&contents)?;
@@ -68,7 +69,9 @@ impl Project {
Ok((path, project))
}
- pub async fn from_file(config: Config) -> Result<(PathBuf, Self), Error> {
+ pub async fn from_file(
+ config: Arc<Config>,
+ ) -> Result<(PathBuf, Self), Error> {
let picked_file = rfd::AsyncFileDialog::new()
.set_title("Open a JSON file...")
.add_filter("*.json, *.JSON", &["json", "JSON"])