Merge pull request #15 from teohhanhui/riir
Implement recolored ascii output
This commit is contained in:
commit
46b618252f
8 changed files with 694 additions and 118 deletions
155
Cargo.lock
generated
155
Cargo.lock
generated
|
@ -26,6 +26,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_colours"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a1558bd2075d341b9ca698ec8eb6fcc55a746b1fc4255585aad5b141d918a80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
|
@ -114,26 +120,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more"
|
|
||||||
version = "1.0.0-beta.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d"
|
|
||||||
dependencies = [
|
|
||||||
"derive_more-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more-impl"
|
|
||||||
version = "1.0.0-beta.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "directories"
|
name = "directories"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
|
@ -152,7 +138,16 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enable-ansi-support"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa4ff3ae2a9aa54bf7ee0983e59303224de742818c1822d89f07da9856d9bc60"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -161,12 +156,28 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fast-srgb8"
|
name = "fast-srgb8"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
|
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -194,12 +205,14 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
name = "hyfetch"
|
name = "hyfetch"
|
||||||
version = "1.4.11"
|
version = "1.4.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"ansi_colours",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bpaf",
|
"bpaf",
|
||||||
"chrono",
|
"chrono",
|
||||||
"deranged",
|
"deranged",
|
||||||
"derive_more",
|
|
||||||
"directories",
|
"directories",
|
||||||
|
"enable-ansi-support",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"palette",
|
"palette",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -208,6 +221,7 @@ dependencies = [
|
||||||
"serde_path_to_error",
|
"serde_path_to_error",
|
||||||
"shell-words",
|
"shell-words",
|
||||||
"strum",
|
"strum",
|
||||||
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -291,6 +305,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.21"
|
version = "0.4.21"
|
||||||
|
@ -433,6 +453,19 @@ version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
@ -549,6 +582,18 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.61"
|
version = "1.0.61"
|
||||||
|
@ -763,6 +808,21 @@ dependencies = [
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
|
"windows_aarch64_msvc 0.42.2",
|
||||||
|
"windows_i686_gnu 0.42.2",
|
||||||
|
"windows_i686_msvc 0.42.2",
|
||||||
|
"windows_x86_64_gnu 0.42.2",
|
||||||
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
|
"windows_x86_64_msvc 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
@ -772,6 +832,15 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -803,6 +872,12 @@ dependencies = [
|
||||||
"windows_x86_64_msvc 0.52.5",
|
"windows_x86_64_msvc 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -815,6 +890,12 @@ version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -827,6 +908,12 @@ version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -845,6 +932,12 @@ version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -857,6 +950,12 @@ version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -869,6 +968,12 @@ version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -881,6 +986,12 @@ version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
|
|
@ -12,23 +12,24 @@ repository = "https://github.com/hykilpikonna/hyfetch"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
aho-corasick = { version = "1.1.3", default-features = false }
|
||||||
ansi_colours = { version = "1.2.2", default-features = false }
|
ansi_colours = { version = "1.2.2", default-features = false }
|
||||||
|
# anstream = { version = "0.6.14", default-features = false }
|
||||||
anyhow = { version = "1.0.86", default-features = false }
|
anyhow = { version = "1.0.86", default-features = false }
|
||||||
bpaf = { version = "0.9.12", default-features = false }
|
bpaf = { version = "0.9.12", default-features = false }
|
||||||
bytemuck = { version = "1.16.1", default-features = false }
|
|
||||||
chrono = { version = "0.4.38", default-features = false }
|
chrono = { version = "0.4.38", default-features = false }
|
||||||
deranged = { version = "0.3.11", default-features = false }
|
deranged = { version = "0.3.11", default-features = false }
|
||||||
derive_more = { version = "1.0.0-beta.6", default-features = false }
|
|
||||||
directories = { version = "5.0.1", default-features = false }
|
directories = { version = "5.0.1", default-features = false }
|
||||||
|
enable-ansi-support = { version = "0.2.1", default-features = false }
|
||||||
indexmap = { version = "2.2.6", default-features = false }
|
indexmap = { version = "2.2.6", default-features = false }
|
||||||
palette = { version = "0.7.6", default-features = false }
|
palette = { version = "0.7.6", default-features = false }
|
||||||
regex = { version = "1.10.5", default-features = false }
|
regex = { version = "1.10.5", default-features = false }
|
||||||
rgb = { version = "0.8.37", default-features = false }
|
|
||||||
serde = { version = "1.0.203", default-features = false }
|
serde = { version = "1.0.203", default-features = false }
|
||||||
serde_json = { version = "1.0.118", default-features = false }
|
serde_json = { version = "1.0.118", default-features = false }
|
||||||
serde_path_to_error = { version = "0.1.16", default-features = false }
|
serde_path_to_error = { version = "0.1.16", default-features = false }
|
||||||
shell-words = { version = "1.1.0", default-features = false }
|
shell-words = { version = "1.1.0", default-features = false }
|
||||||
strum = { version = "0.26.3", default-features = false }
|
strum = { version = "0.26.3", default-features = false }
|
||||||
|
tempfile = { version = "3.10.1", default-features = false }
|
||||||
thiserror = { version = "1.0.61", default-features = false }
|
thiserror = { version = "1.0.61", default-features = false }
|
||||||
tracing = { version = "0.1.40", default-features = false }
|
tracing = { version = "0.1.40", default-features = false }
|
||||||
tracing-subscriber = { version = "0.3.18", default-features = false }
|
tracing-subscriber = { version = "0.3.18", default-features = false }
|
||||||
|
|
|
@ -10,23 +10,22 @@ license = { workspace = true }
|
||||||
default-run = "hyfetch"
|
default-run = "hyfetch"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# ansi_colours = { workspace = true, features = ["rgb"] }
|
aho-corasick = { workspace = true, features = ["perf-literal", "std"] }
|
||||||
|
ansi_colours = { workspace = true, features = [] }
|
||||||
|
# anstream = { workspace = true, features = ["auto"] }
|
||||||
anyhow = { workspace = true, features = ["std"] }
|
anyhow = { workspace = true, features = ["std"] }
|
||||||
bpaf = { workspace = true, features = [] }
|
bpaf = { workspace = true, features = [] }
|
||||||
# bytemuck = { workspace = true, features = [] }
|
|
||||||
chrono = { workspace = true, features = ["clock", "std"] }
|
chrono = { workspace = true, features = ["clock", "std"] }
|
||||||
deranged = { workspace = true, features = ["serde", "std"] }
|
deranged = { workspace = true, features = ["serde", "std"] }
|
||||||
derive_more = { workspace = true, features = ["from", "from_str", "into", "std"] }
|
|
||||||
directories = { workspace = true, features = [] }
|
directories = { workspace = true, features = [] }
|
||||||
indexmap = { workspace = true, features = ["serde", "std"] }
|
indexmap = { workspace = true, features = ["serde", "std"] }
|
||||||
palette = { workspace = true, features = ["std"] }
|
palette = { workspace = true, features = ["std"] }
|
||||||
regex = { workspace = true, features = ["perf", "std", "unicode"] }
|
|
||||||
# rgb = { workspace = true, features = [] }
|
|
||||||
serde = { workspace = true, features = ["derive", "std"] }
|
serde = { workspace = true, features = ["derive", "std"] }
|
||||||
serde_json = { workspace = true, features = ["std"] }
|
serde_json = { workspace = true, features = ["std"] }
|
||||||
serde_path_to_error = { workspace = true, features = [] }
|
serde_path_to_error = { workspace = true, features = [] }
|
||||||
shell-words = { workspace = true, features = ["std"] }
|
shell-words = { workspace = true, features = ["std"] }
|
||||||
strum = { workspace = true, features = ["derive", "std"] }
|
strum = { workspace = true, features = ["derive", "std"] }
|
||||||
|
tempfile = { workspace = true, features = [] }
|
||||||
thiserror = { workspace = true, features = [] }
|
thiserror = { workspace = true, features = [] }
|
||||||
tracing = { workspace = true, features = ["attributes", "std"] }
|
tracing = { workspace = true, features = ["attributes", "std"] }
|
||||||
tracing-subscriber = { workspace = true, features = ["ansi", "fmt", "smallvec", "std", "tracing-log"] }
|
tracing-subscriber = { workspace = true, features = ["ansi", "fmt", "smallvec", "std", "tracing-log"] }
|
||||||
|
@ -36,6 +35,9 @@ indexmap = { workspace = true, features = ["std"] }
|
||||||
regex = { workspace = true, features = ["perf", "std", "unicode"] }
|
regex = { workspace = true, features = ["perf", "std", "unicode"] }
|
||||||
unicode-normalization = { workspace = true, features = ["std"] }
|
unicode-normalization = { workspace = true, features = ["std"] }
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
enable-ansi-support = { workspace = true, features = [] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["autocomplete", "color"]
|
default = ["autocomplete", "color"]
|
||||||
autocomplete = ["bpaf/autocomplete"]
|
autocomplete = ["bpaf/autocomplete"]
|
||||||
|
|
|
@ -13,6 +13,9 @@ use hyfetch::utils::get_cache_path;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
#[cfg(windows)]
|
||||||
|
enable_ansi_support::enable_ansi_support();
|
||||||
|
|
||||||
let options = options().run();
|
let options = options().run();
|
||||||
|
|
||||||
init_tracing_subsriber(options.debug).context("failed to init tracing subscriber")?;
|
init_tracing_subsriber(options.debug).context("failed to init tracing subscriber")?;
|
||||||
|
@ -97,7 +100,8 @@ fn main() -> Result<()> {
|
||||||
};
|
};
|
||||||
let asc = config
|
let asc = config
|
||||||
.color_align
|
.color_align
|
||||||
.recolor_ascii(asc, color_profile, color_mode, config.light_dark);
|
.recolor_ascii(asc, color_profile, color_mode, config.light_dark)
|
||||||
|
.context("failed to recolor ascii")?;
|
||||||
neofetch_util::run(asc, backend, args).context("failed to run")?;
|
neofetch_util::run(asc, backend, args).context("failed to run")?;
|
||||||
|
|
||||||
if options.ask_exit {
|
if options.ask_exit {
|
||||||
|
|
|
@ -1,16 +1,63 @@
|
||||||
use std::num::ParseFloatError;
|
use std::num::{ParseFloatError, ParseIntError};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use anyhow::Result;
|
use aho_corasick::AhoCorasick;
|
||||||
|
use ansi_colours::AsRGB;
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
use deranged::RangedU8;
|
use deranged::RangedU8;
|
||||||
use derive_more::{From, FromStr, Into};
|
use palette::Srgb;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::types::AnsiMode;
|
||||||
|
|
||||||
|
const MINECRAFT_COLORS: [(&str, &str); 30] = [
|
||||||
|
// Minecraft formatting codes
|
||||||
|
// ==========================
|
||||||
|
("&0", "\x1b[38;5;0m"),
|
||||||
|
("&1", "\x1b[38;5;4m"),
|
||||||
|
("&2", "\x1b[38;5;2m"),
|
||||||
|
("&3", "\x1b[38;5;6m"),
|
||||||
|
("&4", "\x1b[38;5;1m"),
|
||||||
|
("&5", "\x1b[38;5;5m"),
|
||||||
|
("&6", "\x1b[38;5;3m"),
|
||||||
|
("&7", "\x1b[38;5;7m"),
|
||||||
|
("&8", "\x1b[38;5;8m"),
|
||||||
|
("&9", "\x1b[38;5;12m"),
|
||||||
|
("&a", "\x1b[38;5;10m"),
|
||||||
|
("&b", "\x1b[38;5;14m"),
|
||||||
|
("&c", "\x1b[38;5;9m"),
|
||||||
|
("&d", "\x1b[38;5;13m"),
|
||||||
|
("&e", "\x1b[38;5;11m"),
|
||||||
|
("&f", "\x1b[38;5;15m"),
|
||||||
|
("&l", "\x1b[1m"), // Enable bold text
|
||||||
|
("&o", "\x1b[3m"), // Enable italic text
|
||||||
|
("&n", "\x1b[4m"), // Enable underlined text
|
||||||
|
("&k", "\x1b[8m"), // Enable hidden text
|
||||||
|
("&m", "\x1b[9m"), // Enable strikethrough text
|
||||||
|
("&r", "\x1b[0m"), // Reset everything
|
||||||
|
// Extended codes (not officially in Minecraft)
|
||||||
|
// ============================================
|
||||||
|
("&-", "\n"), // Line break
|
||||||
|
("&~", "\x1b[39m"), // Reset text color
|
||||||
|
("&*", "\x1b[49m"), // Reset background color
|
||||||
|
("&L", "\x1b[22m"), // Disable bold text
|
||||||
|
("&O", "\x1b[23m"), // Disable italic text
|
||||||
|
("&N", "\x1b[24m"), // Disable underlined text
|
||||||
|
("&K", "\x1b[28m"), // Disable hidden text
|
||||||
|
("&M", "\x1b[29m"), // Disable strikethrough text
|
||||||
|
];
|
||||||
|
const RGB_COLOR_PATTERNS: [&str; 2] = ["&gf(", "&gb("];
|
||||||
|
|
||||||
|
static MINECRAFT_COLORS_AC: OnceLock<(AhoCorasick, Box<[&str; 30]>)> = OnceLock::new();
|
||||||
|
static RGB_COLORS_AC: OnceLock<AhoCorasick> = OnceLock::new();
|
||||||
|
|
||||||
/// Represents the lightness component in HSL.
|
/// Represents the lightness component in HSL.
|
||||||
///
|
///
|
||||||
/// The range of valid values is
|
/// The range of valid values is
|
||||||
/// `(`[`Lightness::MIN`]`..=`[`Lightness::MAX`]`)`.
|
/// `(`[`Lightness::MIN`]`..=`[`Lightness::MAX`]`)`.
|
||||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Deserialize, Into, Serialize)]
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
|
||||||
pub struct Lightness(f32);
|
pub struct Lightness(f32);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -37,21 +84,7 @@ pub enum ParseLightnessError {
|
||||||
/// The range of valid values as supported in neofetch is
|
/// The range of valid values as supported in neofetch is
|
||||||
/// `(`[`NeofetchAsciiIndexedColor::MIN`]`..
|
/// `(`[`NeofetchAsciiIndexedColor::MIN`]`..
|
||||||
/// =`[`NeofetchAsciiIndexedColor::MAX`]`)`.
|
/// =`[`NeofetchAsciiIndexedColor::MAX`]`)`.
|
||||||
#[derive(
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
|
||||||
Copy,
|
|
||||||
Clone,
|
|
||||||
Eq,
|
|
||||||
PartialEq,
|
|
||||||
Ord,
|
|
||||||
PartialOrd,
|
|
||||||
Hash,
|
|
||||||
Debug,
|
|
||||||
Deserialize,
|
|
||||||
From,
|
|
||||||
FromStr,
|
|
||||||
Into,
|
|
||||||
Serialize,
|
|
||||||
)]
|
|
||||||
pub struct NeofetchAsciiIndexedColor(
|
pub struct NeofetchAsciiIndexedColor(
|
||||||
RangedU8<{ NeofetchAsciiIndexedColor::MIN }, { NeofetchAsciiIndexedColor::MAX }>,
|
RangedU8<{ NeofetchAsciiIndexedColor::MIN }, { NeofetchAsciiIndexedColor::MAX }>,
|
||||||
);
|
);
|
||||||
|
@ -61,22 +94,21 @@ pub struct NeofetchAsciiIndexedColor(
|
||||||
///
|
///
|
||||||
/// The range of valid values depends on the number of unique colors in a
|
/// The range of valid values depends on the number of unique colors in a
|
||||||
/// certain preset.
|
/// certain preset.
|
||||||
#[derive(
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
|
||||||
Copy,
|
pub struct PresetIndexedColor(u8);
|
||||||
Clone,
|
|
||||||
Eq,
|
/// Whether the color is for foreground text or background color.
|
||||||
PartialEq,
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
Ord,
|
pub enum ForegroundBackground {
|
||||||
PartialOrd,
|
Foreground,
|
||||||
Hash,
|
Background,
|
||||||
Debug,
|
}
|
||||||
Deserialize,
|
|
||||||
From,
|
pub trait ToAnsiString {
|
||||||
FromStr,
|
/// Converts RGB to ANSI escape code.
|
||||||
Into,
|
fn to_ansi_string(&self, mode: AnsiMode, foreground_background: ForegroundBackground)
|
||||||
Serialize,
|
-> String;
|
||||||
)]
|
}
|
||||||
pub struct PresetIndexedColor(usize);
|
|
||||||
|
|
||||||
impl Lightness {
|
impl Lightness {
|
||||||
const MAX: f32 = 1.0f32;
|
const MAX: f32 = 1.0f32;
|
||||||
|
@ -107,7 +139,175 @@ impl FromStr for Lightness {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Lightness> for f32 {
|
||||||
|
fn from(value: Lightness) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NeofetchAsciiIndexedColor {
|
impl NeofetchAsciiIndexedColor {
|
||||||
const MAX: u8 = 6;
|
const MAX: u8 = 6;
|
||||||
const MIN: u8 = 1;
|
const MIN: u8 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for NeofetchAsciiIndexedColor {
|
||||||
|
type Error = deranged::TryFromIntError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self(value.try_into()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for NeofetchAsciiIndexedColor {
|
||||||
|
type Err = deranged::ParseIntError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self(s.parse()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NeofetchAsciiIndexedColor> for u8 {
|
||||||
|
fn from(value: NeofetchAsciiIndexedColor) -> Self {
|
||||||
|
value.0.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for PresetIndexedColor {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for PresetIndexedColor {
|
||||||
|
type Err = ParseIntError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self(s.parse()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PresetIndexedColor> for u8 {
|
||||||
|
fn from(value: PresetIndexedColor) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToAnsiString for Srgb<u8> {
|
||||||
|
fn to_ansi_string(
|
||||||
|
&self,
|
||||||
|
mode: AnsiMode,
|
||||||
|
foreground_background: ForegroundBackground,
|
||||||
|
) -> String {
|
||||||
|
let c: u8 = match foreground_background {
|
||||||
|
ForegroundBackground::Foreground => 38,
|
||||||
|
ForegroundBackground::Background => 48,
|
||||||
|
};
|
||||||
|
match mode {
|
||||||
|
AnsiMode::Rgb => {
|
||||||
|
let [r, g, b]: [u8; 3] = (*self).into();
|
||||||
|
format!("\x1b[{c};2;{r};{g};{b}m")
|
||||||
|
},
|
||||||
|
AnsiMode::Ansi256 => {
|
||||||
|
let rgb: [u8; 3] = (*self).into();
|
||||||
|
let indexed = rgb.to_ansi256();
|
||||||
|
format!("\x1b[{c};5;{indexed}m")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces extended minecraft color codes in message.
|
||||||
|
///
|
||||||
|
/// Returns message with escape codes.
|
||||||
|
pub fn color<S>(msg: S, mode: AnsiMode) -> Result<String>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let msg = msg.as_ref();
|
||||||
|
|
||||||
|
let msg = {
|
||||||
|
let (ac, escape_codes) = MINECRAFT_COLORS_AC.get_or_init(|| {
|
||||||
|
let (color_codes, escape_codes): (Vec<_>, Vec<_>) =
|
||||||
|
MINECRAFT_COLORS.into_iter().unzip();
|
||||||
|
let ac = AhoCorasick::new(color_codes).unwrap();
|
||||||
|
(
|
||||||
|
ac,
|
||||||
|
escape_codes.try_into().expect(
|
||||||
|
"`MINECRAFT_COLORS` should have the same number of elements as \
|
||||||
|
`MINECRAFT_COLORS_AC.get_or_init(...).1`",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
ac.replace_all(msg, &escape_codes[..])
|
||||||
|
};
|
||||||
|
|
||||||
|
let ac = RGB_COLORS_AC.get_or_init(|| AhoCorasick::new(RGB_COLOR_PATTERNS).unwrap());
|
||||||
|
let mut dst = String::new();
|
||||||
|
let mut ret_err = None;
|
||||||
|
ac.replace_all_with(&msg, &mut dst, |m, _, dst| {
|
||||||
|
let start = m.end();
|
||||||
|
let end = msg[start..]
|
||||||
|
.find(')')
|
||||||
|
.ok_or_else(|| anyhow!("missing closing brace for color code"));
|
||||||
|
let end = match end {
|
||||||
|
Ok(end) => end,
|
||||||
|
Err(err) => {
|
||||||
|
ret_err = Some(err);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let code = &msg[start..end];
|
||||||
|
let foreground_background = if m.pattern().as_usize() == 0 {
|
||||||
|
ForegroundBackground::Foreground
|
||||||
|
} else {
|
||||||
|
ForegroundBackground::Background
|
||||||
|
};
|
||||||
|
|
||||||
|
let rgb: Srgb<u8> = if code.starts_with('#') {
|
||||||
|
let rgb = code.parse().context("failed to parse hex color");
|
||||||
|
match rgb {
|
||||||
|
Ok(rgb) => rgb,
|
||||||
|
Err(err) => {
|
||||||
|
ret_err = Some(err);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let rgb: Result<[&str; 3], _> = code
|
||||||
|
.split(&[',', ';', ' '])
|
||||||
|
.filter(|x| x.is_empty())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| anyhow!("wrong number of rgb components"));
|
||||||
|
let rgb = match rgb {
|
||||||
|
Ok(rgb) => rgb,
|
||||||
|
Err(err) => {
|
||||||
|
ret_err = Some(err);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let rgb = rgb
|
||||||
|
.into_iter()
|
||||||
|
.map(u8::from_str)
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.context("failed to parse rgb components");
|
||||||
|
let rgb: [u8; 3] = match rgb {
|
||||||
|
Ok(rgb) => rgb.try_into().unwrap(),
|
||||||
|
Err(err) => {
|
||||||
|
ret_err = Some(err);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
rgb.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
dst.push_str(&rgb.to_ansi_string(mode, foreground_background));
|
||||||
|
|
||||||
|
true
|
||||||
|
});
|
||||||
|
if let Some(err) = ret_err {
|
||||||
|
Err(err)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(dst)
|
||||||
|
}
|
||||||
|
|
|
@ -23,8 +23,12 @@ pub struct Config {
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn default_lightness(term: &LightDark) -> Lightness {
|
pub fn default_lightness(term: &LightDark) -> Lightness {
|
||||||
match term {
|
match term {
|
||||||
LightDark::Dark => Lightness::new(0.65).unwrap(),
|
LightDark::Dark => {
|
||||||
LightDark::Light => Lightness::new(0.4).unwrap(),
|
Lightness::new(0.65).expect("default lightness should not be invalid")
|
||||||
|
},
|
||||||
|
LightDark::Light => {
|
||||||
|
Lightness::new(0.4).expect("default lightness should not be invalid")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,29 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
use std::io::Write;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::process::ExitStatusExt as _;
|
use std::os::unix::process::ExitStatusExt as _;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::{Command, ExitStatus};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use std::{env, fmt};
|
use std::{env, fmt, iter};
|
||||||
|
|
||||||
|
use aho_corasick::AhoCorasick;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use regex::Regex;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::color_util::{NeofetchAsciiIndexedColor, PresetIndexedColor};
|
use crate::color_util::{
|
||||||
|
color, ForegroundBackground, NeofetchAsciiIndexedColor, PresetIndexedColor, ToAnsiString,
|
||||||
|
};
|
||||||
use crate::distros::Distro;
|
use crate::distros::Distro;
|
||||||
use crate::presets::ColorProfile;
|
use crate::presets::ColorProfile;
|
||||||
use crate::types::{AnsiMode, Backend, LightDark};
|
use crate::types::{AnsiMode, Backend, LightDark};
|
||||||
|
|
||||||
const NEOFETCH_COLOR_PATTERN: &str = r"\$\{c[0-6]\}";
|
const NEOFETCH_COLOR_PATTERNS: [&str; 6] = ["${c1}", "${c2}", "${c3}", "${c4}", "${c5}", "${c6}"];
|
||||||
static NEOFETCH_COLOR_RE: OnceLock<Regex> = OnceLock::new();
|
static NEOFETCH_COLORS_AC: OnceLock<AhoCorasick> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
#[serde(tag = "mode")]
|
#[serde(tag = "mode")]
|
||||||
|
@ -39,14 +43,101 @@ pub enum ColorAlignment {
|
||||||
|
|
||||||
impl ColorAlignment {
|
impl ColorAlignment {
|
||||||
/// Uses the color alignment to recolor an ascii art.
|
/// Uses the color alignment to recolor an ascii art.
|
||||||
|
#[tracing::instrument(level = "debug")]
|
||||||
pub fn recolor_ascii(
|
pub fn recolor_ascii(
|
||||||
&self,
|
&self,
|
||||||
asc: String,
|
asc: String,
|
||||||
color_profile: ColorProfile,
|
color_profile: ColorProfile,
|
||||||
color_mode: AnsiMode,
|
color_mode: AnsiMode,
|
||||||
term: LightDark,
|
term: LightDark,
|
||||||
) -> String {
|
) -> Result<String> {
|
||||||
todo!()
|
let asc = fill_starting(asc).context("failed to fill in starting neofetch color codes")?;
|
||||||
|
|
||||||
|
let reset = color("&~&*", color_mode).expect("color reset should not be invalid");
|
||||||
|
|
||||||
|
let asc = match self {
|
||||||
|
Self::Horizontal {
|
||||||
|
fore_back: Some((fore, back)),
|
||||||
|
}
|
||||||
|
| Self::Vertical {
|
||||||
|
fore_back: Some((fore, back)),
|
||||||
|
} => {
|
||||||
|
let fore: u8 = (*fore).into();
|
||||||
|
let back: u8 = (*back).into();
|
||||||
|
|
||||||
|
// Replace foreground colors
|
||||||
|
let asc = asc.replace(
|
||||||
|
&format!("${{c{fore}}}"),
|
||||||
|
&color(
|
||||||
|
match term {
|
||||||
|
LightDark::Light => "&0",
|
||||||
|
LightDark::Dark => "&f",
|
||||||
|
},
|
||||||
|
color_mode,
|
||||||
|
)
|
||||||
|
.expect("foreground color should not be invalid"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let lines: Vec<_> = asc.split('\n').collect();
|
||||||
|
|
||||||
|
// Add new colors
|
||||||
|
let asc = match self {
|
||||||
|
Self::Horizontal { .. } => {
|
||||||
|
let length = lines.len();
|
||||||
|
let length: u8 = length.try_into().expect("`length` should fit in `u8`");
|
||||||
|
let ColorProfile { colors } = color_profile
|
||||||
|
.with_length(length)
|
||||||
|
.context("failed to spread color profile to length")?;
|
||||||
|
let mut asc = String::new();
|
||||||
|
for (i, line) in lines.into_iter().enumerate() {
|
||||||
|
let line = line.replace(
|
||||||
|
&format!("${{c{back}}}"),
|
||||||
|
&colors[i].to_ansi_string(color_mode, {
|
||||||
|
// note: this is "background" in the ascii art, but foreground
|
||||||
|
// text in terminal
|
||||||
|
ForegroundBackground::Foreground
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
asc.push_str(&line);
|
||||||
|
asc.push_str(&reset);
|
||||||
|
asc.push('\n');
|
||||||
|
}
|
||||||
|
asc
|
||||||
|
},
|
||||||
|
Self::Vertical { .. } => {
|
||||||
|
unimplemented!(
|
||||||
|
"vertical color alignment with fore and back colors not implemented"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove existing colors
|
||||||
|
let asc = {
|
||||||
|
let ac = NEOFETCH_COLORS_AC
|
||||||
|
.get_or_init(|| AhoCorasick::new(NEOFETCH_COLOR_PATTERNS).unwrap());
|
||||||
|
const N: usize = NEOFETCH_COLOR_PATTERNS.len();
|
||||||
|
let replacements: [&str; N] = iter::repeat("")
|
||||||
|
.take(N)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
ac.replace_all(&asc, &replacements)
|
||||||
|
};
|
||||||
|
|
||||||
|
asc
|
||||||
|
},
|
||||||
|
Self::Horizontal { fore_back: None } | Self::Vertical { fore_back: None } => {
|
||||||
|
todo!()
|
||||||
|
},
|
||||||
|
Self::Custom { colors } => {
|
||||||
|
todo!()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(asc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,8 +200,24 @@ where
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug")]
|
||||||
pub fn run(asc: String, backend: Backend, args: Option<&Vec<String>>) -> Result<()> {
|
pub fn run(asc: String, backend: Backend, args: Option<&Vec<String>>) -> Result<()> {
|
||||||
todo!()
|
match backend {
|
||||||
|
Backend::Neofetch => {
|
||||||
|
run_neofetch(asc, args).context("failed to run neofetch")?;
|
||||||
|
},
|
||||||
|
Backend::Fastfetch => {
|
||||||
|
todo!();
|
||||||
|
},
|
||||||
|
Backend::FastfetchOld => {
|
||||||
|
todo!();
|
||||||
|
},
|
||||||
|
Backend::Qwqfetch => {
|
||||||
|
todo!();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets distro ascii width and height, ignoring color code.
|
/// Gets distro ascii width and height, ignoring color code.
|
||||||
|
@ -120,18 +227,26 @@ where
|
||||||
{
|
{
|
||||||
let asc = asc.as_ref();
|
let asc = asc.as_ref();
|
||||||
|
|
||||||
let Some(width) = NEOFETCH_COLOR_RE
|
let asc = {
|
||||||
.get_or_init(|| Regex::new(NEOFETCH_COLOR_PATTERN).unwrap())
|
let ac =
|
||||||
.replace_all(asc, "")
|
NEOFETCH_COLORS_AC.get_or_init(|| AhoCorasick::new(NEOFETCH_COLOR_PATTERNS).unwrap());
|
||||||
.split('\n')
|
const N: usize = NEOFETCH_COLOR_PATTERNS.len();
|
||||||
.map(|line| line.len())
|
let replacements: [&str; N] = iter::repeat("")
|
||||||
.max()
|
.take(N)
|
||||||
else {
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
ac.replace_all(asc, &replacements)
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(width) = asc.split('\n').map(|line| line.len()).max() else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
let width: u8 = width.try_into().expect("`width` should fit in `u8`");
|
||||||
let height = asc.split('\n').count();
|
let height = asc.split('\n').count();
|
||||||
|
let height: u8 = height.try_into().expect("`height` should fit in `u8`");
|
||||||
|
|
||||||
(width as u8, height as u8)
|
(width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes sure every line are the same width.
|
/// Makes sure every line are the same width.
|
||||||
|
@ -146,13 +261,69 @@ where
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
for line in asc.split('\n') {
|
for line in asc.split('\n') {
|
||||||
let (line_w, _) = ascii_size(line);
|
let (line_w, _) = ascii_size(line);
|
||||||
|
buf.push_str(line);
|
||||||
let pad = " ".repeat((w - line_w) as usize);
|
let pad = " ".repeat((w - line_w) as usize);
|
||||||
buf.push_str(&format!("{line}{pad}\n"))
|
buf.push_str(&pad);
|
||||||
|
buf.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fills the missing starting placeholders.
|
||||||
|
///
|
||||||
|
/// e.g. `"${c1}...\n..."` -> `"${c1}...\n${c1}..."`
|
||||||
|
fn fill_starting<S>(asc: S) -> Result<String>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let asc = asc.as_ref();
|
||||||
|
|
||||||
|
let ac = NEOFETCH_COLORS_AC.get_or_init(|| AhoCorasick::new(NEOFETCH_COLOR_PATTERNS).unwrap());
|
||||||
|
|
||||||
|
let mut new = String::new();
|
||||||
|
let mut last = None;
|
||||||
|
for line in asc.split('\n') {
|
||||||
|
let mut matches = ac.find_iter(line).peekable();
|
||||||
|
|
||||||
|
match matches.peek() {
|
||||||
|
Some(m) if m.start() == 0 => {
|
||||||
|
// line starts with neofetch color code, do nothing
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
new.push_str(last.ok_or_else(|| {
|
||||||
|
anyhow!("failed to find neofetch color code from a previous line")
|
||||||
|
})?);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
new.push_str(line);
|
||||||
|
new.push('\n');
|
||||||
|
|
||||||
|
// Get the last placeholder for the next line
|
||||||
|
if let Some(m) = matches.last() {
|
||||||
|
last = Some(&line[m.span()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(new)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs neofetch command.
|
||||||
|
#[tracing::instrument(level = "debug")]
|
||||||
|
fn run_neofetch_command<S>(args: &[S]) -> Result<()>
|
||||||
|
where
|
||||||
|
S: AsRef<OsStr> + fmt::Debug,
|
||||||
|
{
|
||||||
|
let mut command = make_neofetch_command(args).context("failed to make neofetch command")?;
|
||||||
|
|
||||||
|
let status = command
|
||||||
|
.status()
|
||||||
|
.context("failed to execute neofetch command as child process")?;
|
||||||
|
process_command_status(&status).context("neofetch command exited with error")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs neofetch command, returning the piped stdout output.
|
/// Runs neofetch command, returning the piped stdout output.
|
||||||
#[tracing::instrument(level = "debug")]
|
#[tracing::instrument(level = "debug")]
|
||||||
fn run_neofetch_command_piped<S>(args: &[S]) -> Result<String>
|
fn run_neofetch_command_piped<S>(args: &[S]) -> Result<String>
|
||||||
|
@ -165,26 +336,7 @@ where
|
||||||
.output()
|
.output()
|
||||||
.context("failed to execute neofetch as child process")?;
|
.context("failed to execute neofetch as child process")?;
|
||||||
debug!(?output, "neofetch output");
|
debug!(?output, "neofetch output");
|
||||||
|
process_command_status(&output.status).context("neofetch command exited with error")?;
|
||||||
if !output.status.success() {
|
|
||||||
let err = if let Some(code) = output.status.code() {
|
|
||||||
anyhow!("neofetch process exited with status code: {code}")
|
|
||||||
} else {
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
anyhow!(
|
|
||||||
"neofetch process terminated by signal: {}",
|
|
||||||
output
|
|
||||||
.status
|
|
||||||
.signal()
|
|
||||||
.expect("either one of status code or signal should be set")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
unimplemented!("status code not expected to be `None` on non-Unix platforms")
|
|
||||||
};
|
|
||||||
Err(err)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let out = String::from_utf8(output.stdout)
|
let out = String::from_utf8(output.stdout)
|
||||||
.context("failed to process neofetch output as it contains invalid UTF-8")?
|
.context("failed to process neofetch output as it contains invalid UTF-8")?
|
||||||
|
@ -210,8 +362,67 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_command_status(status: &ExitStatus) -> Result<()> {
|
||||||
|
if status.success() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let err = if let Some(code) = status.code() {
|
||||||
|
anyhow!("child process exited with status code: {code}")
|
||||||
|
} else {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
anyhow!(
|
||||||
|
"child process terminated by signal: {}",
|
||||||
|
status
|
||||||
|
.signal()
|
||||||
|
.expect("either one of status code or signal should be set")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
unimplemented!("status code not expected to be `None` on non-Unix platforms")
|
||||||
|
};
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug")]
|
#[tracing::instrument(level = "debug")]
|
||||||
fn get_distro_name() -> Result<String> {
|
fn get_distro_name() -> Result<String> {
|
||||||
run_neofetch_command_piped(&["ascii_distro_name"])
|
run_neofetch_command_piped(&["ascii_distro_name"])
|
||||||
.context("failed to get distro name from neofetch")
|
.context("failed to get distro name from neofetch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs neofetch with colors.
|
||||||
|
#[tracing::instrument(level = "debug")]
|
||||||
|
fn run_neofetch(asc: String, args: Option<&Vec<String>>) -> Result<()> {
|
||||||
|
// Escape backslashes here because backslashes are escaped in neofetch for
|
||||||
|
// printf
|
||||||
|
let asc = asc.replace('\\', r"\\");
|
||||||
|
|
||||||
|
// Write temp file
|
||||||
|
let mut temp_file =
|
||||||
|
NamedTempFile::with_prefix("ascii.txt").context("failed to create temp file for ascii")?;
|
||||||
|
temp_file
|
||||||
|
.write_all(asc.as_bytes())
|
||||||
|
.context("failed to write ascii to temp file")?;
|
||||||
|
|
||||||
|
// Call neofetch with the temp file
|
||||||
|
let temp_file_path = temp_file.into_temp_path();
|
||||||
|
let args = {
|
||||||
|
let mut v = vec![
|
||||||
|
"--ascii",
|
||||||
|
"--source",
|
||||||
|
temp_file_path
|
||||||
|
.to_str()
|
||||||
|
.expect("temp file path should not contain invalid UTF-8"),
|
||||||
|
"--ascii-colors",
|
||||||
|
];
|
||||||
|
if let Some(args) = args {
|
||||||
|
let args: Vec<_> = args.iter().map(|s| &**s).collect();
|
||||||
|
v.extend(args);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
};
|
||||||
|
run_neofetch_command(&args).context("failed to run neofetch command")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -146,8 +146,9 @@ impl Preset {
|
||||||
// sourced from https://www.flagcolorcodes.com/autoromantic
|
// sourced from https://www.flagcolorcodes.com/autoromantic
|
||||||
Self::Autoromantic => ColorProfile::from_hex_colors(
|
Self::Autoromantic => ColorProfile::from_hex_colors(
|
||||||
// symbol interpreted
|
// symbol interpreted
|
||||||
vec!["#99D9EA", "#99D9EA", "#3DA542", "#7F7F7F", "#7F7F7F"],
|
vec!["#99D9EA", "#3DA542", "#7F7F7F"],
|
||||||
),
|
)
|
||||||
|
.and_then(|c| c.with_weights(vec![2, 1, 2])),
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/autosexual
|
// sourced from https://www.flagcolorcodes.com/autosexual
|
||||||
Self::Autosexual => ColorProfile::from_hex_colors(vec!["#99D9EA", "#7F7F7F"]),
|
Self::Autosexual => ColorProfile::from_hex_colors(vec!["#99D9EA", "#7F7F7F"]),
|
||||||
|
@ -192,15 +193,17 @@ impl Preset {
|
||||||
|
|
||||||
// used colorpicker to source form https://www.deviantart.com/pride-flags/art/Demifae-870194777
|
// used colorpicker to source form https://www.deviantart.com/pride-flags/art/Demifae-870194777
|
||||||
Self::Demifae => ColorProfile::from_hex_colors(vec![
|
Self::Demifae => ColorProfile::from_hex_colors(vec![
|
||||||
"#7F7F7F", "#7F7F7F", "#C5C5C5", "#C5C5C5", "#97C3A4", "#C4DEAE", "#FFFFFF",
|
"#7F7F7F", "#C5C5C5", "#97C3A4", "#C4DEAE", "#FFFFFF", "#FCA2C5", "#AB7EDF",
|
||||||
"#FCA2C5", "#AB7EDF", "#C5C5C5", "#C5C5C5", "#7F7F7F", "#7F7F7F",
|
"#C5C5C5", "#7F7F7F",
|
||||||
]),
|
])
|
||||||
|
.and_then(|c| c.with_weights(vec![2, 2, 1, 1, 1, 1, 1, 2, 2])),
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/demifaun
|
// sourced from https://www.flagcolorcodes.com/demifaun
|
||||||
Self::Demifaun => ColorProfile::from_hex_colors(vec![
|
Self::Demifaun => ColorProfile::from_hex_colors(vec![
|
||||||
"#7F7F7F", "#7F7F7F", "#C6C6C6", "#C6C6C6", "#FCC688", "#FFF19C", "#FFFFFF",
|
"#7F7F7F", "#C6C6C6", "#FCC688", "#FFF19C", "#FFFFFF", "#8DE0D5", "#9682EC",
|
||||||
"#8DE0D5", "#9682EC", "#C6C6C6", "#C6C6C6", "#7F7F7F", "#7F7F7F",
|
"#C6C6C6", "#7F7F7F",
|
||||||
]),
|
])
|
||||||
|
.and_then(|c| c.with_weights(vec![2, 2, 1, 1, 1, 1, 1, 2, 2])),
|
||||||
|
|
||||||
// yellow sourced from https://lgbtqia.fandom.com/f/p/4400000000000041031
|
// yellow sourced from https://lgbtqia.fandom.com/f/p/4400000000000041031
|
||||||
// other colors sourced from demiboy and demigirl flags
|
// other colors sourced from demiboy and demigirl flags
|
||||||
|
@ -272,9 +275,9 @@ impl Preset {
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/greygender
|
// sourced from https://www.flagcolorcodes.com/greygender
|
||||||
Self::Greygender => ColorProfile::from_hex_colors(vec![
|
Self::Greygender => ColorProfile::from_hex_colors(vec![
|
||||||
"#B3B3B3", "#B3B3B3", "#FFFFFF", "#062383", "#062383", "#FFFFFF", "#535353",
|
"#B3B3B3", "#FFFFFF", "#062383", "#FFFFFF", "#535353",
|
||||||
"#535353",
|
])
|
||||||
]),
|
.and_then(|c| c.with_weights(vec![2, 1, 2, 1, 2])),
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/greysexual
|
// sourced from https://www.flagcolorcodes.com/greysexual
|
||||||
Self::Greysexual => ColorProfile::from_hex_colors(vec![
|
Self::Greysexual => ColorProfile::from_hex_colors(vec![
|
||||||
|
@ -381,7 +384,7 @@ impl Preset {
|
||||||
"#FF6692", "#FF9A98", "#FFB883", "#FBFFA8", "#85BCFF", "#9D85FF", "#A510FF",
|
"#FF6692", "#FF9A98", "#FFB883", "#FBFFA8", "#85BCFF", "#9D85FF", "#A510FF",
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
.expect("presets should not be invalid")
|
.expect("preset color profiles should not be invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,6 +427,46 @@ impl ColorProfile {
|
||||||
Ok(Self::new(weighted_colors))
|
Ok(Self::new(weighted_colors))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new color profile, with the colors spread to the specified
|
||||||
|
/// length.
|
||||||
|
pub fn with_length(&self, length: u8) -> Result<Self> {
|
||||||
|
let orig_len = self.colors.len();
|
||||||
|
let orig_len: u8 = orig_len.try_into().expect("`orig_len` should fit in `u8`");
|
||||||
|
if length < orig_len {
|
||||||
|
unimplemented!("compressing length of color profile not implemented");
|
||||||
|
}
|
||||||
|
let center_i = (orig_len as f32 / 2.0).floor() as usize;
|
||||||
|
|
||||||
|
// How many copies of each color should be displayed at least?
|
||||||
|
let repeats = (length as f32 / orig_len as f32).floor() as usize;
|
||||||
|
let repeats: u8 = repeats.try_into().expect("`repeats` should fit in `u8`");
|
||||||
|
let mut weights: Vec<u8> = iter::repeat(repeats).take(orig_len as usize).collect();
|
||||||
|
|
||||||
|
// How many extra spaces left?
|
||||||
|
let mut extras = length % orig_len;
|
||||||
|
|
||||||
|
// If there is an odd space left, extend the center by one space
|
||||||
|
if extras % 2 == 1 {
|
||||||
|
extras -= 1;
|
||||||
|
weights[center_i] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add weight to border until there's no space left (extras must be even at this
|
||||||
|
// point)
|
||||||
|
// TODO: this gives a horrible result when `extras` is still large relative to
|
||||||
|
// `orig_len` - we should probably distribute even if slightly uneven
|
||||||
|
let mut border_i = 0;
|
||||||
|
while extras > 0 {
|
||||||
|
extras -= 2;
|
||||||
|
weights[border_i] += 1;
|
||||||
|
let weights_len = weights.len();
|
||||||
|
weights[weights_len - border_i - 1] += 1;
|
||||||
|
border_i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.with_weights(weights)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new color profile, with the colors lightened by a multiplier.
|
/// Creates a new color profile, with the colors lightened by a multiplier.
|
||||||
pub fn lighten(&self, multiplier: f32) -> Self {
|
pub fn lighten(&self, multiplier: f32) -> Self {
|
||||||
let mut rgb_f32_colors: Vec<LinSrgb> =
|
let mut rgb_f32_colors: Vec<LinSrgb> =
|
||||||
|
|
Loading…
Reference in a new issue