fuelen

fuelen

HTML2Text - extract readable plain text from HTML using Rust NIF

HTML2Text provides a simple and efficient way to extract readable plain text from HTML content. It leverages the power of Rust’s html2text crate to deliver fast HTML parsing and text extraction while maintaining the logical structure and readability of the content.

https://github.com/fuelen/html2text

Most Liked

fuelen

fuelen

v0.3.0 is out with two major additions: annotated rich text output and an inspectable HTML container.

Rich text (convert_rich/2)

Returns structured {text, [annotation]} tuples instead of formatted strings, so you can build your own renderer (Slack, Discord, email, etc.):

HTML2Text.convert_rich("<p>Hello <strong>world</strong></p>")
#=> {:ok, [[{"Hello ", []}, {"world", [:strong]}]]}

HTML2Text.convert_rich(~s(<a href="https://example.com"><em>click</em></a>))
#=> {:ok, [[{"click", [{:link, "https://example.com"}, :emphasis]}]]}

Annotations: :strong, :emphasis, :strikeout, :code, {:link, url}, {:image, src}, {:preformat, bool}, {:colour, {r, g, b}}, {:bg_colour, {r, g, b}}.

CSS colour extraction is supported via use_doc_css: true (parses <style> tags and inline styles).

HTML container (HTML2Text.HTML)

A struct that renders HTML as formatted text when inspected in IEx — bold, italic, clickable links (OSC 8), CSS true color, and more:

%{subject: "Alert", body: HTML2Text.HTML.new(email_html)}

# In IEx you see formatted text instead of raw tags:
# %{subject: "Alert", body: #HTML2Text.HTML<
#     Dear customer,
#     Your order has been shipped.
#   >}

Short content stays inline: #HTML2Text.HTML<bold>. to_string/1 returns the original HTML.

Other changes

  • empty_img_mode option: :ignore (default), {:replace, text}, or :filename
  • Updated html2text Rust crate from 0.15.1 to 0.16.7 (rowspan support, bug fixes)
  • HTML2Text.Error custom exception for bang functions
fuelen

fuelen

html2text v0.2.0 released — breaking changes and a cleaner API!

This version introduces a new, more consistent API with proper error handling and an optional keyword list for configuration.


What changed

Before (v0.1.x):

HTML2Text.convert(html, width)
# => returns plain string
  • The second argument was required and only accepted a width (integer or :infinity)
  • Errors (like width too narrow) would raise directly

Now (v0.2.0):

HTML2Text.convert(html, opts)
# => {:ok, result} | {:error, reason}

HTML2Text.convert!(html, opts)
# => result (raises on error)
  • convert/2 now returns {:ok, text} or {:error, reason}
  • convert!/2 is a new function that raises on error (for convenience)
  • The second parameter is now an optional keyword list of options

Where Next?

Popular in Announcing Top

josevalim
Yes, yet another parser combinator library! Most of the parser combinators in the ecosystem are either compile-time, often using AST tra...
159 19228 141
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
bryanjos
Hi, I just published version 0.23.0 of Elixirscript. https://github.com/bryanjos/elixirscript/blob/master/CHANGELOG.md Most of the chan...
New
brainlid
LangChain is short for Language Chain. An LLM, or Large Language Model, is the “Language” part. This library makes it easier for Elixir a...
New
Qqwy
Hello everyone, I wrote a small library today called MapDiff. It returns a map listing the (smallest amount of) changes to get from map...
New
fuelen
Hey folks! Want to present a toolkit for writing command-line user interfaces. It provides a convenient interface for colorizing text...
New
Qqwy
TypeCheck: Fast and flexible runtime type-checking for your Elixir projects. Core ideas Type- and function specifications are const...
336 14327 100
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
wfgilman
I’ve cleaned up and open sourced three financial libraries I was using for my company. They are bindings for the APIs of these three comp...
New
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

We're in Beta

About us Mission Statement