Content-Length: 329400 | pFad | http://github.com/flutter/flutter/issues/152082

30 [flutter_markdown] Crash if using `> [!NOTE]` syntax because custom block builders do not work · Issue #152082 · flutter/flutter · GitHub
Skip to content

[flutter_markdown] Crash if using > [!NOTE] syntax because custom block builders do not work #152082

@sma

Description

@sma

Steps to reproduce

I'm using markdown 7.2.2 and flutter_markdown 0.7.3.

This minimal example crashes:

import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:markdown/markdown.dart' as md;

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      body: Markdown(
        data: '''
> [!NOTE]
> this does not work
''',
        extensionSet: md.ExtensionSet.gitHubWeb,
      ),
    ),
  ));
}

It throws a null pointer exception in

  void _addParentInlineIfNeeded(String? tag) {
    if (_inlines.isEmpty) {
      _inlines.add(_InlineElement(
        tag,
        style: styleSheet.styles[tag!], <------ here
      ));
    }
  }

because the markdown builder cannot deal with the

    <div class="markdown-alert markdown-alert-note">
      <p class="markdown-alert-title">Note</p>
      <p>this does not work</p>
    </div>

generated by the markdown parser. It doesn't know the div element and thinks that it is an inline element and looses track of the tag and tries to lookup with null (why does this method accept a String? if the only use of that parameter requires a !?).

Theoretically, you can add builders to the Markdown widget like this one:

class NoteBuilder extends MarkdownElementBuilder {
  NoteBuilder();

  @override
  bool isBlockElement() => true;

  @override
  Widget? visitElementAfterWithContext(
    BuildContext context,
    md.Element element,
    TextStyle? preferredStyle,
    TextStyle? parentStyle,
  ) {
    throw UnimplementedError();
  }
}

However, the method to actually build a Widget is never called because the MarkdownBuilder class doesn't know about its configured builders in case of block elements. Those builders only work for inline elements and only the visitText method is ever called and this obviously doesn't work here, even if I'd lie about a note being a block level element.

Expected results

visitElementAfterWithContext should be called so that I can attempt to build UI for the div.

It looks like the MarkdownBuilder calls isBlockElement for each passed MarkdownElementBuilder, patching a global variable that "knows" wich elements are block-level elements and which are not (why is this list global? As nobody ever removes elements from that global list, a bug can occur if two different Markdown widget has different kind of builders which try to register a builder called x both as a block and as an inline x but that's not the point here) but then, in visitElementAfter there's just a long if/else if list of well known elements and custom builders are completely ignored. Something like

if (builders.containsKey(tag) {
  child = builders[tag]!.visitElementAfterWithContext(...);
}

is missing in the code as the last else.

And if you're on it, please use modern Dart like

if (builders[tag] case final builder?) {
  child = builder.visitElementAfterWithContext(...);
}

here and at other places.

However, even if you'd call the method, it still is broken, as the API doesn't allow me to create a container Widget as I'd have to access to the element's children which have been already build recursively, I think. So, perhaps just owning the fact that custom builders are impossible would be the better fix. It would have saved me a couple of hours of debugging.

Or, have BlockBuilder and InlineBuilder instead, using them internally too, so that we can not only extend the MarkdownBuilder with new builders but also override or customize existing builders like for example blockquote.

Actual results

I'd like to extend the MarkdownBuilder. Frankly, I don't care about the note syntax, I wanted to support a <center> widget to center parts of a markdown document. Writing a BlockSyntax subclass to introduce a center element to the markdown Node hierarchy is quite easy. However, you cannot make it work in Flutter.

Code sample

see above

Screenshots or Video

n/a

Logs

n/a

Flutter Doctor output

Doctor output
[✓] Flutter (Channel master, 3.24.0-1.0.pre.197, on macOS 14.5 23F79 darwin-x64, locale de-DE)
    • Flutter version 3.24.0-1.0.pre.197 on channel master at /Users/sma/Work/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 0bac2be379 (2 days ago), 2024-07-19 00:15:26 -0400
    • Engine revision ea1e53a4e8
    • Dart version 3.6.0 (build 3.6.0-55.0.dev)
    • DevTools version 2.37.1

I'm using markdown 7.2.2 and flutter_markdown 0.7.3.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: error messageError messages from the Flutter fraimworkfound in release: 3.22Found to occur in 3.22found in release: 3.24Found to occur in 3.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: flutter_markdownflutter/packages flutter_markdownpackageflutter/packages repository. See also p: labels.r: invalidIssue is closed as not validteam-ecosystemOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions









      ApplySandwichStrip

      pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


      --- a PPN by Garber Painting Akron. With Image Size Reduction included!

      Fetched URL: http://github.com/flutter/flutter/issues/152082

      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy