class Wrapper def self.wrap(text, prefix = ' > ', length = 80) pure = '' ansi_code = {} while (md = text.match(/\e\[\d+;?\d*m/)) pos = md.begin(0) + pure.length pure += md.pre_match text = md.post_match append_in_hash(ansi_code, pos, md.match(0)) end pure += text offset = 0 ansi_extra = {} rows = pure.length / length last_code = nil rows.times do |i| pos = (i + 1) * length last_code = last_ansi_by_range(ansi_code, last_code, offset, pos) if last_code append_in_hash(ansi_extra, pos, "\e[0m\n#{prefix}#{last_code}") elsif pos < pure.length append_in_hash(ansi_extra, pos, "\n#{prefix}") end offset = pos + 1 end ansi_extra.each_pair do |k, v| append_in_hash(ansi_code, k, v.first) end ansi_code = ansi_code.sort final = pure offset = 0 ansi_code.each do |k, v| insert_text = v.join final = final.insert(k + offset, insert_text) offset += insert_text.length end final end def self.last_ansi_by_range(ansi_code, last_code, offset, pos) pos.downto(offset) do |i| next unless ansi_code.has_key?(i) result = ansi_code[i].last result = nil if result == "\e[0m" return result end last_code end def self.append_in_hash(hash, key, value) if hash.has_key?(key) hash[key] << value else hash[key] = [value] end end end