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