diff --git a/Cargo.lock b/Cargo.lock index 80ae01f..5d29338 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -847,6 +847,7 @@ dependencies = [ "lazy_static", "libcosmic", "log", + "mime_guess", "rfd", "rust-embed", "serde", @@ -2716,6 +2717,22 @@ dependencies = [ "objc", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4636,6 +4653,15 @@ dependencies = [ "tinystr", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/Cargo.toml b/Cargo.toml index 2bffaf9..fe28f0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ env_logger = "0.10.0" fontdb = "0.15.0" lazy_static = "1.4.0" log = "0.4.20" +mime_guess = "2" rfd = "0.12.0" serde = { version = "1", features = ["serde_derive"] } syntect = "5.1.0" diff --git a/src/main.rs b/src/main.rs index 609d70a..59d0a15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,9 @@ mod config; mod localize; +pub use self::mime_icon::{mime_icon, FALLBACK_MIME_ICON}; +mod mime_icon; + use self::menu::menu_bar; mod menu; @@ -212,7 +215,7 @@ impl App { .insert() .position(position) .indent(indent) - .icon(icon::from_name(node.icon_name()).size(16).icon()) + .icon(node.icon(16)) .text(node.name().to_string()) .data(node); @@ -247,7 +250,7 @@ impl App { let id = self .nav_model .insert() - .icon(icon::from_name(node.icon_name()).size(16).icon()) + .icon(node.icon(16)) .text(node.name().to_string()) .data(node) .id(); @@ -265,7 +268,7 @@ impl App { self.tab_model .insert() .text(tab.title()) - .icon(icon::from_name("text-x-generic").size(16).icon()) + .icon(tab.icon(16)) .data::(tab) .closable() .activate(); @@ -494,8 +497,7 @@ impl Application for App { match node_opt { Some(node) => { // Update icon - self.nav_model - .icon_set(id, icon::from_name(node.icon_name()).size(16).icon()); + self.nav_model.icon_set(id, node.icon(16)); match node { ProjectNode::Folder { path, open, .. } => { diff --git a/src/mime_icon.rs b/src/mime_icon.rs new file mode 100644 index 0000000..34cec50 --- /dev/null +++ b/src/mime_icon.rs @@ -0,0 +1,17 @@ +use cosmic::widget::icon; +use std::path::Path; + +pub const FALLBACK_MIME_ICON: &str = "text-x-generic"; + +pub fn mime_icon>(path: P, size: u16) -> icon::Icon { + let path = path.as_ref(); + for mime in mime_guess::from_path(path).iter() { + //TODO: correct some common issues (like application/x-sh not being found) + let icon_name = mime.essence_str().replace("/", "-"); + let named = icon::from_name(icon_name).size(size); + if named.clone().path().is_some() { + return named.icon(); + } + } + icon::from_name(FALLBACK_MIME_ICON).size(size).icon() +} diff --git a/src/project.rs b/src/project.rs index c8d70c6..6d24c69 100644 --- a/src/project.rs +++ b/src/project.rs @@ -1,11 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-only +use cosmic::widget::{icon, Icon}; use std::{ cmp::Ordering, fs, io, path::{Path, PathBuf}, }; +use crate::mime_icon; + #[derive(Clone, Debug, Eq, PartialEq)] pub enum ProjectNode { Folder { @@ -47,17 +50,17 @@ impl ProjectNode { }) } - pub fn icon_name(&self) -> &str { + pub fn icon(&self, size: u16) -> Icon { match self { //TODO: different icon for project root? - Self::Folder { open, .. } => { - if *open { - "go-down-symbolic" - } else { - "go-next-symbolic" - } - } - Self::File { .. } => "text-x-generic", + Self::Folder { open, .. } => icon::from_name(if *open { + "go-down-symbolic" + } else { + "go-next-symbolic" + }) + .size(size) + .icon(), + Self::File { path, .. } => mime_icon(path, size), } } diff --git a/src/tab.rs b/src/tab.rs index 06b1648..66fde17 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only +use cosmic::widget::{icon, Icon}; use cosmic_text::{Attrs, Buffer, Edit, Shaping, SyntaxEditor, ViEditor, Wrap}; use std::{fs, path::PathBuf, sync::Mutex}; -use crate::{fl, Config, FONT_SYSTEM, SYNTAX_SYSTEM}; +use crate::{fl, mime_icon, Config, FALLBACK_MIME_ICON, FONT_SYSTEM, SYNTAX_SYSTEM}; pub struct Tab { pub path_opt: Option, @@ -95,6 +96,13 @@ impl Tab { } } + pub fn icon(&self, size: u16) -> Icon { + match &self.path_opt { + Some(path) => mime_icon(path, size), + None => icon::from_name(FALLBACK_MIME_ICON).size(size).icon(), + } + } + pub fn title(&self) -> String { //TODO: show full title when there is a conflict if let Some(path) = &self.path_opt {