public BlockBoundaryArtifact(CodeBlockInfo blockInfo, BoundaryType type)
            : base(ArtifactTreatAs.Code, type == BoundaryType.Start ? blockInfo.OuterStart : blockInfo.OuterEnd, 0, 0, MarkdownClassificationTypes.MarkdownCode, true)
        {
            BlockInfo = blockInfo;
            Boundary = type;

            // Replace the BlockInfo's TextRanges with our created
            // artifacts so that they will be adjusted as the user
            // edits the text. TextRangeCollection shifts existing
            // artifacts as the user types elsewhere.
            if (type == BoundaryType.Start)
                BlockInfo.OuterStart = this;
            else
                BlockInfo.OuterEnd = this;
        }
        public CodeLineArtifact(CodeBlockInfo blockInfo, ITextRange range, int leftLength, int rightLength)
            : base(ArtifactTreatAs.Code, range, leftLength, rightLength, MarkdownClassificationTypes.MarkdownCode, true)
        {
            if (blockInfo == null) throw new ArgumentNullException("blockInfo");

            BlockInfo = blockInfo;
        }
            protected override bool ReadContent()
            {
                SkipSpaces(3);
                var sepStart = stream.Position;
                if (TryConsume("```"))
                    fence = "```";
                else if (TryConsume("~~~"))
                    fence = "~~~";
                else
                    return false;

                blockInfo = new CodeBlockInfo { OuterStart = TextRange.FromBounds(sepStart, stream.Position) };

                var langRange = TryConsumeContentLine();
                if (langRange != null)
                    blockInfo.Language = stream.GetSubstringAt(langRange.Start, langRange.Length);

                while (true)
                {
                    var range = TryConsumeContentLine();
                    if (range == null)
                        break;
                    ReportArtifact(new CodeLineArtifact(blockInfo, range, 0, 0));
                }
                // If the stream ended without a closing fence, give an empty end.
                if (blockInfo.OuterEnd == null)
                    blockInfo.OuterEnd = new TextRange(stream.Length, 0);
                return true;
            }
 protected override bool ReadContent()
 {
     var blockInfo = new CodeBlockInfo { OuterStart = new TextRange(stream.Position, 0) };
     lineStart = stream.Position;
     if (!TryReadSpaces(spaceCount))
         return false;
     while (true)
     {
         var thisLineStart = lineStart;
         var range = TryConsumeContentLine();
         if (range == null)
             break;
         blockInfo.OuterEnd = new TextRange(range.End, 0);
         // Get the character count of the indent, which may be different if tabs are involved.
         var indentSize = range.Start - thisLineStart;
         range.Expand(-indentSize, 0);
         ReportArtifact(new CodeLineArtifact(blockInfo, range, indentSize, 0));
     }
     return true;
 }