# frozen_string_literal: true module MakeMenu module Console # Monkeypatch for `String`, adds methods to change console text colo(u)r module ColorString COLORS = { white: 0, normal: 0, bold: 1, dark: 2, underline: 4, blink: 5, invert: 7, black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, grey: 37, black_bg: 40, red_bg: 41, green_bg: 42, yellow_bg: 43, blue_bg: 44, magenta_bg: 45, cyan_bg: 46, grey_bg: 47, dark_grey: 90, light_red: 91, light_green: 92, light_yellow: 93, light_blue: 94, light_magenta: 95, light_cyan: 96, light_grey: 97, dark_grey_bg: 100, light_red_bg: 101, light_green_bg: 102, light_yellow_bg: 103, light_blue_bg: 104, light_magenta_bg: 105, light_cyan_bg: 106, light_grey_bg: 107 }.freeze COLORS.each do |name, code| define_method name do color(code) end end # Apply specified color code to the String # @param [Array, Symbol, Integer] color_code Can be a key in the COLORS array, # an integer ANSI code for text color, or an array of either to be applied in order # @return [String] String enclosed by formatting characters def color(color_code) case color_code when Array color_code.inject(self) { |string, code| string.color(code) } when Symbol color(COLORS[color_code]) else "\e[#{color_code}m#{self}\e[0m" end end # Changes all occurrences of `char` to `fore_color` # and all other characters to `back_color` def highlight(char, fore_color, back_color) inside_highlight = false output = '' buffer = '' each_char do |c| if c == char unless inside_highlight output += buffer.color(COLORS[back_color.to_sym]) buffer = '' inside_highlight = true end elsif inside_highlight output += buffer.color(COLORS[fore_color.to_sym]).bold buffer = '' inside_highlight = false end buffer += c end output += if inside_highlight buffer.color(COLORS[fore_color.to_sym]).bold else buffer.color(COLORS[back_color.to_sym]) end output end # Remove color codes from the string def decolor gsub(/\e\[\d+m/, '') end # Align the string, ignoring color code characters which would otherwise mess up String#center, etc. def align(alignment = :left, width: nil, char: ' ', pad_right: false) width ||= ::TTY::Screen.cols case alignment when :left right_pad = width - decolor.length "#{self}#{char * right_pad}" when :center left_pad = [(width - decolor.length) / 2, 0].max right_pad = width - left_pad - decolor.length "#{char * left_pad}#{self}#{pad_right ? char * right_pad : ''}" when :right left_pad = width - decolor.length "#{char * left_pad}#{self}" end end # Align each line of a string def align_block(alignment = :left) split("\n") .map { |line| line.align(alignment) } .join("\n") end end end end