diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 000000000..3393fdae2 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,3 @@ +newline_style = "Unix" +# The "Default" setting has a heuristic which splits lines too aggresively. +use_small_heuristics = "Max" diff --git a/Cargo.lock b/Cargo.lock index 0ef123891..4b68a4ccc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,12 +57,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "arc-swap" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" - [[package]] name = "arrayref" version = "0.3.6" @@ -208,12 +202,6 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -[[package]] -name = "bytes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16" - [[package]] name = "cc" version = "1.0.60" @@ -276,15 +264,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "cloudabi" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" -dependencies = [ - "bitflags", -] - [[package]] name = "color_quant" version = "1.1.0" @@ -535,101 +514,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "futures" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95314d38584ffbfda215621d723e0a3906f032e03ae5551e650058dac83d4797" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0448174b01148032eed37ac4aed28963aaaa8cfa93569a08e5b479bbc6c2c151" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18eaa56102984bed2c88ea39026cff3ce3b4c7f508ca970cedf2450ea10d4e46" - -[[package]] -name = "futures-executor" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f8e0c9258abaea85e78ebdda17ef9666d390e987f006be6080dfe354b708cb" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1798854a4727ff944a7b12aa999f58ce7aa81db80d2dfaaf2ba06f065ddd2b" - -[[package]] -name = "futures-macro" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3ca3f17d6e8804ae5d3df7a7d35b2b3a6fe89dac84b31872720fc3060a0b11" - -[[package]] -name = "futures-task" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d502af37186c4fef99453df03e374683f8a1eec9dcc1e66b3b82dc8278ce3c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "futures-util" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abcb44342f62e6f3e8ac427b8aa815f724fd705dfad060b18ac7866c15bb8e34" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", -] - [[package]] name = "generic-array" version = "0.12.3" @@ -825,15 +709,6 @@ dependencies = [ "tiff", ] -[[package]] -name = "instant" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" -dependencies = [ - "cfg-if", -] - [[package]] name = "itertools" version = "0.9.0" @@ -919,15 +794,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lock_api" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.11" @@ -999,44 +865,12 @@ dependencies = [ "autocfg", ] -[[package]] -name = "mio" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53a6ea5f38c0a48ca42159868c6d8e1bd56c0451238856cc08d58563643bdc3" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" -dependencies = [ - "socket2", - "winapi", -] - [[package]] name = "more-asserts" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" -[[package]] -name = "ntapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a31937dea023539c72ddae0e3571deadc1414b300483fa7aaec176168cfa9d2" -dependencies = [ - "winapi", -] - [[package]] name = "num-integer" version = "0.1.43" @@ -1102,7 +936,7 @@ checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" [[package]] name = "onefetch" -version = "2.5.0" +version = "2.6.0" dependencies = [ "ansi_term 0.12.1", "askalono", @@ -1112,7 +946,6 @@ dependencies = [ "color_quant", "colored", "error-chain", - "futures", "git2", "image", "json", @@ -1123,7 +956,6 @@ dependencies = [ "regex", "strum", "tokei", - "tokio", ] [[package]] @@ -1138,19 +970,8 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.7.2", -] - -[[package]] -name = "parking_lot" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" -dependencies = [ - "instant", - "lock_api 0.4.1", - "parking_lot_core 0.8.0", + "lock_api", + "parking_lot_core", ] [[package]] @@ -1160,22 +981,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ "cfg-if", - "cloudabi 0.0.3", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" -dependencies = [ - "cfg-if", - "cloudabi 0.1.0", - "instant", + "cloudabi", "libc", "redox_syscall", "smallvec", @@ -1246,38 +1052,6 @@ dependencies = [ "sha-1", ] -[[package]] -name = "pin-project" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkg-config" version = "0.3.18" @@ -1308,12 +1082,6 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" -[[package]] -name = "proc-macro-nested" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" - [[package]] name = "proc-macro2" version = "1.0.24" @@ -1423,9 +1191,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", @@ -1435,9 +1203,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "rmp" @@ -1548,22 +1316,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "signal-hook-registry" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" -dependencies = [ - "arc-swap", - "libc", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - [[package]] name = "slug" version = "0.1.4" @@ -1579,18 +1331,6 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" -[[package]] -name = "socket2" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "winapi", -] - [[package]] name = "strsim" version = "0.8.0" @@ -1745,7 +1485,7 @@ dependencies = [ "ignore", "log", "once_cell", - "parking_lot 0.10.2", + "parking_lot", "rayon", "regex", "serde", @@ -1755,39 +1495,6 @@ dependencies = [ "toml", ] -[[package]] -name = "tokio" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f1b20504fd0aa9dab3ae17e8c4dd9431e5e08fd6921689f9745a4004883a17" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "lazy_static", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot 0.11.0", - "pin-project-lite", - "signal-hook-registry", - "slab", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48caa7b66c7a6ec943edf78d21a594fbeb24e536c781da67d5c32edec54103f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "toml" version = "0.5.6" diff --git a/Cargo.toml b/Cargo.toml index 562f87ffc..3ee4bb37f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ edition = "2018" name = "onefetch" description = "Git repository summary on your terminal" -version = "2.5.0" +version = "2.6.0" authors = ["o2sh "] readme = "README.md" license = "MIT" @@ -30,8 +30,6 @@ clap = "2.33.3" strum = { version = "0.19.5", features = ["derive"] } image = "0.23.11" regex = "1" -futures = "0.3.7" -tokio = { version = "0.3.2", features = ["full"] } error-chain = "0.12" [target.'cfg(windows)'.dependencies] diff --git a/README.md b/README.md index 00d9a54db..3150f886f 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,4 @@ As of now, onefetch supports more than 50 different programming languages; if yo Contributions are very welcome! See [CONTRIBUTING](https://github.com/o2sh/onefetch/blob/master/CONTRIBUTING.md) for more info. -### More: \[[Installation](https://github.com/o2sh/onefetch/wiki/Installation)\] \[[Getting Started](https://github.com/o2sh/onefetch/wiki/getting-started)\] \[[Wiki](https://github.com/o2sh/onefetch/wiki)\] +### More: \[[Wiki](https://github.com/o2sh/onefetch/wiki)\] \[[Installation](https://github.com/o2sh/onefetch/wiki/Installation)\] \[[Getting Started](https://github.com/o2sh/onefetch/wiki/getting-started)\] diff --git a/assets/go.png b/assets/go.png index 54952df11..75ab78f69 100644 Binary files a/assets/go.png and b/assets/go.png differ diff --git a/assets/linux.png b/assets/linux.png index 5f50c8c05..3e5267e15 100644 Binary files a/assets/linux.png and b/assets/linux.png differ diff --git a/onefetch.1 b/onefetch.1 index 4881231a6..c6505014b 100644 --- a/onefetch.1 +++ b/onefetch.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13. -.TH ONEFETCH "1" "October 2020" "onefetch 2.5.0" "User Commands" +.TH ONEFETCH "1" "November 2020" "onefetch 2.6.0" "User Commands" .SH NAME -onefetch \- manual page for onefetch 2.5.0 +onefetch \- manual page for onefetch 2.6.0 .SH DESCRIPTION -onefetch 2.5.0 +onefetch 2.6.0 Git repository summary on your terminal .SS "USAGE:" .IP diff --git a/resources/java.ascii b/resources/java.ascii index 38ebb06e4..fa977a369 100644 --- a/resources/java.ascii +++ b/resources/java.ascii @@ -9,14 +9,14 @@ {0} ||| ||| {0} || || {0} | | -{1} ssss s ss -{1} ssssssssssssssss ss -{1} s ss -{1} ssssssssssssssss sss +{1} #### # ## +{1} ################ ## +{1} # ## +{1} ################ ### {1} -{1} ssssssssssssss -{1}ssss sssssss s -{1}sssss ssss -{1} sssssssssssssssssssss s -{1} sss -{1} sssssssssssssss \ No newline at end of file +{1} ############## +{1}#### ####### # +{1}##### #### +{1} ##################### # +{1} ### +{1} ############### \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6755751d3..e9ad490e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,9 +50,5 @@ fn main() { } fn is_git_installed() -> bool { - Command::new("git") - .arg("--version") - .stdout(Stdio::null()) - .status() - .is_ok() + Command::new("git").arg("--version").stdout(Stdio::null()).status().is_ok() } diff --git a/src/onefetch/ascii_art.rs b/src/onefetch/ascii_art.rs index 6d5a0d162..558f9c573 100644 --- a/src/onefetch/ascii_art.rs +++ b/src/onefetch/ascii_art.rs @@ -29,13 +29,7 @@ impl<'a> AsciiArt<'a> { (acc_s.min(line_s), acc_e.max(line_e)) }); - AsciiArt { - content: Box::new(lines.into_iter()), - colors, - bold, - start, - end, - } + AsciiArt { content: Box::new(lines.into_iter()), colors, bold, start, end } } pub fn width(&self) -> usize { assert!(self.end >= self.start); @@ -96,9 +90,8 @@ struct Tokens<'a>(&'a str); impl<'a> Iterator for Tokens<'a> { type Item = Token; fn next(&mut self) -> Option { - let (s, tok) = color_token(self.0) - .or_else(|| space_token(self.0)) - .or_else(|| char_token(self.0))?; + let (s, tok) = + color_token(self.0).or_else(|| space_token(self.0)).or_else(|| char_token(self.0))?; self.0 = s; Some(tok) @@ -129,9 +122,7 @@ impl<'a> Tokens<'a> { last_non_space } fn leading_spaces(&mut self) -> usize { - self.take_while(|token| !token.is_solid()) - .filter(|token| token.is_space()) - .count() + self.take_while(|token| !token.is_solid()).filter(|token| token.is_space()).count() } fn truncate(self, mut start: usize, end: usize) -> impl 'a + Iterator { assert!(start <= end); @@ -269,40 +260,19 @@ mod test { let colors_shim = Vec::new(); - assert_eq!( - Tokens("").render(&colors_shim, 0, 0, true), - "\u{1b}[1;37m\u{1b}[0m" - ); + assert_eq!(Tokens("").render(&colors_shim, 0, 0, true), "\u{1b}[1;37m\u{1b}[0m"); - assert_eq!( - Tokens(" ").render(&colors_shim, 0, 0, true), - "\u{1b}[1;37m\u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 0, 0, true), "\u{1b}[1;37m\u{1b}[0m"); - assert_eq!( - Tokens(" ").render(&colors_shim, 0, 5, true), - "\u{1b}[1;37m \u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 0, 5, true), "\u{1b}[1;37m \u{1b}[0m"); - assert_eq!( - Tokens(" ").render(&colors_shim, 1, 5, true), - "\u{1b}[1;37m \u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 1, 5, true), "\u{1b}[1;37m \u{1b}[0m"); - assert_eq!( - Tokens(" ").render(&colors_shim, 3, 5, true), - "\u{1b}[1;37m \u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 3, 5, true), "\u{1b}[1;37m \u{1b}[0m"); - assert_eq!( - Tokens(" ").render(&colors_shim, 0, 4, true), - "\u{1b}[1;37m \u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 0, 4, true), "\u{1b}[1;37m \u{1b}[0m"); - assert_eq!( - Tokens(" ").render(&colors_shim, 0, 3, true), - "\u{1b}[1;37m \u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 0, 3, true), "\u{1b}[1;37m \u{1b}[0m"); assert_eq!( Tokens(" {1} {5} {9} a").render(&colors_shim, 4, 10, true), @@ -310,22 +280,13 @@ mod test { ); // Tests for bold disabled - assert_eq!( - Tokens(" ").render(&colors_shim, 0, 0, false), - "\u{1b}[37m\u{1b}[0m" - ); - assert_eq!( - Tokens(" ").render(&colors_shim, 0, 5, false), - "\u{1b}[37m \u{1b}[0m" - ); + assert_eq!(Tokens(" ").render(&colors_shim, 0, 0, false), "\u{1b}[37m\u{1b}[0m"); + assert_eq!(Tokens(" ").render(&colors_shim, 0, 5, false), "\u{1b}[37m \u{1b}[0m"); } #[test] fn truncate() { - assert_eq!( - Tokens("").truncate(0, 0).collect::>(), - Tokens("").collect::>() - ); + assert_eq!(Tokens("").truncate(0, 0).collect::>(), Tokens("").collect::>()); assert_eq!( Tokens(" ").truncate(0, 0).collect::>(), @@ -353,9 +314,7 @@ mod test { ); assert_eq!( - Tokens(" {1} {5} {9} a") - .truncate(4, 10) - .collect::>(), + Tokens(" {1} {5} {9} a").truncate(4, 10).collect::>(), Tokens("{1}{5} {9} a").collect::>() ); } diff --git a/src/onefetch/cli.rs b/src/onefetch/cli.rs index ae1f879ad..d300af922 100644 --- a/src/onefetch/cli.rs +++ b/src/onefetch/cli.rs @@ -36,12 +36,11 @@ impl Cli { /// Build `Options` from command line arguments. pub fn new() -> Result { #[cfg(not(windows))] - let possible_backends = ["kitty", "sixel"]; + let possible_backends = ["kitty", "iterm", "sixel"]; #[cfg(windows)] let possible_backends = []; - let color_values = &[ - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", - ]; + let color_values = + &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"]; let matches = App::new(crate_name!()) .version(crate_version!()) .about(crate_description!()) @@ -239,7 +238,6 @@ impl Cli { let image_backend = if image.is_some() { if let Some(backend_name) = matches.value_of("image-backend") { - image_backends::check_if_supported(backend_name)?; image_backends::get_image_backend(backend_name) } else { image_backends::get_best_backend() diff --git a/src/onefetch/cli_utils.rs b/src/onefetch/cli_utils.rs index dc6710588..4fc042632 100644 --- a/src/onefetch/cli_utils.rs +++ b/src/onefetch/cli_utils.rs @@ -24,20 +24,25 @@ impl Printer { if self.info.config.art_off { buf.push_str(&info_str); } else if let Some(custom_image) = &self.info.config.image { - buf.push_str(&self.info.config.image_backend.as_ref().unwrap().add_image( - info_lines.map(|s| format!("{}{}", center_pad, s)).collect(), - custom_image, - self.info.config.image_colors, - )); + buf.push_str( + &self + .info + .config + .image_backend + .as_ref() + .unwrap() + .add_image( + info_lines.map(|s| format!("{}{}", center_pad, s)).collect(), + custom_image, + self.info.config.image_colors, + ) + .chain_err(|| "Error while drawing image")?, + ); } else { let mut logo_lines = if let Some(custom_ascii) = &self.info.config.ascii_input { AsciiArt::new(custom_ascii, &colors, !self.info.config.no_bold) } else { - AsciiArt::new( - self.get_ascii(), - &self.info.colors, - !self.info.config.no_bold, - ) + AsciiArt::new(self.get_ascii(), &self.info.colors, !self.info.config.no_bold) }; loop { diff --git a/src/onefetch/error.rs b/src/onefetch/error.rs index 667602cb8..ce0537e94 100644 --- a/src/onefetch/error.rs +++ b/src/onefetch/error.rs @@ -7,6 +7,8 @@ error_chain! { Clap(::clap::Error) #[cfg(feature = "application")]; Io(::std::io::Error); ParseIntError(::std::num::ParseIntError); + Image(image::error::ImageError); + Utf8(std::string::FromUtf8Error); } } diff --git a/src/onefetch/image_backends/iterm.rs b/src/onefetch/image_backends/iterm.rs new file mode 100644 index 000000000..8f2392b91 --- /dev/null +++ b/src/onefetch/image_backends/iterm.rs @@ -0,0 +1,65 @@ +use { + crate::onefetch::error::*, + image::{imageops::FilterType, DynamicImage, GenericImageView}, + libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ}, + std::env, +}; + +pub struct ITermBackend {} + +impl ITermBackend { + pub fn new() -> Self { + ITermBackend {} + } + + pub fn supported() -> bool { + let term_program = env::var("TERM_PROGRAM").unwrap_or_else(|_| "".to_string()); + term_program == "iTerm.app" + } +} + +impl super::ImageBackend for ITermBackend { + fn add_image( + &self, + lines: Vec, + image: &DynamicImage, + _colors: usize, + ) -> Result { + let tty_size = unsafe { + let tty_size: winsize = std::mem::zeroed(); + ioctl(STDOUT_FILENO, TIOCGWINSZ, &tty_size); + tty_size + }; + let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel); + let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel); + + // resize image to fit the text height with the Lanczos3 algorithm + let image = image.resize( + u32::max_value(), + (lines.len() as f64 / height_ratio) as u32, + FilterType::Lanczos3, + ); + let _image_columns = width_ratio * f64::from(image.width()); + let image_rows = height_ratio * f64::from(image.height()); + + let mut bytes: Vec = Vec::new(); + image.write_to(&mut bytes, image::ImageOutputFormat::Png)?; + let encoded_image = base64::encode(bytes); + let mut image_data = Vec::::new(); + + image_data.extend(b"\x1B]1337;File=inline=1:"); + image_data.extend(encoded_image.bytes()); + image_data.extend(b"\x07"); + + image_data.extend(format!("\x1B[{}A", image_rows as u32 - 1).as_bytes()); // move cursor to start of image + let mut i = 0; + for line in &lines { + image_data.extend(format!("\x1B[s{}\x1B[u\x1B[1B", line).as_bytes()); + i += 1; + } + image_data + .extend(format!("\n\x1B[{}B", lines.len().max(image_rows as usize) - i).as_bytes()); // move cursor to end of image + + Ok(String::from_utf8(image_data)?) + } +} diff --git a/src/onefetch/image_backends/kitty.rs b/src/onefetch/image_backends/kitty.rs index 8ce7b7e86..37f064378 100644 --- a/src/onefetch/image_backends/kitty.rs +++ b/src/onefetch/image_backends/kitty.rs @@ -1,9 +1,11 @@ use { + crate::onefetch::error::*, image::{imageops::FilterType, DynamicImage, GenericImageView}, libc::{ c_void, ioctl, poll, pollfd, read, tcgetattr, tcsetattr, termios, winsize, ECHO, ICANON, POLLIN, STDIN_FILENO, STDOUT_FILENO, TCSANOW, TIOCGWINSZ, }, + std::env, std::time::Instant, }; @@ -15,6 +17,10 @@ impl KittyBackend { } pub fn supported() -> bool { + if !env::var("KITTY_WINDOW_ID").unwrap_or_else(|_| "".to_string()).is_empty() { + return true; + } + // save terminal attributes and disable canonical input processing mode let old_attributes = unsafe { let mut old_attributes: termios = std::mem::zeroed(); @@ -29,24 +35,13 @@ impl KittyBackend { // generate red rgba test image let mut test_image = Vec::::with_capacity(32 * 32 * 4); - test_image.extend( - std::iter::repeat([255, 0, 0, 255].iter()) - .take(32 * 32) - .flatten(), - ); + test_image.extend(std::iter::repeat([255, 0, 0, 255].iter()).take(32 * 32).flatten()); // print the test image with the action set to query - println!( - "\x1B_Gi=1,f=32,s=32,v=32,a=q;{}\x1B\\", - base64::encode(&test_image) - ); + println!("\x1B_Gi=1,f=32,s=32,v=32,a=q;{}\x1B\\", base64::encode(&test_image)); let start_time = Instant::now(); - let mut stdin_pollfd = pollfd { - fd: STDIN_FILENO, - events: POLLIN, - revents: 0, - }; + let mut stdin_pollfd = pollfd { fd: STDIN_FILENO, events: POLLIN, revents: 0 }; let allowed_bytes = [0x1B, b'_', b'G', b'\\']; let mut buf = Vec::::new(); loop { @@ -77,7 +72,12 @@ impl KittyBackend { } impl super::ImageBackend for KittyBackend { - fn add_image(&self, lines: Vec, image: &DynamicImage, _colors: usize) -> String { + fn add_image( + &self, + lines: Vec, + image: &DynamicImage, + _colors: usize, + ) -> Result { let tty_size = unsafe { let tty_size: winsize = std::mem::zeroed(); ioctl(STDOUT_FILENO, TIOCGWINSZ, &tty_size); @@ -98,25 +98,16 @@ impl super::ImageBackend for KittyBackend { // convert the image to rgba samples let rgba_image = image.to_rgba(); let flat_samples = rgba_image.as_flat_samples(); - let raw_image = flat_samples - .image_slice() - .expect("Conversion from image to rgba samples failed"); - assert_eq!( - image.width() as usize * image.height() as usize * 4, - raw_image.len() - ); + let raw_image = + flat_samples.image_slice().expect("Conversion from image to rgba samples failed"); + assert_eq!(image.width() as usize * image.height() as usize * 4, raw_image.len()); let encoded_image = base64::encode(&raw_image); // image data is base64 encoded let mut image_data = Vec::::new(); for chunk in encoded_image.as_bytes().chunks(4096) { // send a 4096 byte chunk of base64 encoded rgba image data image_data.extend( - format!( - "\x1B_Gf=32,s={},v={},m=1,a=T;", - image.width(), - image.height() - ) - .as_bytes(), + format!("\x1B_Gf=32,s={},v={},m=1,a=T;", image.width(), image.height()).as_bytes(), ); image_data.extend(chunk); image_data.extend(b"\x1B\\"); @@ -131,6 +122,6 @@ impl super::ImageBackend for KittyBackend { image_data .extend(format!("\n\x1B[{}B", lines.len().max(image_rows as usize) - i).as_bytes()); // move cursor to end of image - String::from_utf8(image_data).unwrap() + Ok(String::from_utf8(image_data)?) } } diff --git a/src/onefetch/image_backends/mod.rs b/src/onefetch/image_backends/mod.rs index 90479ae11..ef0fed95d 100644 --- a/src/onefetch/image_backends/mod.rs +++ b/src/onefetch/image_backends/mod.rs @@ -1,19 +1,23 @@ use crate::onefetch::error::*; use image::DynamicImage; +#[cfg(not(windows))] +pub mod iterm; #[cfg(not(windows))] pub mod kitty; #[cfg(not(windows))] pub mod sixel; pub trait ImageBackend { - fn add_image(&self, lines: Vec, image: &DynamicImage, colors: usize) -> String; + fn add_image(&self, lines: Vec, image: &DynamicImage, colors: usize) -> Result; } #[cfg(not(windows))] pub fn get_best_backend() -> Option> { if kitty::KittyBackend::supported() { Some(Box::new(kitty::KittyBackend::new())) + } else if iterm::ITermBackend::supported() { + Some(Box::new(iterm::ITermBackend::new())) } else if sixel::SixelBackend::supported() { Some(Box::new(sixel::SixelBackend::new())) } else { @@ -21,32 +25,11 @@ pub fn get_best_backend() -> Option> { } } -pub fn check_if_supported(backend_name: &str) -> Result<()> { - #[cfg(windows)] - return Err(format!("{} image backend is not supported", backend_name).into()); - - #[cfg(not(windows))] - match backend_name { - "kitty" => { - if !kitty::KittyBackend::supported() { - return Err("Kitty image backend is not supported".into()); - } - } - "sixel" => { - if !sixel::SixelBackend::supported() { - return Err("Sixel image backend is not supported".into()); - } - } - _ => unreachable!(), - }; - - Ok(()) -} - pub fn get_image_backend(backend_name: &str) -> Option> { #[cfg(not(windows))] let backend = Some(match backend_name { "kitty" => Box::new(kitty::KittyBackend::new()) as Box, + "iterm" => Box::new(iterm::ITermBackend::new()) as Box, "sixel" => Box::new(sixel::SixelBackend::new()) as Box, _ => unreachable!(), }); diff --git a/src/onefetch/image_backends/sixel.rs b/src/onefetch/image_backends/sixel.rs index 8ebe79395..954f6f21c 100644 --- a/src/onefetch/image_backends/sixel.rs +++ b/src/onefetch/image_backends/sixel.rs @@ -1,4 +1,5 @@ use { + crate::onefetch::error::*, color_quant::NeuQuant, image::{ imageops::{colorops, FilterType}, @@ -35,11 +36,7 @@ impl SixelBackend { println!("\x1B[c"); let start_time = Instant::now(); - let mut stdin_pollfd = pollfd { - fd: STDIN_FILENO, - events: POLLIN, - revents: 0, - }; + let mut stdin_pollfd = pollfd { fd: STDIN_FILENO, events: POLLIN, revents: 0 }; let mut buf = Vec::::new(); loop { // check for timeout while polling to avoid blocking the main thread @@ -71,7 +68,7 @@ impl SixelBackend { } impl super::ImageBackend for SixelBackend { - fn add_image(&self, lines: Vec, image: &DynamicImage, colors: usize) -> String { + fn add_image(&self, lines: Vec, image: &DynamicImage, colors: usize) -> Result { let tty_size = unsafe { let tty_size: winsize = std::mem::zeroed(); ioctl(STDOUT_FILENO, TIOCGWINSZ, &tty_size); @@ -97,7 +94,11 @@ impl super::ImageBackend for SixelBackend { // reduce the amount of colors using dithering colorops::dither( &mut rgba_image, - &NeuQuant::new(10, colors, flat_samples.image_slice().unwrap()), + &NeuQuant::new( + 10, + colors, + flat_samples.image_slice().ok_or("Error while slicing the image")?, + ), ); let rgb_image = ImageBuffer::from_fn(rgba_image.width(), rgba_image.height(), |x, y| { let rgba_pixel = rgba_image.get_pixel(x, y); @@ -164,6 +165,6 @@ impl super::ImageBackend for SixelBackend { image_data .extend(format!("\n\x1B[{}B", lines.len().max(image_rows as usize) - i).as_bytes()); // move cursor to end of image - String::from_utf8(image_data).unwrap() + Ok(String::from_utf8(image_data)?) } } diff --git a/src/onefetch/info.rs b/src/onefetch/info.rs index 088cc3e79..1e0b173cb 100644 --- a/src/onefetch/info.rs +++ b/src/onefetch/info.rs @@ -6,7 +6,7 @@ use { colored::{Color, ColoredString, Colorize}, git2::Repository, regex::Regex, - tokio::process::Command, + std::process::Command, }; pub struct Info { @@ -103,11 +103,7 @@ impl std::fmt::Display for Info { } if !self.config.disabled_fields.languages && !self.languages.is_empty() { - let title = if self.languages.len() > 1 { - "Languages" - } else { - "Language" - }; + let title = if self.languages.len() > 1 { "Languages" } else { "Language" }; let languages_str = self.get_language_field(title); @@ -129,11 +125,7 @@ impl std::fmt::Display for Info { } if !self.config.disabled_fields.authors && !self.authors.is_empty() { - let title = if self.authors.len() > 1 { - "Authors" - } else { - "Author" - }; + let title = if self.authors.len() > 1 { "Authors" } else { "Author" }; let author_str = self.get_author_field(title); @@ -219,33 +211,19 @@ impl std::fmt::Display for Info { } impl Info { - #[tokio::main] - pub async fn new(config: Cli) -> Result { + pub fn new(config: Cli) -> Result { let repo = Repository::discover(&config.path) .chain_err(|| "Could not find a valid git repo on the current path")?; - let workdir = repo - .workdir() - .chain_err(|| "Unable to run onefetch on bare git repo")?; + let workdir = repo.workdir().chain_err(|| "Unable to run onefetch on bare git repo")?; let workdir_str = workdir.to_str().unwrap(); let (languages_stats, number_of_lines) = Language::get_language_statistics(workdir_str, &config.excluded)?; - - let ( - git_history, - (number_of_tags, number_of_branches), - (git_v, git_user), - version, - pending, - repo_size, - ) = futures::join!( - Info::get_git_history(workdir_str, config.no_merges), - Info::get_number_of_tags_branches(workdir_str), - Info::get_git_version_and_username(workdir_str), - Info::get_version(workdir_str), - Info::get_pending_changes(workdir_str), - Info::get_packed_size(workdir_str) - ); - + let git_history = Info::get_git_history(workdir_str, config.no_merges); + let (number_of_tags, number_of_branches) = Info::get_number_of_tags_branches(workdir_str); + let (git_v, git_user) = Info::get_git_version_and_username(workdir_str); + let version = Info::get_version(workdir_str); + let pending = Info::get_pending_changes(workdir_str); + let repo_size = Info::get_packed_size(workdir_str); let (repository_name, repository_url) = Info::get_repo_name_and_url(&repo); let current_commit_info = Info::get_current_commit_info(&repo); let creation_date = Info::get_creation_date(&git_history); @@ -289,7 +267,7 @@ impl Info { }) } - async fn get_git_history(dir: &str, no_merges: bool) -> Vec { + fn get_git_history(dir: &str, no_merges: bool) -> Vec { let mut args = vec!["-C", dir, "log"]; if no_merges { args.push("--no-merges"); @@ -297,22 +275,17 @@ impl Info { args.push("--pretty=%cr\t%ae\t%an"); - let output = Command::new("git") - .args(args) - .output() - .await - .expect("Failed to execute git."); + let output = Command::new("git").args(args).output().expect("Failed to execute git."); let output = String::from_utf8_lossy(&output.stdout); output.lines().map(|x| x.to_string()).collect::>() } - async fn get_number_of_tags_branches(dir: &str) -> (usize, usize) { + fn get_number_of_tags_branches(dir: &str) -> (usize, usize) { let tags = { let output = Command::new("git") .args(vec!["-C", dir, "tag"]) .output() - .await .expect("Failed to execute git."); let tags = String::from_utf8_lossy(&output.stdout); @@ -324,7 +297,6 @@ impl Info { let output = Command::new("git") .args(vec!["-C", dir, "branch", "-r"]) .output() - .await .expect("Failed to execute git."); let branches = String::from_utf8_lossy(&output.stdout); @@ -340,9 +312,7 @@ impl Info { } fn get_repo_name_and_url(repo: &Repository) -> (String, String) { - let config = repo - .config() - .chain_err(|| "Could not retrieve git configuration data"); + let config = repo.config().chain_err(|| "Could not retrieve git configuration data"); let mut remote_url = String::new(); let mut repository_name = String::new(); @@ -375,15 +345,10 @@ impl Info { } fn get_current_commit_info(repo: &Repository) -> Result { - let head = repo - .head() - .chain_err(|| "Error while retrieving reference information")?; - let head_oid = head - .target() - .ok_or("Error while retrieving reference information")?; - let refs = repo - .references() - .chain_err(|| "Error while retrieving reference information")?; + let head = repo.head().chain_err(|| "Error while retrieving reference information")?; + let head_oid = head.target().ok_or("Error while retrieving reference information")?; + let refs = + repo.references().chain_err(|| "Error while retrieving reference information")?; let refs_info = refs .filter_map(|reference| match reference { Ok(reference) => match (reference.target(), reference.shorthand()) { @@ -410,9 +375,7 @@ impl Info { let author_email = line.split('\t').collect::>()[1].to_string(); let author_name = line.split('\t').collect::>()[2].to_string(); let commit_count = authors.entry(author_email.to_string()).or_insert(0); - author_name_by_email - .entry(author_email.to_string()) - .or_insert(author_name); + author_name_by_email.entry(author_email.to_string()).or_insert(author_name); *commit_count += 1; total_commits += 1; } @@ -426,11 +389,7 @@ impl Info { .into_iter() .map(|(author, count)| { ( - author_name_by_email - .get(&author) - .unwrap() - .trim_matches('\'') - .to_string(), + author_name_by_email.get(&author).unwrap().trim_matches('\'').to_string(), count, count * 100 / total_commits, ) @@ -440,12 +399,9 @@ impl Info { authors } - async fn get_git_version_and_username(dir: &str) -> (String, String) { - let version = Command::new("git") - .arg("--version") - .output() - .await - .expect("Failed to execute git."); + fn get_git_version_and_username(dir: &str) -> (String, String) { + let version = + Command::new("git").arg("--version").output().expect("Failed to execute git."); let version = String::from_utf8_lossy(&version.stdout).replace('\n', ""); let username = Command::new("git") @@ -455,13 +411,12 @@ impl Info { .arg("--get") .arg("user.name") .output() - .await .expect("Failed to execute git."); let username = String::from_utf8_lossy(&username.stdout).replace('\n', ""); (version, username) } - async fn get_version(dir: &str) -> Result { + fn get_version(dir: &str) -> Result { let output = Command::new("git") .arg("-C") .arg(dir) @@ -469,7 +424,6 @@ impl Info { .arg("--abbrev=0") .arg("--tags") .output() - .await .expect("Failed to execute git."); let output = String::from_utf8_lossy(&output.stdout); @@ -486,14 +440,13 @@ impl Info { number_of_commits.to_string() } - async fn get_pending_changes(dir: &str) -> Result { + fn get_pending_changes(dir: &str) -> Result { let output = Command::new("git") .arg("-C") .arg(dir) .arg("status") .arg("--porcelain") .output() - .await .expect("Failed to execute git."); let output = String::from_utf8_lossy(&output.stdout); @@ -535,21 +488,18 @@ impl Info { } } - async fn get_packed_size(dir: &str) -> Result { + fn get_packed_size(dir: &str) -> Result { let output = Command::new("git") .arg("-C") .arg(dir) .arg("count-objects") .arg("-vH") .output() - .await .expect("Failed to execute git."); let output = String::from_utf8_lossy(&output.stdout); let lines = output.to_string(); - let size_line = lines - .split('\n') - .find(|line| line.starts_with("size-pack:")); + let size_line = lines.split('\n').find(|line| line.starts_with("size-pack:")); let repo_size = match size_line { None => "??", @@ -561,7 +511,6 @@ impl Info { .arg(dir) .arg("ls-files") .output() - .await .expect("Failed to execute git."); // To check if command executed successfully or not let error = &output.stderr; @@ -659,11 +608,8 @@ impl Info { } fn get_formatted_subtitle_label(&self, label: &str) -> ColoredString { - let formatted_label = format!( - "{}{} ", - label.color(self.color_set.subtitle), - ":".color(self.color_set.colon) - ); + let formatted_label = + format!("{}{} ", label.color(self.color_set.subtitle), ":".color(self.color_set.colon)); self.bold(&formatted_label) } diff --git a/src/onefetch/info_fields.rs b/src/onefetch/info_fields.rs index 6442cf3ab..dfa671be2 100644 --- a/src/onefetch/info_fields.rs +++ b/src/onefetch/info_fields.rs @@ -45,9 +45,7 @@ pub enum InfoFields { } pub fn get_disabled_fields(fields_to_hide: Vec) -> Result { - let mut disabled_fields = InfoFieldOn { - ..Default::default() - }; + let mut disabled_fields = InfoFieldOn { ..Default::default() }; for field in fields_to_hide.iter() { let item = InfoFields::from_str(field.to_lowercase().as_str()) diff --git a/src/onefetch/language.rs b/src/onefetch/language.rs index 39c45f491..b622934bc 100644 --- a/src/onefetch/language.rs +++ b/src/onefetch/language.rs @@ -194,11 +194,11 @@ define_languages! { { Haskell, "haskell.ascii", "Haskell", define_colors!( [Color::Cyan, Color::Magenta, Color::Blue] : [Color::TrueColor{ r:69, g:58, b:98 }, Color::TrueColor{ r:94, g:80, b:134 }, Color::TrueColor{ r:143, g:78, b:139 }] ) }, { Html, "html.ascii", "HTML", define_colors!( [Color::Red, Color::White] ) }, { Idris, "idris.ascii", "Idris", define_colors!( [Color::Red] ) }, - { Java, "java.ascii", "Java", define_colors!( [Color::Blue, Color::Red] : [Color::TrueColor{ r:244, g:67 ,b:54}, Color::TrueColor{ r:22, g:101 ,b:192} ] ) }, + { Java, "java.ascii", "Java", define_colors!( [Color::Red, Color::Blue] : [Color::TrueColor{ r:244, g:67 ,b:54}, Color::TrueColor{ r:22, g:101 ,b:192} ] ) }, { JavaScript, "javascript.ascii", "JavaScript", define_colors!( [Color::Yellow] : [Color::TrueColor{ r:236, g:230 ,b:83} ]) }, { Jsx, "jsx.ascii", "JSX", define_colors!( [Color::Yellow] ) }, { Julia, "julia.ascii", "Julia", define_colors!( [Color::White, Color::Blue, Color::Green, Color::Red, Color::Magenta] ) }, - { Jupyter, "jupyter.ascii", "Jupyter-Notebooks", define_colors!( [Color::White, Color::Yellow, Color::White] ), "jupyter-notebooks" }, + { Jupyter, "jupyter.ascii", "Jupyter-Notebooks", define_colors!( [Color::White, Color::Yellow, Color::White] : [Color::TrueColor{ r:255, g:255 ,b:255}, Color::TrueColor{ r:255, g:112 ,b:15}, Color::TrueColor{ r:158, g:158 ,b:158} ] ), "jupyter-notebooks" }, { Kotlin, "kotlin.ascii", "Kotlin", define_colors!( [Color::Blue, Color::Yellow, Color::Magenta] ) }, { Lisp, "lisp.ascii", "Lisp", define_colors!( [Color::White] ) }, { Lua, "lua.ascii", "Lua", define_colors!( [Color::Blue, Color::White] ) }, @@ -339,21 +339,14 @@ impl Language { let mut languages = tokei::Languages::new(); let required_languages = get_all_language_types(); - let tokei_config = Config { - types: Some(required_languages), - ..Config::default() - }; + let tokei_config = Config { types: Some(required_languages), ..Config::default() }; if !ignored_directories.is_empty() { let re = Regex::new(r"((.*)+/)+(.*)").unwrap(); let mut v = Vec::with_capacity(ignored_directories.len()); for ignored in ignored_directories { if re.is_match(&ignored) { - let p = if ignored.starts_with('/') { - "**" - } else { - "**/" - }; + let p = if ignored.starts_with('/') { "**" } else { "**/" }; v.push(format!("{}{}", p, ignored)); } else { v.push(String::from(ignored)); diff --git a/src/onefetch/license.rs b/src/onefetch/license.rs index e6c7a9c5e..db4b61854 100644 --- a/src/onefetch/license.rs +++ b/src/onefetch/license.rs @@ -6,10 +6,8 @@ use { const LICENSE_FILES: [&str; 3] = ["LICENSE", "LICENCE", "COPYING"]; -static CACHE_DATA: &[u8] = include_bytes!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/resources/licenses/cache.bin.zstd" -)); +static CACHE_DATA: &[u8] = + include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/resources/licenses/cache.bin.zstd")); const MIN_THRESHOLD: f32 = 0.8; pub struct Detector { @@ -25,9 +23,7 @@ impl Detector { pub fn get_project_license(&self, dir: &str) -> Result { fn is_license_file>(file_name: S) -> bool { - LICENSE_FILES - .iter() - .any(|&name| file_name.as_ref().starts_with(name)) + LICENSE_FILES.iter().any(|&name| file_name.as_ref().starts_with(name)) } let mut output = fs::read_dir(dir)