visitElementBefore method

  1. @override
bool visitElementBefore(
  1. Element element
)

Called when an Element has been reached, before its children have been visited.

Returns false to skip its children.

Implementation

@override
bool visitElementBefore(md.Element element) {
  switch (element.tag) {
    case 'h1':
      _enterHeading(theme.h1);
      return true;
    case 'h2':
      _enterHeading(theme.h2);
      return true;
    case 'h3':
      _enterHeading(theme.h3);
      return true;
    case 'h4':
      _enterHeading(theme.h4);
      return true;
    case 'h5':
      _enterHeading(theme.h5);
      return true;
    case 'h6':
      _enterHeading(theme.h6);
      return true;

    case 'p':
      _ensureNewline();
      _enterParagraph();
      return true;

    case 'blockquote':
      final style = _cascadeBlock(
        _blockStack.last.style,
        theme.blockQuote,
        toBlock: false,
      );
      _enterBlock(style, _currentWidth);
      return true;

    case 'ul':
    case 'ol':
      _listCounters.add(0);
      _listIsOrdered.add(element.tag == 'ol');
      _ensureNewline();

      var style = theme.list.style;
      if (theme.list.levelIndent != null && theme.list.levelIndent! > 0) {
        style = GlamourBlockStyle(
          style: style.style,
          margin: (style.margin ?? 0) + theme.list.levelIndent!,
          indent: style.indent,
          indentToken: style.indentToken,
        );
      }
      final merged = _cascadeBlock(
        _blockStack.last.style,
        style,
        toBlock: false,
      );
      _enterBlock(merged, _currentWidth);
      return true;

    case 'li':
      _ensureNewline();
      _visitListItem(element);
      return true;

    case 'strong':
      _inlineStack.add(theme.strong);
      return true;
    case 'em':
      _inlineStack.add(theme.emph);
      return true;
    case 'code':
      _inlineStack.add(theme.code.style);
      return true;
    case 'a':
      _inlineStack.add(theme.linkText);
      _linkStack.add(element.attributes['href'] ?? '');
      return true;

    case 'hr':
      _ensureNewline();
      final format = theme.horizontalRule.format ?? '--------';
      _writeRaw('\x1b[0m'); // Reset before HR
      _writeRaw(theme.horizontalRule.toStyle.render(format));
      _ensureNewline();
      return true;

    case 'input':
      // Handle task list checkboxes
      final type = element.attributes['type'];
      if (type == 'checkbox') {
        final checked = element.attributes['checked'] == 'true';
        _writeStyled(
          checked ? theme.task.ticked : theme.task.unticked,
          theme.task.style,
        );
        return false; // Don't visit children
      }
      return true;

    case 'table':
      _tableHeaders.clear();
      _tableRows.clear();
      _currentRow.clear();
      return true;

    case 'thead':
      _inTableHead = true;
      return true;

    case 'tbody':
      _inTableHead = false;
      return true;

    case 'tr':
      // End current row
      if (_currentRow.isNotEmpty) {
        if (_inTableHead) {
          _tableHeaders.addAll(_currentRow);
        } else {
          _tableRows.add(List.from(_currentRow));
        }
        _currentRow.clear();
      }
      return true;

    case 'th':
      _inTableCell = true;
      return true;
    case 'td':
      _inTableCell = true;
      return true;

    default:
      return true;
  }
}