Skip to content

Commit

Permalink
cleanup markdown tables
Browse files Browse the repository at this point in the history
  • Loading branch information
codemaestro64 committed Jul 19, 2021
1 parent c31798a commit 121701f
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 193 deletions.
242 changes: 49 additions & 193 deletions ui/renderers/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package renderers

import (
"fmt"
"image"
"io"
"regexp"
"strings"
Expand All @@ -19,8 +20,9 @@ import (
type labelFunc func(string) decredmaterial.Label

type Renderer struct {
theme *decredmaterial.Theme
isList bool
theme *decredmaterial.Theme
isList bool
isListItem bool

prefix string
padAccumulator []string
Expand All @@ -31,7 +33,7 @@ type Renderer struct {
styleGroups []map[string]string
isHTML bool

table *tableRenderer
table *table
}

const (
Expand Down Expand Up @@ -198,8 +200,13 @@ func (r *Renderer) renderWords(lbl decredmaterial.Label) {

func (r *Renderer) renderMarkdown(lbl decredmaterial.Label) {
content := r.stringBuilder.String()
if strings.TrimSpace(r.prefix) != "" && strings.TrimSpace(content) == "" {
return
}

r.stringBuilder.Reset()

labelText := lbl.Text
words := strings.Fields(content)
words = append([]string{r.prefix}, words...)
r.prefix = ""
Expand All @@ -215,13 +222,31 @@ func (r *Renderer) renderMarkdown(lbl decredmaterial.Label) {

word := words[i] + " "
if i == 0 {
word = words[i]
word = labelText + " " + words[i]
}
lbl.Text = word
return lbl.Layout(gtx)
})
}
r.containers = append(r.containers, wdgt)

var container layout.Widget
if r.isListItem {
container = func(gtx C) D {
return layout.Flex{}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return D{
Size: image.Point{
X: 10,
},
}
}),
layout.Flexed(1, wdgt),
)
}
} else {
container = wdgt
}
r.containers = append(r.containers, container)
}

