Something went wrong. Try again.
CLI that turns LLM input into well-formatted Conventional Commits
Something went wrong. Try again.
git-format wrapBody.go
3.8 kB · 170 lines
Go
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>//// SPDX-License-Identifier: AGPL-3.0-or-later
package main
import ( "html" "regexp" "strings"
"github.com/microcosm-cc/bluemonday")
var numberedListRegex = regexp.MustCompile(`^\d+\.\s`)
func formatBody(body string) (string, error) { p := bluemonday.UGCPolicy() sanitized := html.UnescapeString(p.Sanitize(body))
lines := strings.Split(sanitized, "\n") var result []string var plainTextBuffer []string
flushPlainText := func() { if len(plainTextBuffer) > 0 { joined := strings.Join(plainTextBuffer, " ") wrapped := wordWrap(joined, 72) result = append(result, wrapped) plainTextBuffer = nil } }
for _, line := range lines { // Preserve indented lines (4+ spaces or tab) as preformatted code if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") { result = append(result, line) continue }
trimmed := strings.TrimSpace(line) if trimmed == "" { flushPlainText() result = append(result, "") continue }
if strings.HasPrefix(trimmed, "- ") || strings.HasPrefix(trimmed, "* ") { flushPlainText() marker := trimmed[:2] content := trimmed[2:] wrapped := wrapWithHangingIndent(marker, " ", content, 72) result = append(result, wrapped) continue }
if numberedListRegex.MatchString(trimmed) { flushPlainText() parts := strings.SplitN(trimmed, " ", 2) marker := parts[0] + " " content := "" if len(parts) > 1 { content = parts[1] } indent := strings.Repeat(" ", len(marker)) wrapped := wrapWithHangingIndent(marker, indent, content, 72) result = append(result, wrapped) continue }
plainTextBuffer = append(plainTextBuffer, trimmed) }
flushPlainText()
return strings.Join(result, "\n"), nil}
func wrapWithHangingIndent(firstPrefix, contPrefix, text string, width int) string { firstWidth := width - len(firstPrefix) contWidth := width - len(contPrefix)
words := strings.Fields(text) if len(words) == 0 { return firstPrefix }
var lines []string var currentLine strings.Builder var currentWidth int isFirstLine := true
for _, word := range words { wordLen := len(word) maxWidth := firstWidth if !isFirstLine { maxWidth = contWidth }
if currentLine.Len() == 0 { currentLine.WriteString(word) currentWidth = wordLen } else if currentWidth+1+wordLen <= maxWidth { currentLine.WriteString(" ") currentLine.WriteString(word) currentWidth += 1 + wordLen } else { if isFirstLine { lines = append(lines, firstPrefix+currentLine.String()) isFirstLine = false } else { lines = append(lines, contPrefix+currentLine.String()) } currentLine.Reset() currentLine.WriteString(word) currentWidth = wordLen } }
if currentLine.Len() > 0 { if isFirstLine { lines = append(lines, firstPrefix+currentLine.String()) } else { lines = append(lines, contPrefix+currentLine.String()) } }
return strings.Join(lines, "\n")}
func wordWrap(text string, width int) string { words := strings.Fields(text) if len(words) == 0 { return "" }
var result strings.Builder var currentLine strings.Builder var currentWidth int
for _, word := range words { wordLen := len(word)
if currentLine.Len() == 0 { currentLine.WriteString(word) currentWidth = wordLen } else if currentWidth+1+wordLen <= width { currentLine.WriteString(" ") currentLine.WriteString(word) currentWidth += 1 + wordLen } else { if result.Len() > 0 { result.WriteString("\n") } result.WriteString(currentLine.String()) currentLine.Reset() currentLine.WriteString(word) currentWidth = wordLen } }
if currentLine.Len() > 0 { if result.Len() > 0 { result.WriteString("\n") } result.WriteString(currentLine.String()) }
return result.String()}