main.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package main
  2. import (
  3. "bytes"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. "github.com/sagernet/sing-box/log"
  8. )
  9. func main() {
  10. err := filepath.Walk("docs", func(path string, info os.FileInfo, err error) error {
  11. if err != nil {
  12. return err
  13. }
  14. if info.IsDir() {
  15. return nil
  16. }
  17. if !strings.HasSuffix(path, ".md") {
  18. return nil
  19. }
  20. return processFile(path)
  21. })
  22. if err != nil {
  23. log.Fatal(err)
  24. }
  25. }
  26. func processFile(path string) error {
  27. content, err := os.ReadFile(path)
  28. if err != nil {
  29. return err
  30. }
  31. lines := strings.Split(string(content), "\n")
  32. modified := false
  33. result := make([]string, 0, len(lines))
  34. inQuoteBlock := false
  35. materialLines := []int{} // indices of :material- lines in the block
  36. for _, line := range lines {
  37. // Check for quote block start
  38. if strings.HasPrefix(line, "!!! quote \"") && strings.Contains(line, "sing-box") {
  39. inQuoteBlock = true
  40. materialLines = nil
  41. result = append(result, line)
  42. continue
  43. }
  44. // Inside a quote block
  45. if inQuoteBlock {
  46. trimmed := strings.TrimPrefix(line, " ")
  47. isMaterialLine := strings.HasPrefix(trimmed, ":material-")
  48. isEmpty := strings.TrimSpace(line) == ""
  49. isIndented := strings.HasPrefix(line, " ")
  50. if isMaterialLine {
  51. materialLines = append(materialLines, len(result))
  52. result = append(result, line)
  53. continue
  54. }
  55. // Block ends when:
  56. // - Empty line AFTER we've seen material lines, OR
  57. // - Non-indented, non-empty line
  58. blockEnds := (isEmpty && len(materialLines) > 0) || (!isEmpty && !isIndented)
  59. if blockEnds {
  60. // Process collected material lines
  61. if len(materialLines) > 0 {
  62. for j, idx := range materialLines {
  63. isLast := j == len(materialLines)-1
  64. resultLine := strings.TrimRight(result[idx], " ")
  65. if !isLast {
  66. // Add trailing two spaces for non-last lines
  67. resultLine += " "
  68. }
  69. if result[idx] != resultLine {
  70. modified = true
  71. result[idx] = resultLine
  72. }
  73. }
  74. }
  75. inQuoteBlock = false
  76. materialLines = nil
  77. }
  78. }
  79. result = append(result, line)
  80. }
  81. // Handle case where file ends while still in a block
  82. if inQuoteBlock && len(materialLines) > 0 {
  83. for j, idx := range materialLines {
  84. isLast := j == len(materialLines)-1
  85. resultLine := strings.TrimRight(result[idx], " ")
  86. if !isLast {
  87. resultLine += " "
  88. }
  89. if result[idx] != resultLine {
  90. modified = true
  91. result[idx] = resultLine
  92. }
  93. }
  94. }
  95. if modified {
  96. newContent := strings.Join(result, "\n")
  97. if !bytes.Equal(content, []byte(newContent)) {
  98. log.Info("formatted: ", path)
  99. return os.WriteFile(path, []byte(newContent), 0o644)
  100. }
  101. }
  102. return nil
  103. }