class HtmlWriter extends HtmlAppendableBase<HtmlWriter> {
    private @Nullable NodeRendererContext context;
    private @Nullable AttributablePart useAttributes;

    public HtmlWriter(int indentSize, int formatOptions) {
        super(indentSize, formatOptions);
    }

    public HtmlWriter(HtmlWriter other, boolean inheritIndent) {
        super(other, inheritIndent);
        context = other.context;
    }

    public HtmlWriter(int indentSize, int formatOptions, boolean suppressOpenTagLine, boolean suppressCloseTagLine) {
        this(null, indentSize, formatOptions, suppressOpenTagLine, suppressCloseTagLine);
    }

    public HtmlWriter(@Nullable Appendable appendable, int indentSize, int formatOptions, boolean suppressOpenTagLine, boolean suppressCloseTagLine) {
        super(appendable, indentSize, formatOptions);
        setSuppressOpenTagLine(suppressOpenTagLine);
        setSuppressCloseTagLine(suppressCloseTagLine);
    }

    void setContext(@NotNull NodeRendererContext context) {
        this.context = context;
    }

    public @NotNull NodeRendererContext getContext() {
        assert context != null;
        return context;
    }

    public @NotNull HtmlWriter srcPos() {
        return context == null ? this : srcPos(context.getCurrentNode().getChars());
    }

    public @NotNull HtmlWriter srcPosWithEOL() {
        return context == null ? this : srcPosWithEOL(context.getCurrentNode().getChars());
    }

    public @NotNull HtmlWriter srcPosWithTrailingEOL() {
        return context == null ? this : srcPosWithTrailingEOL(context.getCurrentNode().getChars());
    }

    public @NotNull HtmlWriter srcPos(@NotNull BasedSequence sourceText) {
        if (sourceText.isNotNull()) {
            BasedSequence trimmed = sourceText.trimEOL();
            return srcPos(trimmed.getStartOffset(), trimmed.getEndOffset());
        }
        return this;
    }

    @SuppressWarnings("WeakerAccess")
    public @NotNull HtmlWriter srcPosWithEOL(@NotNull BasedSequence sourceText) {
        if (sourceText.isNotNull()) {
            return srcPos(sourceText.getStartOffset(), sourceText.getEndOffset());
        }
        return this;
    }

    @SuppressWarnings("WeakerAccess")
    public @NotNull HtmlWriter srcPosWithTrailingEOL(@NotNull BasedSequence sourceText) {
        if (sourceText.isNotNull()) {
            int endOffset = sourceText.getEndOffset();
            BasedSequence base = sourceText.getBaseSequence();

            while (endOffset < base.length()) {
                char c = base.charAt(endOffset);
                if (c != ' ' && c != '\t') break;
                endOffset++;
            }

            if (endOffset < base.length() && base.charAt(endOffset) == '\r') {
                endOffset++;
            }

            if (endOffset < base.length() && base.charAt(endOffset) == '\n') {
                endOffset++;
            }
            return srcPos(sourceText.getStartOffset(), endOffset);
        }
        return this;
    }

    public @NotNull HtmlWriter srcPos(int startOffset, int endOffset) {
        if (startOffset <= endOffset && context != null && !context.getHtmlOptions().sourcePositionAttribute.isEmpty()) {
            super.attr(context.getHtmlOptions().sourcePositionAttribute, startOffset + "-" + endOffset);
        }
        return this;
    }

    @NotNull
    public HtmlWriter withAttr() {
        return withAttr(AttributablePart.NODE);
    }

    public @NotNull HtmlWriter withAttr(@NotNull AttributablePart part) {
        super.withAttr();
        useAttributes = part;
        return this;
    }

    public @NotNull HtmlWriter withAttr(@NotNull LinkStatus status) {
        attr(Attribute.LINK_STATUS_ATTR, status.getName());
        return withAttr(AttributablePart.LINK);
    }

    public @NotNull HtmlWriter withAttr(@NotNull ResolvedLink resolvedLink) {
        return withAttr(resolvedLink.getStatus());
    }

