├── .circleci └── config.yml ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── jekyll-gh-pages.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── tables.rs ├── examples ├── html2term.rs └── html2text.rs ├── html2text-web-demo ├── .cargo │ └── config.toml ├── .gitignore ├── Cargo.toml ├── Trunk.toml ├── index.html └── src │ └── lib.rs ├── pages ├── .gitignore ├── _config.yml ├── _includes │ └── head.html ├── assets │ ├── demo-main.js │ └── demo.css └── index.markdown ├── rust.yml └── src ├── ansi_colours.rs ├── css.rs ├── css ├── parser.rs └── types.rs ├── lib.rs ├── macros.rs ├── markup5ever_rcdom.rs ├── render ├── mod.rs └── text_renderer.rs └── tests.rs /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | win: circleci/windows@2.2.0 5 | 6 | jobs: 7 | build-stable: 8 | docker: 9 | - image: cimg/rust:1.80.1 10 | steps: 11 | - checkout 12 | - run: cargo --version 13 | - run: cargo build 14 | - run: cargo test 15 | - run: 16 | name: Install tools 17 | command: | 18 | rustup component add rustfmt clippy 19 | - run: 20 | name: Check formatting 21 | command: | 22 | cargo fmt --all -- --check --color=auto 23 | - run: 24 | name: Clippy 25 | command: | 26 | cargo clippy 27 | build-css: 28 | docker: 29 | - image: cimg/rust:1.80.1 30 | steps: 31 | - checkout 32 | - run: cargo --version 33 | - run: cargo build --features=css 34 | - run: cargo test --features=css 35 | build-1-72: 36 | docker: 37 | - image: cimg/rust:1.72 38 | steps: 39 | - checkout 40 | - run: cargo --version 41 | - run: cargo build --features=css 42 | - run: cargo test --features=css 43 | build-windows: 44 | executor: 45 | name: win/default 46 | size: medium 47 | shell: bash.exe 48 | environment: 49 | PATHk 50 | steps: 51 | - checkout 52 | - run: 53 | name: Install Rust 54 | command: | 55 | curl https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe --output rustup-init.exe 56 | ./rustup-init.exe -y 57 | - run: 58 | name: Update PATH and cargo config 59 | command: | 60 | echo "[net]" >> $USERPROFILE/.cargo/config 61 | echo "git-fetch-with-cli = true" >> $USERPROFILE/.cargo/config 62 | echo 'export PATH=$USERPROFILE/.cargo/bin:$PATH' >> $BASH_ENV 63 | - run: 64 | name: Build 65 | command: | 66 | cargo build 67 | - run: 68 | name: Tests 69 | command: | 70 | cargo test 71 | 72 | workflows: 73 | version: 2 74 | build: 75 | jobs: 76 | - "build-stable" 77 | - "build-css" 78 | - "build-1-72" 79 | - "build-windows" 80 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | day: "friday" 8 | rebase-strategy: "disabled" 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | test-action: 14 | name: Check semver compatibility 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout sources 18 | uses: actions/checkout@v2 19 | 20 | - name: Install stable toolchain 21 | uses: actions-rs/toolchain@v1 22 | with: 23 | toolchain: stable 24 | profile: minimal 25 | override: true 26 | 27 | - name: Check semver 28 | uses: obi1kenobi/cargo-semver-checks-action@v2 29 | with: 30 | version-tag-prefix: '' 31 | -------------------------------------------------------------------------------- /.github/workflows/jekyll-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Build and deploy demo site 3 | 4 | on: 5 | # Allows you to run this workflow manually from the Actions tab 6 | workflow_dispatch: 7 | 8 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 15 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 16 | concurrency: 17 | group: "pages" 18 | cancel-in-progress: false 19 | 20 | jobs: 21 | # Build job: 22 | build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | - name: Setup Pages 28 | uses: actions/configure-pages@v5 29 | - name: Install trunk 30 | run: cargo install trunk --version=0.21.13 31 | - name: Install WASM rust target 32 | run: rustup target add wasm32-unknown-unknown 33 | - name: Build WASM module 34 | run: trunk build 35 | working-directory: ./html2text-web-demo 36 | - name: Copy WASM assets 37 | run: cp html2text-web-demo/dist/html2text-web-demo{.js,_bg.wasm} ./pages/assets/ 38 | - name: Build with Jekyll 39 | uses: actions/jekyll-build-pages@v1 40 | with: 41 | source: ./pages 42 | destination: ./_site 43 | - name: Upload artifact 44 | uses: actions/upload-pages-artifact@v3 45 | 46 | # Deployment job 47 | deploy: 48 | environment: 49 | name: github-pages 50 | url: ${{ steps.deployment.outputs.page_url }} 51 | runs-on: ubuntu-latest 52 | needs: build 53 | steps: 54 | - name: Deploy to GitHub Pages 55 | id: deployment 56 | uses: actions/deploy-pages@v4 57 | 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Possible log types: 4 | 5 | - `[added]` for new features. 6 | - `[changed]` for changes in existing functionality. 7 | - `[deprecated]` for once-stable features removed in upcoming releases. 8 | - `[removed]` for deprecated features removed in this release. 9 | - `[fixed]` for any bug fixes. 10 | - `[security]` to invite users to upgrade in case of vulnerabilities. 11 | 12 | ### Latest 13 | 14 | ### 0.15.1 15 | 16 | - [added] CSS: Support basic attribute selectors (`div[attr="bar"]`). 17 | - [changed] Various improvements to syntax highlighting: 18 | - It uses the priority of the `x-syntax` rule. 19 | - Now supported on non-`
` elements. 20 | - No longer strips contained tags when highlighting 21 | - Compatible with `display: x-raw-dom` extension (e.g. to colour the HTML) 22 | - [fixed] With `pad_block_width` enabled, do a better job of padding blocks. 23 | In particular, the padding gets the block's background colour (when CSS etc. 24 | are being used). 25 | 26 | ### 0.15.0 27 | 28 | - [added] Syntax highlighting support for `` blocks 29 | (`Config::register_highlighter` and CSS `x-syntax: foo`) 30 | - [changed] CSS extensions (until now `display: x-raw-dom`, and only if the 31 | `css_ext` Cargo feature is enabled) are now only available in agent and user CSS. 32 | This is a breaking change, but is not likely to affect many users. 33 | 34 | ### 0.14.4 35 | 36 | - [added] `RcDom::serialize`, and expose a few more of the `RcDom` types. 37 | - [added] Online [demo page](https://jugglerchris.github.io/rust-html2text/) 38 | 39 | ### 0.14.3 40 | 41 | - [changed] Updated dependencies, including html5ever 0.31. 42 | 43 | ### 0.14.2 44 | 45 | - [fixed] An issue with multiple verions of markup5ever being included. 46 | (thanks anna-hope) 47 | 48 | ### 0.14.1 49 | 50 | - [fixed] An issue with `FragmentStart`s being lost (thanks toiletbril) 51 | - [fixed] An infinite loop if tabs inside `` wrapped past the width 52 | (thanks nshp) 53 | 54 | ### 0.14.0 55 | 56 | - [changed] Various small refactors (thanks sftse) 57 | - [changed] `Config::rich()` no longer includes decorations around `` etc. - 58 | use `Config::rich().do_decorate()` to get the old behaviour. 59 | - [fixed] Remove unnecessary empty lines at the start of lists (thanks russellbanks) 60 | - [added] New CSS support: `::before`/`::after` and `content: "string"`, which is now 61 | used for simple decorations. With CSS enabled, this allows for customising 62 | the display of `foo` without writing a decorator. 63 | - [added] Add support for `` and `
` (thanks noahbaculi) 64 | - [changed] Link footnotes are now configurable independently of the decorator, and on 65 | by default for `config::plain()` but can be enabled or disabled with 66 | `config.link_footnotes(true/false)`. The footnote references (e.g. `[1]`) are added 67 | in the main renderer, and the actual footnotes are written in a default implementation 68 | of `TextDecorator::finalise()` so can be customised. 69 | 70 | ### 0.13.6 71 | 72 | - [fixed] Fixed issue parsing CSS rules with known rules but unknown values, 73 | which caused parsing to stop instead of just skipping the unkown rule. 74 | 75 | ### 0.13.5 76 | 77 | - [added] CSS support for `:nth-child()` (not yet with the `of foo`). 78 | - [added] Non-standard `display: x-raw-dom` for debugging (with `css_ext` 79 | feature flag). 80 | - [fixed] An issue which could (apparently rarely) miss out some output depending on wrapping 81 | - [fixed] CSS parsing stopped when it hit an at-rule. 82 | - [added] Add `--show-css` option to `html2text` example for debugging what rules were parsed. 83 | - [added] Add poor-man's inspect mode to `html2term` - `I` to enable/disable, and arrows to navigate 84 | around the DOM. Implemented using `:nth-child` and `x-raw-dom`. 85 | 86 | ### 0.13.4 87 | 88 | - [fixed] Fix a debug assertion from a double-counted length increment 89 | (thanks JadedBlueeyes). 90 | 91 | ### 0.13.3 92 | 93 | - [fixed] Handle some obsolete `bgcolor=...` attributes. 94 | - [added] html2text example has `--show-render` to help debugging render issues. 95 | - [changed] Some error handling and other tidyups (thanks sftse) 96 | 97 | ### 0.13.2 98 | 99 | - [fixed] Fixed errors when building with Rust 1.72. 100 | 101 | ### 0.13.1 102 | 103 | - [added] html2text now has --show-dom 104 | - [fixed] Support background CSS property (for colour) 105 | - [fixed] Some edge cases with CSS styles on whitespace 106 | 107 | ### 0.13.0 108 | 109 | - [added] Support CSS white-space: pre-wrap (and normal, pre). 110 | 111 | ### 0.13.0-alpha.2 112 | 113 | - [changed] Updated html5ever and markup5ever crate versions. This has meant 114 | updating the MSRV, which is now set to 1.72. 115 | - [fixed] Add `Config::no_link_wrapping()` (thanks JadeBlueEyes) 116 | - [fixed] Fix panic with empty table inside a list (thanks sftse) 117 | - [changed] Top level convenience functions (`from_read` etc.) now return 118 | `Result<..>` instead of panicking (thanks sftse) 119 | - [fixed] Fix panic with very large HTML `colspan` (thanks pycui) 120 | - [changed] CSS updates: 121 | - Separate user agent, author, and user CSS layers 122 | - Improve the style precedence between layers and implement specificity. 123 | 124 | ### 0.13.0-alpha.1 125 | 126 | - [fixed] Table rows with colours would disappear. (thanks tkapias) 127 | 128 | ### 0.13.0-alpha.0 129 | 130 | - [changed] Replaced LightningCSS with a smaller CSS parser. There is a chance 131 | that some CSS edge cases which no longer work; if so this would be a bug. 132 | - [removed] Some previously `pub` items and methods which are either internal 133 | implementation details or considered redundant have been removed or made 134 | private (thanks sftse). Please open an issue for anything removed that was 135 | being used. 136 | 137 | Of note, `RenderTree::render_plain()` and `RenderTree::render_rich()` have 138 | been removed. Replace code like: 139 | 140 | ```rust 141 | let text = html2text::parse(html)? 142 | .render_plain(80)? 143 | .into_string()?; 144 | ``` 145 | with: 146 | ```rust 147 | let text = html2text::config::plain() 148 | .render_to_string(html2text::parse(html)?)? 149 | ``` 150 | - [changed] Some names moved out of `text_renderer` module, so some `use` statements 151 | may need updating. 152 | - [changed] Replace some `unwrap()` with improved patterns (thanks sftse). 153 | - [changed] Updated some dependencies 154 | 155 | ### 0.12.5 156 | 157 | - [changed] Updated some dependencies 158 | - [added] The `html2text` example now has `--ignore-css-colour`, which ignores CSS 159 | colour information but still uses `display: none`, for example. 160 | - [added] The `html2text` example now has `--only-css` option, to not use 161 | default colours when CSS colours are being used. 162 | - [fixed] Make the dummy `dashmap` depenency optional so it's not included 163 | unnecessarily when CSS isn't enabled (thanks xmakro) 164 | 165 | ### 0.12.4 166 | 167 | - [changed] Update the previous `max-height: 0` to also look at `height: 0` and require 168 | `overflow: hidden` as well. 169 | This helps with a hack some e-mail senders use for e-mail previews. (thanks tkapias) 170 | 171 | ### 0.12.3 172 | 173 | - [changed] Treat `max-height: 0` as if it's `display: none` when CSS is enabled. 174 | This helps with a hack some e-mail senders use for e-mail previews. (thanks tkapias) 175 | 176 | ### 0.12.2 177 | 178 | - [changed] Bump version of lightningcss dependency to fix build failures. 179 | 180 | ### 0.12.1 181 | 182 | - [fixed] Fix a case where Err(TooNarrow) was returned unnecessarily. (thanks sftse) 183 | - [added] Add new rendering options `Config::raw_mode()` and 184 | `Config::no_table_borders()` (thanks sftse) 185 | - [changed] Formatting, clippy and other tidy-ups (thanks sftse) 186 | - [changed] Cargo fmt now enforced in CI 187 | 188 | ### 0.12.0 189 | 190 | - [changed] Updated termion dev-dependency 191 | - [added] Support `` HTML elements 192 | - [added] Export `RcDom` publically. It was already returned by a pub function. 193 | - [added] Update handling of width overflow: 194 | With `Config::allow_width_overflow()`, prefer returning output wider 195 | than requested, instead of returning `Err(TooNarrow)`. 196 | `Config::min_wrap_width()` sets the minimum text wrap width (default 197 | 3). The minimum width (before overflow or `TooNarrow`) is now 198 | handled more cleanly. 199 | - [added] CSS: use color/bgcolor attributes on elements. 200 | 201 | ### 0.11.0 202 | 203 | - [fixed] CSS: rules marked !important were ignored. 204 | - [changed] html\_trace feature now uses the `log` crate. 205 | - [changed] Bumped MSRV to 1.63 (matching Debian stable) due to some dependencies. 206 | 207 | ### 0.10.3 208 | 209 | - [fixed] A panic on some unlucky text wrapping coincidences. 210 | - [fixed] Use dep:backtrace in Cargo.toml to avoid implicit feature. 211 | 212 | ### 0.10.2 213 | 214 | - [fixed] CSS: Ignore transparent colours. 215 | 216 | ### 0.10.1 217 | 218 | - [fixed] `max_width` was not working with some render methods. 219 | 220 | ### 0.10.0 221 | 222 | - [added] Simple support for ``, ``, and `
` (thanks sgtatham) 223 | - [added] Added background-color support 224 | - [fixed] CSS support didn't work in some places, such as `` elements. 225 | - [added] Add support for `style` attributes. 226 | - [added] Styles apply to table borders 227 | - [changed] Update some dependencies 228 | - [fixed] Fix a few places which caused excess blank lines or empty tables 229 | 230 | ### 0.9.4 231 | 232 | - [changed] Updated the termion dev-dependency to 2.0. 233 | 234 | ### 0.9.3 235 | 236 | - [changed] Added cargo categories and update to 2021 edition. 237 | 238 | ### 0.9.2 239 | 240 | - [fixed] CSS didn't work inside ` ` or `
`. 241 | - [added] Add methods to get and use the intermediate HTML DOM and RenderTree 242 | from Config. 243 | - [fixed] Removed some clones which are no longer necessary now that Box
244 | works. 245 | 246 | ### 0.9.1 247 | 248 | - [fixed] Various documentation issues (thanks sgtatham) 249 | - [changed] CSS color rules now work for elements other than span. 250 | 251 | ### 0.9.0 252 | 253 | - [changed] `Config::add_css` now returns `Result` instead of panicking on 254 | CSS parse errors. Errors from parsing document CSS are ignored. 255 | - [added] Support `` when CSS is enabled. 256 | - [added] `Config::max_wrap_width()` to wrap text to a norrower width than 257 | the overal size available. 258 | - [added] Add --wrap-width and --css options to html2text example. 259 | 260 | ### 0.8.0 261 | 262 | - [added] CSS: Support more extensive selectors 263 | - [changed] CSS handling defaults to off; use `Config::use_doc_css()` 264 | or `Config::add_css` to use CSS. 265 | 266 | ### 0.7.1 267 | 268 | - [added] Now recognised CSS `display:none` 269 | - [added] Can now add extra CSS rules via `Config::add_css`. 270 | - [changed] StyleData::coloured is no longer public. 271 | 272 | ### 0.7.0 273 | 274 | - [changed] Remove some noisy stderr output when encoutering control chars 275 | (thanks sftse) 276 | - [added] A builder-based config API. 277 | - [changed] Updated MSRV to 1.60 278 | - [fixed] Fixed #88: panic when a width of zero passed in (thanks bingen13) 279 | - [fixed] Fixed #90: Fixed a divide-by-zero panic with colspan=0 (thanks mtorromeo) 280 | - [added] Add very basic CSS colour support (under the css feature flag) 281 | - [changed] Removed ansi\_colours feature (from\_read\_coloured is always available) 282 | - [changed] Overhauled error handling. Internally (and in the lower level 283 | API) errors (mainly "TooNarrow") are passed around with `Result`. Fixed 284 | some panics and infinite loops. (Thanks WIZeaz for fuzzing) 285 | 286 | ### 0.6.0 287 | 288 | - [changed] Improve layout of tables thanks to sftse: 289 | - Table column size estimates have been improved when the source HTML has a lot 290 | of unnecessary whitespace. 291 | - Move the URL footnotes out to the top level, also improving layout of tables 292 | containing links. 293 | - [changed] Some APIs have slightly changed as part of the table improvements, 294 | though most users should not be affeted. 295 | 296 | ### 0.5.1 297 | 298 | - [fixed] Some tables were rendered too wide. 299 | 300 | ### 0.5.0 301 | 302 | - [changed] Rich Image annotations now include the src attirbute (thanks spencerwi). 303 | 304 | ### 0.4.5 305 | 306 | - [fixed] Preserve empty lines in pre blocks (thanks kpagacz). 307 | 308 | ### 0.4.4 309 | 310 | - [fixed] Fix some panics when enumerated lists are in tables (thanks sfts). 311 | - [fixed] Impove table size estimation to include links. 312 | 313 | ### 0.4.3 314 | 315 | - [changed] MSRV is now 1.56. 316 | - [fixed] Fix some panics when very large widths are used with tables. 317 | 318 | ### 0.4.2 319 | 320 | - [changed] Moved the rcdom module directly into src/ 321 | 322 | ### 0.4.1 (unpublished) 323 | 324 | - [changed] rcdom now vendored as a module. 325 | 326 | ### 0.4.0 (unpublished) 327 | 328 | - [changed] Update html5ever to v0.26. 329 | - [changed] MSRV is now 1.49. 330 | 331 | ### 0.3.1 332 | 333 | - [changed] Update the build badges to reflect the updated CI configuration. 334 | 335 | ### 0.3.0 336 | 337 | - [added] New experimental `from_read_coloured()` (under `ansi_colours` feature). 338 | - [added] Add `into_tagged_strings` and `tagged_strings` methods to `TaggedLine` 339 | (thanks Robin Krahl) 340 | - [added] Add `width` method to `TaggedString` (thanks Robin Krahl) 341 | - [changed] Keep annotations in `TextRenderer::into_lines` (thanks Robin Krahl) 342 | - [fixed] Add colon to reference style link (thanks zakaluka) 343 | - [added] Allow text decorators to customise block prefix strings (thanks SardineFish) 344 | - [fixed] Fixed some problems rendering some complicated tables, including a panic 345 | and near-infinite loops. 346 | - [changed] Tables which are too wide to possibly render in the given width are now 347 | arranged vertically instead (with `///`) lines. 348 | - [changed] A number of small table rendering improvements. 349 | - [changed] MSRV is now 1.41. 350 | 351 | ### 0.2.1 352 | 353 | - [added] New entry points - split HTML parsing from rendering the output, 354 | thanks Robin Krahl. 355 | - [fixed] Decorators weren't being used for preformatted text. 356 | 357 | ### 0.2.0 358 | 359 | - [added] Support ` ` strikeout text. 360 | 361 | ### 0.1.14 (2020-08-07) 362 | 363 | - [fixed] A table with an `id` attribute on `` would be hidden. 364 | 365 | ### 0.1.13 (2020-07-21) 366 | 367 | - [changed] Run cargo fmt (thanks crunchyjesus) 368 | - [added] CHANGELOG.md 369 | - [fixed] Some text near a fragment start (`id="foo"` attribute) could be 370 | lost if it needed breaking across lines. 371 | - [added] Experimentally add dependabot configuration. 372 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anstream" 31 | version = "0.6.18" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 34 | dependencies = [ 35 | "anstyle", 36 | "anstyle-parse", 37 | "anstyle-query", 38 | "anstyle-wincon", 39 | "colorchoice", 40 | "is_terminal_polyfill", 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle" 46 | version = "1.0.10" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 49 | 50 | [[package]] 51 | name = "anstyle-parse" 52 | version = "0.2.6" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 55 | dependencies = [ 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-query" 61 | version = "1.1.2" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 64 | dependencies = [ 65 | "windows-sys", 66 | ] 67 | 68 | [[package]] 69 | name = "anstyle-wincon" 70 | version = "3.0.8" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" 73 | dependencies = [ 74 | "anstyle", 75 | "once_cell_polyfill", 76 | "windows-sys", 77 | ] 78 | 79 | [[package]] 80 | name = "argparse" 81 | version = "0.2.2" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "3f8ebf5827e4ac4fd5946560e6a99776ea73b596d80898f357007317a7141e47" 84 | 85 | [[package]] 86 | name = "autocfg" 87 | version = "1.4.0" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 90 | 91 | [[package]] 92 | name = "backtrace" 93 | version = "0.3.75" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 96 | dependencies = [ 97 | "addr2line", 98 | "cfg-if", 99 | "libc", 100 | "miniz_oxide", 101 | "object", 102 | "rustc-demangle", 103 | "windows-targets", 104 | ] 105 | 106 | [[package]] 107 | name = "base64" 108 | version = "0.22.1" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 111 | 112 | [[package]] 113 | name = "bincode" 114 | version = "1.3.3" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 117 | dependencies = [ 118 | "serde", 119 | ] 120 | 121 | [[package]] 122 | name = "bitflags" 123 | version = "1.3.2" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 126 | 127 | [[package]] 128 | name = "bitflags" 129 | version = "2.9.1" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 132 | 133 | [[package]] 134 | name = "cc" 135 | version = "1.2.25" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" 138 | dependencies = [ 139 | "shlex", 140 | ] 141 | 142 | [[package]] 143 | name = "cfg-if" 144 | version = "1.0.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 147 | 148 | [[package]] 149 | name = "colorchoice" 150 | version = "1.0.3" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 153 | 154 | [[package]] 155 | name = "crc32fast" 156 | version = "1.4.2" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 159 | dependencies = [ 160 | "cfg-if", 161 | ] 162 | 163 | [[package]] 164 | name = "deranged" 165 | version = "0.4.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 168 | dependencies = [ 169 | "powerfmt", 170 | ] 171 | 172 | [[package]] 173 | name = "env_filter" 174 | version = "0.1.3" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" 177 | dependencies = [ 178 | "log", 179 | "regex", 180 | ] 181 | 182 | [[package]] 183 | name = "env_logger" 184 | version = "0.11.8" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" 187 | dependencies = [ 188 | "anstream", 189 | "anstyle", 190 | "env_filter", 191 | "jiff", 192 | "log", 193 | ] 194 | 195 | [[package]] 196 | name = "equivalent" 197 | version = "1.0.2" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 200 | 201 | [[package]] 202 | name = "flate2" 203 | version = "1.1.1" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" 206 | dependencies = [ 207 | "crc32fast", 208 | "miniz_oxide", 209 | ] 210 | 211 | [[package]] 212 | name = "fnv" 213 | version = "1.0.7" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 216 | 217 | [[package]] 218 | name = "futf" 219 | version = "0.1.5" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 222 | dependencies = [ 223 | "mac", 224 | "new_debug_unreachable", 225 | ] 226 | 227 | [[package]] 228 | name = "gimli" 229 | version = "0.31.1" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 232 | 233 | [[package]] 234 | name = "hashbrown" 235 | version = "0.15.3" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" 238 | 239 | [[package]] 240 | name = "html2text" 241 | version = "0.15.1" 242 | dependencies = [ 243 | "argparse", 244 | "backtrace", 245 | "env_logger", 246 | "html5ever", 247 | "log", 248 | "nom", 249 | "syntect", 250 | "tendril", 251 | "termion", 252 | "thiserror 2.0.12", 253 | "unicode-width", 254 | ] 255 | 256 | [[package]] 257 | name = "html5ever" 258 | version = "0.31.0" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c" 261 | dependencies = [ 262 | "log", 263 | "mac", 264 | "markup5ever", 265 | "match_token", 266 | ] 267 | 268 | [[package]] 269 | name = "indexmap" 270 | version = "2.9.0" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 273 | dependencies = [ 274 | "equivalent", 275 | "hashbrown", 276 | ] 277 | 278 | [[package]] 279 | name = "is_terminal_polyfill" 280 | version = "1.70.1" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 283 | 284 | [[package]] 285 | name = "itoa" 286 | version = "1.0.15" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 289 | 290 | [[package]] 291 | name = "jiff" 292 | version = "0.2.14" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" 295 | dependencies = [ 296 | "jiff-static", 297 | "log", 298 | "portable-atomic", 299 | "portable-atomic-util", 300 | "serde", 301 | ] 302 | 303 | [[package]] 304 | name = "jiff-static" 305 | version = "0.2.14" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" 308 | dependencies = [ 309 | "proc-macro2", 310 | "quote", 311 | "syn", 312 | ] 313 | 314 | [[package]] 315 | name = "libc" 316 | version = "0.2.172" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 319 | 320 | [[package]] 321 | name = "libredox" 322 | version = "0.1.3" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 325 | dependencies = [ 326 | "bitflags 2.9.1", 327 | "libc", 328 | "redox_syscall", 329 | ] 330 | 331 | [[package]] 332 | name = "linked-hash-map" 333 | version = "0.5.6" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 336 | 337 | [[package]] 338 | name = "lock_api" 339 | version = "0.4.13" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 342 | dependencies = [ 343 | "autocfg", 344 | "scopeguard", 345 | ] 346 | 347 | [[package]] 348 | name = "log" 349 | version = "0.4.27" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 352 | 353 | [[package]] 354 | name = "mac" 355 | version = "0.1.1" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 358 | 359 | [[package]] 360 | name = "markup5ever" 361 | version = "0.16.1" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a" 364 | dependencies = [ 365 | "log", 366 | "tendril", 367 | "web_atoms", 368 | ] 369 | 370 | [[package]] 371 | name = "match_token" 372 | version = "0.1.0" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" 375 | dependencies = [ 376 | "proc-macro2", 377 | "quote", 378 | "syn", 379 | ] 380 | 381 | [[package]] 382 | name = "memchr" 383 | version = "2.7.4" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 386 | 387 | [[package]] 388 | name = "minimal-lexical" 389 | version = "0.2.1" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 392 | 393 | [[package]] 394 | name = "miniz_oxide" 395 | version = "0.8.8" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 398 | dependencies = [ 399 | "adler2", 400 | ] 401 | 402 | [[package]] 403 | name = "new_debug_unreachable" 404 | version = "1.0.6" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 407 | 408 | [[package]] 409 | name = "nom" 410 | version = "7.1.3" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 413 | dependencies = [ 414 | "memchr", 415 | "minimal-lexical", 416 | ] 417 | 418 | [[package]] 419 | name = "num-conv" 420 | version = "0.1.0" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 423 | 424 | [[package]] 425 | name = "numtoa" 426 | version = "0.2.4" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" 429 | 430 | [[package]] 431 | name = "object" 432 | version = "0.36.7" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 435 | dependencies = [ 436 | "memchr", 437 | ] 438 | 439 | [[package]] 440 | name = "once_cell" 441 | version = "1.21.3" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 444 | 445 | [[package]] 446 | name = "once_cell_polyfill" 447 | version = "1.70.1" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 450 | 451 | [[package]] 452 | name = "onig" 453 | version = "6.5.1" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" 456 | dependencies = [ 457 | "bitflags 2.9.1", 458 | "libc", 459 | "once_cell", 460 | "onig_sys", 461 | ] 462 | 463 | [[package]] 464 | name = "onig_sys" 465 | version = "69.9.1" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" 468 | dependencies = [ 469 | "cc", 470 | "pkg-config", 471 | ] 472 | 473 | [[package]] 474 | name = "parking_lot" 475 | version = "0.12.4" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 478 | dependencies = [ 479 | "lock_api", 480 | "parking_lot_core", 481 | ] 482 | 483 | [[package]] 484 | name = "parking_lot_core" 485 | version = "0.9.11" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 488 | dependencies = [ 489 | "cfg-if", 490 | "libc", 491 | "redox_syscall", 492 | "smallvec", 493 | "windows-targets", 494 | ] 495 | 496 | [[package]] 497 | name = "phf" 498 | version = "0.11.3" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 501 | dependencies = [ 502 | "phf_shared", 503 | ] 504 | 505 | [[package]] 506 | name = "phf_codegen" 507 | version = "0.11.3" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 510 | dependencies = [ 511 | "phf_generator", 512 | "phf_shared", 513 | ] 514 | 515 | [[package]] 516 | name = "phf_generator" 517 | version = "0.11.3" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 520 | dependencies = [ 521 | "phf_shared", 522 | "rand", 523 | ] 524 | 525 | [[package]] 526 | name = "phf_shared" 527 | version = "0.11.3" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 530 | dependencies = [ 531 | "siphasher", 532 | ] 533 | 534 | [[package]] 535 | name = "pkg-config" 536 | version = "0.3.32" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 539 | 540 | [[package]] 541 | name = "plist" 542 | version = "1.7.1" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" 545 | dependencies = [ 546 | "base64", 547 | "indexmap", 548 | "quick-xml", 549 | "serde", 550 | "time", 551 | ] 552 | 553 | [[package]] 554 | name = "portable-atomic" 555 | version = "1.11.0" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" 558 | 559 | [[package]] 560 | name = "portable-atomic-util" 561 | version = "0.2.4" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" 564 | dependencies = [ 565 | "portable-atomic", 566 | ] 567 | 568 | [[package]] 569 | name = "powerfmt" 570 | version = "0.2.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 573 | 574 | [[package]] 575 | name = "precomputed-hash" 576 | version = "0.1.1" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 579 | 580 | [[package]] 581 | name = "proc-macro2" 582 | version = "1.0.95" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 585 | dependencies = [ 586 | "unicode-ident", 587 | ] 588 | 589 | [[package]] 590 | name = "quick-xml" 591 | version = "0.32.0" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" 594 | dependencies = [ 595 | "memchr", 596 | ] 597 | 598 | [[package]] 599 | name = "quote" 600 | version = "1.0.40" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 603 | dependencies = [ 604 | "proc-macro2", 605 | ] 606 | 607 | [[package]] 608 | name = "rand" 609 | version = "0.8.5" 610 | source = "registry+https://github.com/rust-lang/crates.io-index" 611 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 612 | dependencies = [ 613 | "rand_core", 614 | ] 615 | 616 | [[package]] 617 | name = "rand_core" 618 | version = "0.6.4" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 621 | 622 | [[package]] 623 | name = "redox_syscall" 624 | version = "0.5.12" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" 627 | dependencies = [ 628 | "bitflags 2.9.1", 629 | ] 630 | 631 | [[package]] 632 | name = "redox_termios" 633 | version = "0.1.3" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" 636 | 637 | [[package]] 638 | name = "regex" 639 | version = "1.11.1" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 642 | dependencies = [ 643 | "aho-corasick", 644 | "memchr", 645 | "regex-automata", 646 | "regex-syntax", 647 | ] 648 | 649 | [[package]] 650 | name = "regex-automata" 651 | version = "0.4.9" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 654 | dependencies = [ 655 | "aho-corasick", 656 | "memchr", 657 | "regex-syntax", 658 | ] 659 | 660 | [[package]] 661 | name = "regex-syntax" 662 | version = "0.8.5" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 665 | 666 | [[package]] 667 | name = "rustc-demangle" 668 | version = "0.1.24" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 671 | 672 | [[package]] 673 | name = "ryu" 674 | version = "1.0.20" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 677 | 678 | [[package]] 679 | name = "same-file" 680 | version = "1.0.6" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 683 | dependencies = [ 684 | "winapi-util", 685 | ] 686 | 687 | [[package]] 688 | name = "scopeguard" 689 | version = "1.2.0" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 692 | 693 | [[package]] 694 | name = "serde" 695 | version = "1.0.219" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 698 | dependencies = [ 699 | "serde_derive", 700 | ] 701 | 702 | [[package]] 703 | name = "serde_derive" 704 | version = "1.0.219" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 707 | dependencies = [ 708 | "proc-macro2", 709 | "quote", 710 | "syn", 711 | ] 712 | 713 | [[package]] 714 | name = "serde_json" 715 | version = "1.0.140" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 718 | dependencies = [ 719 | "itoa", 720 | "memchr", 721 | "ryu", 722 | "serde", 723 | ] 724 | 725 | [[package]] 726 | name = "shlex" 727 | version = "1.3.0" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 730 | 731 | [[package]] 732 | name = "siphasher" 733 | version = "1.0.1" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 736 | 737 | [[package]] 738 | name = "smallvec" 739 | version = "1.15.0" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 742 | 743 | [[package]] 744 | name = "string_cache" 745 | version = "0.8.9" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" 748 | dependencies = [ 749 | "new_debug_unreachable", 750 | "parking_lot", 751 | "phf_shared", 752 | "precomputed-hash", 753 | "serde", 754 | ] 755 | 756 | [[package]] 757 | name = "string_cache_codegen" 758 | version = "0.5.4" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" 761 | dependencies = [ 762 | "phf_generator", 763 | "phf_shared", 764 | "proc-macro2", 765 | "quote", 766 | ] 767 | 768 | [[package]] 769 | name = "syn" 770 | version = "2.0.101" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 773 | dependencies = [ 774 | "proc-macro2", 775 | "quote", 776 | "unicode-ident", 777 | ] 778 | 779 | [[package]] 780 | name = "syntect" 781 | version = "5.2.0" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" 784 | dependencies = [ 785 | "bincode", 786 | "bitflags 1.3.2", 787 | "flate2", 788 | "fnv", 789 | "once_cell", 790 | "onig", 791 | "plist", 792 | "regex-syntax", 793 | "serde", 794 | "serde_derive", 795 | "serde_json", 796 | "thiserror 1.0.69", 797 | "walkdir", 798 | "yaml-rust", 799 | ] 800 | 801 | [[package]] 802 | name = "tendril" 803 | version = "0.4.3" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 806 | dependencies = [ 807 | "futf", 808 | "mac", 809 | "utf-8", 810 | ] 811 | 812 | [[package]] 813 | name = "termion" 814 | version = "4.0.5" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "3669a69de26799d6321a5aa713f55f7e2cd37bd47be044b50f2acafc42c122bb" 817 | dependencies = [ 818 | "libc", 819 | "libredox", 820 | "numtoa", 821 | "redox_termios", 822 | ] 823 | 824 | [[package]] 825 | name = "thiserror" 826 | version = "1.0.69" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 829 | dependencies = [ 830 | "thiserror-impl 1.0.69", 831 | ] 832 | 833 | [[package]] 834 | name = "thiserror" 835 | version = "2.0.12" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 838 | dependencies = [ 839 | "thiserror-impl 2.0.12", 840 | ] 841 | 842 | [[package]] 843 | name = "thiserror-impl" 844 | version = "1.0.69" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 847 | dependencies = [ 848 | "proc-macro2", 849 | "quote", 850 | "syn", 851 | ] 852 | 853 | [[package]] 854 | name = "thiserror-impl" 855 | version = "2.0.12" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 858 | dependencies = [ 859 | "proc-macro2", 860 | "quote", 861 | "syn", 862 | ] 863 | 864 | [[package]] 865 | name = "time" 866 | version = "0.3.41" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 869 | dependencies = [ 870 | "deranged", 871 | "itoa", 872 | "num-conv", 873 | "powerfmt", 874 | "serde", 875 | "time-core", 876 | "time-macros", 877 | ] 878 | 879 | [[package]] 880 | name = "time-core" 881 | version = "0.1.4" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 884 | 885 | [[package]] 886 | name = "time-macros" 887 | version = "0.2.22" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 890 | dependencies = [ 891 | "num-conv", 892 | "time-core", 893 | ] 894 | 895 | [[package]] 896 | name = "unicode-ident" 897 | version = "1.0.18" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 900 | 901 | [[package]] 902 | name = "unicode-width" 903 | version = "0.2.0" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 906 | 907 | [[package]] 908 | name = "utf-8" 909 | version = "0.7.6" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 912 | 913 | [[package]] 914 | name = "utf8parse" 915 | version = "0.2.2" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 918 | 919 | [[package]] 920 | name = "walkdir" 921 | version = "2.5.0" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 924 | dependencies = [ 925 | "same-file", 926 | "winapi-util", 927 | ] 928 | 929 | [[package]] 930 | name = "web_atoms" 931 | version = "0.1.2" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e" 934 | dependencies = [ 935 | "phf", 936 | "phf_codegen", 937 | "string_cache", 938 | "string_cache_codegen", 939 | ] 940 | 941 | [[package]] 942 | name = "winapi-util" 943 | version = "0.1.9" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 946 | dependencies = [ 947 | "windows-sys", 948 | ] 949 | 950 | [[package]] 951 | name = "windows-sys" 952 | version = "0.59.0" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 955 | dependencies = [ 956 | "windows-targets", 957 | ] 958 | 959 | [[package]] 960 | name = "windows-targets" 961 | version = "0.52.6" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 964 | dependencies = [ 965 | "windows_aarch64_gnullvm", 966 | "windows_aarch64_msvc", 967 | "windows_i686_gnu", 968 | "windows_i686_gnullvm", 969 | "windows_i686_msvc", 970 | "windows_x86_64_gnu", 971 | "windows_x86_64_gnullvm", 972 | "windows_x86_64_msvc", 973 | ] 974 | 975 | [[package]] 976 | name = "windows_aarch64_gnullvm" 977 | version = "0.52.6" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 980 | 981 | [[package]] 982 | name = "windows_aarch64_msvc" 983 | version = "0.52.6" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 986 | 987 | [[package]] 988 | name = "windows_i686_gnu" 989 | version = "0.52.6" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 992 | 993 | [[package]] 994 | name = "windows_i686_gnullvm" 995 | version = "0.52.6" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 998 | 999 | [[package]] 1000 | name = "windows_i686_msvc" 1001 | version = "0.52.6" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1004 | 1005 | [[package]] 1006 | name = "windows_x86_64_gnu" 1007 | version = "0.52.6" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1010 | 1011 | [[package]] 1012 | name = "windows_x86_64_gnullvm" 1013 | version = "0.52.6" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1016 | 1017 | [[package]] 1018 | name = "windows_x86_64_msvc" 1019 | version = "0.52.6" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1022 | 1023 | [[package]] 1024 | name = "yaml-rust" 1025 | version = "0.4.5" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 1028 | dependencies = [ 1029 | "linked-hash-map", 1030 | ] 1031 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "html2text" 3 | version = "0.15.1" 4 | authors = ["Chris Emerson"] 5 | description = "Render HTML as plain text." 6 | repository = "https://github.com/jugglerchris/rust-html2text/" 7 | readme = "README.md" 8 | documentation = "https://docs.rs/html2text/" 9 | edition = "2021" 10 | rust-version = "1.72" 11 | categories = ["text-processing"] 12 | 13 | keywords = ["html", "text"] 14 | license = "MIT" 15 | 16 | [dependencies] 17 | html5ever = "0.31.0" 18 | tendril = "0.4" 19 | unicode-width = "0.2" 20 | backtrace = { version = "0.3", optional=true } 21 | thiserror = "2.0.0" 22 | log = { version = "0.4.20", optional = true } 23 | nom = { version = "7.1.3", optional = true } 24 | 25 | [features] 26 | html_trace = ["dep:log"] 27 | html_trace_bt = ["html_trace", "dep:backtrace"] 28 | default = [] 29 | css = [ "dep:nom" ] 30 | css_ext = ["css"] 31 | 32 | [[example]] 33 | name = "html2term" 34 | path = "examples/html2term.rs" 35 | 36 | [[example]] 37 | name = "html2text" 38 | path = "examples/html2text.rs" 39 | 40 | [dev-dependencies] 41 | env_logger = "0.11.6" 42 | argparse = "0.2.2" 43 | log = "0.4.20" 44 | syntect = "5.2.0" 45 | 46 | [target.'cfg(unix)'.dev-dependencies] 47 | termion = "4.0" 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Chris Emerson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://app.circleci.com/pipelines/github/jugglerchris/rust-html2text?filter=all) 2 | 3 | # html2text 4 | 5 | html2text is a [Rust](http://www.rust-lang.org/) crate which converts HTML to 6 | plain text (as in Rust `String`) or text spans with annotations like colours, 7 | e.g. optionally using CSS. See [the online demo](https://jugglerchris.github.io/rust-html2text/) 8 | for examples of the output. 9 | 10 | It makes use of the [Servo project](https://github.com/servo/servo)'s HTML 11 | parser, [html5ever](https://github.com/servo/html5ever/), using the DOM to 12 | generate text (which can optionally include annotations for some features such 13 | as hyperlinks). 14 | 15 | The project aims to do a reasonable job of rendering reasonable HTML in a 16 | terminal or other places where HTML needs to be converted to text (for 17 | example the text/plain fallback in HTML e-mails). 18 | 19 | With features (see below) some CSS/colour support is available. 20 | 21 | ## Examples 22 | 23 | The simple functions like `from_read()` return formatted text (in various 24 | formats including plain text). 25 | 26 | ```rust 27 | use html2text::from_read; 28 | let html = b" 29 | 30 |
"; 34 | assert_eq!(from_read(&html[..], 20).unwrap(), 35 | "\ 36 | * Item one 37 | * Item two 38 | * Item three 39 | "); 40 | ``` 41 | 42 | A lower level API gives a bit more control. This give the same result (except for 43 | returning errors as Result instead of panicking): 44 | 45 | ```rust 46 | use html2text::config; 47 | 48 | let html = b" 49 |- Item one
31 |- Item two
32 |- Item three
33 |50 |
"; 54 | 55 | assert_eq!( 56 | config::plain() 57 | .string_from_read(&html[..], 20) 58 | .unwrap(), 59 | "\ 60 | * Item one 61 | * Item two 62 | * Item three 63 | "); 64 | ``` 65 | 66 | A couple of simple demonstration programs are included as examples: 67 | 68 | ### html2text 69 | 70 | The simplest example uses `from_read` to convert HTML on stdin into plain 71 | text: 72 | 73 | ```sh 74 | $ cargo run --example html2text < foo.html 75 | [...] 76 | ``` 77 | 78 | ### html2term 79 | 80 | A very simple example of using the rich interface (`from_read_rich`) for a 81 | slightly interactive console HTML viewer is provided as `html2term`. 82 | 83 | ```sh 84 | $ cargo run --example html2term foo.html 85 | [...] 86 | ``` 87 | 88 | Note that this example takes the HTML file as a parameter so that it can 89 | read keys from stdin. 90 | 91 | ## Cargo Features 92 | 93 | |Feature| Description| 94 | |-------|------------| 95 | |css | Limited handling of CSS, adding Coloured nodes to the render tree. | 96 | |html\_trace| Add verbose internal logging (not recommended) | 97 | |html\_trace\_bt| Add backtraces to the verbose internal logging | 98 | 99 | ### CSS support 100 | 101 | When the `css` feature is enabled, some simple CSS handling is available. 102 | 103 | Style rules are taken from: 104 | * If `Config::use_doc_css()` is called, then style from the document: 105 | * ` 19 | 38 | 39 | 40 |- Item one
51 |- Item two
52 |- Item three
53 |Html2text demo
41 | CSS 42 |
43 | Colour 44 |
45 | 66 |
67 | 68 | 69 | 70 |