func (r *Renderer) getLabel(lbl decredmaterial.Label, text string) decredmaterial.Label {
Expand Down Expand Up @@ -317,6 +342,7 @@ func (r *Renderer) renderEmptyLine() {
func (r *Renderer) renderList(node *ast.ListItem, entering bool) {
if entering {
r.isList = true
r.isListItem = true
switch {
// numbered list
case node.ListFlags&ast.ListTypeOrdered != 0:
Expand All @@ -336,16 +362,18 @@ func (r *Renderer) renderList(node *ast.ListItem, entering bool) {

// no flags means it's the normal bullet point list
default:
r.prefix += " " + bulletUnicode + " "
r.prefix += bulletUnicode + " "
}
} else {
r.isListItem = false
}
}

func (r *Renderer) renderTable(entering bool) {
if entering {
r.table = newTableRenderer(r.theme)
r.table = newTable(r.theme)
} else {
r.containers = append(r.containers, r.table.Render())
r.containers = append(r.containers, r.table.render())
r.table = nil
}
}
Expand All @@ -354,27 +382,29 @@ func (r *Renderer) renderTableCell(node *ast.TableCell) {
content := r.stringBuilder.String()
r.stringBuilder.Reset()

align := CellAlignLeft
align := cellAlignLeft
switch node.Align {
case ast.TableAlignmentRight:
align = CellAlignRight
align = cellAlignRight
case ast.TableAlignmentCenter:
align = CellAlignCenter
align = cellAlignCenter
}

var alignment cellAlign
if node.IsHeader {
r.table.AddHeaderCell(content, align)
alignment = align
} else {
r.table.AddBodyCell(content, CellAlignCopyHeader)
alignment = cellAlignCopyHeader
}
r.table.addCell(content, alignment, node.IsHeader)
}

func (r *Renderer) renderTableRow(node *ast.TableRow, entering bool) {
if _, ok := node.Parent.(*ast.TableBody); ok && entering {
r.table.NextBodyRow()
}
if _, ok := node.Parent.(*ast.TableFooter); ok && entering {
r.table.NextBodyRow()
if entering {
switch node.Parent.(type) {
case *ast.TableHeader, *ast.TableBody, *ast.TableFooter:
r.table.startNextRow()
}
}
}

Expand Down Expand Up @@ -432,178 +462,4 @@ func (r *Renderer) getLinkWidget(gtx layout.Context, linkWord string) D {
lbl.Color = r.theme.Color.Primary
return lbl.Layout(gtx)
})
}

type CellAlign int

const (
CellAlignLeft CellAlign = iota
CellAlignRight
CellAlignCenter
CellAlignCopyHeader
)

type tableCell struct {
content string
alignment CellAlign
contentLength float64
}

type tableRenderer struct {
header []tableCell
body [][]tableCell

widths []float64
theme *decredmaterial.Theme
}

func newTableRenderer(theme *decredmaterial.Theme) *tableRenderer {
return &tableRenderer{
theme: theme,
}
}

func (tr *tableRenderer) AddHeaderCell(content string, alignment CellAlign) {
tr.header = append(tr.header, tableCell{
content: content,
contentLength: float64(len(content)),
alignment: alignment,
})
tr.widths = append(tr.widths, 0)
}

func (tr *tableRenderer) NextBodyRow() {
tr.body = append(tr.body, nil)
}

func (tr *tableRenderer) AddBodyCell(content string, alignement CellAlign) {
row := tr.body[len(tr.body)-1]
row = append(row, tableCell{
content: content,
contentLength: float64(len(content)),
alignment: alignement,
})
tr.body[len(tr.body)-1] = row
}

// normalize ensure that the table has the same number of cells
// in each rows, header or not.
func (tr *tableRenderer) normalize() {
width := len(tr.header)
/**for _, row := range tr.body {
//width = max(width, len(row))
}**/

// grow the header if needed
for len(tr.header) < width {
tr.header = append(tr.header, tableCell{})
}

// grow lines if needed
for i := range tr.body {
for len(tr.body[i]) < width {
tr.body[i] = append(tr.body[i], tableCell{})
}
}
}

func (tr *tableRenderer) copyAlign() {
for i, row := range tr.body {
for j, cell := range row {
if cell.alignment == CellAlignCopyHeader {
tr.body[i][j].alignment = tr.header[j].alignment
}
}
}
}

func (tr *tableRenderer) calculateLengths() {
textLenghts := make([]float64, len(tr.header))

for i := range tr.header {
index := i
textLenghts[index] = tr.header[index].contentLength
}

for i := range tr.body {
index := i
for k := range tr.body[index] {
kIndex := k
if textLenghts[kIndex] < tr.body[index][kIndex].contentLength {
textLenghts[kIndex] = tr.body[index][kIndex].contentLength
}
}
}

total := float64(0)
for i := range textLenghts {
index := i
total += textLenghts[index]
}

totalWidthRecouped := float64(0)
cutWidths := []int{}
for i := range textLenghts {
index := i
tr.widths[index] = (textLenghts[index] / total) * float64(100)
if tr.widths[index] > 40 {
totalWidthRecouped += tr.widths[index] - 40
tr.widths[index] = 40
cutWidths = append(cutWidths, index)
}
}

averageWidthToAdd := totalWidthRecouped / float64(len(tr.widths)-len(cutWidths))
for i := range tr.widths {
index := i
for k := range cutWidths {
kIndex := k
if index == kIndex {
continue
}
tr.widths[index] += averageWidthToAdd
}
}
}

func (tr *tableRenderer) Render() layout.Widget {
var tableChildren []layout.FlexChild
tr.normalize()
tr.copyAlign()

tr.calculateLengths()

if tr.header != nil {
header := tr.getTableRow(tr.header)
tableChildren = append(tableChildren, layout.Rigid(header))
}

for i := range tr.body {
index := i
row := tr.getTableRow(tr.body[index])
tableChildren = append(tableChildren, layout.Rigid(row))
}

return func(gtx C) D {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, tableChildren...)
}
}

func (tr *tableRenderer) getTableRow(row []tableCell) layout.Widget {
children := make([]layout.FlexChild, len(row))
for i := range row {
index := i
children[index] = layout.Rigid(func(gtx C) D {
gtx.Constraints.Max.X = int((tr.widths[index] / 100) * float64(gtx.Constraints.Max.X))
gtx.Constraints.Min.X = gtx.Constraints.Max.X
return tr.theme.Body2(row[index].content).Layout(gtx)
})
}

return func(gtx C) D {
gtx.Constraints.Min.X = gtx.Constraints.Max.X
dims := layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}.Layout(gtx, children...)
dims.Size.Y += 5
return dims
}
}
}
Loading

0 comments on commit 121701f

Please sign in to comment.