dotfiles

regexghost dotfiles and scripts
git clone https://git.regexghost.com/dotfiles.git
Log | Files | Refs | README

tablealigner.go (4032B)


      1 package main
      2 
      3 import (
      4 	"fmt"
      5 	"unicode/utf8"
      6 	"os"
      7 	"strings"
      8 	"regexp"
      9 	"os/exec"
     10 )
     11 
     12 func Print(str string) {
     13 	cmd := exec.Command("notify-send", str)
     14 	cmd.Run()
     15 }
     16 
     17 // This is definitely not a good solution to wide characters
     18 var EMOJIS []rune = []rune{'❌', '✅', '❔', '❓', '📅', '🚗', '🌙', '⏳'}
     19 
     20 func isEmoji(r rune) bool {
     21 	for _, emoji := range EMOJIS {
     22 		if r == emoji {
     23 			return true
     24 		}
     25 	}
     26 	return false
     27 }
     28 
     29 func properLen(input string) int {
     30 	var noEndSpaces string = strings.TrimRight(input, " ")
     31 	var length int = utf8.RuneCountInString(noEndSpaces) + 1
     32 
     33 	for _, r := range noEndSpaces {
     34 		if isEmoji(r) {
     35 			length++
     36 		}
     37 	}
     38 	return length
     39 }
     40 
     41 func readFile(filename string) []string {
     42 	dat, err := os.ReadFile(filename)
     43 	if err != nil {
     44 		panic(err)
     45 	}
     46 
     47 	return strings.Split(string(dat), "\n")
     48 }
     49 
     50 func testForAlignRow(line string) bool {
     51 	if len(line) < 1 {
     52 		return false
     53 	}
     54 
     55 	if line[0] != '|' || line[len(line)-1] != '|' {
     56 		return false
     57 	}
     58 	split := strings.Split(line, "|")
     59 	var isCorrect = regexp.MustCompile("^(-*:* *)*$").MatchString
     60 	for _, x := range split {
     61 		if !isCorrect(x) {
     62 			return false
     63 		}
     64 	}
     65 
     66 	return true
     67 }
     68 
     69 func testForEnd(line string) bool {
     70 	if len(line) == 0 || line[0] != '|' {
     71 		return true
     72 	}
     73 	return false
     74 }
     75 
     76 func findTables(input []string) [][]int {
     77 	var tables [][]int
     78 
     79 	var inTable bool = false
     80 
     81 	for i, line := range input {
     82 		if !inTable && testForAlignRow(line) {
     83 			tables = append(tables, []int{i-1})
     84 			inTable = true
     85 		} else if inTable && testForEnd(line) {
     86 			tables[len(tables)-1] = append(tables[len(tables)-1], i-1)
     87 			inTable = false
     88 		}
     89 	}
     90 
     91 	return tables
     92 }
     93 
     94 func calcLengths(thisTable []string) []int {
     95 	numCells := strings.Count(thisTable[0], "|") - 1
     96 
     97 	if numCells < 1 {
     98 		os.Exit(1)
     99 	}
    100 
    101 	var columnLengths []int = make([]int, numCells)
    102 
    103 	for i, line := range thisTable {
    104 		if i == 1 {
    105 			continue
    106 		}
    107 		cells := strings.Split(line, "|")
    108 		cells = cells[1:len(cells)-1]
    109 
    110 		for j, cell := range cells {
    111 			var cellLen int = properLen(cell)
    112 			if cellLen > columnLengths[j] {
    113 				columnLengths[j] = cellLen
    114 			}
    115 		}
    116 	}
    117 	return columnLengths
    118 }
    119 
    120 func alignTable(table []int, data[]string) []string {
    121 	thisTable := data[table[0]:table[1]+1]
    122 	columnLengths := calcLengths(thisTable)
    123 
    124 	for i:=0; i<len(thisTable); i++ {
    125 		cells := strings.Split(thisTable[i], "|")
    126 		cells = cells[1:len(cells)-1]
    127 
    128 		newCells := []string{}
    129 		for j, cell := range cells {
    130 			cell = strings.TrimRight(cell, " ") + " "
    131 			var cellLen int = properLen(cell)
    132 			if cellLen != columnLengths[j] {
    133 				var paddedCell string = padCell(cell, cellLen, i, j, columnLengths)
    134 				newCells = append(newCells, paddedCell)
    135 
    136 			} else {
    137 				newCells = append(newCells, cell)
    138 			}
    139 		}
    140 		// Build new row string
    141 		var newCellString string = "|"
    142 		for _, cell := range newCells {
    143 			newCellString = newCellString + cell + "|"
    144 		}
    145 		thisTable[i] = newCellString
    146 	}
    147 	return data
    148 }
    149 
    150 func padCell(cell string, cellLen int, i int, j int, columnLengths []int) string {
    151 	var paddedCell string
    152 	if i == 1 {
    153 		paddedCell = " :" + strings.Repeat("-", columnLengths[j]-4) + ": "
    154 	} else {
    155 		paddedCell = cell + strings.Repeat(" ", columnLengths[j]-cellLen)
    156 	}
    157 	return paddedCell
    158 }
    159 
    160 func alignTables(tables [][]int, data []string) []string {
    161 	for _, table := range tables {
    162 		data = alignTable(table, data)
    163 	}
    164 	return data
    165 }
    166 
    167 func saveToFile(data []string, filename string) {
    168 	if len(data[len(data)-1]) == 0 {
    169 		data = data[:len(data)-1]
    170 	}
    171 	var toSave string
    172 	for _, line := range data {
    173 		toSave = toSave + line + "\n"
    174 	}
    175 	err := os.WriteFile(filename, []byte(toSave), 0666)
    176 	if err != nil {
    177 		panic(err)
    178 	}
    179 }
    180 
    181 func main() {
    182 	if len(os.Args) != 3 {
    183 		fmt.Println("Usage: \n  tablealigner input.md output.md")
    184 		panic("wrong args")
    185 	}
    186 
    187 	var inputFile string = os.Args[1]
    188 	var outputFile string = os.Args[2]
    189 	if os.Args[1] == "-s" {
    190 		inputFile = os.Args[2]
    191 		outputFile = os.Args[2]
    192 	}
    193 
    194 	data := readFile(inputFile)
    195 
    196 	tables := findTables(data)
    197 	data = alignTables(tables, data)
    198 
    199 	saveToFile(data, outputFile)
    200 }