Compare commits

...

10 Commits

6 changed files with 427 additions and 64 deletions

232
Cargo.lock generated
View File

@ -124,6 +124,18 @@ dependencies = [
"libloading 0.7.4",
]
[[package]]
name = "atk-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@ -235,6 +247,16 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cairo-sys-rs"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "calloop"
version = "0.12.4"
@ -277,6 +299,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cfg-expr"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6100bc57b6209840798d95cb2775684849d332f7bd788db2a8c8caf7ef82a41a"
dependencies = [
"smallvec",
"target-lexicon",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -805,6 +837,36 @@ dependencies = [
"slab",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "gdk-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"system-deps",
]
[[package]]
name = "gethostname"
version = "0.4.3"
@ -832,6 +894,19 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "gio-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
"winapi",
]
[[package]]
name = "gl_generator"
version = "0.14.0"
@ -849,6 +924,16 @@ version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945"
[[package]]
name = "glib-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "glow"
version = "0.13.1"
@ -882,6 +967,17 @@ dependencies = [
"wgpu",
]
[[package]]
name = "gobject-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "gpu-alloc"
version = "0.6.0"
@ -934,6 +1030,24 @@ dependencies = [
"bitflags 2.4.2",
]
[[package]]
name = "gtk-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722"
dependencies = [
"atk-sys",
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "guillotiere"
version = "0.6.2"
@ -979,6 +1093,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.4"
@ -1013,7 +1133,7 @@ dependencies = [
"log",
"num-traits",
"palette",
"raw-window-handle",
"raw-window-handle 0.6.0",
"smol_str",
"thiserror",
"web-time",
@ -1047,7 +1167,7 @@ dependencies = [
"iced_futures",
"log",
"once_cell",
"raw-window-handle",
"raw-window-handle 0.6.0",
"rustc-hash",
"thiserror",
"unicode-segmentation",
@ -1423,7 +1543,7 @@ dependencies = [
"log",
"ndk-sys",
"num_enum",
"raw-window-handle",
"raw-window-handle 0.6.0",
"thiserror",
]
@ -1611,6 +1731,18 @@ dependencies = [
"syn 2.0.48",
]
[[package]]
name = "pango-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -1833,6 +1965,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "977b1e897f9d764566891689e642653e5ed90c6895106acd005eb4c1d0203991"
[[package]]
name = "raw-window-handle"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "raw-window-handle"
version = "0.6.0"
@ -1872,6 +2010,29 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b"
[[package]]
name = "rfd"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0d8ab342bcc5436e04d3a4c1e09e17d74958bfaddf8d5fad6f85607df0f994f"
dependencies = [
"block",
"dispatch",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"log",
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle 0.5.2",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "roxmltree"
version = "0.18.1"
@ -1983,6 +2144,15 @@ dependencies = [
"syn 2.0.48",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]]
name = "simd-adler32"
version = "0.3.7"
@ -2082,7 +2252,7 @@ dependencies = [
"log",
"memmap2 0.9.3",
"objc",
"raw-window-handle",
"raw-window-handle 0.6.0",
"redox_syscall 0.4.1",
"rustix",
"tiny-xlib",
@ -2163,6 +2333,25 @@ dependencies = [
"libc",
]
[[package]]
name = "system-deps"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331"
dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"toml",
"version-compare",
]
[[package]]
name = "target-lexicon"
version = "0.12.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
[[package]]
name = "termcolor"
version = "1.4.1"
@ -2177,7 +2366,9 @@ name = "thief-book-manager"
version = "0.1.0"
dependencies = [
"iced",
"rfd",
"tokio",
"walkdir",
]
[[package]]
@ -2264,11 +2455,26 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "toml"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
@ -2277,6 +2483,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
@ -2384,6 +2592,12 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "version-compare"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]]
name = "version_check"
version = "0.9.4"
@ -2630,7 +2844,7 @@ dependencies = [
"naga",
"parking_lot 0.12.1",
"profiling",
"raw-window-handle",
"raw-window-handle 0.6.0",
"smallvec",
"static_assertions",
"wasm-bindgen",
@ -2658,7 +2872,7 @@ dependencies = [
"once_cell",
"parking_lot 0.12.1",
"profiling",
"raw-window-handle",
"raw-window-handle 0.6.0",
"rustc-hash",
"smallvec",
"thiserror",
@ -2700,7 +2914,7 @@ dependencies = [
"parking_lot 0.12.1",
"profiling",
"range-alloc",
"raw-window-handle",
"raw-window-handle 0.6.0",
"renderdoc-sys",
"rustc-hash",
"smallvec",
@ -2769,7 +2983,7 @@ dependencies = [
"clipboard_macos",
"clipboard_wayland",
"clipboard_x11",
"raw-window-handle",
"raw-window-handle 0.6.0",
"thiserror",
]
@ -3016,7 +3230,7 @@ dependencies = [
"once_cell",
"orbclient",
"percent-encoding",
"raw-window-handle",
"raw-window-handle 0.6.0",
"redox_syscall 0.3.5",
"rustix",
"sctk-adwaita",

View File

@ -7,4 +7,6 @@ edition = "2021"
[dependencies]
iced = { git = "https://github.com/iced-rs/iced.git", version = "0.12.0", features = ["tokio"] }
rfd = "0.13.0"
tokio = { version = "1.35.1", features = ["fs"] }
walkdir = "2.4.0"

101
src/application.rs Normal file
View File

@ -0,0 +1,101 @@
use std::{path::PathBuf, sync::Arc};
use iced::{
executor,
widget::{button, column, row, scrollable, text, text_editor, vertical_rule, Column},
Application, Command, Element, Length, Theme,
};
use crate::{
file::{default_file, load_file, load_folder},
project::ProjectState,
Error,
};
#[derive(Debug, Clone)]
pub enum Message {
Open,
Edit(text_editor::Action),
FileOpened(Result<(PathBuf, Arc<String>), Error>),
FolderSelected(Result<PathBuf, Error>),
}
pub struct BookManagerApp {
project: Option<ProjectState>,
book_path: Option<PathBuf>,
book_content: text_editor::Content,
io_error: Option<Error>,
}
impl Application for BookManagerApp {
type Executor = executor::Default;
type Flags = ();
type Message = Message;
type Theme = Theme;
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
(
Self {
project: None,
book_path: None,
book_content: text_editor::Content::new(),
io_error: None,
},
Command::perform(load_file(default_file()), Message::FileOpened),
)
}
fn title(&self) -> String {
String::from("Thief Book Manager")
}
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
match message {
Message::Edit(action) => self.book_content.perform(action),
Message::FileOpened(result) => match result {
Ok((path, content)) => {
self.book_content = text_editor::Content::with_text(&content);
self.book_path = Some(path);
}
Err(error) => self.io_error = Some(error),
},
Message::FolderSelected(result) => match result {
Ok(path) => self.project = Some(ProjectState::new(path)),
Err(error) => self.io_error = Some(error),
},
Message::Open => {
return Command::perform(load_folder(), Message::FolderSelected);
}
}
Command::none()
}
fn view(&self) -> Element<'_, Self::Message> {
let hello_world = text("Hello, world!");
let controls = row![button("Open").on_press(Message::Open)];
let active_editor = text_editor(&self.book_content).on_action(Message::Edit);
let mut books: Vec<Element<'_, Self::Message>> = vec![];
if let Some(project) = &self.project {
for (file_name, _) in project.books.iter() {
books.push(text(file_name.clone()).into());
}
}
let left_panel = column![
text(books.len()),
scrollable(Column::with_children(books).spacing(10).padding(10))
.width(Length::Fixed(256.0))
];
let right_panel = column![hello_world, controls, active_editor]
.spacing(10)
.padding(10);
row![left_panel, vertical_rule(2), right_panel].into()
}
fn theme(&self) -> Theme {
Theme::Dark
}
}

34
src/file.rs Normal file
View File

@ -0,0 +1,34 @@
use std::{path::PathBuf, sync::Arc};
use crate::Error;
pub async fn load_file(path: PathBuf) -> Result<(PathBuf, Arc<String>), Error> {
let content = tokio::fs::read_to_string(&path)
.await
.map(Arc::new)
.map_err(|error| error.kind())
.map_err(Error::IO)?;
Ok((path, content))
}
pub async fn pick_file() -> Result<(PathBuf, Arc<String>), Error> {
let file_handle = rfd::AsyncFileDialog::new()
.set_title("Choose a file...")
.pick_file()
.await
.ok_or(Error::DialogClosed)?;
load_file(file_handle.path().to_owned()).await
}
pub fn default_file() -> PathBuf {
PathBuf::from(format!("{}/src/main.rs", env!("CARGO_MANIFEST_DIR")))
}
pub async fn load_folder() -> Result<PathBuf, Error> {
let file_handle = rfd::AsyncFileDialog::new()
.set_title("Choose project folder...")
.pick_folder()
.await
.ok_or(Error::DialogClosed)?;
Ok(file_handle.path().to_owned())
}

View File

@ -1,60 +1,18 @@
use iced::{
executor,
widget::{column, text, text_editor},
Application, Command, Element, Result, Settings, Theme,
};
mod application;
mod file;
mod project;
#[derive(Debug, Clone)]
enum Message {
Edit(text_editor::Action),
}
use std::io;
struct BookManagerApp {
book_content: text_editor::Content,
}
use application::BookManagerApp;
use iced::{Application, Settings};
impl Application for BookManagerApp {
type Executor = executor::Default;
type Flags = ();
type Message = Message;
type Theme = Theme;
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
(
Self {
book_content: text_editor::Content::new(),
},
Command::none(),
)
}
fn title(&self) -> String {
String::from("Thief Book Manager")
}
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
match message {
Message::Edit(action) => self.book_content.perform(action),
}
Command::none()
}
fn view(&self) -> Element<'_, Self::Message> {
let hello_world = text("Hello, world!");
let active_editor = text_editor(&self.book_content).on_action(Message::Edit);
column![hello_world, active_editor]
.spacing(10)
.padding(10)
.into()
}
fn theme(&self) -> Theme {
Theme::Dark
}
}
fn main() -> Result {
fn main() -> iced::Result {
BookManagerApp::run(Settings::default())
}
#[derive(Debug, Clone)]
enum Error {
DialogClosed,
IO(io::ErrorKind),
}

54
src/project.rs Normal file
View File

@ -0,0 +1,54 @@
use std::{
collections::HashMap,
ffi::OsStr,
path::{Path, PathBuf},
};
use walkdir::WalkDir;
#[derive(Debug, Clone)]
pub struct Book {
pub path: PathBuf,
pub file_name: String,
pub languages: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ProjectState {
pub path: PathBuf,
pub books: HashMap<String, Book>,
}
impl ProjectState {
pub fn new(path: PathBuf) -> Self {
let search_path = path.join("books");
let mut books = HashMap::new();
let book_walker = WalkDir::new(search_path.clone()).into_iter();
for entry in book_walker.flatten() {
if entry.metadata().is_ok_and(|md| md.is_dir()) {
continue;
}
let path = entry.path();
let extension = path.extension().and_then(OsStr::to_str);
if extension.is_some_and(|ext| ext.to_lowercase() == "str") {
let language = file_name_string(path.parent().unwrap()).to_lowercase();
let file_name = file_name_string(path).to_lowercase();
books
.entry(file_name.clone())
.and_modify(|b: &mut Book| b.languages.push(language.clone()))
.or_insert(Book {
path: path.to_owned(),
file_name,
languages: vec![language],
});
}
}
Self { path, books }
}
}
fn file_name_string(path: &Path) -> String {
let file_name = path.file_name();
file_name.map(|s| s.to_str().unwrap().to_owned()).unwrap()
}