0.2.0
Upgrading from 0.0.x? See the
migration guide. 0.2.x is almost entirely
backward compatible — the only required code change is a newalertbranch
for directMD$Block.map/switchcallers.
- ADDED: Opt-in, dependency-free syntax highlighting for fenced code blocks
(65+ languages, GitHub light/dark themes). Assign aSyntaxHighlighterto the
newMarkdownThemeData.highlighterfield; the default (unset) renders code as
plain monospace, so existing usage is unchanged. New public API on
package:flutter_md/highlight.dart:SyntaxHighlighter,MarkdownHighlighter,
CodeHighlightTheme,Grammar,GrammarToken,compileHighlightPattern
(SyntaxHighlighter/CodeHighlightThemeare also re-exported from the main
entrypoint). Each language is its own library
(package:flutter_md/highlight/<lang>.dart, e.g.HighlightDart.grammar) with
no central registry, so importing one never references the others and unused
grammars tree-shake away — a Dart-only app adds ~0 beyond the engine; all 65
add ~62 KB gzipped.HighlightThemes.githubDark/githubLight
(highlight/themes.dart) provide ready themes;allHighlightLanguages
(highlight/all.dart) is a convenience registry of every grammar for
demos/tooling (it references all languages, so unused ones can no longer
tree-shake away). The highlighter only partitions text — never edits it — so
selection and copy stay aligned. Grammars are generated by
tool/highlight_codegen(adapted from Prism, MIT). - ADDED: Cross-block and cross-widget text selection. A
MarkdownSelectionControlleranchors the selection on the immutable model, so
it spans multiple blocks and multipleMarkdownWidgets and survives list
disposal (e.g. chat scrolling). New public API:MarkdownSelectionController,
MarkdownSelectionScope,MarkdownSelectionGroup,MarkdownPosition,
MarkdownSelection,MarkdownDocumentRef,MarkdownSelectedContent
(+ document/block),MarkdownSelectionFormatter/
MarkdownPlainTextFormatter/MarkdownMarkupFormatter,
MarkdownReconciliationPolicy,MarkdownSelectionSurface,
markdownBlockRenderedText, and
SelectableBlockPainter/SelectableTextBlock. - ADDED:
StreamingMarkdownParser, an incremental parser for streaming
sources such as LLM token output. It freezes completed blocks (a block ends at
a blank line, outside any open code fence) so only the still-growing tail is
re-parsed as tokens arrive — turning theO(N²)cost of re-parsing the whole
buffer on every token into roughlyO(tail)(3–14× faster on a full message
stream inbenchmark/streaming_benchmark.dart).parser.add(chunk)returns
the growingMarkdown, always identical block-for-block to
Markdown.fromString(everythingSoFar), and aStream<String>.toMarkdown()
extension wires it into a stream transform. Pass a configuredMarkdownDecoder
(e.g.inlineMath: true) to matchMarkdown.fromString. The batch
MarkdownDecoderhot path is byte-for-byte unchanged. - ADDED:
MarkdownMarkupFormatter, a built-in "Copy as Markdown" formatter.
Pass it togetText()(or setcontroller.formatter) to reconstruct Markdown
structure on copy — heading#s, nested list markers with task checkboxes,
blockquote/alert>prefixes, fenced code and pipe tables — for blocks the
selection covers in full; partially-selected boundary blocks fall back to the
plain sliced text so nothing outside the selection is emitted. The default
copy behaviour is unchanged (MarkdownPlainTextFormatter). - ADDED:
MarkdownWidgetgains optionaldocumentIdandcontroller
parameters (resolved from the ambient scope). Backward compatible: a widget
with nodocumentIdis inert. - ADDED: Lists and tables are now interactively selectable. A new
MultiPainterSelectablemixin (+SelectableFragment) maps pointer positions
and highlight boxes across the manyTextPainters of a list's items or a
table's cells, so a drag can start or end inside a list item or table cell and
the copied text keeps the\n/\tseparators ofmarkdownBlockRenderedText. - ADDED: Keyboard shortcuts and a context toolbar on
MarkdownSelectionScope,
mirroringSelectableRegion/SelectableText. When focused:Ctrl/Cmd+C
copies,Ctrl/Cmd+Aselects all,Shift+arrows extend by character / word /
line / document (and vertically by geometry),Escclears. Right-click
(desktop) / long-press (mobile) shows an adaptive Copy / Select-all toolbar.
The scope is now aStatefulWidgetwith a publicMarkdownSelectionScopeState
(copySelection/selectAll/clearSelection/showToolbar/
hideToolbar/contextMenuButtonItems/contextMenuAnchors). New
customization params:focusNode,enabled,selectionColor,
contextMenuBuilder,magnifierConfiguration,selectionControls,
onSelectionChanged. New controller ops:selectionColor,
globalSelectionRects,moveSelectionEdgeToGlobal, and the
extendSelectionBy*family;MarkdownPosition.copyWith. - ADDED: Native selection handles and a magnifier on touch platforms,
driven by Flutter'sSelectionOverlay. Selection endpoints push
LeaderLayers from the render objects so the handles follow the content as it
scrolls (and across multipleMarkdownWidgets); dragging a handle adjusts the
selection and shows the platform magnifier. Handles/magnifier respect the
platform (selectionControls,magnifierConfiguration) and are absent on
desktop, matchingSelectableText. New surface geometry:
localSelectionRects,setSelectionHandleLayers,repaintSelection, and
MarkdownSelectionController.selectionHandleEndpoints/
MarkdownHandleEndpoints. - ADDED: Word- and block-granular selection gestures. Double-click/tap
selects the word under the pointer, triple-click/tap selects the whole block,
a single click collapses (clears) the selection, andShift-click extends it.
Dragging after a double/triple click keeps word/block granularity; a touch
long-press grabs the whole word (then extends by word), and a touch
double-tap selects the word and pops the toolbar. Word boundaries use the
platform word segmentation (TextPainter.getWordBoundary), so double-click
keeps intra-word punctuation like apostrophes (can't). New controller ops:
selectWordAtGlobal,selectBlockAtGlobal,wordSelectionAt,
blockSelectionAt,extendSelectionGranular, andwordRangeIn; new surface
geometryMarkdownSelectionSurface.wordBoundaryForGlobal. - ADDED: Mouse cursor feedback — a
MarkdownWidgetshows the click (hand)
cursor over actionable links, the text (I-beam) cursor while it participates
in a selection controller, and otherwise the default cursor. - CHANGED:
MarkdownWidget's render object now draws the selection
highlight outside the cached contentPictureand becomes a repaint boundary
when selectable, so selection/drag repaints do not rebuild the glyph cache.
The highlight color is now customizable via the controller / scope. The
highlight is painted on top of (rather than beneath) the glyphs, so a
translucent selection stays visible over opaque backgrounds — code fences,
inline code, and==marked==spans. - EXAMPLE: Reworked the demo tabs — a longer, richer chat (tables, code,
nested/task lists, alerts, math, token-by-token streaming with a typing
indicator, Select-all/Clear) and a Selection tab that spans every block type.
0.1.0
- ADDED: GitHub-style alert blocks (
> [!NOTE],> [!TIP],> [!IMPORTANT],
> [!WARNING],> [!CAUTION]) via the newMD$Alertblock andMD$AlertType. - ADDED: GitHub task-list items (
- [ ]/- [x]) viaMD$ListItem.checked
andMD$ListItem.isTask, rendered with a checkbox. - ADDED: Table column alignment (
:---,:--:,---:) captured on
MD$Table.alignmentsand applied when rendering. - ADDED:
linkStyleonMarkdownThemeDatato customize link text styling
(thanks @inamhusain, #22). - ADDED: Per-type alert accent colors via
MarkdownThemeData.alertColors
andalertColorFor. - ADDED: Opt-in
$...$inline LaTeX math conversion to Unicode, disabled
by default. Enable withMarkdownDecoder(inlineMath: true)or
Markdown.fromString(text, inlineMath: true). Supports LaTeX commands
(\alpha,\rightarrow, ...), superscripts/subscripts (x^2,H_2O,
x^{10}), is code-span and code-block safe, and preserves currency ($5).
The command table is configurable viamathReplacements(extend the
exportedkMarkdownMathCommands). Originally proposed in #21 by
@ibragimov05. - FIXED:
\$is now a recognized backslash escape, producing a literal
dollar sign (and opting a$...$run out of math conversion). - CHANGED: Thematic breaks now support
***and___(and spaced variants
like- - -), and no longer greedily consume text after---. - CHANGED:
~~~fenced code blocks are now recognized in addition to```. - FIXED: Emphasis no longer leaks to the end of the line for stray or
unterminated markers (e.g.5 * 6 = 30,**bold never closed). - FIXED: Intraword underscores are no longer treated as emphasis
(e.g.snake_case,object_idare preserved). - FIXED: ATX headings require a space after
#;#hashtagand 7+#
are no longer headings, and trailing#sequences are stripped. - FIXED: Emphasis surrounding a link/image is now merged onto the link span.
- FIXED: Link/image targets support
<url>and single-quoted titles. - FIXED:
MarkdownThemeData.copyWithno longer dropsbuilderandonLinkTap. - BREAKING:
MD$Block.map/maybeMapgained analertbranch for the new
MD$Alertblock type. - PERFORMANCE: Rewrote the parser hot path — a single-span fast path for
plain text, first-code-unit guards that keep regexes off paragraph lines,
hand-rolled list-line and link-target parsing (removing per-line / per-link
RegExpallocation), lazy link-extraction gated on[, and a range-copy
escape rebuild (no more per-character hash-set lookups). Together with math
now being opt-in, the default parse path is roughly 45% faster across
representative workloads (links −68%, lists −61%, escapes −68%). Output is
byte-identical, guarded by a golden snapshot test. - TESTS: Added a golden characterization snapshot, a corner-case regression
suite, span-offset invariants, and unit tests for the node model, theme, and
widget; wired every test file intotest/unit_test.dartso CI runs the full
suite (370+ tests, previously only a fraction ran).parser.dart,
nodes.dart,markdown.dart,theme.dart, andwidget.dartare now at
~100% line coverage. - ADDED:
benchmark/parser_benchmark.dart(a multi-scenario
benchmark_harnesssuite) andbenchmark/compare.dart(a low-noise
before/after comparison tool). - DOCS: Documented alerts, task lists, table alignment, thematic-break
variants, and opt-in inline math in the README.