rfix 2.0.4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/rfix +11 -90
- data/lib/rfix.rb +10 -9
- data/lib/rfix/branch/reference.rb +2 -2
- data/lib/rfix/branch/upstream.rb +2 -4
- data/lib/rfix/cli/command.rb +14 -1
- data/lib/rfix/cli/command/all.rb +21 -0
- data/lib/rfix/cli/command/base.rb +30 -19
- data/lib/rfix/cli/command/branch.rb +2 -0
- data/lib/rfix/cli/command/help.rb +2 -0
- data/lib/rfix/cli/command/info.rb +6 -1
- data/lib/rfix/cli/command/local.rb +2 -0
- data/lib/rfix/cli/command/origin.rb +2 -0
- data/lib/rfix/cli/command/setup.rb +2 -0
- data/lib/rfix/cli/command/status.rb +39 -0
- data/lib/rfix/collector.rb +69 -0
- data/lib/rfix/diff.rb +69 -0
- data/lib/rfix/extension/comment_config.rb +15 -0
- data/lib/rfix/extension/offense.rb +17 -14
- data/lib/rfix/extension/pastel.rb +7 -4
- data/lib/rfix/extension/progresbar.rb +15 -0
- data/lib/rfix/extension/strings.rb +10 -2
- data/lib/rfix/file.rb +5 -3
- data/lib/rfix/file/base.rb +21 -14
- data/lib/rfix/file/deleted.rb +2 -0
- data/lib/rfix/file/ignored.rb +2 -0
- data/lib/rfix/file/null.rb +17 -0
- data/lib/rfix/file/tracked.rb +39 -23
- data/lib/rfix/file/undefined.rb +17 -0
- data/lib/rfix/file/untracked.rb +3 -1
- data/lib/rfix/formatter.rb +67 -71
- data/lib/rfix/highlighter.rb +1 -3
- data/lib/rfix/rake/gemfile.rb +26 -23
- data/lib/rfix/repository.rb +59 -96
- data/lib/rfix/types.rb +24 -14
- data/lib/rfix/version.rb +1 -1
- data/rfix.gemspec +11 -3
- data/vendor/cli-ui/Gemfile +17 -0
- data/vendor/cli-ui/Gemfile.lock +60 -0
- data/vendor/cli-ui/LICENSE.txt +21 -0
- data/vendor/cli-ui/README.md +224 -0
- data/vendor/cli-ui/Rakefile +20 -0
- data/vendor/cli-ui/bin/console +14 -0
- data/vendor/cli-ui/cli-ui.gemspec +25 -0
- data/vendor/cli-ui/dev.yml +14 -0
- data/vendor/cli-ui/lib/cli/ui.rb +233 -0
- data/vendor/cli-ui/lib/cli/ui/ansi.rb +157 -0
- data/vendor/cli-ui/lib/cli/ui/color.rb +84 -0
- data/vendor/cli-ui/lib/cli/ui/formatter.rb +192 -0
- data/vendor/cli-ui/lib/cli/ui/frame.rb +269 -0
- data/vendor/cli-ui/lib/cli/ui/frame/frame_stack.rb +98 -0
- data/vendor/cli-ui/lib/cli/ui/frame/frame_style.rb +120 -0
- data/vendor/cli-ui/lib/cli/ui/frame/frame_style/box.rb +166 -0
- data/vendor/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +139 -0
- data/vendor/cli-ui/lib/cli/ui/glyph.rb +84 -0
- data/vendor/cli-ui/lib/cli/ui/os.rb +67 -0
- data/vendor/cli-ui/lib/cli/ui/printer.rb +59 -0
- data/vendor/cli-ui/lib/cli/ui/progress.rb +90 -0
- data/vendor/cli-ui/lib/cli/ui/prompt.rb +297 -0
- data/vendor/cli-ui/lib/cli/ui/prompt/interactive_options.rb +484 -0
- data/vendor/cli-ui/lib/cli/ui/prompt/options_handler.rb +29 -0
- data/vendor/cli-ui/lib/cli/ui/spinner.rb +66 -0
- data/vendor/cli-ui/lib/cli/ui/spinner/async.rb +40 -0
- data/vendor/cli-ui/lib/cli/ui/spinner/spin_group.rb +263 -0
- data/vendor/cli-ui/lib/cli/ui/stdout_router.rb +232 -0
- data/vendor/cli-ui/lib/cli/ui/terminal.rb +46 -0
- data/vendor/cli-ui/lib/cli/ui/truncater.rb +102 -0
- data/vendor/cli-ui/lib/cli/ui/version.rb +5 -0
- data/vendor/cli-ui/lib/cli/ui/widgets.rb +77 -0
- data/vendor/cli-ui/lib/cli/ui/widgets/base.rb +27 -0
- data/vendor/cli-ui/lib/cli/ui/widgets/status.rb +61 -0
- data/vendor/cli-ui/lib/cli/ui/wrap.rb +56 -0
- data/vendor/cli-ui/test/cli/ui/ansi_test.rb +32 -0
- data/vendor/cli-ui/test/cli/ui/cli_ui_test.rb +23 -0
- data/vendor/cli-ui/test/cli/ui/color_test.rb +40 -0
- data/vendor/cli-ui/test/cli/ui/formatter_test.rb +79 -0
- data/vendor/cli-ui/test/cli/ui/glyph_test.rb +68 -0
- data/vendor/cli-ui/test/cli/ui/printer_test.rb +103 -0
- data/vendor/cli-ui/test/cli/ui/progress_test.rb +46 -0
- data/vendor/cli-ui/test/cli/ui/prompt/options_handler_test.rb +39 -0
- data/vendor/cli-ui/test/cli/ui/prompt_test.rb +348 -0
- data/vendor/cli-ui/test/cli/ui/spinner/spin_group_test.rb +39 -0
- data/vendor/cli-ui/test/cli/ui/spinner_test.rb +141 -0
- data/vendor/cli-ui/test/cli/ui/stdout_router_test.rb +32 -0
- data/vendor/cli-ui/test/cli/ui/terminal_test.rb +26 -0
- data/vendor/cli-ui/test/cli/ui/truncater_test.rb +31 -0
- data/vendor/cli-ui/test/cli/ui/widgets/status_test.rb +49 -0
- data/vendor/cli-ui/test/cli/ui/widgets_test.rb +15 -0
- data/vendor/cli-ui/test/test_helper.rb +53 -0
- data/vendor/cli-ui/tmp/cache/bootsnap/compile-cache/d9/c036af0f3dc494 +0 -0
- data/vendor/cli-ui/tmp/cache/bootsnap/load-path-cache +0 -0
- data/vendor/dry-cli/lib/dry/cli/command.rb +2 -1
- data/vendor/dry-cli/tmp/cache/bootsnap/compile-cache/ff/a22a5daafbd74c +0 -0
- data/vendor/dry-cli/tmp/cache/bootsnap/load-path-cache +0 -0
- data/vendor/strings-ansi/tmp/cache/bootsnap/compile-cache/79/49cf49407b370e +0 -0
- data/vendor/strings-ansi/tmp/cache/bootsnap/load-path-cache +0 -0
- metadata +170 -9
- data/lib/rfix/extension/string.rb +0 -12
- data/lib/rfix/indicator.rb +0 -19
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'cli/ui'
|
2
|
+
require 'io/console'
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module UI
|
6
|
+
module Terminal
|
7
|
+
DEFAULT_WIDTH = 80
|
8
|
+
DEFAULT_HEIGHT = 24
|
9
|
+
|
10
|
+
# Returns the width of the terminal, if possible
|
11
|
+
# Otherwise will return DEFAULT_WIDTH
|
12
|
+
#
|
13
|
+
def self.width
|
14
|
+
winsize[1]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the width of the terminal, if possible
|
18
|
+
# Otherwise, will return DEFAULT_HEIGHT
|
19
|
+
#
|
20
|
+
def self.height
|
21
|
+
winsize[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.winsize
|
25
|
+
@winsize ||= begin
|
26
|
+
winsize = IO.console.winsize
|
27
|
+
setup_winsize_trap
|
28
|
+
|
29
|
+
if winsize.any?(&:zero?)
|
30
|
+
[DEFAULT_HEIGHT, DEFAULT_WIDTH]
|
31
|
+
else
|
32
|
+
winsize
|
33
|
+
end
|
34
|
+
rescue
|
35
|
+
[DEFAULT_HEIGHT, DEFAULT_WIDTH]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.setup_winsize_trap
|
40
|
+
@winsize_trap ||= Signal.trap('WINCH') do
|
41
|
+
@winsize = nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cli/ui'
|
4
|
+
|
5
|
+
module CLI
|
6
|
+
module UI
|
7
|
+
# Truncater truncates a string to a provided printable width.
|
8
|
+
module Truncater
|
9
|
+
PARSE_ROOT = :root
|
10
|
+
PARSE_ANSI = :ansi
|
11
|
+
PARSE_ESC = :esc
|
12
|
+
PARSE_ZWJ = :zwj
|
13
|
+
|
14
|
+
ESC = 0x1b
|
15
|
+
LEFT_SQUARE_BRACKET = 0x5b
|
16
|
+
ZWJ = 0x200d # emojipedia.org/emoji-zwj-sequences
|
17
|
+
SEMICOLON = 0x3b
|
18
|
+
|
19
|
+
# EMOJI_RANGE in particular is super inaccurate. This is best-effort.
|
20
|
+
# If you need this to be more accurate, we'll almost certainly accept a
|
21
|
+
# PR improving it.
|
22
|
+
EMOJI_RANGE = 0x1f300..0x1f5ff
|
23
|
+
NUMERIC_RANGE = 0x30..0x39
|
24
|
+
LC_ALPHA_RANGE = 0x40..0x5a
|
25
|
+
UC_ALPHA_RANGE = 0x60..0x71
|
26
|
+
|
27
|
+
TRUNCATED = "\x1b[0m…"
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def call(text, printing_width)
|
31
|
+
return text if text.size <= printing_width
|
32
|
+
|
33
|
+
width = 0
|
34
|
+
mode = PARSE_ROOT
|
35
|
+
truncation_index = nil
|
36
|
+
|
37
|
+
codepoints = text.codepoints
|
38
|
+
codepoints.each.with_index do |cp, index|
|
39
|
+
case mode
|
40
|
+
when PARSE_ROOT
|
41
|
+
case cp
|
42
|
+
when ESC # non-printable, followed by some more non-printables.
|
43
|
+
mode = PARSE_ESC
|
44
|
+
when ZWJ # non-printable, followed by another non-printable.
|
45
|
+
mode = PARSE_ZWJ
|
46
|
+
else
|
47
|
+
width += width(cp)
|
48
|
+
if width >= printing_width
|
49
|
+
truncation_index ||= index
|
50
|
+
# it looks like we could break here but we still want the
|
51
|
+
# width calculation for the rest of the characters.
|
52
|
+
end
|
53
|
+
end
|
54
|
+
when PARSE_ESC
|
55
|
+
mode = case cp
|
56
|
+
when LEFT_SQUARE_BRACKET
|
57
|
+
PARSE_ANSI
|
58
|
+
else
|
59
|
+
PARSE_ROOT
|
60
|
+
end
|
61
|
+
when PARSE_ANSI
|
62
|
+
# ANSI escape codes preeeetty much have the format of:
|
63
|
+
# \x1b[0-9;]+[A-Za-z]
|
64
|
+
case cp
|
65
|
+
when NUMERIC_RANGE, SEMICOLON
|
66
|
+
when LC_ALPHA_RANGE, UC_ALPHA_RANGE
|
67
|
+
mode = PARSE_ROOT
|
68
|
+
else
|
69
|
+
# unexpected. let's just go back to the root state I guess?
|
70
|
+
mode = PARSE_ROOT
|
71
|
+
end
|
72
|
+
when PARSE_ZWJ
|
73
|
+
# consume any character and consider it as having no width
|
74
|
+
# width(x+ZWJ+y) = width(x).
|
75
|
+
mode = PARSE_ROOT
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Without the `width <= printing_width` check, we truncate
|
80
|
+
# "foo\x1b[0m" for a width of 3, but it should not be truncated.
|
81
|
+
# It's specifically for the case where we decided "Yes, this is the
|
82
|
+
# point at which we'd have to add a truncation!" but it's actually
|
83
|
+
# the end of the string.
|
84
|
+
return text if !truncation_index || width <= printing_width
|
85
|
+
|
86
|
+
codepoints[0...truncation_index].pack('U*') + TRUNCATED
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def width(printable_codepoint)
|
92
|
+
case printable_codepoint
|
93
|
+
when EMOJI_RANGE
|
94
|
+
2
|
95
|
+
else
|
96
|
+
1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require('cli/ui')
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module UI
|
5
|
+
# Widgets are formatter objects with more custom implementations than the
|
6
|
+
# other features, which all center around formatting text with colours,
|
7
|
+
# etc.
|
8
|
+
#
|
9
|
+
# If you want to extend CLI::UI with your own widgets, you may want to do
|
10
|
+
# something like this:
|
11
|
+
#
|
12
|
+
# require('cli/ui')
|
13
|
+
# class MyWidget < CLI::UI::Widgets::Base
|
14
|
+
# # ...
|
15
|
+
# end
|
16
|
+
# CLI::UI::Widgets.register('my-widget') { MyWidget }
|
17
|
+
# puts(CLI::UI.fmt("{{@widget/my-widget:args}}"))
|
18
|
+
module Widgets
|
19
|
+
MAP = {}
|
20
|
+
|
21
|
+
autoload(:Base, 'cli/ui/widgets/base')
|
22
|
+
|
23
|
+
def self.register(name, &cb)
|
24
|
+
MAP[name] = cb
|
25
|
+
end
|
26
|
+
|
27
|
+
autoload(:Status, 'cli/ui/widgets/status')
|
28
|
+
register('status') { Widgets::Status }
|
29
|
+
|
30
|
+
# Looks up a widget by handle
|
31
|
+
#
|
32
|
+
# ==== Raises
|
33
|
+
# Raises InvalidWidgetHandle if the widget is not available.
|
34
|
+
#
|
35
|
+
# ==== Returns
|
36
|
+
# A callable widget, to be invoked like `.call(argstring)`
|
37
|
+
#
|
38
|
+
def self.lookup(handle)
|
39
|
+
MAP.fetch(handle.to_s).call
|
40
|
+
rescue KeyError, NameError
|
41
|
+
raise(InvalidWidgetHandle, handle)
|
42
|
+
end
|
43
|
+
|
44
|
+
# All available widgets by name
|
45
|
+
#
|
46
|
+
def self.available
|
47
|
+
MAP.keys
|
48
|
+
end
|
49
|
+
|
50
|
+
class InvalidWidgetHandle < ArgumentError
|
51
|
+
def initialize(handle)
|
52
|
+
super
|
53
|
+
@handle = handle
|
54
|
+
end
|
55
|
+
|
56
|
+
def message
|
57
|
+
keys = Widget.available.join(',')
|
58
|
+
"invalid widget handle: #{@handle} " \
|
59
|
+
"-- must be one of CLI::UI::Widgets.available (#{keys})"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class InvalidWidgetArguments < ArgumentError
|
64
|
+
def initialize(argstring, pattern)
|
65
|
+
super
|
66
|
+
@argstring = argstring
|
67
|
+
@pattern = pattern
|
68
|
+
end
|
69
|
+
|
70
|
+
def message
|
71
|
+
"invalid widget arguments: #{@argstring} " \
|
72
|
+
"-- must match pattern: #{@pattern.inspect}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require('cli/ui')
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module UI
|
5
|
+
module Widgets
|
6
|
+
class Base
|
7
|
+
def self.call(argstring)
|
8
|
+
new(argstring).render
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(argstring)
|
12
|
+
pat = self.class.argparse_pattern
|
13
|
+
unless (@match_data = pat.match(argstring))
|
14
|
+
raise(Widgets::InvalidWidgetArguments.new(argstring, pat))
|
15
|
+
end
|
16
|
+
@match_data.names.each do |name|
|
17
|
+
instance_variable_set(:"@#{name}", @match_data[name])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.argparse_pattern
|
22
|
+
const_get(:ARGPARSE_PATTERN)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
require('cli/ui')
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module UI
|
6
|
+
module Widgets
|
7
|
+
class Status < Widgets::Base
|
8
|
+
ARGPARSE_PATTERN = %r{
|
9
|
+
\A (?<succeeded> \d+)
|
10
|
+
: (?<failed> \d+)
|
11
|
+
: (?<working> \d+)
|
12
|
+
: (?<pending> \d+) \z
|
13
|
+
}x # e.g. "1:23:3:404"
|
14
|
+
OPEN = Color::RESET.code + Color::BOLD.code + '[' + Color::RESET.code
|
15
|
+
CLOSE = Color::RESET.code + Color::BOLD.code + ']' + Color::RESET.code
|
16
|
+
ARROW = Color::RESET.code + Color::GRAY.code + '◂' + Color::RESET.code
|
17
|
+
COMMA = Color::RESET.code + Color::GRAY.code + ',' + Color::RESET.code
|
18
|
+
|
19
|
+
SPINNER_STOPPED = '⠿'
|
20
|
+
EMPTY_SET = '∅'
|
21
|
+
|
22
|
+
def render
|
23
|
+
if zero?(@succeeded) && zero?(@failed) && zero?(@working) && zero?(@pending)
|
24
|
+
Color::RESET.code + Color::BOLD.code + EMPTY_SET + Color::RESET.code
|
25
|
+
else
|
26
|
+
# [ 0✓ , 2✗ ◂ 3⠼ ◂ 4⌛︎ ]
|
27
|
+
"#{OPEN}#{succeeded_part}#{COMMA}#{failed_part}#{ARROW}#{working_part}#{ARROW}#{pending_part}#{CLOSE}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def zero?(num_str)
|
34
|
+
num_str == '0'
|
35
|
+
end
|
36
|
+
|
37
|
+
def colorize_if_nonzero(num_str, rune, color)
|
38
|
+
color = Color::GRAY if zero?(num_str)
|
39
|
+
color.code + num_str + rune
|
40
|
+
end
|
41
|
+
|
42
|
+
def succeeded_part
|
43
|
+
colorize_if_nonzero(@succeeded, Glyph::CHECK.char, Color::GREEN)
|
44
|
+
end
|
45
|
+
|
46
|
+
def failed_part
|
47
|
+
colorize_if_nonzero(@failed, Glyph::X.char, Color::RED)
|
48
|
+
end
|
49
|
+
|
50
|
+
def working_part
|
51
|
+
rune = zero?(@working) ? SPINNER_STOPPED : Spinner.current_rune
|
52
|
+
colorize_if_nonzero(@working, rune, Color::BLUE)
|
53
|
+
end
|
54
|
+
|
55
|
+
def pending_part
|
56
|
+
colorize_if_nonzero(@pending, Glyph::HOURGLASS.char, Color::WHITE)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'cli/ui'
|
3
|
+
require 'cli/ui/frame/frame_stack'
|
4
|
+
require 'cli/ui/frame/frame_style'
|
5
|
+
|
6
|
+
module CLI
|
7
|
+
module UI
|
8
|
+
class Wrap
|
9
|
+
def initialize(input)
|
10
|
+
@input = input
|
11
|
+
end
|
12
|
+
|
13
|
+
def wrap
|
14
|
+
max_width = Terminal.width - Frame.prefix_width
|
15
|
+
width = 0
|
16
|
+
final = []
|
17
|
+
# Create an alternation of format codes of parameter lengths 1-20, since + and {1,n} not allowed in lookbehind
|
18
|
+
format_codes = (1..20).map { |n| /\x1b\[[\d;]{#{n}}m/ }.join('|')
|
19
|
+
codes = ''
|
20
|
+
@input.split(/(?=\s|\x1b\[[\d;]+m|\r)|(?<=\s|#{format_codes})/).each do |token|
|
21
|
+
case token
|
22
|
+
when '\x1B[0?m'
|
23
|
+
codes = ''
|
24
|
+
final << token
|
25
|
+
when /\x1b\[[\d;]+m/
|
26
|
+
codes += token # Track in use format codes so that they are resent after frame coloring
|
27
|
+
final << token
|
28
|
+
when "\n"
|
29
|
+
final << "\n#{codes}"
|
30
|
+
width = 0
|
31
|
+
when /\s/
|
32
|
+
token_width = ANSI.printing_width(token)
|
33
|
+
if width + token_width <= max_width
|
34
|
+
final << token
|
35
|
+
width += token_width
|
36
|
+
else
|
37
|
+
final << "\n#{codes}"
|
38
|
+
width = 0
|
39
|
+
end
|
40
|
+
else
|
41
|
+
token_width = ANSI.printing_width(token)
|
42
|
+
if width + token_width <= max_width
|
43
|
+
final << token
|
44
|
+
width += token_width
|
45
|
+
else
|
46
|
+
final << "\n#{codes}"
|
47
|
+
final << token
|
48
|
+
width = token_width
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
final.join
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module UI
|
5
|
+
class ANSITest < MiniTest::Test
|
6
|
+
def test_sgr
|
7
|
+
assert_equal("\x1b[1;34m", ANSI.sgr('1;34'))
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_printing_width
|
11
|
+
assert_equal(4, ANSI.printing_width("\x1b[38;2;100;100;100mtest\x1b[0m"))
|
12
|
+
assert_equal(0, ANSI.printing_width(''))
|
13
|
+
|
14
|
+
assert_equal(3, ANSI.printing_width('>🔧<'))
|
15
|
+
assert_equal(1, ANSI.printing_width('👩💻'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_line_skip_with_shift
|
19
|
+
next_line_expected = "\e[1B\e[1G"
|
20
|
+
previous_line_expected = "\e[1A\e[1G"
|
21
|
+
|
22
|
+
assert_equal(next_line_expected, ANSI.next_line)
|
23
|
+
assert_equal(previous_line_expected, ANSI.previous_line)
|
24
|
+
|
25
|
+
CLI::UI::OS.stubs(:current).returns(CLI::UI::OS::Windows)
|
26
|
+
|
27
|
+
assert_equal("#{next_line_expected}\e[1D", ANSI.next_line)
|
28
|
+
assert_equal("#{previous_line_expected}\e[1D", ANSI.previous_line)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
class UITest < MiniTest::Test
|
5
|
+
def test_resolve_test
|
6
|
+
input = 'a{{blue:b {{*}}{{bold:c {{red:d}}}}{{bold: e}}}} f'
|
7
|
+
expected = "\e[0ma\e[0;94mb \e[0;33m⭑\e[0;94;1mc \e[0;94;1;31md\e[0;94;1m e\e[0m f"
|
8
|
+
actual = CLI::UI.resolve_text(input)
|
9
|
+
assert_equal(expected, actual)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_color
|
13
|
+
prev = CLI::UI.enable_color?
|
14
|
+
|
15
|
+
CLI::UI.enable_color = true
|
16
|
+
assert_equal("\e[0;31ma\e[0m", CLI::UI.fmt('{{red:a}}'))
|
17
|
+
CLI::UI.enable_color = false
|
18
|
+
assert_equal('a', CLI::UI.fmt('{{red:a}}'))
|
19
|
+
ensure
|
20
|
+
CLI::UI.enable_color = prev
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module UI
|
5
|
+
class ColorTest < MiniTest::Test
|
6
|
+
def test_colors
|
7
|
+
assert_equal("\x1b[31m", Color::RED.code)
|
8
|
+
assert_equal("\x1b[32m", Color::GREEN.code)
|
9
|
+
assert_equal("\x1b[33m", Color::YELLOW.code)
|
10
|
+
assert_equal("\x1b[94m", Color::BLUE.code)
|
11
|
+
assert_equal("\x1b[35m", Color::MAGENTA.code)
|
12
|
+
assert_equal("\x1b[36m", Color::CYAN.code)
|
13
|
+
assert_equal("\x1b[0m", Color::RESET.code)
|
14
|
+
assert_equal("\x1b[1m", Color::BOLD.code)
|
15
|
+
assert_equal("\x1b[97m", Color::WHITE.code)
|
16
|
+
|
17
|
+
assert_equal('36', Color::CYAN.sgr)
|
18
|
+
assert_equal(:bold, Color::BOLD.name)
|
19
|
+
|
20
|
+
assert_equal(Color::BLUE, Color.lookup(:blue))
|
21
|
+
assert_equal(Color::RESET, Color.lookup(:reset))
|
22
|
+
|
23
|
+
assert_raises(Color::InvalidColorName) do
|
24
|
+
Color.lookup(:foobar)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_useful_exception
|
29
|
+
e = begin
|
30
|
+
Color.lookup(:foobar)
|
31
|
+
rescue => e
|
32
|
+
e
|
33
|
+
end
|
34
|
+
assert_match(/invalid color: :foobar/, e.message) # error
|
35
|
+
assert_match(/Color\.available/, e.message) # where to find colors
|
36
|
+
assert_match(/:green/, e.message) # list of valid colors
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|