Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 104 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions converters/html/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **Syntax highlighting now uses giallo instead of syntect** — both inline-style and
class-based HTML output use giallo's built-in grammars and themes. The preferred
attributes are now `:highlight-style:` and `:highlight-css:`, while the legacy
`:syntect-style:` and `:syntect-css:` names remain supported.
- **Use shared `replace_apostrophes` from converters-core** — smart apostrophe logic moved to
converters-core for reuse across converters.
- **Use `strip_quotes` for attribute value handling** — replaced manual `trim_matches('"')`
Expand Down
6 changes: 3 additions & 3 deletions converters/html/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ publish = false
default = ["pre-spec-subs"]
# Asciidoctor-compatible subs= attribute. Experimental - may be removed when AsciiDoc spec finalizes.
pre-spec-subs = ["acdc-parser/pre-spec-subs", "acdc-converters-core/pre-spec-subs"]
# Enable syntax highlighting for source blocks using syntect
highlighting = ["dep:syntect"]
# Enable syntax highlighting for source blocks using giallo
highlighting = ["dep:giallo"]
# Render terminal-converter output into selectable HTML via libghostty-vt.
terminal = ["dep:acdc-converters-terminal", "acdc-converters-terminal/emulator", "acdc-converters-terminal/highlighting"]

Expand All @@ -20,7 +20,7 @@ acdc-converters-core.workspace = true
acdc-converters-terminal = { workspace = true, optional = true }
acdc-parser.workspace = true
chrono.workspace = true
syntect = { version = "5.3", optional = true, default-features = false, features = ["default-fancy"] }
giallo = { git = "https://github.com/getzola/giallo.git", branch = "fancy-regex", optional = true, features = ["dump"] }
thiserror.workspace = true
tracing.workspace = true

Expand Down
8 changes: 4 additions & 4 deletions converters/html/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Table of contents entries are also numbered when `:sectnums:` is set.

=== Syntax Highlighting

Source blocks with a language specified render with syntax highlighting (requires the `highlighting` feature flag). Uses syntect with inline CSS styles.
Source blocks with a language specified render with syntax highlighting (requires the `highlighting` feature flag). The converter uses giallo and emits inline CSS styles by default. Set `:highlight-style:` to choose a giallo theme, or `:highlight-css: class` to emit reusable `syntax-*` classes instead. The legacy `:syntect-style:` and `:syntect-css:` names remain accepted for compatibility.

[source,console]
....
Expand Down Expand Up @@ -347,7 +347,7 @@ server-side, to keep that input away from the emulator.

==== Syntax highlighting CSS

When using class-based syntax highlighting (`:syntect-css: class`), the highlighting CSS is handled the same way, embedded by default, or linked/written to disk when `:linkcss:` is set. See the <<Syntax Highlighting>> section above.
When using class-based syntax highlighting (`:highlight-css: class`), the highlighting CSS is handled the same way, embedded by default, or linked/written to disk when `:linkcss:` is set. See the <<Syntax Highlighting>> section above.

=== Docinfo files

Expand Down Expand Up @@ -453,7 +453,7 @@ Most output is class-based and fully overridable by the seams above. A few eleme
|===
| Inline-styled | How to override

| Syntax-highlighted code colours | Inline is the default; set `:syntect-css: class` to emit overridable `syntax-*` classes (plus a `<style>` block) instead.
| Syntax-highlighted code colours | Inline is the default; set `:highlight-css: class` to emit overridable `syntax-*` classes (plus a `<style>` block) instead.
| A recording's own colours | The cell palette, plus a replay container's background/foreground when the cast recorded a theme; use `!important`.
| Table column and table widths | Per-table values (matches Asciidoctor); use `!important`.
| Page break; image `align`/`float` (semantic backend) | Match Asciidoctor's output; use `!important`.
Expand Down Expand Up @@ -739,5 +739,5 @@ The HTML converter:
While the HTML converter aims for compatibility with Asciidoctor, there are some known differences and limitations.

