mirror of
https://github.com/cwinfo/matterbridge.git
synced 2024-11-27 02:01:35 +00:00
230 lines
4.4 KiB
Go
230 lines
4.4 KiB
Go
|
// Copyright 2015 The Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package markdown
|
||
|
|
||
|
import (
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
func getLine(s *StateBlock, line int) string {
|
||
|
pos := s.BMarks[line] + s.BlkIndent
|
||
|
max := s.EMarks[line]
|
||
|
if pos >= max {
|
||
|
return ""
|
||
|
}
|
||
|
return s.Src[pos:max]
|
||
|
}
|
||
|
|
||
|
func escapedSplit(s string) (result []string) {
|
||
|
pos := 0
|
||
|
escapes := 0
|
||
|
lastPos := 0
|
||
|
backTicked := false
|
||
|
lastBackTick := 0
|
||
|
|
||
|
for pos < len(s) {
|
||
|
ch := s[pos]
|
||
|
if ch == '`' {
|
||
|
if backTicked {
|
||
|
backTicked = false
|
||
|
lastBackTick = pos
|
||
|
} else if escapes%2 == 0 {
|
||
|
backTicked = true
|
||
|
lastBackTick = pos
|
||
|
}
|
||
|
} else if ch == '|' && (escapes%2 == 0) && !backTicked {
|
||
|
result = append(result, s[lastPos:pos])
|
||
|
lastPos = pos + 1
|
||
|
}
|
||
|
|
||
|
if ch == '\\' {
|
||
|
escapes++
|
||
|
} else {
|
||
|
escapes = 0
|
||
|
}
|
||
|
|
||
|
pos++
|
||
|
|
||
|
if pos == len(s) && backTicked {
|
||
|
backTicked = false
|
||
|
pos = lastBackTick + 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return append(result, s[lastPos:])
|
||
|
}
|
||
|
|
||
|
var rColumn = regexp.MustCompile("^:?-+:?$")
|
||
|
|
||
|
func ruleTable(s *StateBlock, startLine, endLine int, silent bool) bool {
|
||
|
if !s.Md.Tables {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if startLine+2 > endLine {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
nextLine := startLine + 1
|
||
|
|
||
|
if s.SCount[nextLine] < s.BlkIndent {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if s.SCount[nextLine]-s.BlkIndent >= 4 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
pos := s.BMarks[nextLine] + s.TShift[nextLine]
|
||
|
if pos >= s.EMarks[nextLine] {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
src := s.Src
|
||
|
ch := src[pos]
|
||
|
pos++
|
||
|
|
||
|
if ch != '|' && ch != '-' && ch != ':' {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
for pos < s.EMarks[nextLine] {
|
||
|
ch = src[pos]
|
||
|
if ch != '|' && ch != '-' && ch != ':' && !byteIsSpace(ch) {
|
||
|
return false
|
||
|
}
|
||
|
pos++
|
||
|
}
|
||
|
|
||
|
//
|
||
|
|
||
|
lineText := getLine(s, startLine+1)
|
||
|
|
||
|
columns := strings.Split(lineText, "|")
|
||
|
var aligns []Align
|
||
|
for i := 0; i < len(columns); i++ {
|
||
|
t := strings.TrimSpace(columns[i])
|
||
|
if t == "" {
|
||
|
if i == 0 || i == len(columns)-1 {
|
||
|
continue
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if !rColumn.MatchString(t) {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if t[len(t)-1] == ':' {
|
||
|
if t[0] == ':' {
|
||
|
aligns = append(aligns, AlignCenter)
|
||
|
} else {
|
||
|
aligns = append(aligns, AlignRight)
|
||
|
}
|
||
|
} else if t[0] == ':' {
|
||
|
aligns = append(aligns, AlignLeft)
|
||
|
} else {
|
||
|
aligns = append(aligns, AlignNone)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lineText = strings.TrimSpace(getLine(s, startLine))
|
||
|
if strings.IndexByte(lineText, '|') == -1 {
|
||
|
return false
|
||
|
}
|
||
|
if s.SCount[startLine]-s.BlkIndent >= 4 {
|
||
|
return false
|
||
|
}
|
||
|
columns = escapedSplit(strings.TrimSuffix(strings.TrimPrefix(lineText, "|"), "|"))
|
||
|
columnCount := len(columns)
|
||
|
if columnCount > len(aligns) {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if silent {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
tableTok := &TableOpen{
|
||
|
Map: [2]int{startLine, 0},
|
||
|
}
|
||
|
s.PushOpeningToken(tableTok)
|
||
|
s.PushOpeningToken(&TheadOpen{
|
||
|
Map: [2]int{startLine, startLine + 1},
|
||
|
})
|
||
|
s.PushOpeningToken(&TrOpen{
|
||
|
Map: [2]int{startLine, startLine + 1},
|
||
|
})
|
||
|
|
||
|
for i := 0; i < len(columns); i++ {
|
||
|
s.PushOpeningToken(&ThOpen{
|
||
|
Align: aligns[i],
|
||
|
Map: [2]int{startLine, startLine + 1},
|
||
|
})
|
||
|
s.PushToken(&Inline{
|
||
|
Content: strings.TrimSpace(columns[i]),
|
||
|
Map: [2]int{startLine, startLine + 1},
|
||
|
})
|
||
|
s.PushClosingToken(&ThClose{})
|
||
|
}
|
||
|
|
||
|
s.PushClosingToken(&TrClose{})
|
||
|
s.PushClosingToken(&TheadClose{})
|
||
|
|
||
|
tbodyTok := &TbodyOpen{
|
||
|
Map: [2]int{startLine + 2, 0},
|
||
|
}
|
||
|
s.PushOpeningToken(tbodyTok)
|
||
|
|
||
|
for nextLine = startLine + 2; nextLine < endLine; nextLine++ {
|
||
|
if s.SCount[nextLine] < s.BlkIndent {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
lineText = strings.TrimSpace(getLine(s, nextLine))
|
||
|
if strings.IndexByte(lineText, '|') == -1 {
|
||
|
break
|
||
|
}
|
||
|
if s.SCount[nextLine]-s.BlkIndent >= 4 {
|
||
|
break
|
||
|
}
|
||
|
columns = escapedSplit(strings.TrimPrefix(strings.TrimSuffix(lineText, "|"), "|"))
|
||
|
|
||
|
if len(columns) < len(aligns) {
|
||
|
columns = append(columns, make([]string, len(aligns)-len(columns))...)
|
||
|
} else if len(columns) > len(aligns) {
|
||
|
columns = columns[:len(aligns)]
|
||
|
}
|
||
|
|
||
|
s.PushOpeningToken(&TrOpen{})
|
||
|
for i := 0; i < columnCount; i++ {
|
||
|
tdOpen := TdOpen{}
|
||
|
if i < len(aligns) {
|
||
|
tdOpen.Align = aligns[i]
|
||
|
}
|
||
|
s.PushOpeningToken(&tdOpen)
|
||
|
|
||
|
inline := Inline{}
|
||
|
if i < len(columns) {
|
||
|
inline.Content = strings.TrimSpace(columns[i])
|
||
|
}
|
||
|
s.PushToken(&inline)
|
||
|
|
||
|
s.PushClosingToken(&TdClose{})
|
||
|
}
|
||
|
s.PushClosingToken(&TrClose{})
|
||
|
}
|
||
|
|
||
|
s.PushClosingToken(&TbodyClose{})
|
||
|
s.PushClosingToken(&TableClose{})
|
||
|
|
||
|
tableTok.Map[1] = nextLine
|
||
|
tbodyTok.Map[1] = nextLine
|
||
|
s.Line = nextLine
|
||
|
|
||
|
return true
|
||
|
}
|