diff --git a/examples/html2term.rs b/examples/html2term.rs
index a1c2937..141479f 100644
--- a/examples/html2term.rs
+++ b/examples/html2term.rs
@@ -269,21 +269,17 @@ mod top {
Key::Char('k') | Key::Up => {
if inspect_path.is_empty() {
doc_y = doc_y.saturating_sub(1);
- } else {
- if *inspect_path.last().unwrap() > 1 {
- *inspect_path.last_mut().unwrap() -= 1;
- annotated = rerender(&dom, &inspect_path, width, &options);
- }
+ } else if *inspect_path.last().unwrap() > 1 {
+ *inspect_path.last_mut().unwrap() -= 1;
+ annotated = rerender(&dom, &inspect_path, width, &options);
}
}
Key::Char('h') | Key::Left => {
if inspect_path.is_empty() {
doc_x = doc_x.saturating_sub(1);
- } else {
- if inspect_path.len() > 1 {
- inspect_path.pop();
- annotated = rerender(&dom, &inspect_path, width, &options);
- }
+ } else if inspect_path.len() > 1 {
+ inspect_path.pop();
+ annotated = rerender(&dom, &inspect_path, width, &options);
}
}
Key::Char('l') | Key::Right => {
@@ -378,7 +374,7 @@ mod top {
};
if inspect_path.is_empty() {
let render_tree = config
- .dom_to_render_tree(&dom)
+ .dom_to_render_tree(dom)
.expect("Failed to build render tree");
config
.render_to_lines(render_tree, width)
@@ -405,7 +401,7 @@ mod top {
)
.expect("Invalid CSS");
let render_tree = config
- .dom_to_render_tree(&dom)
+ .dom_to_render_tree(dom)
.expect("Failed to build render tree");
config
.render_to_lines(render_tree, width)
diff --git a/src/ansi_colours.rs b/src/ansi_colours.rs
index 9dd54a1..5c9a19e 100644
--- a/src/ansi_colours.rs
+++ b/src/ansi_colours.rs
@@ -4,10 +4,11 @@
//! can be achieved using inline characters sent to the terminal such as
//! underlining in some terminals).
-use crate::{parse, RichAnnotation, RichDecorator};
+use crate::RichAnnotation;
use std::io;
/// Reads HTML from `input`, and returns text wrapped to `width` columns.
+///
/// The text is returned as a `Vec>`; the annotations are vectors
/// of `RichAnnotation`. The "outer" annotation comes first in the `Vec`.
///
@@ -24,16 +25,5 @@ where
R: io::Read,
FMap: Fn(&[RichAnnotation], &str) -> String,
{
- let lines = parse(input)?
- .render(width, RichDecorator::new())?
- .into_lines()?;
-
- let mut result = String::new();
- for line in lines {
- for ts in line.tagged_strings() {
- result.push_str(&colour_map(&ts.tag, &ts.s));
- }
- result.push('\n');
- }
- Ok(result)
+ super::config::rich().coloured(input, width, colour_map)
}
diff --git a/src/css.rs b/src/css.rs
index f3207e9..68256e9 100644
--- a/src/css.rs
+++ b/src/css.rs
@@ -16,7 +16,7 @@ use crate::{
use self::parser::Importance;
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum SelectorComponent {
Class(String),
Element(String),
@@ -46,7 +46,7 @@ impl std::fmt::Display for SelectorComponent {
}
}
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Selector {
// List of components, right first so we match from the leaf.
components: Vec,
@@ -132,10 +132,8 @@ impl Selector {
if Rc::ptr_eq(child, node) {
break;
}
- } else {
- if Rc::ptr_eq(child, node) {
- return false;
- }
+ } else if Rc::ptr_eq(child, node) {
+ return false;
}
}
}
@@ -148,14 +146,14 @@ impl Selector {
*/
let idx_offset = idx - b;
if *a == 0 {
- return idx_offset == 0 && Self::do_matches(&comps[1..], &node);
+ return idx_offset == 0 && Self::do_matches(&comps[1..], node);
}
if (idx_offset % a) != 0 {
// Not a multiple
return false;
}
let n = idx_offset / a;
- n >= 0 && Self::do_matches(&comps[1..], &node)
+ n >= 0 && Self::do_matches(&comps[1..], node)
}
},
}
@@ -191,7 +189,7 @@ impl Selector {
}
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Display {
/// display: none
None,
@@ -200,7 +198,7 @@ pub(crate) enum Display {
ExtRawDom,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum Style {
Colour(Colour),
BgColour(Colour),
@@ -208,7 +206,7 @@ pub(crate) enum Style {
WhiteSpace(WhiteSpace),
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct StyleDecl {
style: Style,
importance: Importance,
@@ -232,7 +230,7 @@ impl std::fmt::Display for StyleDecl {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
struct Ruleset {
selector: Selector,
styles: Vec,
@@ -250,7 +248,7 @@ impl std::fmt::Display for Ruleset {
}
/// Stylesheet data which can be used while building the render tree.
-#[derive(Clone, Default, Debug)]
+#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub(crate) struct StyleData {
agent_rules: Vec,
user_rules: Vec,
diff --git a/src/css/parser.rs b/src/css/parser.rs
index 0d64f0c..5e33bfa 100644
--- a/src/css/parser.rs
+++ b/src/css/parser.rs
@@ -390,6 +390,10 @@ pub(crate) fn parse_color_attribute(
parse_color(&value.tokens).or_else(|e| parse_faulty_color(e, text))
}
+fn parse_color_part(text: &str, index: std::ops::Range) -> Option {
+ u8::from_str_radix(text.get(index)?, 16).ok()
+}
+
// Both Firefox and Chromium accept "00aabb" as a bgcolor - I'm not sure this has ever been legal,
// but regrettably I've had e-mails which were unreadable without doing this.
fn parse_faulty_color(
@@ -397,13 +401,11 @@ fn parse_faulty_color(
text: &str,
) -> Result>> {
let text = text.trim();
- if text.chars().all(|c| c.is_hex_digit()) {
- if text.len() == 6 {
- let r = u8::from_str_radix(&text[0..2], 16).unwrap();
- let g = u8::from_str_radix(&text[2..4], 16).unwrap();
- let b = u8::from_str_radix(&text[4..6], 16).unwrap();
- return Ok(Colour::Rgb(r, g, b));
- }
+ let r = parse_color_part(text, 0..2);
+ let g = parse_color_part(text, 2..4);
+ let b = parse_color_part(text, 4..6);
+ if let (Some(r), Some(g), Some(b)) = (r, g, b) {
+ return Ok(Colour::Rgb(r, g, b));
}
Err(e)
}
@@ -620,7 +622,7 @@ fn parse_string_token(text: &str) -> IResult<&str, Token> {
loop {
match chars.next() {
- None => return Ok((&text[text.len()..], Token::String(s.into()))),
+ None => return Ok(("", Token::String(s.into()))),
Some((i, c)) if c == end_char => {
return Ok((&text[i + 1..], Token::String(s.into())));
}
diff --git a/src/lib.rs b/src/lib.rs
index 41bea8a..f40b4f9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -67,11 +67,10 @@ pub mod render;
use render::text_renderer::{
RenderLine, RenderOptions, RichAnnotation, SubRenderer, TaggedLine, TextRenderer,
};
-use render::{Renderer, RichDecorator, TextDecorator};
+use render::{Renderer, TextDecorator};
use html5ever::driver::ParseOpts;
use html5ever::parse_document;
-use html5ever::tendril::TendrilSink;
use html5ever::tree_builder::TreeBuilderOpts;
mod markup5ever_rcdom;
pub use markup5ever_rcdom::RcDom;
@@ -89,7 +88,7 @@ use std::io;
use std::io::Write;
use std::iter::{once, repeat};
-#[derive(Debug, Copy, Clone, Default, PartialEq)]
+#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
pub(crate) enum WhiteSpace {
#[default]
Normal,
@@ -846,7 +845,7 @@ impl RenderNode {
if style.internal_pre {
write!(f, " internal_pre")?;
}
- writeln!(f, "")
+ writeln!(f)
}
fn write_self(
&self,
@@ -858,52 +857,52 @@ impl RenderNode {
match &self.info {
RenderNodeInfo::Text(s) => writeln!(f, "{:indent$}{s:?}", "")?,
RenderNodeInfo::Container(v) => {
- self.write_container("Container", &v, f, indent)?;
+ self.write_container("Container", v, f, indent)?;
}
RenderNodeInfo::Link(targ, v) => {
- self.write_container(&format!("Link({})", targ), &v, f, indent)?;
+ self.write_container(&format!("Link({})", targ), v, f, indent)?;
}
RenderNodeInfo::Em(v) => {
- self.write_container("Em", &v, f, indent)?;
+ self.write_container("Em", v, f, indent)?;
}
RenderNodeInfo::Strong(v) => {
- self.write_container("Strong", &v, f, indent)?;
+ self.write_container("Strong", v, f, indent)?;
}
RenderNodeInfo::Strikeout(v) => {
- self.write_container("Strikeout", &v, f, indent)?;
+ self.write_container("Strikeout", v, f, indent)?;
}
RenderNodeInfo::Code(v) => {
- self.write_container("Code", &v, f, indent)?;
+ self.write_container("Code", v, f, indent)?;
}
RenderNodeInfo::Img(src, title) => {
writeln!(f, "{:indent$}Img src={:?} title={:?}:", "", src, title)?;
}
RenderNodeInfo::Block(v) => {
- self.write_container("Block", &v, f, indent)?;
+ self.write_container("Block", v, f, indent)?;
}
RenderNodeInfo::Header(depth, v) => {
- self.write_container(&format!("Header({})", depth), &v, f, indent)?;
+ self.write_container(&format!("Header({})", depth), v, f, indent)?;
}
RenderNodeInfo::Div(v) => {
- self.write_container("Div", &v, f, indent)?;
+ self.write_container("Div", v, f, indent)?;
}
RenderNodeInfo::BlockQuote(v) => {
- self.write_container("BlockQuote", &v, f, indent)?;
+ self.write_container("BlockQuote", v, f, indent)?;
}
RenderNodeInfo::Ul(v) => {
- self.write_container("Ul", &v, f, indent)?;
+ self.write_container("Ul", v, f, indent)?;
}
RenderNodeInfo::Ol(start, v) => {
- self.write_container(&format!("Ol({})", start), &v, f, indent)?;
+ self.write_container(&format!("Ol({})", start), v, f, indent)?;
}
RenderNodeInfo::Dl(v) => {
- self.write_container("Dl", &v, f, indent)?;
+ self.write_container("Dl", v, f, indent)?;
}
RenderNodeInfo::Dt(v) => {
- self.write_container("Dt", &v, f, indent)?;
+ self.write_container("Dt", v, f, indent)?;
}
RenderNodeInfo::Dd(v) => {
- self.write_container("Dd", &v, f, indent)?;
+ self.write_container("Dd", v, f, indent)?;
}
RenderNodeInfo::Break => {
writeln!(f, "{:indent$}Break", "", indent = indent)?;
@@ -942,10 +941,10 @@ impl RenderNode {
writeln!(f, "{:indent$}FragStart({}):", "", frag)?;
}
RenderNodeInfo::ListItem(v) => {
- self.write_container("ListItem", &v, f, indent)?;
+ self.write_container("ListItem", v, f, indent)?;
}
RenderNodeInfo::Sup(v) => {
- self.write_container("Sup", &v, f, indent)?;
+ self.write_container("Sup", v, f, indent)?;
}
}
Ok(())
@@ -1307,7 +1306,7 @@ where
}
}
-#[derive(Default, Debug)]
+#[derive(Debug, PartialEq, Eq)]
struct HtmlContext {
#[cfg(feature = "css")]
style_data: css::StyleData,
@@ -2371,13 +2370,11 @@ pub mod config {
wrap_links: self.wrap_links,
}
}
- /// Parse with context.
- fn do_parse(
- &mut self,
- context: &mut HtmlContext,
- input: R,
- ) -> Result {
- super::parse_with_context(input, context)
+
+ /// Reads and parses HTML from `input` and prepares a render tree.
+ pub fn do_parse(&self, input: R) -> Result {
+ let doc = self.parse_html(input)?;
+ self.dom_to_render_tree(&doc)
}
/// Parse the HTML into a DOM structure.
@@ -2439,17 +2436,9 @@ pub mod config {
/// Reads HTML from `input`, and returns a `String` with text wrapped to
/// `width` columns.
- pub fn string_from_read(
- mut self,
- input: R,
- width: usize,
- ) -> Result {
- let mut context = self.make_context();
- let s = self
- .do_parse(&mut context, input)?
- .render_with_context(&mut context, width, self.decorator)?
- .into_string()?;
- Ok(s)
+ pub fn string_from_read(self, input: R, width: usize) -> Result {
+ let render_tree = self.do_parse(input)?;
+ self.render_to_string(render_tree, width)
}
/// Reads HTML from `input`, and returns text wrapped to `width` columns.
@@ -2457,14 +2446,12 @@ pub mod config {
/// of the provided text decorator's `Annotation`. The "outer" annotation comes first in
/// the `Vec`.
pub fn lines_from_read(
- mut self,
+ self,
input: R,
width: usize,
) -> Result>>> {
- let mut context = self.make_context();
- self.do_parse(&mut context, input)?
- .render_with_context(&mut context, width, self.decorator)?
- .into_lines()
+ let render_tree = self.do_parse(input)?;
+ self.render_to_lines(render_tree, width)
}
#[cfg(feature = "css")]
@@ -2549,30 +2536,13 @@ pub mod config {
/// a list of `RichAnnotation` and some text, and returns the text
/// with any terminal escapes desired to indicate those annotations
/// (such as colour).
- pub fn coloured(
- mut self,
- input: R,
- width: usize,
- colour_map: FMap,
- ) -> Result
+ pub fn coloured(self, input: R, width: usize, colour_map: FMap) -> Result
where
R: std::io::Read,
FMap: Fn(&[RichAnnotation], &str) -> String,
{
- let mut context = self.make_context();
- let lines = self
- .do_parse(&mut context, input)?
- .render_with_context(&mut context, width, self.decorator)?
- .into_lines()?;
-
- let mut result = String::new();
- for line in lines {
- for ts in line.tagged_strings() {
- result.push_str(&colour_map(&ts.tag, &ts.s));
- }
- result.push('\n');
- }
- Ok(result)
+ let render_tree = self.do_parse(input)?;
+ self.render_coloured(render_tree, width, colour_map)
}
/// Return coloured text from a RenderTree. `colour_map` is a function which takes a list
@@ -2602,38 +2572,12 @@ pub mod config {
/// Return a Config initialized with a `RichDecorator`.
pub fn rich() -> Config {
- Config {
- decorator: RichDecorator::new(),
- #[cfg(feature = "css")]
- style: Default::default(),
- #[cfg(feature = "css")]
- use_doc_css: false,
- max_wrap_width: None,
- pad_block_width: false,
- allow_width_overflow: false,
- min_wrap_width: MIN_WIDTH,
- raw: false,
- draw_borders: true,
- wrap_links: true,
- }
+ with_decorator(RichDecorator::new())
}
/// Return a Config initialized with a `PlainDecorator`.
pub fn plain() -> Config {
- Config {
- decorator: PlainDecorator::new(),
- #[cfg(feature = "css")]
- style: Default::default(),
- #[cfg(feature = "css")]
- use_doc_css: false,
- max_wrap_width: None,
- pad_block_width: false,
- allow_width_overflow: false,
- min_wrap_width: MIN_WIDTH,
- raw: false,
- draw_borders: true,
- wrap_links: true,
- }
+ with_decorator(PlainDecorator::new())
}
/// Return a Config initialized with a custom decorator.
@@ -2694,11 +2638,6 @@ impl RenderTree {
render_tree_to_string(context, builder, &test_decorator, self.0, &mut io::sink())?;
Ok(RenderedText(builder))
}
-
- /// Render this document using the given `decorator` and wrap it to `width` columns.
- fn render(self, width: usize, decorator: D) -> Result> {
- self.render_with_context(&mut Default::default(), width, decorator)
- }
}
/// A rendered HTML document.
@@ -2722,28 +2661,6 @@ impl RenderedText {
}
}
-fn parse_with_context(mut input: impl io::Read, context: &mut HtmlContext) -> Result {
- let opts = ParseOpts {
- tree_builder: TreeBuilderOpts {
- drop_doctype: true,
- ..Default::default()
- },
- ..Default::default()
- };
- let dom = parse_document(RcDom::default(), opts)
- .from_utf8()
- .read_from(&mut input)?;
- let render_tree =
- dom_to_render_tree_with_context(dom.document.clone(), &mut io::sink(), context)?
- .ok_or(Error::Fail)?;
- Ok(RenderTree(render_tree))
-}
-
-/// Reads and parses HTML from `input` and prepares a render tree.
-pub fn parse(input: impl io::Read) -> Result {
- parse_with_context(input, &mut Default::default())
-}
-
/// Reads HTML from `input`, decorates it using `decorator`, and
/// returns a `String` with text wrapped to `width` columns.
pub fn from_read_with_decorator(input: R, width: usize, decorator: D) -> Result
@@ -2764,6 +2681,7 @@ where
}
/// Reads HTML from `input`, and returns text wrapped to `width` columns.
+///
/// The text is returned as a `Vec>`; the annotations are vectors
/// of `RichAnnotation`. The "outer" annotation comes first in the `Vec`.
pub fn from_read_rich(input: R, width: usize) -> Result>>>
diff --git a/src/markup5ever_rcdom.rs b/src/markup5ever_rcdom.rs
index dfdccd9..ef3ea24 100644
--- a/src/markup5ever_rcdom.rs
+++ b/src/markup5ever_rcdom.rs
@@ -151,7 +151,7 @@ impl Node {
/// Return the element type (if an element)
pub fn element_name(&self) -> Option {
if let NodeData::Element { ref name, .. } = self.data {
- Some(format!("{}", &*name.local_name()))
+ Some(format!("{}", name.local_name()))
} else {
None
}
diff --git a/src/tests.rs b/src/tests.rs
index c06c12c..86ad6c2 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -5,7 +5,7 @@ use crate::{config, Error};
#[cfg(feature = "css")]
use super::render::text_renderer::RichDecorator;
use super::render::text_renderer::{RichAnnotation, TaggedLine, TrivialDecorator};
-use super::{from_read, from_read_with_decorator, parse, TextDecorator};
+use super::{from_read, from_read_with_decorator, TextDecorator};
/// Like assert_eq!(), but prints out the results normally as well
macro_rules! assert_eq_str {
@@ -1361,33 +1361,32 @@ fn test_s() {
#[test]
fn test_multi_parse() {
+ let cfg = config::plain();
let html: &[u8] = b"one two three four five six seven eight nine ten eleven twelve thirteen \
fourteen fifteen sixteen seventeen";
- let tree = parse(html).unwrap();
+ let tree = cfg.do_parse(html).unwrap();
assert_eq!(
"one two three four five six seven eight nine ten eleven twelve thirteen fourteen\n\
fifteen sixteen seventeen\n",
- config::plain().render_to_string(tree.clone(), 80).unwrap()
+ cfg.render_to_string(tree.clone(), 80).unwrap()
);
assert_eq!(
"one two three four five six seven eight nine ten eleven twelve\n\
thirteen fourteen fifteen sixteen seventeen\n",
- config::plain().render_to_string(tree.clone(), 70).unwrap()
+ cfg.render_to_string(tree.clone(), 70).unwrap()
);
assert_eq!(
"one two three four five six seven eight nine ten\n\
eleven twelve thirteen fourteen fifteen sixteen\n\
seventeen\n",
- config::plain().render_to_string(tree.clone(), 50).unwrap()
+ cfg.render_to_string(tree.clone(), 50).unwrap()
);
}
#[test]
fn test_read_rich() {
let html: &[u8] = b"bold";
- let lines = config::rich()
- .render_to_lines(parse(html).unwrap(), 80)
- .unwrap();
+ let lines = config::rich().lines_from_read(html, 80).unwrap();
let tag = vec![RichAnnotation::Strong];
let line = TaggedLine::from_string("*bold*".to_owned(), &tag);
assert_eq!(vec![line], lines);
@@ -1397,7 +1396,7 @@ fn test_read_rich() {
fn test_read_custom() {
let html: &[u8] = b"bold";
let lines = config::with_decorator(TrivialDecorator::new())
- .render_to_lines(parse(html).unwrap(), 80)
+ .lines_from_read(html, 80)
.unwrap();
let tag = vec![()];
let line = TaggedLine::from_string("bold".to_owned(), &tag);
@@ -1409,7 +1408,7 @@ fn test_pre_rich() {
use RichAnnotation::*;
assert_eq!(
config::rich()
- .render_to_lines(parse(&b"test
"[..]).unwrap(), 100)
+ .lines_from_read(&b"test
"[..], 100)
.unwrap(),
[TaggedLine::from_string(
"test".into(),
@@ -1419,7 +1418,7 @@ fn test_pre_rich() {
assert_eq!(
config::rich()
- .render_to_lines(crate::parse("testlong
".as_bytes()).unwrap(), 4)
+ .lines_from_read("testlong
".as_bytes(), 4)
.unwrap(),
[
TaggedLine::from_string("test".into(), &vec![Preformat(false)]),
@@ -1431,10 +1430,7 @@ fn test_pre_rich() {
// tags.
assert_eq!(
config::rich()
- .render_to_lines(
- crate::parse(r#"testlong
"#.as_bytes()).unwrap(),
- 4
- )
+ .lines_from_read(r#"testlong
"#.as_bytes(), 4)
.unwrap(),
[
TaggedLine::from_string("test".into(), &vec![]),
@@ -1531,11 +1527,8 @@ fn test_finalise() {
}
assert_eq!(
- crate::parse("test".as_bytes())
- .unwrap()
- .render(80, TestDecorator)
- .unwrap()
- .into_lines()
+ config::with_decorator(TestDecorator)
+ .lines_from_read("test".as_bytes(), 80)
.unwrap(),
vec![
TaggedLine::from_string("test".to_owned(), &Vec::new()),
@@ -1934,9 +1927,9 @@ fn test_issue_93_x() {
114, 104, 60, 47, 101, 109, 62, 60, 99, 99, 172, 97, 97, 58, 60, 119, 99, 64, 126, 118,
104, 100, 100, 107, 105, 60, 120, 98, 255, 255, 255, 0, 60, 255, 127, 46, 60, 113, 127,
];
- let _local0 = crate::parse(&data[..]).unwrap();
- let d1 = TrivialDecorator::new();
- let _local1 = crate::RenderTree::render(_local0, 1, d1);
+ let cfg = config::with_decorator(TrivialDecorator::new());
+ let _local0 = cfg.do_parse(&data[..]).unwrap();
+ let _local1 = cfg.render_to_string(_local0, 1);
}
#[test]