    @NotNull
    @Override
    public HtmlWriter tag(@NotNull CharSequence tagName, boolean voidElement) {<FILL_FUNCTION_BODY>}
}

        if (useAttributes != null) {
            String attributeValue;
            final Attributes attributes;
            
            if (context != null) {
                attributes = context.extendRenderingNodeAttributes(useAttributes, getAttributes());
                String sourcePositionAttribute = context.getHtmlOptions().sourcePositionAttribute;
                attributeValue = attributes.getValue(sourcePositionAttribute);
            } else {
                attributeValue = "";
                attributes = new Attributes();
            }
                
            if (!attributeValue.isEmpty()) {
                // add to tag ranges
                int pos = attributeValue.indexOf('-');
                int startOffset = -1;
                int endOffset = -1;

                if (pos != -1) {
                    try {
                        startOffset = Integer.parseInt(attributeValue.substring(0, pos));
                    } catch (Throwable ignored) {

                    }
                    try {
                        endOffset = Integer.parseInt(attributeValue.substring(pos + 1));
                    } catch (Throwable ignored) {

                    }
                }

                if (startOffset >= 0 && startOffset < endOffset) {
                    ArrayList<TagRange> tagRanges = HtmlRenderer.TAG_RANGES.get(context.getDocument());
                    tagRanges.add(new TagRange(tagName, startOffset, endOffset));
                }
            }

            setAttributes(attributes);
            useAttributes = null;
        }

        super.tag(tagName, voidElement);
        return this;
    
