Module: Clack::Utils

Defined in:
lib/clack/utils.rb

Overview

Utility functions for text manipulation and formatting

Class Method Summary collapse

Class Method Details

.display_width(string) ⇒ Integer

Calculate the terminal display width (columns) of a string. ASCII and most chars: width 1. CJK ideographs, fullwidth forms, common emoji: width 2. Zero-width joiners, combining marks, variation selectors: width 0.

Parameters:

  • string (String)

Returns:

  • (Integer)


27
28
29
30
31
32
33
34
35
36
# File 'lib/clack/utils.rb', line 27

def display_width(string)
  str = string.to_s
  return 0 if str.empty?

  width = 0
  str.grapheme_clusters.each do |cluster|
    width += grapheme_width(cluster)
  end
  width
end

.strip_ansi(text) ⇒ String

Strip ANSI escape sequences from text

Parameters:

  • text (String)

    Text with ANSI codes

Returns:

  • (String)

    Text without ANSI codes



10
11
12
# File 'lib/clack/utils.rb', line 10

def strip_ansi(text)
  text.to_s.gsub(/\e\[[0-9;]*[a-zA-Z]/, "")
end

.truncate(text, width, ellipsis: "...") ⇒ String

Truncate text to width with ellipsis

Parameters:

  • text (String)

    Text to truncate

  • width (Integer)

    Maximum width

  • ellipsis (String) (defaults to: "...")

    Ellipsis string (default: “…”)

Returns:

  • (String)

    Truncated text



71
72
73
74
75
76
77
78
79
# File 'lib/clack/utils.rb', line 71

def truncate(text, width, ellipsis: "...")
  return text if visible_length(text) <= width

  target = width - visible_length(ellipsis)
  return ellipsis if target <= 0

  # Handle ANSI codes: we need to truncate visible chars while preserving codes
  truncate_visible(text, target) + ellipsis
end

.visible_length(text) ⇒ Integer

Get visible length (display width in columns) of text after stripping ANSI. Uses display_width to correctly measure CJK, emoji, combining chars.

Parameters:

  • text (String)

Returns:

  • (Integer)

    display columns



18
19
20
# File 'lib/clack/utils.rb', line 18

def visible_length(text)
  display_width(strip_ansi(text))
end

.wrap(text, width) ⇒ String

Wrap text to a specified width, preserving ANSI codes

Parameters:

  • text (String)

    Text to wrap

  • width (Integer)

    Maximum line width

Returns:

  • (String)

    Wrapped text



42
43
44
45
46
47
48
49
50
# File 'lib/clack/utils.rb', line 42

def wrap(text, width)
  return text if width <= 0

  lines = []
  text.to_s.each_line do |line|
    lines.concat(wrap_line(line.chomp, width))
  end
  lines.join("\n")
end

.wrap_with_prefix(text, prefix, width) ⇒ String

Wrap text with a prefix on each line

Parameters:

  • text (String)

    Text to wrap

  • prefix (String)

    Prefix for each line (e.g., “│ ”)

  • width (Integer)

    Total width including prefix

Returns:

  • (String)

    Wrapped and prefixed text



57
58
59
60
61
62
63
64
# File 'lib/clack/utils.rb', line 57

def wrap_with_prefix(text, prefix, width)
  prefix_len = visible_length(prefix)
  content_width = width - prefix_len
  return text if content_width <= 0

  wrapped = wrap(text, content_width)
  wrapped.lines.map { |line| "#{prefix}#{line.chomp}" }.join("\n")
end