Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

text.go 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package utils
  4. import "bytes"
  5. import "time"
  6. // WordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
  7. func WordWrap(text string, lineWidth int) []string {
  8. var lines []string
  9. var cacheLine, cacheWord bytes.Buffer
  10. for _, char := range text {
  11. if char == '\r' {
  12. continue
  13. } else if char == '\n' {
  14. cacheLine.Write(cacheWord.Bytes())
  15. lines = append(lines, cacheLine.String())
  16. cacheWord.Reset()
  17. cacheLine.Reset()
  18. } else if (char == ' ' || char == '-') && cacheLine.Len()+cacheWord.Len()+1 < lineWidth {
  19. // natural word boundary
  20. cacheLine.Write(cacheWord.Bytes())
  21. cacheLine.WriteRune(char)
  22. cacheWord.Reset()
  23. } else if lineWidth <= cacheLine.Len()+cacheWord.Len()+1 {
  24. // time to wrap to next line
  25. if cacheLine.Len() < (lineWidth / 2) {
  26. // this word takes up more than half a line... just split in the middle of the word
  27. cacheLine.Write(cacheWord.Bytes())
  28. cacheLine.WriteRune(char)
  29. cacheWord.Reset()
  30. } else {
  31. cacheWord.WriteRune(char)
  32. }
  33. lines = append(lines, cacheLine.String())
  34. cacheLine.Reset()
  35. } else {
  36. // normal character
  37. cacheWord.WriteRune(char)
  38. }
  39. }
  40. if 0 < cacheWord.Len() {
  41. cacheLine.Write(cacheWord.Bytes())
  42. }
  43. if 0 < cacheLine.Len() {
  44. lines = append(lines, cacheLine.String())
  45. }
  46. return lines
  47. }
  48. type MessagePair struct {
  49. Message string
  50. Msgid string
  51. }
  52. // SplitMessage represents a message that's been split for sending.
  53. type SplitMessage struct {
  54. MessagePair
  55. Wrapped []MessagePair // if this is nil, `Message` didn't need wrapping and can be sent to anyone
  56. Time time.Time
  57. }
  58. const defaultLineWidth = 400
  59. func MakeSplitMessage(original string, origIs512 bool) (result SplitMessage) {
  60. result.Message = original
  61. result.Msgid = GenerateSecretToken()
  62. result.Time = time.Now().UTC()
  63. if !origIs512 && defaultLineWidth < len(original) {
  64. wrapped := WordWrap(original, defaultLineWidth)
  65. result.Wrapped = make([]MessagePair, len(wrapped))
  66. for i, wrappedMessage := range wrapped {
  67. result.Wrapped[i] = MessagePair{
  68. Message: wrappedMessage,
  69. Msgid: GenerateSecretToken(),
  70. }
  71. }
  72. }
  73. return
  74. }
  75. // TokenLineBuilder is a helper for building IRC lines composed of delimited tokens,
  76. // with a maximum line length.
  77. type TokenLineBuilder struct {
  78. lineLen int
  79. delim string
  80. buf bytes.Buffer
  81. result []string
  82. }
  83. func (t *TokenLineBuilder) Initialize(lineLen int, delim string) {
  84. t.lineLen = lineLen
  85. t.delim = delim
  86. }
  87. // Add adds a token to the line, creating a new line if necessary.
  88. func (t *TokenLineBuilder) Add(token string) {
  89. tokenLen := len(token)
  90. if t.buf.Len() != 0 {
  91. tokenLen += len(t.delim)
  92. }
  93. if t.lineLen < t.buf.Len()+tokenLen {
  94. t.result = append(t.result, t.buf.String())
  95. t.buf.Reset()
  96. }
  97. if t.buf.Len() != 0 {
  98. t.buf.WriteString(t.delim)
  99. }
  100. t.buf.WriteString(token)
  101. }
  102. // Lines terminates the line-building and returns all the lines.
  103. func (t *TokenLineBuilder) Lines() (result []string) {
  104. result = t.result
  105. t.result = nil
  106. if t.buf.Len() != 0 {
  107. result = append(result, t.buf.String())
  108. t.buf.Reset()
  109. }
  110. return
  111. }