// Copyright 2023 The Go 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 ( "bytes" "strings" ) type tableTrimmed string func isTableSpace(c byte) bool { return c == ' ' || c == '\t' || c == '\v' || c == '\f' } func tableTrimSpace(s string) string { i := 0 for i < len(s) && isTableSpace(s[i]) { i++ } j := len(s) for j > i && isTableSpace(s[j-1]) { j-- } return s[i:j] } func tableTrimOuter(row string) tableTrimmed { row = tableTrimSpace(row) if len(row) > 0 && row[0] == '|' { row = row[1:] } if len(row) > 0 && row[len(row)-1] == '|' { row = row[:len(row)-1] } return tableTrimmed(row) } func isTableStart(hdr1, delim1 string) bool { // Scan potential delimiter string, counting columns. // This happens on every line of text, // so make it relatively quick - nothing expensive. col := 0 delim := tableTrimOuter(delim1) i := 0 for ; ; col++ { for i < len(delim) && isTableSpace(delim[i]) { i++ } if i >= len(delim) { break } if i < len(delim) && delim[i] == ':' { i++ } if i >= len(delim) || delim[i] != '-' { return false } i++ for i < len(delim) && delim[i] == '-' { i++ } if i < len(delim) && delim[i] == ':' { i++ } for i < len(delim) && isTableSpace(delim[i]) { i++ } if i < len(delim) && delim[i] == '|' { i++ } } if strings.TrimSpace(hdr1) == "|" { // https://github.com/github/cmark-gfm/pull/127 and // https://github.com/github/cmark-gfm/pull/128 // fixed a buffer overread by rejecting | by itself as a table line. // That seems to violate the spec, but we will play along. return false } return col == tableCount(tableTrimOuter(hdr1)) } func tableCount(row tableTrimmed) int { col := 1 prev := byte(0) for i := 0; i < len(row); i++ { c := row[i] if c == '|' && prev != '\\' { col++ } prev = c } return col } type tableBuilder struct { hdr tableTrimmed delim tableTrimmed rows []tableTrimmed } func (b *tableBuilder) start(hdr, delim string) { b.hdr = tableTrimOuter(hdr) b.delim = tableTrimOuter(delim) } func (b *tableBuilder) addRow(row string) { b.rows = append(b.rows, tableTrimOuter(row)) } type Table struct { Position Header []*Text Align []string // 'l', 'c', 'r' for left, center, right; 0 for unset Rows [][]*Text } func (t *Table) PrintHTML(buf *bytes.Buffer) { buf.WriteString("
") hdr.PrintHTML(buf) buf.WriteString(" | \n") } buf.WriteString("
---|
") cell.PrintHTML(buf) buf.WriteString(" | \n") } buf.WriteString("