lib/strings/wrap.rb in strings-0.1.8 vs lib/strings/wrap.rb in strings-0.2.0

- old
+ new

@@ -1,66 +1,63 @@ # frozen_string_literal: true -require 'strings-ansi' -require 'unicode/display_width' -require 'unicode_utils/each_grapheme' +require "strings-ansi" +require "unicode/display_width" +require "unicode_utils/each_grapheme" -require_relative 'fold' - module Strings module Wrap DEFAULT_WIDTH = 80 - NEWLINE = "\n".freeze - SPACE = " ".freeze + NEWLINE = "\n" + SPACE = " " LINE_BREAK = %r{\r\n|\r|\n}.freeze - LINE_BREAKS = "\r\n+|\r+|\n+".freeze + LINE_BREAKS = "\r\n+|\r+|\n+" # Wrap a text into lines no longer than wrap_at length. # Preserves existing lines and existing word boundaries. # # @example # Strings::Wrap.wrap("Some longish text", 8) # # => "Some \nlongish \ntext" # # @api public - def wrap(text, wrap_at = DEFAULT_WIDTH, separator: nil) + def wrap(text, wrap_at = DEFAULT_WIDTH, separator: NEWLINE) if text.scan(/[[:print:]]/).length < wrap_at.to_i || wrap_at.to_i.zero? return text end + ansi_stack = [] - sep = separator || text[LINE_BREAK] || NEWLINE - text.split(%r{#{LINE_BREAKS}}, -1).map do |paragraph| - format_paragraph(paragraph, wrap_at, ansi_stack) - end * sep + text.lines.map do |line| + format_line(line, wrap_at, ansi_stack).join(separator) + end.join end module_function :wrap - # Format paragraph to be maximum of wrap_at length + # Format line to be maximum of wrap_at length # - # @param [String] paragraph - # the paragraph to format + # @param [String] text_line + # the line to format # @param [Integer] wrap_at - # the maximum length to wrap the paragraph + # the maximum length to wrap the line # # @return [Array[String]] # the wrapped lines # # @api private - def format_paragraph(paragraph, wrap_at, ansi_stack) - cleared_para = Fold.fold(paragraph) + def format_line(text_line, wrap_at, ansi_stack) lines = [] line = [] word = [] ansi = [] ansi_matched = false word_length = 0 line_length = 0 char_length = 0 # visible char length - text_length = display_width(cleared_para) + text_length = display_width(text_line) total_length = 0 - UnicodeUtils.each_grapheme(cleared_para) do |char| + UnicodeUtils.each_grapheme(text_line) do |char| # we found ansi let's consume if char == Strings::ANSI::CSI || ansi.length > 0 ansi << char if Strings::ANSI.only_ansi?(ansi.join) ansi_matched = true @@ -113,11 +110,11 @@ end lines << insert_ansi(line.join, ansi_stack) unless line.empty? lines << insert_ansi(word.join, ansi_stack) unless word.empty? lines end - module_function :format_paragraph + module_function :format_line # Insert ANSI code into string # # Check if there are any ANSI states, if present # insert ANSI codes at given positions unwinding the stack. @@ -149,10 +146,14 @@ next elsif !matched_reset # ansi without reset matched_reset = false new_stack << ansi # keep the ansi next if ansi[1] == length - output.insert(-1, ansi_reset) # add reset at the end + if output.end_with?(NEWLINE) + output.insert(-2, ansi_reset) + else + output.insert(-1, ansi_reset) # add reset at the end + end end output.insert(ansi[1], ansi[0]) end