- The `css-signature` attribute is not supported. Use a document ID instead (`[[my-id]]` above the title).
- Syntax highlighting uses syntect with inline CSS styles rather than external highlight.js or Pygments. Language coverage may differ.
- Syntax highlighting uses giallo with inline CSS styles rather than external highlight.js or Pygments. Language coverage may differ.
- The `html5s` backend is inspired by Jakub Jirutka's https://github.com/jirutka/asciidoctor-html5s[asciidoctor-html5s] gem but is a separate implementation with its own output.
4 changes: 2 additions & 2 deletions converters/html/src/html_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ impl<'a, 'd, W: Write> HtmlVisitor<'a, 'd, W> {
/// Emit syntax highlighting CSS in `<head>` when class-based mode is active.
///
/// - Without `linkcss`: embeds CSS in a `<style>` block (default).
/// - With `linkcss`: emits a `<link>` to `{stylesdir}/acdc-syntect.css`.
/// - With `linkcss`: emits a `<link>` to `{stylesdir}/acdc-highlight.css`.
#[cfg(feature = "highlighting")]
fn maybe_emit_syntax_css(&mut self) -> Result<(), Error> {
if self
Expand All @@ -218,7 +218,7 @@ impl<'a, 'd, W: Write> HtmlVisitor<'a, 'd, W> {
self.writer,
r#"<link rel="stylesheet" href="{}/{}">"#,
stylesdir.trim_end_matches('/'),
crate::SYNTECT_STYLESHEET
crate::HIGHLIGHT_STYLESHEET
)?;
} else if let Ok(css) = crate::syntax::highlight_css(&theme_name) {
writeln!(self.writer, "<style>\n{css}</style>")?;
Expand Down
22 changes: 13 additions & 9 deletions converters/html/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,10 @@ pub struct RenderOptions {
pub(crate) const COPYCSS_DEFAULT: &str = "";
pub(crate) const STYLESDIR_DEFAULT: &str = ".";
pub(crate) const STYLESHEET_DEFAULT: &str = "";
/// Default filename for the syntect syntax highlighting stylesheet (class-based mode).
/// Default filename for the syntax highlighting stylesheet (class-based mode).
/// Analogous to asciidoctor's `asciidoctor-coderay.css` / `asciidoctor-pygments.css`.
#[cfg(feature = "highlighting")]
pub(crate) const SYNTECT_STYLESHEET: &str = "acdc-syntect.css";
pub(crate) const HIGHLIGHT_STYLESHEET: &str = "acdc-highlight.css";
// NOTE: If you change the values below, you need to also change them in `load_css`
pub(crate) const STYLESHEET_LIGHT_MODE: &str = "asciidoctor-light-mode.css";
pub(crate) const STYLESHEET_DARK_MODE: &str = "asciidoctor-dark-mode.css";
Expand Down Expand Up @@ -459,8 +459,10 @@ pub(crate) fn load_css(dark_mode: bool, variant: HtmlVariant) -> &'static str {

/// Resolve the syntax highlighting theme name and mode from document attributes.
///
/// - `:syntect-style:` overrides the theme (falls back to light/dark default).
/// - `:syntect-css: class` switches to CSS-class mode (default is inline).
/// - `:highlight-style:` (or legacy `:syntect-style:`) overrides the theme
/// (falls back to light/dark default).
/// - `:highlight-css: class` (or legacy `:syntect-css: class`) switches to
/// CSS-class mode (default is inline).
#[cfg(feature = "highlighting")]
pub(crate) fn resolve_highlight_settings(
document_attributes: &DocumentAttributes<'_>,
Expand All @@ -470,7 +472,8 @@ pub(crate) fn resolve_highlight_settings(
.is_some_and(|v| !matches!(v, AttributeValue::Bool(false) | AttributeValue::None));

let theme_name: String = document_attributes
.get("syntect-style")
.get("highlight-style")
.or_else(|| document_attributes.get("syntect-style"))
.and_then(|v| match v {
AttributeValue::String(s) if !s.is_empty() => Some(s.to_string()),
AttributeValue::String(_) | AttributeValue::Bool(_) | AttributeValue::None | _ => None,
Expand All @@ -484,7 +487,8 @@ pub(crate) fn resolve_highlight_settings(
});

let mode = if document_attributes
.get("syntect-css")
.get("highlight-css")
.or_else(|| document_attributes.get("syntect-css"))
.is_some_and(|v| matches!(v, AttributeValue::String(s) if s == "class"))
{
syntax::HighlightMode::Class
Expand Down Expand Up @@ -762,8 +766,8 @@ impl<'a> Processor<'a> {
}
}

/// Write the syntect CSS file next to the HTML output when `linkcss` is set
/// and class-based syntax highlighting is active.
/// Write the syntax highlighting CSS file next to the HTML output when
/// `linkcss` is set and class-based syntax highlighting is active.
///
/// Analogous to how asciidoctor writes `asciidoctor-coderay.css` /
/// `asciidoctor-pygments.css` alongside the output.
Expand Down Expand Up @@ -811,7 +815,7 @@ impl<'a> Processor<'a> {
output_dir.join(&stylesdir)
};

let dest_path = dest_dir.join(SYNTECT_STYLESHEET);
let dest_path = dest_dir.join(HIGHLIGHT_STYLESHEET);

if let Err(e) = std::fs::create_dir_all(&dest_dir) {
diagnostics.warn_with_advice(
Expand Down
Loading
Loading