highline 2.0.0.pre.develop.2 → 2.0.0.pre.develop.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changelog.md +28 -0
- data/README.md +188 -0
- data/Rakefile +0 -11
- data/highline.gemspec +2 -4
- data/lib/highline.rb +170 -73
- data/lib/highline/builtin_styles.rb +18 -2
- data/lib/highline/color_scheme.rb +15 -5
- data/lib/highline/compatibility.rb +6 -1
- data/lib/highline/custom_errors.rb +43 -6
- data/lib/highline/import.rb +10 -3
- data/lib/highline/list.rb +95 -7
- data/lib/highline/list_renderer.rb +36 -17
- data/lib/highline/menu.rb +73 -18
- data/lib/highline/paginator.rb +10 -0
- data/lib/highline/question.rb +98 -41
- data/lib/highline/question/answer_converter.rb +19 -0
- data/lib/highline/question_asker.rb +21 -17
- data/lib/highline/simulate.rb +10 -1
- data/lib/highline/statement.rb +62 -38
- data/lib/highline/string.rb +26 -25
- data/lib/highline/string_extensions.rb +60 -32
- data/lib/highline/style.rb +125 -25
- data/lib/highline/template_renderer.rb +25 -1
- data/lib/highline/terminal.rb +124 -1
- data/lib/highline/terminal/io_console.rb +6 -75
- data/lib/highline/terminal/ncurses.rb +7 -8
- data/lib/highline/terminal/unix_stty.rb +35 -81
- data/lib/highline/version.rb +1 -1
- data/lib/highline/wrapper.rb +9 -0
- data/test/test_highline.rb +1 -1
- metadata +6 -13
- data/INSTALL +0 -59
- data/README.rdoc +0 -77
- data/setup.rb +0 -1360
@@ -1,11 +1,16 @@
|
|
1
1
|
#coding: utf-8
|
2
2
|
|
3
3
|
class HighLine
|
4
|
+
# Builtin Styles that are included at HighLine initialization.
|
5
|
+
# It has the basic styles like :bold and :underline.
|
4
6
|
module BuiltinStyles
|
7
|
+
# Included callback
|
8
|
+
# @param base [Class, Module] base class
|
5
9
|
def self.included(base)
|
6
10
|
base.extend ClassMethods
|
7
11
|
end
|
8
12
|
|
13
|
+
# Basic styles' ANSI escape codes like :bold => "\e[1m"
|
9
14
|
STYLE_LIST = {
|
10
15
|
erase_line: "\e[K",
|
11
16
|
erase_char: "\e[P",
|
@@ -27,8 +32,10 @@ class HighLine
|
|
27
32
|
const_set style + "_STYLE", Style.new(name: style_name, code: code, builtin: true)
|
28
33
|
end
|
29
34
|
|
35
|
+
# Basic Style names like CLEAR, BOLD, UNDERLINE
|
30
36
|
STYLES = %w{CLEAR RESET BOLD DARK UNDERLINE UNDERSCORE BLINK REVERSE CONCEALED}
|
31
37
|
|
38
|
+
# A Hash with the basic colors an their ANSI escape codes.
|
32
39
|
COLOR_LIST = {
|
33
40
|
black: { code: "\e[30m", rgb: [0, 0, 0] },
|
34
41
|
red: { code: "\e[31m", rgb: [128, 0, 0] },
|
@@ -56,6 +63,7 @@ class HighLine
|
|
56
63
|
const_set color + "_STYLE", style
|
57
64
|
end
|
58
65
|
|
66
|
+
# The builtin styles basic colors like black, red, green.
|
59
67
|
BASIC_COLORS = %w{BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE GRAY GREY NONE}
|
60
68
|
|
61
69
|
colors = BASIC_COLORS.dup
|
@@ -68,6 +76,8 @@ class HighLine
|
|
68
76
|
colors << light_color
|
69
77
|
const_set light_color + '_STYLE', const_get(color + '_STYLE').light
|
70
78
|
end
|
79
|
+
|
80
|
+
# The builtin styles' colors like LIGHT_RED and BRIGHT_BLUE.
|
71
81
|
COLORS = colors
|
72
82
|
|
73
83
|
colors.each do |color|
|
@@ -78,11 +88,17 @@ class HighLine
|
|
78
88
|
|
79
89
|
ON_NONE_STYLE.rgb = [255,255,255] # Override; white background
|
80
90
|
|
91
|
+
# BuiltinStyles class methods to be extended.
|
81
92
|
module ClassMethods
|
82
|
-
RGB_COLOR = /^(ON_)?(RGB_)([A-F0-9]{6})(_STYLE)?$/
|
83
93
|
|
94
|
+
# Regexp to match against RGB style constant names.
|
95
|
+
RGB_COLOR_PATTERN = /^(ON_)?(RGB_)([A-F0-9]{6})(_STYLE)?$/
|
96
|
+
|
97
|
+
# const_missing callback for automatically respond to
|
98
|
+
# builtin constants (without explicitly defining them)
|
99
|
+
# @param name [Symbol] missing constant name
|
84
100
|
def const_missing(name)
|
85
|
-
if name.to_s =~
|
101
|
+
if name.to_s =~ RGB_COLOR_PATTERN
|
86
102
|
on = $1
|
87
103
|
suffix = $4
|
88
104
|
|
@@ -8,19 +8,18 @@
|
|
8
8
|
#
|
9
9
|
# This is Free Software. See LICENSE and COPYING for details
|
10
10
|
|
11
|
+
|
11
12
|
class HighLine
|
12
13
|
#
|
13
14
|
# ColorScheme objects encapsulate a named set of colors to be used in the
|
14
|
-
# HighLine.
|
15
|
+
# {HighLine.color} method call. For example, by applying a ColorScheme that
|
15
16
|
# has a <tt>:warning</tt> color then the following could be used:
|
16
17
|
#
|
17
|
-
#
|
18
|
+
# color("This is a warning", :warning)
|
18
19
|
#
|
19
20
|
# A ColorScheme contains named sets of HighLine color constants.
|
20
21
|
#
|
21
|
-
#
|
22
|
-
# and using it:
|
23
|
-
#
|
22
|
+
# @example Instantiating a color scheme, applying it to HighLine, and using it:
|
24
23
|
# ft = HighLine::ColorScheme.new do |cs|
|
25
24
|
# cs[:headline] = [ :bold, :yellow, :on_black ]
|
26
25
|
# cs[:horizontal_line] = [ :bold, :white ]
|
@@ -49,6 +48,7 @@ class HighLine
|
|
49
48
|
# converted to <tt>:symbols</tt> and values are converted to HighLine
|
50
49
|
# constants.
|
51
50
|
#
|
51
|
+
# @param h [Hash]
|
52
52
|
def initialize( h = nil )
|
53
53
|
@scheme = Hash.new
|
54
54
|
load_from_hash(h) if h
|
@@ -56,6 +56,7 @@ class HighLine
|
|
56
56
|
end
|
57
57
|
|
58
58
|
# Load multiple colors from key/value pairs.
|
59
|
+
# @param h [Hash]
|
59
60
|
def load_from_hash( h )
|
60
61
|
h.each_pair do |color_tag, constants|
|
61
62
|
self[color_tag] = constants
|
@@ -63,33 +64,42 @@ class HighLine
|
|
63
64
|
end
|
64
65
|
|
65
66
|
# Does this color scheme include the given tag name?
|
67
|
+
# @param color_tag [#to_sym]
|
68
|
+
# @return [Boolean]
|
66
69
|
def include?( color_tag )
|
67
70
|
@scheme.keys.include?(to_symbol(color_tag))
|
68
71
|
end
|
69
72
|
|
70
73
|
# Allow the scheme to be accessed like a Hash.
|
74
|
+
# @param color_tag [#to_sym]
|
75
|
+
# @return [Style]
|
71
76
|
def []( color_tag )
|
72
77
|
@scheme[to_symbol(color_tag)]
|
73
78
|
end
|
74
79
|
|
75
80
|
# Retrieve the original form of the scheme
|
81
|
+
# @param color_tag [#to_sym]
|
76
82
|
def definition( color_tag )
|
77
83
|
style = @scheme[to_symbol(color_tag)]
|
78
84
|
style && style.list
|
79
85
|
end
|
80
86
|
|
81
87
|
# Retrieve the keys in the scheme
|
88
|
+
# @return [Array] of keys
|
82
89
|
def keys
|
83
90
|
@scheme.keys
|
84
91
|
end
|
85
92
|
|
86
93
|
# Allow the scheme to be set like a Hash.
|
94
|
+
# @param color_tag [#to_sym]
|
95
|
+
# @param constants [Array<Symbol>] Array of Style symbols
|
87
96
|
def []=( color_tag, constants )
|
88
97
|
@scheme[to_symbol(color_tag)] = HighLine::Style.new(:name=>color_tag.to_s.downcase.to_sym,
|
89
98
|
:list=>constants, :no_index=>true)
|
90
99
|
end
|
91
100
|
|
92
101
|
# Retrieve the color scheme hash (in original definition format)
|
102
|
+
# @return [Hash] scheme as Hash. It may be reused in a new ColorScheme.
|
93
103
|
def to_hash
|
94
104
|
@scheme.inject({}) { |hsh, pair| key, value = pair; hsh[key] = value.list; hsh }
|
95
105
|
end
|
@@ -1,18 +1,23 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
unless STDIN.respond_to? :getbyte
|
4
|
+
# HighLine adds #getbyte alias to #getc when #getbyte is not available.
|
4
5
|
class IO
|
6
|
+
# alias to #getc when #getbyte is not available
|
5
7
|
alias_method :getbyte, :getc
|
6
8
|
end
|
7
9
|
|
10
|
+
# HighLine adds #getbyte alias to #getc when #getbyte is not available.
|
8
11
|
class StringIO
|
12
|
+
# alias to #getc when #getbyte is not available
|
9
13
|
alias_method :getbyte, :getc
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
13
17
|
unless "".respond_to? :each_line
|
14
|
-
#
|
18
|
+
# HighLine adds #each_line alias to #each when each_line is not available.
|
15
19
|
class String
|
20
|
+
# alias to #each when each_line is not available.
|
16
21
|
alias_method :each_line, :each
|
17
22
|
end
|
18
23
|
end
|
@@ -1,19 +1,56 @@
|
|
1
1
|
class HighLine
|
2
|
+
|
3
|
+
# Internal HighLine errors.
|
2
4
|
module CustomErrors
|
3
|
-
#
|
4
|
-
class
|
5
|
+
# An error that responds to :explanation_key
|
6
|
+
class ExplainableError < StandardError
|
7
|
+
# Explanation key as Symbol or nil. Used to
|
8
|
+
# select the proper error message to be displayed.
|
9
|
+
# @return [nil, Symbol] explanation key to get the
|
10
|
+
# proper error message.
|
11
|
+
def explanation_key
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Bare Question error
|
17
|
+
class QuestionError < ExplainableError
|
18
|
+
# (see ExplainableError#explanation_key)
|
19
|
+
def explanation_key
|
20
|
+
nil
|
21
|
+
end
|
5
22
|
end
|
6
23
|
|
7
|
-
|
24
|
+
# Invalid Question error
|
25
|
+
class NotValidQuestionError < ExplainableError
|
26
|
+
# (see ExplainableError#explanation_key)
|
27
|
+
def explanation_key
|
28
|
+
:not_valid
|
29
|
+
end
|
8
30
|
end
|
9
31
|
|
10
|
-
|
32
|
+
# Out of Range Question error
|
33
|
+
class NotInRangeQuestionError < ExplainableError
|
34
|
+
# (see ExplainableError#explanation_key)
|
35
|
+
def explanation_key
|
36
|
+
:not_in_range
|
37
|
+
end
|
11
38
|
end
|
12
39
|
|
13
|
-
|
40
|
+
# Unconfirmed Question error
|
41
|
+
class NoConfirmationQuestionError < ExplainableError
|
42
|
+
# (see ExplainableError#explanation_key)
|
43
|
+
def explanation_key
|
44
|
+
nil
|
45
|
+
end
|
14
46
|
end
|
15
47
|
|
16
|
-
|
48
|
+
# Unavailable auto complete error
|
49
|
+
class NoAutoCompleteMatch < ExplainableError
|
50
|
+
# (see ExplainableError#explanation_key)
|
51
|
+
def explanation_key
|
52
|
+
:no_completion
|
53
|
+
end
|
17
54
|
end
|
18
55
|
end
|
19
56
|
end
|
data/lib/highline/import.rb
CHANGED
@@ -14,11 +14,12 @@ $terminal = HighLine.new
|
|
14
14
|
|
15
15
|
#
|
16
16
|
# <tt>require "highline/import"</tt> adds shortcut methods to Kernel, making
|
17
|
-
# agree
|
17
|
+
# {HighLine#agree}, {HighLine#ask}, {HighLine#choose} and {HighLine#say}
|
18
|
+
# globally available. This is handy for
|
18
19
|
# quick and dirty input and output. These methods use the HighLine object in
|
19
|
-
# the global variable <tt>$terminal</tt>, which is initialized to
|
20
|
+
# the global variable <tt>$terminal</tt>, which is initialized to use
|
20
21
|
# <tt>$stdin</tt> and <tt>$stdout</tt> (you are free to change this).
|
21
|
-
# Otherwise, these methods are identical to their HighLine counterparts, see that
|
22
|
+
# Otherwise, these methods are identical to their {HighLine} counterparts, see that
|
22
23
|
# class for detailed explanations.
|
23
24
|
#
|
24
25
|
module Kernel
|
@@ -26,6 +27,8 @@ module Kernel
|
|
26
27
|
def_delegators :$terminal, :agree, :ask, :choose, :say
|
27
28
|
end
|
28
29
|
|
30
|
+
# When requiring 'highline/import' HighLine adds {#or_ask} to Object so
|
31
|
+
# it is globally available.
|
29
32
|
class Object
|
30
33
|
#
|
31
34
|
# Tries this object as a _first_answer_ for a HighLine::Question. See that
|
@@ -33,6 +36,10 @@ class Object
|
|
33
36
|
#
|
34
37
|
# *Warning*: This Object will be passed to String() before set.
|
35
38
|
#
|
39
|
+
# @param args [Array<#to_s>]
|
40
|
+
# @param details [lambda] block to be called with the question
|
41
|
+
# instance as argument.
|
42
|
+
# @return [String] answer
|
36
43
|
def or_ask( *args, &details )
|
37
44
|
ask(*args) do |question|
|
38
45
|
question.first_answer = String(self)
|
data/lib/highline/list.rb
CHANGED
@@ -1,18 +1,76 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
class HighLine
|
4
|
+
|
5
|
+
# List class with some convenience methods like {#col_down}.
|
4
6
|
class List
|
5
|
-
|
6
|
-
|
7
|
+
|
8
|
+
# Original given *items* argument.
|
9
|
+
# It's frozen at initialization time and
|
10
|
+
# all later transformations will happen on {#list}.
|
11
|
+
# @return [Array]
|
12
|
+
attr_reader :items
|
13
|
+
|
14
|
+
# Number of columns for each list row.
|
15
|
+
# @return [Integer]
|
16
|
+
attr_reader :cols
|
17
|
+
|
18
|
+
# Columns turn into rows in transpose mode.
|
19
|
+
# @return [Boolean]
|
20
|
+
#
|
21
|
+
# @example A two columns array like this:
|
22
|
+
# [ [ "a", "b" ],
|
23
|
+
# [ "c", "d" ],
|
24
|
+
# [ "e", "f" ],
|
25
|
+
# [ "g", "h" ],
|
26
|
+
# [ "i", "j" ] ]
|
27
|
+
#
|
28
|
+
# @example When in transpose mode will be like this:
|
29
|
+
# [ [ "a", "c", "e", "g", "i" ],
|
30
|
+
# [ "b", "d", "f", "h", "j" ] ]
|
31
|
+
#
|
32
|
+
# @see #col_down_mode
|
33
|
+
|
34
|
+
attr_reader :transpose_mode
|
35
|
+
|
36
|
+
|
37
|
+
# Content are distributed first by column in col down mode.
|
38
|
+
# @return [Boolean]
|
39
|
+
#
|
40
|
+
# @example A two columns array like this:
|
41
|
+
# [ [ "a", "b" ],
|
42
|
+
# [ "c", "d" ],
|
43
|
+
# [ "e", "f" ],
|
44
|
+
# [ "g", "h" ],
|
45
|
+
# [ "i", "j" ] ]
|
46
|
+
#
|
47
|
+
# @example In col down mode will be like this:
|
48
|
+
# [ [ "a", "f"],
|
49
|
+
# [ "b", "g"],
|
50
|
+
# [ "c", "h"],
|
51
|
+
# [ "d", "i"],
|
52
|
+
# [ "e", "j"] ]
|
53
|
+
#
|
54
|
+
# @see #transpose_mode
|
55
|
+
|
56
|
+
attr_reader :col_down_mode
|
57
|
+
|
58
|
+
# @param items [#to_a] an array of items to compose the list.
|
59
|
+
# @param options [Hash] a hash of options to tailor the list.
|
60
|
+
# @option options [Boolean] :transpose (false) set {#transpose_mode}.
|
61
|
+
# @option options [Boolean] :col_down (false) set {#col_down_mode}.
|
62
|
+
# @option options [Integer] :cols (1) set {#cols}.
|
7
63
|
|
8
64
|
def initialize(items, options = {})
|
9
|
-
@items = items
|
65
|
+
@items = items.to_a.dup.freeze
|
10
66
|
@transpose_mode = options.fetch(:transpose) { false }
|
11
67
|
@col_down_mode = options.fetch(:col_down) { false }
|
12
68
|
@cols = options.fetch(:cols) { 1 }
|
13
69
|
build
|
14
70
|
end
|
15
71
|
|
72
|
+
# Transpose the (already sliced by rows) list, turning its rows into columns.
|
73
|
+
# @return [self]
|
16
74
|
def transpose
|
17
75
|
first_row = @list[0]
|
18
76
|
other_rows = @list[1..-1]
|
@@ -20,47 +78,77 @@ class HighLine
|
|
20
78
|
self
|
21
79
|
end
|
22
80
|
|
81
|
+
# Slice the list by rows and transpose it.
|
82
|
+
# @return [self]
|
23
83
|
def col_down
|
24
84
|
slice_by_rows
|
25
85
|
transpose
|
26
86
|
self
|
27
87
|
end
|
28
88
|
|
89
|
+
# Slice the list by rows. The row count is calculated
|
90
|
+
# indirectly based on the {#cols} param and the items count.
|
91
|
+
# @return [self]
|
29
92
|
def slice_by_rows
|
30
93
|
@list = items_sliced_by_rows
|
31
94
|
self
|
32
95
|
end
|
33
96
|
|
97
|
+
# Slice the list by cols based on the {#cols} param.
|
98
|
+
# @return [self]
|
34
99
|
def slice_by_cols
|
35
100
|
@list = items_sliced_by_cols
|
36
101
|
self
|
37
102
|
end
|
38
103
|
|
104
|
+
# Set the cols number.
|
105
|
+
# @return [self]
|
39
106
|
def cols=(cols)
|
40
107
|
@cols = cols
|
41
108
|
build
|
42
109
|
end
|
43
110
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
111
|
+
# Returns an Array representation of the list
|
112
|
+
# in its current state.
|
113
|
+
# @return [Array] @list.dup
|
48
114
|
def list
|
49
115
|
@list.dup
|
50
116
|
end
|
51
117
|
|
118
|
+
# (see #list)
|
119
|
+
def to_a
|
120
|
+
list
|
121
|
+
end
|
122
|
+
|
123
|
+
# Stringfies the list in its current state.
|
124
|
+
# It joins each individual _cell_ with the current
|
125
|
+
# {#row_join_string} between them.
|
126
|
+
# It joins each individual row with a
|
127
|
+
# newline character. So the returned String is
|
128
|
+
# suitable to be directly outputed
|
129
|
+
# to the screen, preserving row/columns divisions.
|
130
|
+
# @return [String]
|
52
131
|
def to_s
|
53
132
|
list.map { |row| stringfy(row) }.join
|
54
133
|
end
|
55
134
|
|
135
|
+
# The String that will be used to join each
|
136
|
+
# cell of the list and stringfying it.
|
137
|
+
# @return [String] defaults to " " (space)
|
56
138
|
def row_join_string
|
57
139
|
@row_join_string ||= " "
|
58
140
|
end
|
59
141
|
|
142
|
+
# Set the {#row_join_string}.
|
143
|
+
# @see #row_join_string
|
60
144
|
def row_join_string=(string)
|
61
145
|
@row_join_string = string
|
62
146
|
end
|
63
147
|
|
148
|
+
# Returns the row join string size.
|
149
|
+
# Useful for calculating the actual size of
|
150
|
+
# rendered list.
|
151
|
+
# @return [Integer]
|
64
152
|
def row_join_str_size
|
65
153
|
row_join_string.size
|
66
154
|
end
|
@@ -4,24 +4,34 @@ require 'highline/template_renderer'
|
|
4
4
|
require 'highline/wrapper'
|
5
5
|
require 'highline/list'
|
6
6
|
|
7
|
+
#
|
8
|
+
# This class is a utility for quickly and easily laying out lists
|
9
|
+
# to be used by HighLine.
|
10
|
+
#
|
7
11
|
class HighLine::ListRenderer
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
20
|
-
|
12
|
+
# Items list
|
13
|
+
# @return [Array]
|
14
|
+
attr_reader :items
|
15
|
+
|
16
|
+
# @return [Symbol] the current mode the List is being rendered
|
17
|
+
# @see #initialize for more details see mode parameter of #initialize
|
18
|
+
attr_reader :mode
|
19
|
+
|
20
|
+
# Changes the behaviour of some modes. Example, in :inline mode
|
21
|
+
# the option is treated as the 'end separator' (defaults to " or ")
|
22
|
+
# @return option parameter that changes the behaviour of some modes.
|
23
|
+
attr_reader :option
|
24
|
+
|
25
|
+
# @return [HighLine] context
|
26
|
+
attr_reader :highline
|
27
|
+
|
28
|
+
# The only required parameters are _items_ and _highline_.
|
29
|
+
# @param items [Array] the Array of items to list
|
30
|
+
# @param mode [Symbol] controls how that list is formed
|
31
|
+
# @param option has different effects, depending on the _mode_.
|
32
|
+
# @param highline [HighLine] a HighLine instance to direct the output to.
|
21
33
|
#
|
22
|
-
#
|
23
|
-
# to list. A specified _mode_ controls how that list is formed and _option_
|
24
|
-
# has different effects, depending on the _mode_. Recognized modes are:
|
34
|
+
# Recognized modes are:
|
25
35
|
#
|
26
36
|
# <tt>:columns_across</tt>:: _items_ will be placed in columns,
|
27
37
|
# flowing from left to right. If given,
|
@@ -46,7 +56,16 @@ class HighLine::ListRenderer
|
|
46
56
|
# Each member of the _items_ Array is passed through ERb and thus can contain
|
47
57
|
# their own expansions. Color escape expansions do not contribute to the
|
48
58
|
# final field width.
|
49
|
-
|
59
|
+
|
60
|
+
def initialize(items, mode = :rows, option = nil, highline)
|
61
|
+
@highline = highline
|
62
|
+
@mode = mode
|
63
|
+
@option = option
|
64
|
+
@items = render_list_items(items)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Render the list using the appropriate mode and options.
|
68
|
+
# @return [String] rendered list as String
|
50
69
|
def render
|
51
70
|
return "" if items.empty?
|
52
71
|
|