<methods>public void <init>(com.vladsch.flexmark.util.sequence.LineAppendable, boolean) ,public void <init>(int, int) ,public void <init>(@Nullable Appendable, int, int) ,public @NotNull HtmlWriter addIndentOnFirstEOL(@NotNull Runnable) ,public @NotNull HtmlWriter addPrefix(@NotNull CharSequence) ,public @NotNull HtmlWriter addPrefix(@NotNull CharSequence, boolean) ,public @NotNull HtmlWriter append(char) ,public @NotNull HtmlWriter append(@NotNull CharSequence) ,public @NotNull HtmlWriter append(@NotNull CharSequence, int, int) ,public @NotNull HtmlWriter append(@NotNull LineAppendable, int, int, boolean) ,public @NotNull HtmlWriter append(char, int) ,public T appendTo(@NotNull T, boolean, int, int, int, int) throws java.io.IOException,public @NotNull HtmlWriter attr(@NotNull CharSequence, @NotNull CharSequence) ,public transient @NotNull HtmlWriter attr(@NotNull Attribute []) ,public @NotNull HtmlWriter attr(@NotNull Attributes) ,public @NotNull HtmlWriter blankLine() ,public @NotNull HtmlWriter blankLine(int) ,public @NotNull HtmlWriter blankLineIf(boolean) ,public @NotNull HtmlWriter changeOptions(int, int) ,public @NotNull HtmlWriter closePre() ,public @NotNull HtmlWriter closePreFormatted() ,public @NotNull HtmlWriter closeTag(@NotNull CharSequence) ,public int column() ,public boolean endsWithEOL() ,public int getAfterEolPrefixDelta() ,public com.vladsch.flexmark.util.html.Attributes getAttributes() ,public @NotNull BasedSequence getBeforeEolPrefix() ,public @NotNull ISequenceBuilder<?,?> getBuilder() ,public @NotNull HtmlAppendable getEmptyAppendable() ,public @NotNull BasedSequence getIndentPrefix() ,public @NotNull BasedSequence getLine(int) ,public int getLineCount() ,public int getLineCountWithPending() ,public @NotNull LineInfo getLineInfo(int) ,public @NotNull Iterable<BasedSequence> getLines(int, int, int, boolean) ,public @NotNull Iterable<LineInfo> getLinesInfo(int, int, int) ,public @NotNull Stack<String> getOpenTags() ,public @NotNull List<String> getOpenTagsAfterLast(@NotNull CharSequence) ,public @NotNull BitFieldSet<LineAppendable.Options> getOptionSet() ,public int getOptions() ,public int getPendingEOL() ,public int getPendingSpace() ,public @NotNull BasedSequence getPrefix() ,public int getTrailingBlankLines(int) ,public boolean inPre() ,public @NotNull HtmlWriter indent() ,public void insertLine(int, @NotNull CharSequence, @NotNull CharSequence) ,public boolean isPendingSpace() ,public boolean isPreFormatted() ,public boolean isSuppressCloseTagLine() ,public boolean isSuppressOpenTagLine() ,public @NotNull Iterator<LineInfo> iterator() ,public @NotNull HtmlWriter line() ,public @NotNull HtmlWriter lineIf(boolean) ,public @NotNull HtmlWriter lineOnFirstText(boolean) ,public @NotNull HtmlWriter lineWithTrailingSpaces(int) ,public int offset() ,public int offsetWithPending() ,public @NotNull HtmlWriter openPre() ,public @NotNull HtmlWriter openPreFormatted(boolean) ,public @NotNull HtmlWriter popOptions() ,public @NotNull HtmlWriter popPrefix() ,public @NotNull HtmlWriter popPrefix(boolean) ,public @NotNull HtmlWriter pushOptions() ,public @NotNull HtmlWriter pushPrefix() ,public @NotNull HtmlWriter raw(@NotNull CharSequence) ,public @NotNull HtmlWriter raw(@NotNull CharSequence, int) ,public @NotNull HtmlWriter rawIndentedPre(@NotNull CharSequence) ,public @NotNull HtmlWriter rawPre(@NotNull CharSequence) ,public @NotNull HtmlWriter removeExtraBlankLines(int, int, int, int) ,public @NotNull HtmlWriter removeIndentOnFirstEOL(@NotNull Runnable) ,public @NotNull HtmlWriter removeLines(int, int) ,public @NotNull HtmlWriter setAttributes(@NotNull Attributes) ,public @NotNull HtmlWriter setIndentPrefix(@Nullable CharSequence) ,public void setLine(int, @NotNull CharSequence, @NotNull CharSequence) ,public @NotNull HtmlWriter setOptions(int) ,public @NotNull HtmlWriter setPrefix(@NotNull CharSequence) ,public @NotNull HtmlWriter setPrefix(@Nullable CharSequence, boolean) ,public void setPrefixLength(int, int) ,public @NotNull HtmlWriter setSuppressCloseTagLine(boolean) ,public void setSuppressOpenTagLine(boolean) ,public @NotNull HtmlWriter tag(@NotNull CharSequence) ,public @NotNull HtmlWriter tag(@NotNull CharSequence, @NotNull Runnable) ,public @NotNull HtmlWriter tag(@NotNull CharSequence, boolean) ,public @NotNull HtmlWriter tag(@NotNull CharSequence, boolean, boolean, @NotNull Runnable) ,public @NotNull HtmlWriter tagIndent(@NotNull CharSequence, @NotNull Runnable) ,public @NotNull HtmlWriter tagLine(@NotNull CharSequence) ,public @NotNull HtmlWriter tagLine(@NotNull CharSequence, boolean) ,public @NotNull HtmlWriter tagLine(@NotNull CharSequence, @NotNull Runnable) ,public @NotNull HtmlWriter tagLineIndent(@NotNull CharSequence, @NotNull Runnable) ,public @NotNull HtmlWriter tagVoid(@NotNull CharSequence) ,public @NotNull HtmlWriter tagVoidLine(@NotNull CharSequence) ,public @NotNull HtmlWriter text(@NotNull CharSequence) ,public @NotNull CharSequence toSequence(int, int, boolean) ,public @NotNull String toString() ,public @NotNull String toString(int, int, boolean) ,public @NotNull HtmlWriter unIndent() ,public @NotNull HtmlWriter unIndentNoEol() ,public @NotNull HtmlWriter withAttr() ,public @NotNull HtmlWriter withCondIndent() ,public @NotNull HtmlWriter withCondLineOnChildText() <variables>private final non-sealed com.vladsch.flexmark.util.sequence.LineAppendable appendable,private @Nullable MutableAttributes currentAttributes,private boolean indentOnFirstEol,private boolean lineOnChildText,private final @NotNull Stack<String> openTags,private boolean suppressCloseTagLine,private boolean suppressOpenTagLine,private boolean withAttributes