func DetectAtxHeader(first, second Line, detectors Detectors) Handler { if !bytes.HasPrefix(first.Bytes, []byte("#")) { return nil } done := false return HandlerFunc(func(line Line, ctx Context) (bool, error) { if done { return false, nil } done = true block := md.AtxHeaderBlock{ Raw: md.Raw{md.Run(line)}, } text := bytes.TrimRight(line.Bytes, "\n") text = bytes.Trim(text, "#") if len(text) > 0 { block.Level, _ = mdutils.OffsetIn(line.Bytes, text) } else { block.Level = len(bytes.TrimRight(line.Bytes, "\n")) } if block.Level > 6 { block.Level = 6 } spanRegion := md.Raw{md.Run{ Line: line.Line, Bytes: bytes.Trim(text, mdutils.Whites), }} ctx.Emit(block) parseSpans(spanRegion, ctx) ctx.Emit(md.End{}) return true, nil }) }
func DetectEmphasis(s *Context) (consumed int) { rest := s.Buf[s.Pos:] if !isEmph(rest[0]) { return 0 } // find substring composed solely of '*' and '_' i := 1 for i < len(rest) && isEmph(rest[i]) { i++ } indicator := rest[:i] // "right-fringe-mark" r, _ := utf8.DecodeRune(rest[len(indicator):]) rightFringe := emphasisFringeRank(r) r, _ = utf8.DecodeLastRune(s.Buf[:s.Pos]) leftFringe := emphasisFringeRank(r) // <0 means "left-flanking", >0 "right-flanking", 0 "non-flanking" flanking := leftFringe - rightFringe if flanking == 0 { return len(indicator) } // split into "emphasis-tag-strings" - subslices of the same char tags := [][]byte{} prev := 0 for curr := 1; curr <= len(indicator); curr++ { if curr == len(indicator) || indicator[curr] != indicator[prev] { tags = append(tags, indicator[prev:curr]) prev = curr } } // left-flanking? if yes, add some openings if flanking < 0 { for _, tag := range tags { pos, _ := mdutils.OffsetIn(s.Buf, tag) s.Openings.Push(MaybeOpening{ Tag: string(tag), Pos: pos, }) } return len(indicator) } // right-flanking; maybe a closing tag closingEmphasisTags(s, tags) return len(indicator) }
func DetectOrderedList(start, second Line, detectors Detectors) Handler { m := reOrderedList.FindSubmatch(start.Bytes) if m == nil { return nil } var buf *defaultContext block := &md.OrderedListBlock{ Starter: md.Run{start.Line, m[1]}, // firstNumber, _ := strconv.Atoi(string(m[2])) } var item *md.ItemBlock var carry *Line var parser *Parser return HandlerFunc(func(next Line, ctx Context) (bool, error) { if next.EOF() { return listEnd2(parser, buf, ctx) } prev := carry carry = &next if prev == nil { buf = &defaultContext{ mode: ctx.GetMode(), detectors: changedParagraphDetector(ctx, false, true), spanDetectors: ctx.GetSpanDetectors(), } block.Raw = append(block.Raw, md.Run(next)) buf.Emit(block) if ctx.GetMode() != TopBlocks { item = &md.ItemBlock{} item.Raw = append(item.Raw, md.Run(next)) buf.Emit(item) parser = &Parser{ Context: buf, } } return pass(parser, next, next.Bytes[len(block.Starter.Bytes):]) } nextBytes := bytes.TrimRight(next.Bytes, "\n") if prev.isBlank() { if next.isBlank() { return listEnd2(parser, buf, ctx) } if !reOrderedList.Match(nextBytes) && next.hasNonSpaceInPrefix(len(block.Starter.Bytes)) { return listEnd2(parser, buf, ctx) } } else { if !reOrderedList.Match(nextBytes) && next.hasNonSpaceInPrefix(len(block.Starter.Bytes)) && !next.hasFourSpacePrefix() && (reUnorderedList.Match(nextBytes) || reHorizontalRule.Match(nextBytes)) { return listEnd2(parser, buf, ctx) } } block.Raw = append(block.Raw, md.Run(next)) m := reOrderedList.FindSubmatch(next.Bytes) if m != nil { text := bytes.TrimLeft(m[1], " ") spaces, _ := mdutils.OffsetIn(m[1], text) if spaces >= len(block.Starter.Bytes) { m = nil } } if m != nil { if ctx.GetMode() != TopBlocks { _, err := end(parser, buf) if err != nil { return false, err } item = &md.ItemBlock{} item.Raw = append(item.Raw, md.Run(next)) buf.Emit(item) parser = &Parser{ Context: buf, } } return pass(parser, next, next.Bytes[len(m[1]):]) } if ctx.GetMode() != TopBlocks { item.Raw = append(item.Raw, md.Run(next)) } return pass(parser, next, trimLeftN(next.Bytes, " ", len(block.Starter.Bytes))) }) }