1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
# frozen_string_literal: true
# Helpers related to visual formatting of outputs
module InternalEventsCli
module Helpers
module Formatting
DEFAULT_WINDOW_WIDTH = 100
DEFAULT_WINDOW_HEIGHT = 30
# When to format as "info":
# - When a header is needed to organize contextual
# information. These headers should always be all caps.
# - As a supplemental way to highlight the most important
# text within a menu or informational text.
# - Optionally, for URLs
def format_info(string)
pastel.cyan(string)
end
# When to format as "warning":
# - To highlight the first sentence/phrase describing a
# problem the user needs to address. Any further text
# explantion should be left unformatted.
# - To highlight an explanation of why the user cannot take
# a particular action.
def format_warning(string)
pastel.yellow(string)
end
# When to format as "selection":
# - As a supplemental way of indicating something was
# selected or the current state of an interaction.
def format_selection(string)
pastel.green(string)
end
# When to format as "help":
# - To format supplemental information on how to interact
# with prompts. This should always be in parenthesis.
# - To indicate disabled or unavailable menu options.
# - To indicate meta-information in menu options or
# informational text.
def format_help(string)
pastel.bright_black(string)
end
# When to format as "prompt":
# - When we need the user to input information. The text
# should describe the action the user should take to move
# forward, like `Input text` or `Select one`
# - As header text on multi-screen steps in a flow. Always
# include a counter when this is the case.
def format_prompt(string)
pastel.magenta(string)
end
# When to format as "error":
# - When the CLI encounters unexpected problems that may
# require broader changes by the Analytics Instrumentation
# Group or out of band configuration.
# - To highlight special characters used to symbolize that
# there was an error or that an option is not available.
def format_error(string)
pastel.red(string)
end
# Strips all existing color/text style
def clear_format(string)
pastel.strip(string)
end
# When to format as "heading":
# - At the beginning or end of complete flows, to create
# visual separation and indicate logical breakpoints.
def format_heading(string)
[divider, pastel.cyan(string), divider].join("\n")
end
# Used for grouping prompts that occur on the same screen
# or as part of the same step of a flow.
#
# Counter is exluded if total is 1.
# The subject's formatting is extended to the counter.
#
# @return [String] ex) -- EATING COOKIES (2/3): Chocolate Chip --
# @param subject [String] describes task generically ex) EATING COOKIES
# @param item [String] describes specific context ex) Chocolate Chip
# @param count [Integer] ex) 2
# @param total [Integer] ex) 3
def format_subheader(subject, item, count, total)
formatting_end = "\e[0m"
suffix = formatting_end if subject[-formatting_end.length..] == formatting_end
"-- #{[subject.chomp(formatting_end), counter(count, total)].compact.join(' ')}:#{suffix} #{item} --"
end
def format_prefix(prefix, string)
string.lines.map { |line| line.prepend(prefix) }.join
end
# When to use a divider:
# - As separation between whole flows or format the layout
# of a screen or the layout of CLI outputs.
# - Dividers should not be used to differentiate between
# prompts on the same screen.
def divider
"-" * window_size
end
def progress_bar(step, total, titles = [])
breadcrumbs = [
titles[0..(step - 1)],
format_selection(titles[step]),
titles[(step + 1)..]
]
status = " Step #{step} / #{total} : #{breadcrumbs.flatten.join(' > ')}"
total_length = window_size - 4
step_length = step / total.to_f * total_length
incomplete = '-' * [(total_length - step_length - 1), 0].max
complete = '=' * [(step_length - 1), 0].max
"#{status}\n|==#{complete}>#{incomplete}|\n"
end
# Formats a counter if there's anything to count
#
# @return [String, nil] ex) "(3/4)""
def counter(idx, total)
"(#{idx + 1}/#{total})" if total > 1
end
private
def pastel
@pastel ||= Pastel.new
end
def window_size
Integer(fetch_window_size)
rescue StandardError
DEFAULT_WINDOW_WIDTH
end
def window_height
Integer(fetch_window_height)
rescue StandardError
DEFAULT_WINDOW_HEIGHT
end
def fetch_window_size
`tput cols`
end
def fetch_window_height
`tput lines`
end
end
end
end
|