예제 #1
0
파일: atxheader.go 프로젝트: akavel/vfmd
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
	})
}
예제 #2
0
파일: detector.go 프로젝트: akavel/vfmd
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)
}
예제 #3
0
파일: olist.go 프로젝트: akavel/vfmd
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)))
	})
}