terminal-light-1.4.0/.cargo_vcs_info.json0000644000000001360000000000100137560ustar { "git": { "sha1": "1538dd456b1712f0c551eb487e580c391d7fe769" }, "path_in_vcs": "" }terminal-light-1.4.0/.gitignore000064400000000000000000000000431046102023000145330ustar 00000000000000Cargo.lock target .bacon-locations terminal-light-1.4.0/Cargo.lock0000644000000235500000000000100117360ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "coolor" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e93977247fb916abeee1ff8c6594c9b421fd9c26c9b720a3944acb2a7de27b" [[package]] name = "crossterm" version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ "bitflags 2.4.1", "crossterm_winapi", "libc", "mio", "parking_lot", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "lock_api" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] [[package]] name = "mio" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", "wasi", "windows-sys 0.36.1", ] [[package]] name = "nix" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.4.1", "cfg-if", "cfg_aliases", "libc", ] [[package]] name = "parking_lot" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-sys 0.32.0", ] [[package]] name = "proc-macro2" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "signal-hook" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", "mio", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] [[package]] name = "smallvec" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "terminal-light" version = "1.4.0" dependencies = [ "coolor", "crossterm", "thiserror", "xterm-query", ] [[package]] name = "thiserror" version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" dependencies = [ "windows_aarch64_msvc 0.32.0", "windows_i686_gnu 0.32.0", "windows_i686_msvc 0.32.0", "windows_x86_64_gnu 0.32.0", "windows_x86_64_msvc 0.32.0", ] [[package]] name = "windows-sys" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ "windows_aarch64_msvc 0.36.1", "windows_i686_gnu 0.36.1", "windows_i686_msvc 0.36.1", "windows_x86_64_gnu 0.36.1", "windows_x86_64_msvc 0.36.1", ] [[package]] name = "windows_aarch64_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "xterm-query" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f29504d0a2ca8c1714781c1395a8a660d2557b2cf9c9669433153fc903e9bfc" dependencies = [ "nix", "thiserror", ] terminal-light-1.4.0/Cargo.toml0000644000000020740000000000100117570ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "terminal-light" version = "1.4.0" authors = ["dystroy "] description = "tells you whether your terminal is dark or light" readme = "README.md" keywords = [ "terminal", "light", "dark", "color", ] categories = ["command-line-interface"] license = "MIT" repository = "https://github.com/Canop/terminal-light" [dependencies.coolor] version = "0.9" [dependencies.crossterm] version = "0.27" [dependencies.thiserror] version = "1.0" [dev-dependencies.crossterm] version = "0.27" [target."cfg(unix)".dependencies.xterm-query] version = "0.4" terminal-light-1.4.0/Cargo.toml.orig000064400000000000000000000012301046102023000154310ustar 00000000000000[package] name = "terminal-light" version = "1.4.0" edition = "2021" authors = ["dystroy "] repository = "https://github.com/Canop/terminal-light" description = "tells you whether your terminal is dark or light" keywords = ["terminal", "light", "dark", "color"] license = "MIT" categories = ["command-line-interface"] readme = "README.md" [dependencies] coolor = "0.9" crossterm = "0.27" thiserror = "1.0" [target.'cfg(unix)'.dependencies] xterm-query = "0.4" [dev-dependencies] crossterm = "0.27" [patch.crates-io] # coolor = { path = "../coolor" } # crossterm = { path = "../crossterm" } # xterm-query = { path = "../xterm-query" } terminal-light-1.4.0/LICENSE000064400000000000000000000020461046102023000135550ustar 00000000000000MIT License Copyright (c) 2021 Canop Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. terminal-light-1.4.0/README.md000064400000000000000000000057421046102023000140350ustar 00000000000000[![MIT][s2]][l2] [![Latest Version][s1]][l1] [![docs][s3]][l3] [![Chat on Miaou][s4]][l4] [s1]: https://img.shields.io/crates/v/terminal-light.svg [l1]: https://crates.io/crates/terminal-light [s2]: https://img.shields.io/badge/license-MIT-blue.svg [l2]: LICENSE [s3]: https://docs.rs/terminal-light/badge.svg [l3]: https://docs.rs/terminal-light/ [s4]: https://miaou.dystroy.org/static/shields/room.svg [l4]: https://miaou.dystroy.org/3 # terminal-light This crate answers the question *"Is the terminal dark or light?"*. It provides * the background color, either as RGB or ANSI * the background color's luma, which varies from 0 (black) to 1 (white) A use case in a TUI is to determine what set of colors would be most suitable depending on the terminal's background: ``` let should_use_light_skin = terminal_light::luma() .map_or(false, |luma| luma > 0.6); ``` If you have very specialized skins, you may choose a more precise switch: ``` match terminal_light::luma() { Ok(luma) if luma > 0.85 => { // Use a "light mode" skin. } Ok(luma) if luma < 0.2 => { // Use a "dark mode" skin. } _ => { // Either we couldn't determine the mode or it's kind of medium. // We should use an itermediate skin, or one defining the background. } } ``` See the included example: ![dark](doc/dark.png) ![light](doc/light.png) # Strategies Here are the various strategies automatically used by terminal-light to answer the big question: ## `$COLORFGBG` strategy This environment variable is set by some terminals, like konsole or the rxvt family. It can also be set by users. Its value is like `15;0` where the second number is the ANSI code for the background color. Upsides: * querying an env variable is a fast operation Downsides: * this env variable isn't always immediately updated when you change the color of the terminal * the value isn't precise: `0` is "dark" and `15` is "light" but the real RGB color is uncertain as the low ANSI codes are often modified by the user ## "Dynamic colors" OSC escape sequence strategy Modern terminals implement this xterm extension: a query making it possible to know the background color as RGB. Terminal-light sends the query on `stdout`, waits for the answer on `stdin` with a timeout of 20ms, then parses this answer. Upsides: * this works well on all tested unix terminals, including on MacOs * the value is precise (RGB) * the value is up to date when it's available Downsides: * waiting for stdin with a timeout isn't implemented on Windows in this crate (help welcome) * this isn't instant, a delay of 10 ms to get the answer isn't unusual * if a not compatible terminal doesn't answer at all, we're waiting for 20ms * it may fail on some terminal multiplexers ## Global strategy used by Terminal-light 1. if we're on a unix-like platform, we try the escape sequence strategy 2. if it failed or we're not on unix, we try the `$COLORFGBG` strategy 3. without a solution, we return a `TlError::Unsupported` error terminal-light-1.4.0/bacon.toml000064400000000000000000000034651046102023000145350ustar 00000000000000# This is a configuration file for the bacon tool # More info at https://github.com/Canop/bacon default_job = "check" [jobs] [jobs.check] command = ["cargo", "check", "--color", "always"] need_stdout = false [jobs.check-win] command = ["cargo", "check", "--color", "always", "--target", "x86_64-pc-windows-gnu"] need_stdout = false [jobs.check-all] command = ["cargo", "check", "--all-targets", "--color", "always"] need_stdout = false watch = ["tests", "benches", "examples"] [jobs.clippy] command = ["cargo", "clippy", "--color", "always"] need_stdout = false [jobs.clippy-all] command = ["cargo", "clippy", "--all-targets", "--color", "always"] need_stdout = false watch = ["tests", "benches", "examples"] [jobs.test] command = ["cargo", "test", "--color", "always"] need_stdout = true watch = ["tests"] [jobs.doc] command = ["cargo", "doc", "--color", "always", "--no-deps"] need_stdout = false # if the doc compiles, then it opens in your browser and bacon switches # to the previous job [jobs.doc-open] command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"] need_stdout = false on_success = "back" # so that we don't open the browser at each change # You can run your application and have the result displayed in bacon, # *if* it makes sense for this crate. You can run an example the same # way. Don't forget the `--color always` part or the errors won't be # properly parsed. [jobs.run] command = ["cargo", "run", "--color", "always"] need_stdout = true # You may define here keybindings that would be specific to # a project, for example a shortcut to launch a specific job. # Shortcuts to internal functions (scrolling, toggling, etc.) # should go in your personal prefs.toml file instead. [keybindings] a = "job:check-all" i = "job:initial" c = "job:clippy" d = "job:doc-open" t = "job:test" r = "job:run" terminal-light-1.4.0/doc/dark.png000064400000000000000000000330041046102023000147420ustar 00000000000000PNG  IHDRV-sBIT|dtEXtSoftwaregnome-screenshot>-tEXtCreation TimeWed 10 Nov 2021 08:38:06 PM CET* IDATxwx?%lBzIR*i(\EDtHUP^HH^B BHXɒf@sw9;+W{ J^;pPBEZph>k#q]PPP(=AJK@'np3\vb')U7g̀nȋ7y[e?'eeP9.Mfc* OeQpTf:?֮^yFΙNxx5>>%S( lUSWtd4 q@e\C0u;B9#Ǡ&Xgoxڄp-ɋ~|4q_Oؔ+ Ӿa2CT~ddv .QZW(w|{>Y6}0猼?'LӕpZbλ+ ,;;U֓k(3zV,f]EP ]'GoLrwau&7Q7LϿqw9Տ֧QM=5d'{2s#;(ƨ:T]ܨ>hZHUB{6?Cnw%ڳswhݵl?jϻ] α3F^G=Ǵ/ټ,zhPOصw悑H%3[lw`<e߲5H3Ybͦl4j?_ W6Vg, Fd\SD=Àޖ!5?eï9eTQK~tiR;i"o~Jtn=lb _:sกɟ!2%_-[֎h4"זWuijcs<6. #o|3z;,k9yq4j;~DFfm۶DRa69},;vFCppOImNZ97CRY1WdF$]:wჭƎFt%>=mZ11L8\ڳ爚51ÙԪY?|{d29N_MܵxFDժALy-.Dzk5j(7W b]\d  33}ɲd x2h~HH0S}F@3>hbJWGųGZϻ^i(Q# @pܖ\m/ؽgcݚk5୷?Q1q,[rL,&N'+PVA͏{L8 F*AB%HH*ܵf yw50wa6O,yv=4ƨ:̂1xis^C-oVtqJX4^`"f3=3~/'u^0T6g3艂+$yQo (8w3Z@Xm [Jggw:Z5ԩ'|$IbԋTZ@{UTU௢j)i=dрI)toLa|',k7veS>ix m [ 1t vȷHZG1-yzxz0aH}oo/zয়~AEL&IIɨT*ڴnɯnh4s^22-s~4_~d2qaz=7tb9CԾ:TV &,~D||O?q'NIyoִre$IdddJZ??_k{!I))\ef5W_֭;1ϯڜwV?OzEVwMq-^J\g_;䩳DR.&4րh]v1F\0ոkmxj;nf<<U\?C >}6M{g\I{}B2nˍTO>jlX9 cKAܥ<,#ᖉ.C)i"SI V2$Y"x2cA:cm.CٓÑ=5ڢi*JTfssa{vZ@A"'WbG?Ώz"ȋ719ד8{v_vq 6=Cl*?RO /M+ً Y;~9)^ u[*$Jf:, 7w@k7e>h4=@ QPRy`5^*"d Ӫ}ąjn.;/pd@s$Z2G 7͸i %e$RZMvAE^:{~PVZ4H;,Et*$ F:Prff(ӑx AZz=joo+ "믝J5h57&Zw,}OJ|.99Cn.5PF9Gq~Y;Ӗٓ[( #"j\wQ tmyycLx }Nhg,ic1E2>[KzQu ɣ.fadžZ6. / by㺙d&각}m5l FX WQ(L5$ y`yRzvrgWzmB'(@ŅXBv앖54=rHg.1 =nZ.4Wt%ztN?jރ5?ec6;Ip>W֎: @Z}6jSS$, s0xx/E_T*:u^ .^>j::7Wq#vjFoKWiHJJJUfMr{Hk.F .u>遧C Wㅂ[IRj#? z芛VC>e]{͖3jW^m /HI& |iΐNZ5Pf *=KˁsA9„~nYz+dh6;G.*1:>^M+\dt y }693(kV|X͊S{|lzwǶ@>{Gǚ\(_pwzD5&|Ećxp䤁Cӳ'nM"$ 9e4LG2=$?=)w1 IZ\RP~2db$psQ<ΟslQE[㇍p3?d9t QU2q,I)8xZk9oQ^m}Z6'>:. W#y~|1+JWشWZjΒsPk5ܺU>s?0RV a^,7{#VYl5__"",UY\rs#zE1YYl~ӦMfŲyԬYMO9$Ibނ'ŋ"Q *2nї:9זG[eϚ ϰb<o8x(<#fN Q5HȲU]dlsUFztş^af̹_`gD]d])P1mRov3>w- m{KFb-=ƨC4j5U&ժUUfn$ܼ^)(_O2nM*5{TLǐ'w\^mz1╗pjIIMe]^yp?Pڼ(+((((TV*pBBKO7hH)놇vץ겐VC%sr|9Sߧl9=WdWJYʻ\O [KS=WK"Yx:Ö-[őiӢDRRE}k(Q~|>c|K(djZsro-ks:*8HW/ThݴL=^ˠ*Rr-W3$$]`득N{)&L iF#%uJ/m۴"3#WY@T~}7߭te}ca4lNDZ˗N^Z7ۛ+qY=Wĕ% pwI* ? U[@j: J승$^/EᇻܖxW˳JRRRHYK9_z}\wO~w\> <{3QNP^:ZYoO+L0L|u{T13IҢU"wMvUQ$n/Ti qatUAۗ%kKr!oK lܡTHPPMcT춤C p>Iؓkiܨ#G ۻ qW;qURGNŞT#{+qZ{֭ Ito8ru ѣ'uȞ# NWGɺu߳'j? _r26riM3кi˹λuYRyHZ٫GhZ6iVU9bkl2lWk1 ֫Å+'MK6-` yi V'ѠA_t9ݪUYm/ ʥ,gA'H肿O vm_Ar*7&%&(WED_$ Bm i H`hS$:m%:&~M ' :0d {;7HZŞ\KKQNmb㮢jiNu{:$Yq$"'"'#nx1~{{e&[Gem"_§Nڼ'Ԯ]oΙ3$ؗymb4oք^xw&Mi䠊Q[*I+{ȗC0ͤj\t|uj׮TtZ&jŵrk3iڴCM<" ܈)ʪyF9v{G=…Kk뇲b6e_}O?%ˋ\ӥsv+x8ʲV___,:`2d210Nڥ#={v zzgʥ,Q'0093tbO(M&[ԏ|ʲ\M}߬%.aM777>1Sg̩*-rNPE\scWT~[pSVML& 7﹌Mxxc2޻ ʳ\NixsҔ2`%ok7*I6@K*R(=PJK\󿌯/=۩o{G\nr }!!A5`yۻMYHEMxm4}zowGP鄇8.QIDAT^Swř½BF`O"oy|H~?Zk+T^vm[QjHsz`ӏ?/^^^, WQ|ݏŢr˿"{y=‰Sg:WT?˃|ő/5T}W No2nBQu!:d ,%%||t~Kbփ#'{S+3g$gJZG4k֘Q#0k|F2,9k$I 9jK͛5ax?e+  Z Of&9oOfI+M'HH"\*O0o}[!U4Y {~:e55wߛ+m..]|%ONtFruj;˧QpF/t̒#{%ENjQ[jܨo!獉cٺuKx~H؃p;ǝ]ٓY;tSfS? ]%pWH0ӓf#_8͉`$t7kZzp$TR)G~:#9S:rt@,{ҫ,Z8 N,+KiK[A^^'OE%r1BŠBPhh,"d/΢"a ~N@E_?*6VDYtƗ䑈X|~Ճ#ɧJL9ӑLIvO͈l= cs!cYg^ݙ/d]^HBgzI4{R"n_vAMeU-ô~ΗAOٲufs6WQ8?"_̟ng8qNCѼ 򗓘2̨Զ3t$9S:r߈:g3r1N<|R,ٳg/|+)5Ĕ\~ra  9 pg7hW” P$Z ׵lT) =)YO]ahղ9۷9^dȗ'KNn.nm9r( \ILݺ/ժ#?$g\ޟhIYj=F ˁzy,WSjY){8STC ;xJY) [WI2~! Q_$>0l_d)KXX=""d2Kk/CDăf6m2+ͣfjLNrƕ:*!/1ts-/%{OqRCHLÑDBE;E !qqW!ø1˙|<} e]ɿ[Iϻ)1U~HL)/rN~ kR0 pw!!ϻIE$1pPd߂$4y.S]7(ky$Th~M*EJr *((((TZ*D %*((((TZ PiQBE %*((((TZ PiQBE %*((((TZ PiQBE %*((((TZ PiQt~]oo{Ӭ\R1>>EEΙNxxhi*SA`ڇPv 3g|3y |>c|}+ 1z&2}c |:|:R_p6OAJJj*/Yj={}C^=U:˿Yw]mVdfdruᡌ=yVcapo&\|ũAU6m2GƍKQZU'dᢥ'PNmf|~|f͞'Ӧ_xe`Zn'7_9p/ hպ9>\cr%~q QQy|GDANd{TV-#Y\E hb붝{}v)z} <{3QTp<== I6ǵZ-_d ܱ7^ @k10qkgO~wF#>`ٖ?gĉ x1}̈ WV^s/L,ZcX8> 5jΠc<ܳ;nZY ghԠ>l&|Z5#PVM&3[a}ֵ>8:F}̌Luw|+^'E9O/^JWGsW*A@:ΧQpF/ cb0q2`L82Kx~SmffS}FÆl߾?lzLf3iu9?]ې j5qWiӪUtJLf}ٵ{+WW一mL 88Fs*xwo|jI$:]d}i˝ԫW4ktd/](]&7lB@|iƜ9 0L8xg~ƍ?'2oOO "(Lժc/1L'pZh;0"AU  9%h7DZu@#%%6[21ܵr*?O&Ij! oo/#)LuN$I?I߾YLYV?OgΜ]s\8y,(Q%0Fmn E:y4 Q$ AB%77wwHw =sMsrѣ+{vGnhZmr6-ʲx|?;]t )1v})^xk;m/\^5SgF# a6*ɥ+Siza9cVKllog࣏&c2&7͸J"],#ΤXbA$.FMKffAg yWlьث<б_pxΐ`4psw{uk0YM%KP@D֔Mdeg3SvÁeZVÍ"-ȼ_1y>|Xrrl|[gDZz,_n99_ҥ#͛7qXcu({xzU軨P\Mj|0 tCh2Xj5~ #"ǒS0:fY9_z._ @` QQ $33 Q HL :LTdFg.>=xEQJp::ͿFT>9Gq߅Ν;FR7ht5̨E뼤Z$zѣ+O>ޯH'OUL&W9%8 mhZy;G?ww̛k/7oŠB+JCRN-֮^b=ֶmKjժˊ"Z XV71\hgIUQW㝸s;A>b߿jcq#vjFoKhRR Wbhݴhݴ4kژ`i|iӦ yHI& SEs~}"PTt'~ǔ'aahWd3ѣ+nZ }ܟyZ,׳rzFCNiiԪUéUzݖMFN9OӦ=V~Tj+Zo[\<#;Aˣwdfdr%kCYlݻu)nZ jARX_~BC '( #^L\5kݻvܹ $%Xm۶AGY?Gg㏿02aͣߏK}5r(il3nZF̔ZWxr^_-$9%/}e"ܴW^{mݺ>ʭ[rsK=1jݺ`]ѽשּׁl6|i&h2u .kGkk;v8K}[,X%d2c5`0#~!/=gb:mM&xGQT8yyIۭ['6o_RL6-01j5n9wizY_9N.~Ϟݬ|01Nҹ;wd*~H_AB/8BY0oΜKp6m8e8~͍OgLaԙ6kJˁZjb2HHIyy &eLAAAA lPKi2JTPPP(=AJ"PiQBE %*((((TZ PiQBE X(IENDB`terminal-light-1.4.0/doc/light.png000064400000000000000000000333001046102023000151270ustar 00000000000000PNG  IHDRWvPPsBIT|dtEXtSoftwaregnome-screenshot>-tEXtCreation TimeWed 10 Nov 2021 08:39:01 PM CETBaL IDATxwxTU_N̤WJ  PzEDE]pu]˺~X~k[Q"7IHBz2>s $$sg2I z̽=s{ނ˜)/ MZ$JSPPPPh(NAAAAE:嶣I0n6A B{r(=8ɀs+p5y>%e&ϣb7}'PV8_63w1FMQ97/}gޙNj6Ye Ƈ ײzFa+ f=k8k!&unI`dfDRaSWC6S e _ґsEڸk)W7k;pt$H&SY^ۣtJ^y#*&\ŸkUh`+np0i`}:tJMn&ܗϼbIW+m0ԕߜtcM?@Xȳc7/GFMv¥/k͋NTv>/pMbWf7 @4Zkw\~)3= O8ADpy'^>Op<?ڇ(ʷ\ȸ~ne銎ti]F3yWy wq:. ,Ԏs?_ёyja婤5+Y€>K|g\oum Ma.k}65-6g@*ixW.dQӸ:gn;ļ O;8JrrCxcAwnr IB.DAjXhDZVUl|]`xRZ+ &I4S\(@a.palV).&u/tK{At gvwJYIܿj-g~O8Ř.Ė]6~GNCvX܌&8\_oF9xkE=UÒUff}UB7k$^5j=|ng6+Enʔ |w,I 6/rvybv0 <<#=lg׋)-w30d-k}-Nʎptl#DEVm;G0mDr4zt,:yvлK2vp2ށ +,XCV^=SPZna^tD~q9_/BfNL?[-3^{' #G~k{lwwSRn捧zg<9|z*,6&Hcdn)䣅kX$çC7ըk_ 3@NIn[ )(M爉[ pnݩ=ps;% <2F}t 8ˣ5MV5k%[ժ=K}2h Fwm]fH^ݴlxM406a6WIMְ(2s\z-ek,n:}΂{S/1uoY˱dnNN"4$} I]Sܧ3z}fNA d܊gN(-B|%DԌ~$_/%&ǧa߱3|` >6!_#g2^Z4uт$E'o'7ZNb"Bk q/,д.tH|5y9̼m)y( yŤK "T~[N_H'߯cDn ՙwtV5JN71s( R⋁:1W'~Z|xf.{f35 OBrb tsF )&⣬dpҧ>_^/A_s&VW0#EJݸ(P\T"K?Bi'Yʯz9q;_~CjUi=ssޅV cyMATeF]wZUW:_vFT_M+5E$*k9A BQI9qQ5\a ZY,6*,H :*yE!I&Oo#ܨ咨ڼ/r3a֕F0\. MS@x},*܀NSv͌?CԶDH*zoLoJˁP=$!f+ 6/܋=;Odx|u +?ˬ:(R!hx׫;nppl.KD@v#Ъ]ݗQ_sH2{[QlbY'2sSR9aC{gc;zsc,$vԢĎHd{ah wld$P`|Ƿ#.R+pWS|ith&*BŸ0"1^E5].aKg#+3(ׇe$īj Oʯ(g5XP>w*1"&\ngeh5`NJPQTN ]׋̸\:3{vd]VXp$v咈 3b;)vhͯ"6|HNmX nOQq0Iqy?.Įç)5T 19vd^NMILD(m[Űdcϑ_yO !Z-gXZW\ I +Y6s6:V0+/*g/c"3ظ8Uy5Dؚ~\ Mm*_ˬ: 1a<[5*j\~1n.'h,{,ji[q2(t$/}ӓ>ͮ<<ᆪ#RwOn^.:'pU{yꣾ|7"5I/5sp=5ۂ?׋̌-QukEd½<>_A!!:`cК]o_U2jܙǘyXmR@5?=[1xJ.?"?jyp{~wVqj s2n'=Y) .;t;neN;)4-*k9& KJx9lA4~@f[0#}u ;wHV^O-ӳH439<,۸Pm1&šlNM4LA~Q9yoϾ; #u殉7'+vmPYMY xz0CGx߳)(SAxv?=I0{_gˬF绕;y߳ټ H뚌Zw;s;~.s[ދj|RֹQ<%m{Q>/̙^E -"in[,L+ӽU058b]ϛ9fTﴍ!!GSo| -MWFZ!(^xogr W_R߭o7 CY^|9?Qg>ٔK/[$Iϗ_\q_NE,#M<\)\ɠ g`j.Go!| Q拓MגvrK]+e-r8ɫ6Wul+ [~ʦ\ lw<AG븨z]SUӿGG~z[p~*|xyGq׍Ch(i\:;8p2FV1Ls-Z5ڃ3=6P?Gc$VN!'uQ)Q]YذFrlyUf 85@eS.rl}=:u=;y n5D?sކQ?NN|pߏҹ%xdu$'Ⴕbku.r0U,B»HzxU\[SH .#yC2xtCBY4ĘЇǝYPw9ո91֛>4F1t A6gtt3|Ir8WK7ңS~zGsg0ʦn#'uKZß$7˷rgK$JM^4"zY: [гSv?xZ,6SG_À=VND<}Yp8TXmDN/RS8n׺rZŨD#ue^5Ή Ep66~&pYo"VlqXyY5o7 ;ګX0f+a%.k+w1 }Cuv3I6F>K˲>!P˦[az5cyg/G22QǢ 1c7?%ZʊY0Rװs@O>×$GN2h,n'|ŗl?ٍHI]Ikɟȥgƽg'N::([GM>Q)Ӓy2 3xwy \qY(R)+,g.!i|1Rww t ԕ7Krb,qWЇ2{S$3n{d\ 2H}=gIr@s4#GPRlJ #?aӞ7i( Ȗ?_~ߚo͡>^odNKjRZs"@J䨯NC%e0[lE :;`h5X3]9*a2!@әmvU`?.k.Aݑ;#ߨw:7N<cfCVH(Ɔ==<_Ы&g*Ӈ2}=]@Q"=ڬU9 }۟p4v=CZgK6jwݨI?l%說<#Wru$ǐީP'b9Opc:bx TiO}i ٢`r zV{`~,^>[Fi\#yV}Hkַtj ."!:0#VVޯIt5ѩư{ftۡRJA?Й&lV08U{ =njZ@;E;֨|?INm1[d/fLwB@ylJ rr$SXZE:7u$odpT:O.W J|֑!:wȭr(?C0j4LRz|mR%փ?*#G]EEԃ/ndn _gC< /62J$Ǧ&DDE NZ 8֑Sk~-rGGkvmP%e۲"w h:!y\g:{+sV[h^O''OCtIf/ۉ06d0)nɑXZ#PJb\n C.)k:j vjsp*<)|mR%4LK]Eԃ/VE&'q<#VOd^VBz۝ `Y~u4=:-ѪլqPOf˾jnty}4r fۃO`Nwqڱ!it:NX2 B$# BS"ΆaIpJ&Z՚P1a620_R>EkYWX$_rhˌqUiڳnL7@8-\Ƕ'ݿG)N[xo3֒ݨ#hԵHҺ&`:ϼ3Qgފ0m|t/;^ ʯ3/)Ooo&̠Y(* DJ8^7 .0;ruj:J*`/R/U}xeh*EA}!W.~Mַ v5̖SaۉICkٴ@:zw 91qlF~{?yx QDtUX.]¶`awUn$91&r e/eB{K"Gr\yޚ3#v%[jG%Y.bwD'/gPcS!0mNEg-`H vf IDATN';(qyfN݁Z} \sZ>rK[D p"BmB39tOi]cIs* Q*((((HeleŖXTPPQˇ.})Wɼ8k!eϩY yWh];<ƛy`2gŏǺ2;g/*ul,^@l1<7.Uќ|I<<&~s_y6ܳ"+4vIM7]8j'Rw&QwF?Mf%Z-yJdtڻosJ)-{]T4&rϊt4ZsC 3P%! UIWx']t'<#_#IEVJ'Xt'YY> +d[s. p勹$@*qݬuo9I+/[ӱMun?$\>& M;"#_c/ FM$ABh4CD@`mI#+](g"Z\N47  (*5֭j9Jeg ەu H=TQO}eOVuUr(= ˛VGW IFH(ŎHU~OD>[$!&uKo"ӲP(Z$JDAAAAE8Z$JSPPPPh(NAAAAE8Z$JSPPPPh(NAAAAE8Z$JSPPPPh(NAAAAE8Z$JSPPPPh(.J+,<mO^h1ϼ3g-x0⬅Η=dLtw)$?_Fv~qBfw/d]nS.j',ݸgry-Z+gscl3n$*k57 @\nS|⃓87y)aÜ/e$ݥfLj/%eV>[<¸!O_FjԽ-=HIiё_\ -nl}CY\ձ %f:35 4jvf4yI]j6>;]n3d6z-qv磅x[E߃3NO_atug6= Vo`Ꝝ);n$'ԛ& Nñ9|zվmwy/osD6 A-zWuIQy_rȫMP~Vf҈4_)q^*۪/.[) :5JeLJ+,ܓ} ֐WD6[8];$ڹj!>l#&"GѣS['=>a=F1_7µXv\Sj|T YzaT*}^Kƹ|<Ętslw8^eL;.8sMdފ9n7#=+v >bһ3 0< ߯ټBEIg<]T>FDA@Vy8p~SP=Aeב :M@\n) [%RռvuDj8S@Jx)L8Wwd#a{fG&{}d#1;vǦ l(lk1u~/&5/Ϝ-QZnkION~q9o|v1D_],ݸI {g\ͤgkօ^yVoOqYEC+?Q};y9̼m)y(Ę%JEd!{ 9;.HϤxH8jVXbBV#IeW?ck87{v`K%9utfS<:mA:1eGT?og.INeu;c$Ą_ 8Au55g&KA@ʩ̜6 Joa/'2s`)u.I7 U1S㷏EIkDA K+(.7nS[CM_?)6R0Od#V ʢ5Ek/*Cl_\FV11?nv FM$ALt+?[YZ0(fnBFNalm9W_vz?~&6u[3*Qq#piv$Dac :{p1[XNN7)sWҡuLڇ}u O?Ѡb.c !Wb惼7%/>0 QeU'Db/I@+M**19q_!˖QD3Scyeo-+ 3ϛrI:|RNc"s N;|!&"bXa ű/.VΖ'2/AQjjb8y67 ;EQg6v3QbQaF,v9nZflaldVy{J"B /]f}[ Zkr3r<yzڧ3͵~@4=:-ѪլqPNf˾5<[HLamM|b#jҎUrI:Of^!SVaeCU`eA*o뾓tj۪0t-yz˖rNPb2Di){:%&v'tBѠ2{~[Ì<4e$ v⣅ض$ e;yo.vl)`O۰Drߤ6?_-̗K7qۘ *wkxo:-Iq~{zۯȬy}з[K"i2n{{"_uMftyg>/ϼUveC[ַ vsWY]n<#ùR4Z{"#vKt琉  <7DpGSaD&?n]#0Vp?Wײsc]ǹcui 7'oF4j[1޳̱l?ΠޝO~.sfúU ד'JR/qAW4'/gPco&;(,T*mV-;/3r$Z>rZ,Jk"Mf^ETn.JSAAA(C -"QBD p -%)((((H"QBTr-niIENDB`terminal-light-1.4.0/examples/dark-or-light/main.rs000064400000000000000000000011301046102023000203150ustar 00000000000000//! Run this with //! cargo run --example dark-or-light fn main() { println!(); match terminal_light::luma() { Ok(luma) if luma > 0.85 => { println!(" You're using a light theme (luma={})", luma); } Ok(luma) if luma < 0.2 => { println!(" You're using a dark theme (luma={})", luma); } Ok(luma) => { println!(" You're using a kind of intermediate theme (luma={})", luma); } Err(e) => { println!(" I couldn't determine the background's luma: {}", e); } } println!(); } terminal-light-1.4.0/examples/fading/main.rs000064400000000000000000000021641046102023000171110ustar 00000000000000//! Demonstrate mixing any ANSI color with the background //! //! Run this with //! cargo run --example fading use { coolor::*, crossterm::style::{self, Stylize}, }; fn print_color(ansi: AnsiColor) { print!("{}", "█".with(style::Color::AnsiValue(ansi.code))); } fn mix(color1: Hsl, weight1: f32, color2: Hsl, weight2: f32) -> Hsl { Color::blend(color1, weight1, color2, weight2).hsl() } fn main() { let bg = match terminal_light::background_color() { Ok(bg) => bg, _ => { println!("Couldn't determine the background color, using default"); AnsiColor::new(234).into() } }; println!("\n Terminal background color: {:?}", bg); println!(" Blending all ANSI colors into the background, using only ANSI colors:"); let bg = bg.hsl(); for code in 1..=255 { let ansi = AnsiColor::new(code); print!(" {:>3} ", code); print_color(ansi); print!(" "); let fg = ansi.to_hsl(); for i in 0..20 { print_color(mix(fg, (20 - i) as f32, bg, i as f32).to_ansi()); } println!(); } } terminal-light-1.4.0/examples/skins/main.rs000064400000000000000000000053521046102023000170120ustar 00000000000000//! This example selects a different skin for ligth or dark terminals //! //! Run it with //! cargo run --example skin use crossterm::style::{Color, ContentStyle}; struct Skin { high_contrast: ContentStyle, low_contrast: ContentStyle, code: ContentStyle, } fn main() { let skin = match terminal_light::luma() { Ok(luma) if luma > 0.6 => { // light theme Skin { high_contrast: ContentStyle { foreground_color: Some(Color::Rgb { r: 40, g: 5, b: 0 }), ..Default::default() }, low_contrast: ContentStyle { foreground_color: Some(Color::Rgb { r: 120, g: 120, b: 80, }), ..Default::default() }, code: ContentStyle { foreground_color: Some(Color::Rgb { r: 50, g: 50, b: 50, }), background_color: Some(Color::Rgb { r: 210, g: 210, b: 210, }), ..Default::default() }, } } _ => { // dark theme Skin { high_contrast: ContentStyle { foreground_color: Some(Color::Rgb { r: 250, g: 180, b: 0, }), ..Default::default() }, low_contrast: ContentStyle { foreground_color: Some(Color::Rgb { r: 180, g: 150, b: 0, }), ..Default::default() }, code: ContentStyle { foreground_color: Some(Color::Rgb { r: 220, g: 220, b: 220, }), background_color: Some(Color::Rgb { r: 80, g: 80, b: 80, }), ..Default::default() }, } } }; println!( "\n {}", skin.low_contrast .apply("This line is easy to read but low intensity") ); println!( "\n {}", skin.high_contrast .apply("This line has a much greater contrast") ); println!("\n {}", skin.code.apply("this.is_meant_to_be(some_code);")); println!(); } terminal-light-1.4.0/src/env.rs000064400000000000000000000024571046102023000145030ustar 00000000000000use crate::*; /// Query the $COLORFGBG env variable and parse /// the result to extract the background in ANSI. #[allow(clippy::iter_skip_next)] pub fn bg_color() -> Result { let s = std::env::var("COLORFGBG").map_err(|_| TlError::NoColorFgBgEnv)?; parse_colorfgbg(&s) } /// Parse the content of the COLORFGBG variable, which is supposed /// to be either like `17;45` or `0;default;15`, with the last token /// being the ansi code of the background color. /// /// Note that there doesn't seem to be any authoritive documentation /// on the exact format. fn parse_colorfgbg(s: &str) -> Result { let token: Vec<&str> = s.split(';').collect(); let bg = match token.len() { 2 => &token[1], 3 => &token[2], _ => { return Err(TlError::WrongFormat(s.to_string())); } }; let code = bg.parse()?; Ok(AnsiColor { code }) } #[test] fn test_parse_color_fgbg() { assert_eq!(parse_colorfgbg("17;45").unwrap(), AnsiColor::new(45)); assert_eq!(parse_colorfgbg("0;default;15").unwrap(), AnsiColor::new(15)); assert!(matches!( parse_colorfgbg("15").unwrap_err(), TlError::WrongFormat(_) )); assert!(matches!( parse_colorfgbg("15;FF").unwrap_err(), TlError::ParseInt(_) )); } terminal-light-1.4.0/src/error.rs000064400000000000000000000011451046102023000150350ustar 00000000000000/// terminal-light error type #[derive(thiserror::Error, Debug)] pub enum TlError { #[error("IO error: {0}")] IO(#[from] std::io::Error), #[cfg(unix)] #[error("Xterm-query error: {0}")] XtermQuery(#[from] xterm_query::XQError), #[error("Parse Int error: {0}")] ParseInt(#[from] std::num::ParseIntError), #[error("Wrong answer format: {0}")] WrongFormat(String), #[error("No $COLORFGBG env variable")] NoColorFgBgEnv, #[error("Var error: {0}")] VarError(#[from] std::env::VarError), #[error("Unsupported platform")] // nothing works Unsupported, } terminal-light-1.4.0/src/lib.rs000064400000000000000000000070361046102023000144570ustar 00000000000000/*! This crate answers the question *"Is the terminal dark or light?"*. It provides * the background color, either as RGB or ANSI * the background color's luma, which varies from 0 (black) to 1 (white) A use case in a TUI is to determine what set of colors would be most suitable depending on the terminal's background: ``` let should_use_light_skin = terminal_light::luma() .map_or(false, |luma| luma > 0.6); ``` If you have very specialized skins, you may choose a more precise switch: ``` match terminal_light::luma() { Ok(luma) if luma > 0.85 => { // Use a "light mode" skin. } Ok(luma) if luma < 0.2 => { // Use a "dark mode" skin. } _ => { // Either we couldn't determine the mode or it's kind of medium. // We should use an itermediate skin, or one defining the background. } } ``` # Strategies ## `$COLORFGBG` strategy This environment variable is set by some terminals, like konsole or the rxvt family. It can also be set by users. Its value is like `15;0` where the second number is the ANSI code for the background color. Bonus: * querying an env variable is a fast operation Malus: * this env variable isn't always immediately updated when you change the color of the terminal * the value isn't precise: `0` is "dark" and `15` is "light" but the real RGB color is uncertain as the low ANSI codes are often modified by the user ## "Dynamic colors" OSC escape sequence strategy Modern terminals implement this xterm extension: a query making it possible to know the background color as RGB. Terminal-light sends the query to `stdout`, waits for the answer on `stdin` with a timeout of 20ms, then analyses this answer. Bonus: * this works well on all tested linux terminals * the value is precise (RGB) * the value is up to date when it's available Malus: * waiting for stdin with a timeout isn't implemented on Windows in this crate (help welcome) * this isn't instant, a delay of 10 ms to get the answer isn't unusual * if a not compatible terminal doesn't answer at all, we're waiting for 20ms * it may fail on some terminal multiplexers ## Global strategy used by Terminal-light 1. if we're on a unix-like platform, we try the escape sequence strategy 2. if it failed or we're not on unix, we try the `$COLORFGBG` strategy 3. without a solution, we return a `TlError::Unsupported` error */ pub mod env; mod error; #[cfg(unix)] mod xterm; pub use {coolor::*, error::*}; /// Try to determine the background color of the terminal. /// /// The result may come as Ansi or Rgb, depending on where /// the information has been found. /// /// If you want it as RGB: /// /// ``` /// let backround_color_rgb = terminal_light::background_color() /// .map(|c| c.rgb()); // may be an error /// ``` pub fn background_color() -> Result { #[cfg(unix)] { let xterm_color = xterm::query_bg_color(); if let Ok(xterm_color) = xterm_color { return Ok(Color::Rgb(xterm_color)); } } let env_color = env::bg_color(); if let Ok(env_color) = env_color { return Ok(Color::Ansi(env_color)); } Err(TlError::Unsupported) } /// Try to return the "luma" value of the terminal's background, characterizing /// the "light" of the color, going from 0 (black) to 1 (white). /// /// You can say a terminal is "dark" when the luma is below 0.2 and /// "light" when it's over 0.9. If you need to choose a pivot between /// "rather dark" and "rather light" then 0.6 should do. pub fn luma() -> Result { background_color().map(|c| c.luma()) } terminal-light-1.4.0/src/main.rs000064400000000000000000000003411046102023000146250ustar 00000000000000use terminal_light::*; /// print the "luma" value of the terminal's background color /// (from 0 (black) to 1 (white)) or an error when it failed. fn main() -> Result<(), TlError> { println!("{}", luma()?); Ok(()) } terminal-light-1.4.0/src/xterm.rs000064400000000000000000000032461046102023000150470ustar 00000000000000use crate::*; fn query(query: &str, timeout_ms: u16) -> Result { use crossterm::terminal::*; let switch_to_raw = !is_raw_mode_enabled()?; if switch_to_raw { enable_raw_mode()?; } let res = xterm_query::query(query, timeout_ms).map_err(|e| e.into()); if switch_to_raw { disable_raw_mode()?; } res } /// Query the bg color, assuming the terminal is in raw mode, /// using the "dynamic colors" OSC escape sequence. pub fn query_bg_color() -> Result { // we use the "dynamic colors" OSC escape sequence. It's sent with a ? for // a query and normally answered by the terminal with a color. // References: // - https://stackoverflow.com/a/28334701/263525 // - https://invisible-island.net/xterm/ctlseqs/ctlseqs.html let s = query("\x1b]11;?\x07", 100)?; // The string we receive is like `"\u{1b}]11;rgb://\u{1b}\\"` // where ``, ``, and `` are 4 hex digits. // Most terminals don't support such precision so they fill the 4 digits // by repeating their 2 digits precision. // For example, supposing the background is in #38A4C9 (blue), // then we receive `"\u{1b}]11;rgb:3838/a4a4/c9c9\u{1b}\\"`. // We read only the most significant hex digits which are good enough // in all cases. match s.strip_prefix("\x1b]11;rgb:") { Some(raw_color) if raw_color.len() >= 14 => Ok(Rgb::new( u8::from_str_radix(&raw_color[0..2], 16)?, u8::from_str_radix(&raw_color[5..7], 16)?, u8::from_str_radix(&raw_color[10..12], 16)?, )), _ => Err(TlError::WrongFormat(s.to_string())), } }