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.

89 lines
2.1 KiB

8 months ago
8 months ago
8 months ago
  1. class Wrapper
  2. def self.wrap(text, prefix = ' > ', length = 80)
  3. text = carriage_return_filler(text.chomp(''), length)
  4. pure = ''
  5. ansi_code = {}
  6. while (md = text.match(/\e\[\d+;?\d*m/))
  7. pos = md.begin(0) + pure.length
  8. pure += md.pre_match
  9. text = md.post_match
  10. append_in_hash(ansi_code, pos, md.match(0))
  11. end
  12. pure += text
  13. offset = 0
  14. ansi_extra = {}
  15. rows = pure.length / length
  16. last_code = nil
  17. rows.times do |i|
  18. pos = (i + 1) * length
  19. last_code = last_ansi_by_range(ansi_code, last_code, offset, pos)
  20. if last_code
  21. append_in_hash(ansi_extra, pos, "\e[0m\n#{prefix}#{last_code}")
  22. elsif pos < pure.length
  23. append_in_hash(ansi_extra, pos, "\n#{prefix}")
  24. end
  25. offset = pos + 1
  26. end
  27. ansi_extra.each_pair do |k, v|
  28. append_in_hash(ansi_code, k, v.first)
  29. end
  30. ansi_code = ansi_code.sort
  31. final = pure
  32. offset = 0
  33. ansi_code.each do |k, v|
  34. insert_text = v.join
  35. final = final.insert(k + offset, insert_text)
  36. offset += insert_text.length
  37. end
  38. final
  39. end
  40. private
  41. def self.carriage_return_filler(text, length)
  42. lines = text.split("\n")
  43. return text if lines.count < 2
  44. last_ansi = nil
  45. final = lines.map do |line|
  46. fill_count = length - line.length
  47. current = line
  48. result = last_ansi ? "#{last_ansi}#{line}" : line
  49. last_ansi = nil if last_ansi == "\e[0m"
  50. while (md = current.match(/\e\[\d+;?\d*m/))
  51. last_ansi = md.to_s
  52. fill_count += last_ansi.length
  53. current = md.post_match
  54. end
  55. result = "#{result}\e[0m" if last_ansi
  56. next result if fill_count < 1
  57. "#{result}#{' ' * fill_count}"
  58. end.join
  59. last_ansi ? "#{final}\e[0m" : final
  60. end
  61. def self.last_ansi_by_range(ansi_code, last_code, offset, pos)
  62. pos.downto(offset) do |i|
  63. next unless ansi_code.has_key?(i)
  64. result = ansi_code[i].last
  65. result = nil if result == "\e[0m"
  66. return result
  67. end
  68. last_code
  69. end
  70. def self.append_in_hash(hash, key, value)
  71. if hash.has_key?(key)
  72. hash[key] << value
  73. else
  74. hash[key] = [value]
  75. end
  76. end
  77. end