diff --git a/Cargo.lock b/Cargo.lock index c26ded9..4a9269e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "ansi_term" version = "0.12.1" @@ -156,6 +162,14 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "anstyle-ratatui" +version = "0.1.0" +dependencies = [ + "anstyle 1.0.13", + "ratatui", +] + [[package]] name = "anstyle-roff" version = "0.3.8" @@ -177,7 +191,7 @@ dependencies = [ "html-escape", "proptest", "snapbox", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -282,6 +296,21 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bdcae87153686017415ce77e48c53e6818a0a058f0e21b56640d1e944967ef8" +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cfg-if" version = "1.0.3" @@ -308,7 +337,7 @@ dependencies = [ "anstream 0.3.2", "anstyle 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "clap_lex", - "strsim", + "strsim 0.10.0", "terminal_size", ] @@ -318,7 +347,7 @@ version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn", @@ -361,6 +390,20 @@ dependencies = [ "owo-colors", ] +[[package]] +name = "compact_str" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + [[package]] name = "condtype" version = "1.3.0" @@ -396,6 +439,41 @@ dependencies = [ "winapi", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -449,6 +527,18 @@ dependencies = [ "litrs", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -471,6 +561,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "getrandom" version = "0.3.3" @@ -483,12 +579,29 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -510,6 +623,34 @@ dependencies = [ "utf8-width", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "instability" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" +dependencies = [ + "darling", + "indoc", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -541,6 +682,15 @@ dependencies = [ "is-terminal", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -593,6 +743,15 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown", +] + [[package]] name = "memchr" version = "2.7.6" @@ -658,6 +817,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -755,6 +920,26 @@ dependencies = [ "rand_core", ] +[[package]] +name = "ratatui" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +dependencies = [ + "bitflags 2.9.4", + "cassowary", + "compact_str", + "indoc", + "instability", + "itertools", + "lru", + "paste", + "strum", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + [[package]] name = "redox_syscall" version = "0.5.17" @@ -818,6 +1003,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "rusty-fork" version = "0.3.0" @@ -933,6 +1124,12 @@ dependencies = [ "anstream 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strip-ansi-escapes" version = "0.2.1" @@ -948,6 +1145,34 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.106" @@ -1038,11 +1263,34 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-truncate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +dependencies = [ + "itertools", + "unicode-segmentation", + "unicode-width 0.1.14", +] + [[package]] name = "unicode-width" -version = "0.2.2" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "utf8-width" @@ -1125,7 +1373,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] diff --git a/crates/anstyle-ratatui/CHANGELOG.md b/crates/anstyle-ratatui/CHANGELOG.md new file mode 100644 index 0000000..94bacb6 --- /dev/null +++ b/crates/anstyle-ratatui/CHANGELOG.md @@ -0,0 +1,11 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/) +and this project adheres to [Semantic Versioning](https://semver.org/). + + +## [Unreleased] - ReleaseDate + + +[Unreleased]: https://github.com/rust-cli/anstyle/compare/anstyle-ratatui-v0.1.0...HEAD diff --git a/crates/anstyle-ratatui/Cargo.toml b/crates/anstyle-ratatui/Cargo.toml new file mode 100644 index 0000000..8e4dfb0 --- /dev/null +++ b/crates/anstyle-ratatui/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "anstyle-ratatui" +version = "0.1.0" +description = "Adapt between ratatui and anstyle" +categories = ["command-line-interface"] +keywords = ["ansi", "terminal", "color", "ratatui"] +repository.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[dependencies] +anstyle = { version = "1.0.0", path = "../anstyle" } +ratatui = { version = "0.29.0", default-features = false } + +[lints] +workspace = true diff --git a/crates/anstyle-ratatui/LICENSE-APACHE b/crates/anstyle-ratatui/LICENSE-APACHE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/crates/anstyle-ratatui/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/crates/anstyle-ratatui/LICENSE-MIT b/crates/anstyle-ratatui/LICENSE-MIT new file mode 100644 index 0000000..a2d0108 --- /dev/null +++ b/crates/anstyle-ratatui/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +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. diff --git a/crates/anstyle-ratatui/README.md b/crates/anstyle-ratatui/README.md new file mode 100644 index 0000000..64f1c56 --- /dev/null +++ b/crates/anstyle-ratatui/README.md @@ -0,0 +1,26 @@ +# anstyle-ratatui + +> Convert between [`ratatui`](https://docs.rs/ratatui) and generic styling types + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/anstyle-ratatui.svg) +[![Crates Status](https://img.shields.io/crates/v/anstyle-ratatui.svg)](https://crates.io/crates/anstyle-ratatui) + +## License + +Licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## [Contribute](../../CONTRIBUTING.md) + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual-licensed as above, without any additional terms or +conditions. + +[Crates.io]: https://crates.io/crates/anstyle-ratatui +[Documentation]: https://docs.rs/anstyle-ratatui diff --git a/crates/anstyle-ratatui/src/lib.rs b/crates/anstyle-ratatui/src/lib.rs new file mode 100644 index 0000000..d0f7211 --- /dev/null +++ b/crates/anstyle-ratatui/src/lib.rs @@ -0,0 +1,184 @@ +//! Convert between [ratatui] and [generic styling types][anstyle] +//! +//! [ratatui]: https://docs.rs/ratatui +//! [anstyle]: https://docs.rs/anstyle + +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs)] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] + +/// Adapt generic styling to [`ratatui`] +pub fn to_ratatui_style(style: anstyle::Style) -> ratatui::style::Style { + let mut ratatui_style = ratatui::style::Style::default(); + + if let Some(fg) = style.get_fg_color() { + ratatui_style = ratatui_style.fg(to_ratatui_color(fg)); + } + if let Some(bg) = style.get_bg_color() { + ratatui_style = ratatui_style.bg(to_ratatui_color(bg)); + } + let modifiers = to_ratatui_modifier(style.get_effects()); + if modifiers != ratatui::style::Modifier::empty() { + ratatui_style = ratatui_style.add_modifier(modifiers); + } + + ratatui_style +} + +/// Adapt [`ratatui`] styling to generic [`anstyle::Style`] +pub fn from_ratatui_style(style: ratatui::style::Style) -> anstyle::Style { + let mut anstyle = anstyle::Style::new(); + + if let Some(fg) = style.fg.and_then(from_ratatui_color) { + anstyle = anstyle.fg_color(Some(fg)); + } + if let Some(bg) = style.bg.and_then(from_ratatui_color) { + anstyle = anstyle.bg_color(Some(bg)); + } + let effects = from_ratatui_modifier(style.add_modifier); + if !effects.is_plain() { + anstyle = anstyle.effects(effects); + } + + anstyle +} + +/// Adapt generic colors to [`ratatui`] +pub fn to_ratatui_color(color: anstyle::Color) -> ratatui::style::Color { + match color { + anstyle::Color::Ansi(ansi) => ansi_to_ratatui_color(ansi), + anstyle::Color::Ansi256(xterm) => xterm_to_ratatui_color(xterm), + anstyle::Color::Rgb(rgb) => rgb_to_ratatui_color(rgb), + } +} + +fn ansi_to_ratatui_color(color: anstyle::AnsiColor) -> ratatui::style::Color { + match color { + anstyle::AnsiColor::Black => ratatui::style::Color::Black, + anstyle::AnsiColor::Red => ratatui::style::Color::Red, + anstyle::AnsiColor::Green => ratatui::style::Color::Green, + anstyle::AnsiColor::Yellow => ratatui::style::Color::Yellow, + anstyle::AnsiColor::Blue => ratatui::style::Color::Blue, + anstyle::AnsiColor::Magenta => ratatui::style::Color::Magenta, + anstyle::AnsiColor::Cyan => ratatui::style::Color::Cyan, + anstyle::AnsiColor::White => ratatui::style::Color::Gray, + anstyle::AnsiColor::BrightBlack => ratatui::style::Color::DarkGray, + anstyle::AnsiColor::BrightRed => ratatui::style::Color::LightRed, + anstyle::AnsiColor::BrightGreen => ratatui::style::Color::LightGreen, + anstyle::AnsiColor::BrightYellow => ratatui::style::Color::LightYellow, + anstyle::AnsiColor::BrightBlue => ratatui::style::Color::LightBlue, + anstyle::AnsiColor::BrightMagenta => ratatui::style::Color::LightMagenta, + anstyle::AnsiColor::BrightCyan => ratatui::style::Color::LightCyan, + anstyle::AnsiColor::BrightWhite => ratatui::style::Color::White, + } +} + +fn xterm_to_ratatui_color(color: anstyle::Ansi256Color) -> ratatui::style::Color { + ratatui::style::Color::Indexed(color.0) +} + +fn rgb_to_ratatui_color(color: anstyle::RgbColor) -> ratatui::style::Color { + ratatui::style::Color::Rgb(color.0, color.1, color.2) +} + +/// Adapt [`ratatui`] colors to generic [`anstyle::Color`] +pub fn from_ratatui_color(color: ratatui::style::Color) -> Option { + match color { + ratatui::style::Color::Reset => None, + ratatui::style::Color::Black => Some(anstyle::AnsiColor::Black.into()), + ratatui::style::Color::Red => Some(anstyle::AnsiColor::Red.into()), + ratatui::style::Color::Green => Some(anstyle::AnsiColor::Green.into()), + ratatui::style::Color::Yellow => Some(anstyle::AnsiColor::Yellow.into()), + ratatui::style::Color::Blue => Some(anstyle::AnsiColor::Blue.into()), + ratatui::style::Color::Magenta => Some(anstyle::AnsiColor::Magenta.into()), + ratatui::style::Color::Cyan => Some(anstyle::AnsiColor::Cyan.into()), + ratatui::style::Color::Gray => Some(anstyle::AnsiColor::White.into()), + ratatui::style::Color::DarkGray => Some(anstyle::AnsiColor::BrightBlack.into()), + ratatui::style::Color::LightRed => Some(anstyle::AnsiColor::BrightRed.into()), + ratatui::style::Color::LightGreen => Some(anstyle::AnsiColor::BrightGreen.into()), + ratatui::style::Color::LightYellow => Some(anstyle::AnsiColor::BrightYellow.into()), + ratatui::style::Color::LightBlue => Some(anstyle::AnsiColor::BrightBlue.into()), + ratatui::style::Color::LightMagenta => Some(anstyle::AnsiColor::BrightMagenta.into()), + ratatui::style::Color::LightCyan => Some(anstyle::AnsiColor::BrightCyan.into()), + ratatui::style::Color::White => Some(anstyle::AnsiColor::BrightWhite.into()), + ratatui::style::Color::Indexed(value) => Some(anstyle::Ansi256Color(value).into()), + ratatui::style::Color::Rgb(r, g, b) => Some(anstyle::RgbColor(r, g, b).into()), + } +} + +/// Adapt generic effects to [`ratatui`] +pub fn to_ratatui_modifier(effects: anstyle::Effects) -> ratatui::style::Modifier { + use ratatui::style::Modifier; + + let mut modifier = Modifier::empty(); + if effects.contains(anstyle::Effects::BOLD) { + modifier |= Modifier::BOLD; + } + if effects.contains(anstyle::Effects::DIMMED) { + modifier |= Modifier::DIM; + } + if effects.contains(anstyle::Effects::ITALIC) { + modifier |= Modifier::ITALIC; + } + if has_underline(effects) { + modifier |= Modifier::UNDERLINED; + } + if effects.contains(anstyle::Effects::BLINK) { + modifier |= Modifier::SLOW_BLINK; + } + if effects.contains(anstyle::Effects::INVERT) { + modifier |= Modifier::REVERSED; + } + if effects.contains(anstyle::Effects::HIDDEN) { + modifier |= Modifier::HIDDEN; + } + if effects.contains(anstyle::Effects::STRIKETHROUGH) { + modifier |= Modifier::CROSSED_OUT; + } + modifier +} + +/// Adapt [`ratatui`] modifiers to [`anstyle::Effects`] +pub fn from_ratatui_modifier(modifier: ratatui::style::Modifier) -> anstyle::Effects { + use ratatui::style::Modifier; + + let mut effects = anstyle::Effects::new(); + if modifier.contains(Modifier::BOLD) { + effects = effects.insert(anstyle::Effects::BOLD); + } + if modifier.contains(Modifier::DIM) { + effects = effects.insert(anstyle::Effects::DIMMED); + } + if modifier.contains(Modifier::ITALIC) { + effects = effects.insert(anstyle::Effects::ITALIC); + } + if modifier.contains(Modifier::UNDERLINED) { + effects = effects.insert(anstyle::Effects::UNDERLINE); + } + if modifier.intersects(Modifier::SLOW_BLINK | Modifier::RAPID_BLINK) { + effects = effects.insert(anstyle::Effects::BLINK); + } + if modifier.contains(Modifier::REVERSED) { + effects = effects.insert(anstyle::Effects::INVERT); + } + if modifier.contains(Modifier::HIDDEN) { + effects = effects.insert(anstyle::Effects::HIDDEN); + } + if modifier.contains(Modifier::CROSSED_OUT) { + effects = effects.insert(anstyle::Effects::STRIKETHROUGH); + } + effects +} + +fn has_underline(effects: anstyle::Effects) -> bool { + effects.contains(anstyle::Effects::UNDERLINE) + || effects.contains(anstyle::Effects::DOUBLE_UNDERLINE) + || effects.contains(anstyle::Effects::CURLY_UNDERLINE) + || effects.contains(anstyle::Effects::DOTTED_UNDERLINE) + || effects.contains(anstyle::Effects::DASHED_UNDERLINE) +} + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/crates/anstyle-svg/Cargo.toml b/crates/anstyle-svg/Cargo.toml index f6513dc..43684ee 100644 --- a/crates/anstyle-svg/Cargo.toml +++ b/crates/anstyle-svg/Cargo.toml @@ -28,7 +28,7 @@ anstyle = { version = "1.0.0", path = "../anstyle" } anstyle-parse = { version = "0.2.6", path = "../anstyle-parse" } anstyle-lossy = { version = "1.0.0", path = "../anstyle-lossy" } html-escape = "0.2.13" -unicode-width = "0.2.2" +unicode-width = "0.2" [dev-dependencies] proptest = "1.7.0"