Skip to content
Merged
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
9 changes: 9 additions & 0 deletions crates/altmd-ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ pub struct Span {
pub struct Document {
/// Top-level block nodes in document order.
pub blocks: Vec<Block>,
/// 1-based source start line for each top-level block, indexed alongside
/// [`blocks`](Self::blocks). An entry is `None` when the line is unknown
/// (for example a relocated footnote definition); a shorter or empty vector
/// means no line information at all. Purely additive: the serializer and the
/// policy reader never consult it, and the renderer only emits it when
/// source positions are requested. It exists so an editor can map a rendered
/// block back to its source line for scroll-sync and click-to-source.
#[serde(default)]
pub block_lines: Vec<Option<u32>>,
}

/// Block-level content. Component nodes arrive in Phase 2.
Expand Down
7 changes: 6 additions & 1 deletion crates/altmd-cli/src/include.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ pub fn resolve_document(document: Document, file: &Path) -> Result<Document> {
// is caught as a cycle.
let mut stack = vec![canon_file];
let blocks = resolve(document.blocks, &jail, &jail, &mut stack, 0)?;
Ok(Document { blocks })
// Splicing includes changes the top-level block list, so the source line map
// no longer applies; drop it rather than carry stale lines.
Ok(Document {
blocks,
..Default::default()
})
}

/// Resolve includes in a block sequence. `current_dir` is the directory relative
Expand Down
18 changes: 17 additions & 1 deletion crates/altmd-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod render;

pub use error::CoreError;
pub use policy::{AiPolicy, Permission, extract_policy};
pub use render::render_document;
pub use render::{RenderOptions, render_document, render_document_with};

// One facade: downstream crates depend on these re-exports, not the sub-crates.
pub use altmd_ast::{
Expand Down Expand Up @@ -72,6 +72,22 @@ pub fn render(source: &str) -> Result<String, CoreError> {
Ok(render_document(&parse(source)?))
}

/// Render alt-markdown `source` to HTML with source positions: each top-level
/// block carries a `data-line="N"` attribute naming the source line it began on.
/// An editor uses this to map a rendered block back to its source for scroll-sync
/// and click-to-source. Otherwise identical to [`render`].
///
/// # Errors
/// Returns [`CoreError`] if the source contains an invalid directive.
pub fn render_with_positions(source: &str) -> Result<String, CoreError> {
Ok(render_document_with(
&parse(source)?,
RenderOptions {
source_positions: true,
},
))
}

/// Serialise a [`Document`] back to alt-markdown source text. Normalising: the
/// output re-parses to an equal AST but is not guaranteed byte-identical to the
/// original source. This is the second half of the edit round-trip.
Expand Down
Loading
Loading