├── .gitignore
├── pages
├── .gitignore
├── _config.yml
├── _includes
│ └── head.html
├── assets
│ ├── demo.css
│ └── demo-main.js
└── index.markdown
├── html2text-web-demo
├── .gitignore
├── .cargo
│ └── config.toml
├── Trunk.toml
├── Cargo.toml
├── index.html
└── src
│ └── lib.rs
├── src
├── css
│ └── types.rs
├── ansi_colours.rs
├── macros.rs
├── render
│ └── mod.rs
├── markup5ever_rcdom.rs
└── css.rs
├── .github
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ └── jekyll-gh-pages.yml
├── rust.yml
├── LICENSE
├── Cargo.toml
├── .circleci
└── config.yml
├── benches
└── tables.rs
├── README.md
├── examples
├── html2text.rs
└── html2term.rs
├── CHANGELOG.md
└── Cargo.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 |
--------------------------------------------------------------------------------
/pages/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 |
--------------------------------------------------------------------------------
/html2text-web-demo/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/html2text-web-demo/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | target = "wasm32-wasip2"
3 |
--------------------------------------------------------------------------------
/src/css/types.rs:
--------------------------------------------------------------------------------
1 | #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2 | pub(crate) enum Importance {
3 | Default,
4 | Important,
5 | }
6 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/pages/_config.yml:
--------------------------------------------------------------------------------
1 | lsi: false
2 | safe: true
3 | source: .
4 | incremental: false
5 | baseurl: "/rust-html2text"
6 | gist:
7 | noscript: false
8 |
9 | theme: minima
10 |
11 | github_username: jugglerchris
12 |
--------------------------------------------------------------------------------
/html2text-web-demo/Trunk.toml:
--------------------------------------------------------------------------------
1 | trunk-version = "^0.21.13"
2 |
3 | [build]
4 | public_url = "/rust-html2text/"
5 | release = true
6 | filehash = false
7 | inject_scripts = true #false
8 | offline = false #true
9 | frozen = true
10 | minify = "on_release"
11 |
--------------------------------------------------------------------------------
/html2text-web-demo/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "html2text-web-demo"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [dependencies]
7 | html2text = { path = "..", features = ["css"] }
8 | ratzilla = "0.0.6"
9 | wasm-bindgen = "0.2.100"
10 |
11 | [lib]
12 | crate-type = ["cdylib", "rlib"]
13 |
--------------------------------------------------------------------------------
/rust.yml:
--------------------------------------------------------------------------------
1 | name: Rust
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Build
20 | run: cargo build --verbose
21 | - name: Run tests
22 | run: cargo test --verbose
23 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/pages/_includes/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {%- seo -%}
6 |
7 | {%- feed_meta -%}
8 | {%- if jekyll.environment == 'production' and site.google_analytics -%}
9 | {%- include google-analytics.html -%}
10 | {%- endif -%}
11 | {%- if page.h2t_wasm -%}
12 |
13 |
14 |
15 | {%- endif -%}
16 | {%- if page.h2t_js -%}
17 |
19 | {%- endif -%}
20 |
21 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/pages/assets/demo.css:
--------------------------------------------------------------------------------
1 | #lib {
2 | background-color: black;
3 | height: 30em;
4 | overflow: scroll;
5 | }
6 | #input_html {
7 | height: 300px;
8 | width: 95%;
9 | overflow: scroll;
10 | }
11 |
12 | #lib pre {
13 | margin: 0;
14 | padding: 0;
15 | overflow: hidden;
16 | background-color: black;
17 | border: 0px;
18 | }
19 |
20 | .warning {
21 | color: red;
22 | }
23 | .warning::before {
24 | content: "⚠️";
25 | }
26 |
27 | div.wrapper {
28 | max-width: 100%;
29 | }
30 | @media screen and (min-width: 1000px) {
31 | #h2tmain {
32 | display: grid;
33 | gap: 10px;
34 | grid-template-columns: 1fr 1fr;
35 | }
36 | #lib_container {
37 | grid-column: 1;
38 | min-width: 45%;
39 | }
40 | #input_container {
41 | grid-column: 1;
42 | grid-row-start: 2;
43 | min-width: 45%;
44 | }
45 | #configtable {
46 | grid-column: 2;
47 | grid-row-start: 1;
48 | grid-row-end: 3;
49 | min-width: 45%;
50 | }
51 | #rust-code-pre {
52 | grid-column: 2;
53 | min-width: 45%;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/ansi_colours.rs:
--------------------------------------------------------------------------------
1 | //! Convenience helper for producing coloured terminal output.
2 | //!
3 | //! This optional helper applies terminal colours (or other effects which
4 | //! can be achieved using inline characters sent to the terminal such as
5 | //! underlining in some terminals).
6 |
7 | use crate::RichAnnotation;
8 | use std::io;
9 |
10 | /// Reads HTML from `input`, and returns text wrapped to `width` columns.
11 | ///
12 | /// The text is returned as a `Vec>`; the annotations are vectors
13 | /// of `RichAnnotation`. The "outer" annotation comes first in the `Vec`.
14 | ///
15 | /// The function `colour_map` is given a slice of `RichAnnotation` and should
16 | /// return a pair of static strings which should be inserted before/after a text
17 | /// span with that annotation; for example a string which sets text colour
18 | /// and a string which sets the colour back to the default.
19 | pub fn from_read_coloured(
20 | input: R,
21 | width: usize,
22 | colour_map: FMap,
23 | ) -> Result
24 | where
25 | R: io::Read,
26 | FMap: Fn(&[RichAnnotation], &str) -> String,
27 | {
28 | super::config::rich().coloured(input, width, colour_map)
29 | }
30 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "html2text"
3 | version = "0.16.5"
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.85"
11 | categories = ["text-processing"]
12 |
13 | keywords = ["html", "text"]
14 | license = "MIT"
15 |
16 | [dependencies]
17 | html5ever = "0.36.1"
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 = "8.0.0", 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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/src/macros.rs:
--------------------------------------------------------------------------------
1 | #[cfg(feature = "html_trace_bt")]
2 | extern crate backtrace;
3 |
4 | /* This is to work around a false positive for the clippy warning
5 | * `match_on_same_arms`.
6 | * See https://github.com/Manishearth/rust-clippy/issues/1390
7 | */
8 | #[cfg(not(feature = "html_trace"))]
9 | #[inline(always)]
10 | pub fn nop() {}
11 |
12 | #[cfg(feature = "html_trace")]
13 | #[macro_export]
14 | #[doc(hidden)]
15 | macro_rules! html_trace {
16 | ($fmt:expr) => {
17 | #[cfg(feature = "html_trace_bt")]
18 | {
19 | let bt = ::backtrace::Backtrace::new();
20 | log::info!( concat!($fmt, " at {:?}"), bt );
21 | }
22 | #[cfg(not(feature = "html_trace_bt"))]
23 | {
24 | log::info!($fmt);
25 | }
26 | };
27 | ($fmt:expr, $( $args:expr ),*) => {
28 | #[cfg(feature = "html_trace_bt")]
29 | {
30 | let bt = ::backtrace::Backtrace::new();
31 | log::info!( concat!($fmt, " at {:?}"), $( $args ),* , bt );
32 | }
33 | #[cfg(not(feature = "html_trace_bt"))]
34 | {
35 | log::info!($fmt, $( $args ),*);
36 | }
37 | };
38 | }
39 | #[cfg(not(feature = "html_trace"))]
40 | #[macro_export]
41 | #[doc(hidden)]
42 | macro_rules! html_trace {
43 | ($fmt:expr) => {
44 | $crate::macros::nop();
45 | };
46 | ($fmt:expr, $( $args:expr ),*) => {
47 | $crate::macros::nop();
48 | };
49 | }
50 |
51 | #[cfg(feature = "html_trace")]
52 | #[macro_export]
53 | #[doc(hidden)]
54 | macro_rules! html_trace_quiet {
55 | ($fmt:expr) => {
56 | log::trace!( $fmt );
57 | };
58 | ($fmt:expr, $( $args:expr ),*) => {
59 | log::trace!( $fmt, $( $args ),* );
60 | };
61 | }
62 |
63 | #[cfg(not(feature = "html_trace"))]
64 | #[macro_export]
65 | #[doc(hidden)]
66 | macro_rules! html_trace_quiet {
67 | ($fmt:expr) => {
68 | $crate::macros::nop();
69 | };
70 | ($fmt:expr, $( $args:expr ),*) => {
71 | $crate::macros::nop();
72 | };
73 | }
74 |
--------------------------------------------------------------------------------
/html2text-web-demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
38 |
39 |
40 | Html2text demo
41 | CSS
42 |
43 | Colour
44 |
45 |
66 |
67 | Update
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/.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.85.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 --all-features
27 | build-css:
28 | docker:
29 | - image: cimg/rust:1.90
30 | steps:
31 | - checkout
32 | - run: cargo --version
33 | - run: cargo build --features=css
34 | - run: cargo test --features=css
35 | build-1-85:
36 | docker:
37 | - image: cimg/rust:1.85
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-85"
79 | - "build-windows"
80 |
--------------------------------------------------------------------------------
/benches/tables.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 | extern crate html2text;
3 | extern crate test;
4 |
5 | use ::test::Bencher;
6 |
7 | use html2text::from_read;
8 |
9 | fn make_html(content: &str) -> String {
10 | String::from("") + content + ""
11 | }
12 |
13 | fn make_tab(cell: &str, rows: usize, cols: usize) -> String {
14 | let mut result = String::from("");
15 | for _ in 0..rows {
16 | result.push_str("");
17 | for _ in 0..cols {
18 | result.push_str("");
19 | result.push_str(cell);
20 | result.push_str(" ");
21 | }
22 | result.push_str(" ");
23 | }
24 | result
25 | }
26 |
27 | #[bench]
28 | fn bench_empty(b: &mut Bencher) {
29 | b.iter(|| from_read(make_html("").as_bytes(), 80));
30 | }
31 |
32 | #[bench]
33 | fn bench_tab_1_1(b: &mut Bencher) {
34 | b.iter(|| from_read(make_html(&make_tab("cell", 1, 1)).as_bytes(), 80));
35 | }
36 | #[bench]
37 | fn bench_tab_2_2(b: &mut Bencher) {
38 | b.iter(|| from_read(make_html(&make_tab("cell", 2, 2)).as_bytes(), 80));
39 | }
40 | #[bench]
41 | fn bench_tab_3_3(b: &mut Bencher) {
42 | b.iter(|| from_read(make_html(&make_tab("cell", 3, 3)).as_bytes(), 80));
43 | }
44 | #[bench]
45 | fn bench_tab_4_4(b: &mut Bencher) {
46 | b.iter(|| from_read(make_html(&make_tab("cell", 4, 4)).as_bytes(), 80));
47 | }
48 | #[bench]
49 | fn bench_tab_5_5(b: &mut Bencher) {
50 | b.iter(|| from_read(make_html(&make_tab("cell", 5, 5)).as_bytes(), 80));
51 | }
52 | #[bench]
53 | fn bench_tab_6_6(b: &mut Bencher) {
54 | b.iter(|| from_read(make_html(&make_tab("cell", 6, 6)).as_bytes(), 80));
55 | }
56 | // Try a table with `depth` nested tables each with `rows` rows and `cols` columns.
57 | fn bench_tab_depth(b: &mut Bencher, content: &str, depth: usize, rows: usize, cols: usize) {
58 | let mut t = String::from(content);
59 | for _ in 0..depth {
60 | t = make_tab(&t, rows, cols);
61 | }
62 | let html = make_html(&t);
63 | b.iter(|| from_read(html.as_bytes(), 80));
64 | }
65 | #[bench]
66 | fn bench_tab_2_1_depth_2(b: &mut Bencher) {
67 | bench_tab_depth(b, "cell", 2, 2, 1);
68 | }
69 | #[bench]
70 | fn bench_tab_3_1_depth_2(b: &mut Bencher) {
71 | bench_tab_depth(b, "cell", 2, 3, 1);
72 | }
73 | #[bench]
74 | fn bench_tab_4_1_depth_2(b: &mut Bencher) {
75 | bench_tab_depth(b, "cell", 2, 4, 1);
76 | }
77 | #[bench]
78 | fn bench_tab_1_2_depth_2(b: &mut Bencher) {
79 | bench_tab_depth(b, "cell", 2, 1, 2);
80 | }
81 | #[bench]
82 | fn bench_tab_1_3_depth_2(b: &mut Bencher) {
83 | bench_tab_depth(b, "cell", 2, 1, 3);
84 | }
85 | #[bench]
86 | fn bench_tab_1_4_depth_2(b: &mut Bencher) {
87 | bench_tab_depth(b, "cell", 2, 1, 4);
88 | }
89 | #[bench]
90 | fn bench_tab_2_depth_2(b: &mut Bencher) {
91 | bench_tab_depth(b, "cell", 2, 2, 2);
92 | }
93 | /*
94 | #[bench]
95 | fn bench_tab_2_depth_3(b: &mut Bencher) {
96 | bench_tab_depth(b, "cell", 3, 2, 2);
97 | }
98 | #[bench]
99 | fn bench_tab_2_depth_4(b: &mut Bencher) {
100 | bench_tab_depth(b, "cell", 4, 2, 2);
101 | }
102 | #[bench]
103 | fn bench_tab_2_depth_5(b: &mut Bencher) {
104 | bench_tab_depth(b, "cell", 5, 2, 2);
105 | }
106 | */
107 |
--------------------------------------------------------------------------------
/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 | Item one
31 | Item two
32 | Item three
33 | ";
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 |
50 | Item one
51 | Item two
52 | Item three
53 | ";
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 | * `
48 |
49 | Hi there
50 | This is some simple text with a link to github
51 |
52 | Item one
53 | Item two
54 | Item three
55 |
56 |
57 | Heading 1 Heading 2 Heading 3
58 | Data 1 Data 2 Data 3
59 | Hello there
60 |
61 |