Module: Tuile::Truncate

Defined in:
lib/tuile/truncate.rb

Overview

Truncates a string to a given column width, preserving ANSI escape sequences and accounting for Unicode display width. Truncated output is suffixed with an ellipsis (‘…`).

Extracted from ‘strings-truncation` 0.1.0 (MIT, Piotr Murach) — only the default end-position, default-omission, no-separator path Tuile uses.

Class Method Summary collapse

Class Method Details

.truncate(text, length:) ⇒ String

Truncate ‘text` to at most `length` display columns. ANSI escape sequences pass through without consuming budget; when characters are dropped, an ellipsis (`…`) is appended (and counts toward `length`).

Parameters:

  • text (String)
  • length (Integer, nil)

    target column width. A ‘nil` returns `text` unchanged.

Returns:

  • (String)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/tuile/truncate.rb', line 45

def truncate(text, length:)
  return text if length.nil? || text.bytesize <= length
  return "" if length.zero?

  budget = length - OMISSION_WIDTH
  scanner = StringScanner.new(text)
  out = +""
  visible = 0
  ansi_open = false
  stop = false

  until scanner.eos? || stop
    if scanner.scan(RESET_REGEXP)
      unless scanner.eos?
        out << scanner.matched
        ansi_open = false
      end
    elsif scanner.scan(ANSI_REGEXP)
      out << scanner.matched
      ansi_open = true
    else
      char = scanner.getch
      new_visible = visible + Unicode::DisplayWidth.of(char)

      if new_visible <= budget || (scanner.check(END_REGEXP) && new_visible <= length)
        out << char
        visible = new_visible
      else
        stop = true
      end
    end
  end

  out << RESET if ansi_open
  out << OMISSION if stop
  out
end