Documentation
¶
Index ¶
- func Code(text string) string
- func CodeLink(url string, text ...string) string
- func FenceMeta(fenceLine string) []string
- func FencedByteRanges(text string) [][2]int
- func Generate(title string) string
- func IsIPMTFenceStart(line string) bool
- func IsIPMTInfo(info string) bool
- func LineStartInlineIpmt(text string) []int
- func Link(url string, text ...string) string
- func NormalizeLF(s string) string
- func RelPath(absPath string, baseDir string) string
- func RelPathWithDisplay(absPath string, outputDir string, projectRoot string) (string, string)
- func SkipFence(lines []string, open int, f Fence) int
- type Fence
- type IPMTBlock
- type InlineIpmt
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CodeLink ¶
CodeLink creates a markdown link with code-formatted display text If text is empty, uses url as the display text url is the link URL text is the optional display text (will be wrapped in backticks)
func FenceMeta ¶
FenceMeta returns the space-separated metadata tokens after "ipmt" in a ```ipmt … fence info-string (e.g. "```ipmt unresolved" → ["unresolved"]). Empty for a bare ```ipmt fence, or when "ipmt" is not the complete language token (e.g. "```ipmtX", "```ipmt-x" → nil — those are not ipmt fences).
func FencedByteRanges ¶
FencedByteRanges returns the half-open byte ranges [start,end) of text covered by fenced code blocks, delimiter lines included. Text is walked as-is (no newline normalization) so the offsets align with the input — FindInlineIpmt uses this to drop matches whose marker or code span sits inside a fence, where they are literal text. An unterminated fence extends to len(text).
func Generate ¶
Generate creates a GitHub-like, ASCII-only markdown anchor slug from a heading title. Rules:
- Convert to lowercase
- Replace spaces with hyphens
- Remove special characters except hyphens, slashes, and dots (slashes and dots are retained, unlike GitHub which strips them)
- Collapse consecutive slashes into single slash
- Remove leading/trailing hyphens
- Collapse multiple hyphens into one
Note: this is ASCII-only. Unlike GitHub, all non-ASCII letters are dropped (e.g. "Über Café" → "ber-caf", "日本語" → ""). Callers compare two Generate outputs against each other, so the divergence is self-consistent for matching, but it is NOT byte-equal to a GitHub heading anchor.
func IsIPMTFenceStart ¶
IsIPMTFenceStart reports whether line opens an ```ipmt``` fenced block (3+ backticks; tilde fences never carry ipmt). "ipmt" must be the complete CommonMark info-string language token, so ```ipmt and ```ipmt <metadata> match, but ```ipmtX and ```ipmt-x (a different language) do not.
NOTE: a true opener also requires that no longer fence is already open — callers that scan whole documents must track fence state (see ParseFenceOpen / SkipFence) or use ScanIPMTBlocks, which does.
func IsIPMTInfo ¶
IsIPMTInfo reports whether a fence info string (as returned by ParseFenceOpen) declares the ipmt language: "ipmt" exactly, optionally followed by whitespace-separated metadata ("ipmt unresolved"). A different language that merely starts with the letters ("ipmtX", "ipmt-x") does not match.
func LineStartInlineIpmt ¶
LineStartInlineIpmt returns the 1-based numbers of lines whose first non-space content is an inline ipmt marker comment (`<!--ipmt-->` or `<!--ipmt:as-token:NAME-->`), with at most 3 spaces of indentation and outside any fenced code block.
Such a line renders BROKEN in static HTML and the VS Code preview alike: CommonMark parses a line beginning (≤3 spaces indent) with `<!--` as an HTML block (type 2, comment), so the markdown engine passes the WHOLE line through verbatim — the adjacent backtick code span never becomes inline `<code>`, and the inline-ipmt rewrite (which keys on `<!--…--><code>`) never fires. Marker and code span both leak out raw.
Fix in the source: put at least one non-marker character before the first marker on the line — lead with a word, or let table/list syntax occupy column 0 (a `| <!--ipmt…` table cell is inline, so it's fine).
Limitation: markers nested inside a blockquote (`> <!--ipmt…`) are NOT detected here — `>` sits at column 0 — yet they break the same way. Callers that care can strip blockquote markers before calling.
func Link ¶
Link creates a complete markdown link string [text](url) If text is empty, uses url as the display text url is the link URL text is the optional display text
func NormalizeLF ¶
NormalizeLF rewrites all line endings in s to "\n".
func RelPath ¶
RelPath creates a relative path from baseDir to absPath absPath is the absolute path to the target file baseDir is the absolute path to the base directory Returns the relative path suitable for markdown links
func RelPathWithDisplay ¶
RelPathWithDisplay creates relative paths for both display and link absPath is the absolute path to the target file outputDir is the absolute path to the directory containing the output markdown file projectRoot is the absolute path to the project root for generating display text Returns: display text (relative to projectRoot), link path (relative to outputDir)
Types ¶
type Fence ¶
Fence identifies an open fenced-code-block delimiter: the fence character and the length of the opening run. The zero value is not a valid fence.
func ParseFenceOpen ¶
ParseFenceOpen reports whether line opens a fenced code block and, if so, returns the fence delimiter and its info string (trimmed; "" for a bare fence). See the package comment for the exact rules.
type IPMTBlock ¶
type IPMTBlock struct {
Index int // 1-based block index within the source
StartLine int // 0-based line index of the opening fence
EndLine int // 0-based line index of the closing fence; -1 if unterminated
Content string // text between fences, joined with "\n"; no trailing newline
Meta []string // info-string tokens after "ipmt" (e.g. ["unresolved"]); empty for a bare fence
}
IPMTBlock describes a fenced ```ipmt``` code block found in a markdown source.
func ScanIPMTBlocks ¶
ScanIPMTBlocks splits text into LF-normalized lines and extracts all ```ipmt``` fenced code blocks. Unterminated blocks have EndLine == -1 and their Content holds everything after the opening fence.
CommonMark-faithful on nesting (see fence.go): a ```ipmt line inside another fenced block — e.g. a ````md documentation example — is literal text, NOT a block; such wrapper fences are skipped wholesale. An ipmt block's closing fence must be at least as long as its opener with no info string, so a ```text line inside the block stays content.
type InlineIpmt ¶
type InlineIpmt struct {
// Byte offsets in the source markdown:
MarkerStart int // start of the `<!--…-->` comment
MarkerEnd int // end (exclusive) of the comment
CodeStart int // start of the opening backtick run
CodeEnd int // end (exclusive) of the closing backtick run
// ContentStart..ContentEnd is the inline-code content between the
// opening and closing backtick runs.
ContentStart int
ContentEnd int
Code string // the content between the backticks (== src[ContentStart:ContentEnd])
// AsToken, when non-empty, is the NAME from an
// `<!--ipmt:as-token:NAME-->` marker — a palette class suffix
// (`e-marker`, `L`, `type-marker`, …). The whole visible Code is
// painted in that style; Code is NOT parsed as ipmt. Empty means a
// bare `<!--ipmt-->` marker (tokenize Code as a valid fragment).
AsToken string
}
InlineIpmt describes one inline ipmt marker in a markdown source: an HTML-comment marker immediately before a backtick-delimited inline code span. Two marker forms:
`<!--ipmt-->` `t-shirt ::c` ← bare: tokenize the code as ipmt `<!--ipmt:as-token:e-marker-->` `::e` ← paint the code in style NAME
The marker MUST come before the code. Whitespace (including tabs and newlines) between marker and the first backtick is tolerated; no other token may appear. The marker is case-insensitive on `ipmt`/`as-token`; the NAME is taken verbatim (case-sensitive, matching the palette class suffix — e.g. `L`, `e-marker`, `type-marker`).
func FindInlineIpmt ¶
func FindInlineIpmt(text string) []InlineIpmt
FindInlineIpmt scans `text` for inline ipmt markers and the adjacent backtick-delimited code spans they apply to. Returns all matches in source order.
Recognition: the marker matches inlineIpmtMarkerRE; after it, only whitespace may appear before the opening backtick run. The opening run is N backticks; the closing run must be exactly N (CommonMark inline code). A match whose marker sits INSIDE a fenced code block — e.g. a ```md example showing the marker syntax — is literal text and is skipped, as is a marker whose code span would cross into a fence (a marker immediately above a ``` opener would otherwise swallow the fence delimiter as its "inline code").
Shared between cmd/ipm-rpc (inline tokens in ipm.embedBuffer) and pkg/mdhtml (static-HTML output). Single source of truth for the marker grammar lives HERE.