You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

text.go 2.1KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package utils
  4. import "bytes"
  5. // WordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
  6. func WordWrap(text string, lineWidth int) []string {
  7. var lines []string
  8. var cacheLine, cacheWord bytes.Buffer
  9. for _, char := range text {
  10. if char == '\r' {
  11. continue
  12. } else if char == '\n' {
  13. cacheLine.Write(cacheWord.Bytes())
  14. lines = append(lines, cacheLine.String())
  15. cacheWord.Reset()
  16. cacheLine.Reset()
  17. } else if (char == ' ' || char == '-') && cacheLine.Len()+cacheWord.Len()+1 < lineWidth {
  18. // natural word boundary
  19. cacheLine.Write(cacheWord.Bytes())
  20. cacheLine.WriteRune(char)
  21. cacheWord.Reset()
  22. } else if lineWidth <= cacheLine.Len()+cacheWord.Len()+1 {
  23. // time to wrap to next line
  24. if cacheLine.Len() < (lineWidth / 2) {
  25. // this word takes up more than half a line... just split in the middle of the word
  26. cacheLine.Write(cacheWord.Bytes())
  27. cacheLine.WriteRune(char)
  28. cacheWord.Reset()
  29. } else {
  30. cacheWord.WriteRune(char)
  31. }
  32. lines = append(lines, cacheLine.String())
  33. cacheLine.Reset()
  34. } else {
  35. // normal character
  36. cacheWord.WriteRune(char)
  37. }
  38. }
  39. if 0 < cacheWord.Len() {
  40. cacheLine.Write(cacheWord.Bytes())
  41. }
  42. if 0 < cacheLine.Len() {
  43. lines = append(lines, cacheLine.String())
  44. }
  45. return lines
  46. }
  47. type MessagePair struct {
  48. Message string
  49. Msgid string
  50. }
  51. // SplitMessage represents a message that's been split for sending.
  52. type SplitMessage struct {
  53. MessagePair
  54. Wrapped []MessagePair // if this is nil, `Message` didn't need wrapping and can be sent to anyone
  55. }
  56. const defaultLineWidth = 400
  57. func MakeSplitMessage(original string, origIs512 bool) (result SplitMessage) {
  58. result.Message = original
  59. result.Msgid = GenerateSecretToken()
  60. if !origIs512 && defaultLineWidth < len(original) {
  61. wrapped := WordWrap(original, defaultLineWidth)
  62. result.Wrapped = make([]MessagePair, len(wrapped))
  63. for i, wrappedMessage := range wrapped {
  64. result.Wrapped[i] = MessagePair{
  65. Message: wrappedMessage,
  66. Msgid: GenerateSecretToken(),
  67. }
  68. }
  69. }
  70. return
  71. }