highline 2.0.0.pre.develop.2 → 2.0.0.pre.develop.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|