tty 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -1
- data/.travis.yml +3 -6
- data/README.md +232 -134
- data/lib/tty/plugins/plugin.rb +56 -0
- data/lib/tty/plugins.rb +75 -0
- data/lib/tty/shell/suggestion.rb +102 -0
- data/lib/tty/shell.rb +41 -14
- data/lib/tty/system/editor.rb +111 -0
- data/lib/tty/system/which.rb +13 -1
- data/lib/tty/system.rb +44 -28
- data/lib/tty/table/border/null.rb +0 -9
- data/lib/tty/table/border/row_line.rb +21 -0
- data/lib/tty/table/border.rb +63 -32
- data/lib/tty/table/border_dsl.rb +1 -1
- data/lib/tty/table/column_set.rb +16 -17
- data/lib/tty/table/field.rb +27 -7
- data/lib/tty/table/header.rb +18 -9
- data/lib/tty/table/operation/alignment_set.rb +20 -25
- data/lib/tty/table/operation/escape.rb +30 -0
- data/lib/tty/table/operation/filter.rb +36 -0
- data/lib/tty/table/operation/truncation.rb +22 -11
- data/lib/tty/table/operation/wrapped.rb +21 -10
- data/lib/tty/table/operations.rb +10 -8
- data/lib/tty/table/orientation/horizontal.rb +1 -1
- data/lib/tty/table/renderer/ascii.rb +3 -3
- data/lib/tty/table/renderer/basic.rb +135 -65
- data/lib/tty/table/renderer/color.rb +1 -4
- data/lib/tty/table/renderer/unicode.rb +3 -3
- data/lib/tty/table/renderer.rb +48 -61
- data/lib/tty/table/row.rb +30 -3
- data/lib/tty/table/transformation.rb +38 -0
- data/lib/tty/table/validatable.rb +7 -5
- data/lib/tty/table.rb +78 -99
- data/lib/tty/terminal/color.rb +2 -2
- data/lib/tty/terminal/echo.rb +1 -1
- data/lib/tty/terminal/pager/basic.rb +52 -0
- data/lib/tty/terminal/pager/system.rb +39 -0
- data/lib/tty/terminal/pager.rb +95 -0
- data/lib/tty/terminal.rb +30 -1
- data/lib/tty/version.rb +1 -1
- data/lib/tty.rb +41 -1
- data/spec/spec_helper.rb +20 -0
- data/spec/tty/plugins/find_spec.rb +28 -0
- data/spec/tty/plugins/load_spec.rb +20 -0
- data/spec/tty/plugins/plugin/load_spec.rb +30 -0
- data/spec/tty/plugins/plugin/new_spec.rb +18 -0
- data/spec/tty/shell/suggest_spec.rb +50 -0
- data/spec/tty/support/conversion_spec.rb +3 -3
- data/spec/tty/support/delegatable_spec.rb +1 -1
- data/spec/tty/support/equatable_spec.rb +6 -9
- data/spec/tty/system/editor/available_spec.rb +40 -0
- data/spec/tty/system/editor/build_spec.rb +40 -0
- data/spec/tty/system/editor/command_spec.rb +16 -0
- data/spec/tty/system/editor/executables_spec.rb +13 -0
- data/spec/tty/system/editor/invoke_spec.rb +38 -0
- data/spec/tty/system/editor/open_spec.rb +27 -0
- data/spec/tty/system/platform_spec.rb +4 -6
- data/spec/tty/system/which/which_spec.rb +48 -0
- data/spec/tty/system/which_spec.rb +8 -34
- data/spec/tty/table/border/ascii/rendering_spec.rb +19 -5
- data/spec/tty/table/border/new_spec.rb +1 -1
- data/spec/tty/table/border/null/rendering_spec.rb +24 -8
- data/spec/tty/table/border/unicode/rendering_spec.rb +19 -5
- data/spec/tty/table/column_set/extract_widths_spec.rb +4 -15
- data/spec/tty/table/column_set/total_width_spec.rb +15 -0
- data/spec/tty/table/data_spec.rb +14 -0
- data/spec/tty/table/each_spec.rb +17 -4
- data/spec/tty/table/each_with_index_spec.rb +34 -6
- data/spec/tty/table/field/length_spec.rb +21 -0
- data/spec/tty/table/field/lines_spec.rb +21 -0
- data/spec/tty/table/filter_spec.rb +23 -0
- data/spec/tty/table/header/call_spec.rb +1 -1
- data/spec/tty/table/header/height_spec.rb +27 -0
- data/spec/tty/table/initialize_spec.rb +6 -6
- data/spec/tty/table/operation/alignment_set/call_spec.rb +39 -0
- data/spec/tty/table/operation/escape/call_spec.rb +16 -0
- data/spec/tty/table/operation/filter/call_spec.rb +17 -0
- data/spec/tty/table/operation/truncation/call_spec.rb +15 -10
- data/spec/tty/table/operation/truncation/truncate_spec.rb +1 -1
- data/spec/tty/table/operation/wrapped/call_spec.rb +15 -10
- data/spec/tty/table/operation/wrapped/wrap_spec.rb +1 -1
- data/spec/tty/table/operations/new_spec.rb +4 -4
- data/spec/tty/table/options_spec.rb +0 -28
- data/spec/tty/table/orientation_spec.rb +5 -6
- data/spec/tty/table/properties_spec.rb +1 -4
- data/spec/tty/table/render_spec.rb +57 -0
- data/spec/tty/table/{renders_with_spec.rb → render_with_spec.rb} +29 -10
- data/spec/tty/table/renderer/ascii/render_spec.rb +68 -0
- data/spec/tty/table/renderer/ascii/separator_spec.rb +28 -0
- data/spec/tty/table/renderer/basic/alignment_spec.rb +18 -16
- data/spec/tty/table/renderer/basic/extract_column_widths_spec.rb +17 -12
- data/spec/tty/table/renderer/basic/filter_spec.rb +53 -0
- data/spec/tty/table/renderer/basic/multiline_content_spec.rb +135 -0
- data/spec/tty/table/renderer/basic/new_spec.rb +13 -2
- data/spec/tty/table/renderer/basic/options_spec.rb +48 -0
- data/spec/tty/table/renderer/basic/render_spec.rb +19 -121
- data/spec/tty/table/renderer/basic/separator_spec.rb +14 -48
- data/spec/tty/table/renderer/basic/truncation_spec.rb +35 -0
- data/spec/tty/table/renderer/basic/wrapping_spec.rb +40 -0
- data/spec/tty/table/{border_spec.rb → renderer/border_spec.rb} +17 -20
- data/spec/tty/table/renderer/select_spec.rb +22 -0
- data/spec/tty/table/{border → renderer}/style_spec.rb +13 -14
- data/spec/tty/table/renderer/unicode/render_spec.rb +68 -0
- data/spec/tty/table/renderer/unicode/separator_spec.rb +26 -0
- data/spec/tty/table/rotate_spec.rb +2 -3
- data/spec/tty/table/row/call_spec.rb +1 -1
- data/spec/tty/table/row/each_spec.rb +31 -0
- data/spec/tty/table/row/height_spec.rb +27 -0
- data/spec/tty/table/to_s_spec.rb +3 -3
- data/spec/tty/table/transformation/extract_tuples_spec.rb +35 -0
- data/spec/tty/table/validatable/validate_options_spec.rb +1 -2
- data/spec/tty/terminal/home_spec.rb +3 -3
- data/spec/tty/terminal/page_spec.rb +13 -0
- data/spec/tty/terminal/pager/available_spec.rb +40 -0
- data/spec/tty/terminal/pager/basic/page_spec.rb +54 -0
- data/spec/tty/terminal/pager/command_spec.rb +16 -0
- data/spec/tty/terminal/pager/executables_spec.rb +13 -0
- data/spec/tty/terminal/pager/page_spec.rb +47 -0
- data/spec/tty/terminal/pager/system/page_spec.rb +29 -0
- data/spec/tty/text/distance/distance_spec.rb +12 -0
- data/tty.gemspec +7 -3
- metadata +160 -27
- data/spec/tty/table/operation/alignment_set/align_rows_spec.rb +0 -53
- data/spec/tty/table/renderer/pick_renderer_spec.rb +0 -25
- data/spec/tty/table/renderer_spec.rb +0 -49
data/lib/tty/plugins.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
|
5
|
+
# A class responsible for managing plugins installation
|
6
|
+
class Plugins
|
7
|
+
|
8
|
+
PLUGIN_PREFIX = 'tty'
|
9
|
+
|
10
|
+
attr_accessor :plugins
|
11
|
+
private :plugins
|
12
|
+
|
13
|
+
# Initialize the Plugins
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
def initialize
|
17
|
+
@plugins = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Load all plugins that are not enabled
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def load
|
24
|
+
plugins.each do |plugin|
|
25
|
+
plugin.load! unless plugin.enabled?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Register plugin with name in internal array
|
30
|
+
#
|
31
|
+
# @param [String] name
|
32
|
+
#
|
33
|
+
# @param [TTY::Plugin] plugin
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def register(name, plugin=false)
|
37
|
+
if plugin && !loaded?(name)
|
38
|
+
plugins << plugin
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Find all installed TTY plugins and store them
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
def find
|
46
|
+
Gem.refresh
|
47
|
+
Gem::Specification.each do |gem|
|
48
|
+
next unless gem.name =~ /^#{PLUGIN_PREFIX}/
|
49
|
+
plugin_name = gem.name[/^#{PLUGIN_PREFIX}-(.*)/, 1]
|
50
|
+
register(plugin_name, Plugin.new(plugin_name, gem))
|
51
|
+
end
|
52
|
+
plugins
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return a list of all plugin names as strings
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
def names
|
59
|
+
plugins.inject(Hash.new) do |hash, plugin|
|
60
|
+
hash[plugin.name] = plugin
|
61
|
+
hash
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Check if plugin is already loaded
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
def loaded?(name)
|
71
|
+
plugins.any? { |plugin| plugin.gem_name == name }
|
72
|
+
end
|
73
|
+
|
74
|
+
end # PluginManager
|
75
|
+
end # TTY
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
# A class responsible for shell prompt interactions.
|
5
|
+
class Shell
|
6
|
+
|
7
|
+
# A class representing a suggestion
|
8
|
+
class Suggestion
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
attr_reader :shell
|
12
|
+
private :shell
|
13
|
+
|
14
|
+
# Number of spaces
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
attr_reader :indent
|
18
|
+
|
19
|
+
# Text for a single suggestion
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
attr_reader :single_text
|
23
|
+
|
24
|
+
# Text for multiple suggestions
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
attr_reader :plural_text
|
28
|
+
|
29
|
+
DEFAULT_INDENT = 8
|
30
|
+
|
31
|
+
SINGLE_TEXT = 'Did you mean this?'
|
32
|
+
|
33
|
+
PLURAL_TEXT = 'Did you mean one of these?'
|
34
|
+
|
35
|
+
# Initialize a Suggestion
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def initialize(options={})
|
39
|
+
@indent = options.fetch(:indent) { DEFAULT_INDENT }
|
40
|
+
@single_text = options.fetch(:single_text) { SINGLE_TEXT }
|
41
|
+
@plural_text = options.fetch(:plural_text) { PLURAL_TEXT }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Suggest matches out of possibile strings
|
45
|
+
#
|
46
|
+
# @param [String] message
|
47
|
+
#
|
48
|
+
# @param [Array[String]] possibilities
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def suggest(message, possibilities)
|
52
|
+
distances = measure_distances(message, possibilities)
|
53
|
+
minimum_distance = distances.keys.min
|
54
|
+
max_distance = distances.keys.max
|
55
|
+
|
56
|
+
if minimum_distance < max_distance
|
57
|
+
suggestions = distances[minimum_distance].sort
|
58
|
+
evaluate(suggestions)
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Measure distances between messag and possibilities
|
65
|
+
#
|
66
|
+
# @param [String] message
|
67
|
+
#
|
68
|
+
# @param [Array[String]] possibilities
|
69
|
+
#
|
70
|
+
# @return [Hash]
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
def measure_distances(message, possibilities)
|
74
|
+
distances = Hash.new { |hash, key| hash[key] = [] }
|
75
|
+
|
76
|
+
possibilities.each do |possibility|
|
77
|
+
distances[Text.distance(message, possibility)] << possibility
|
78
|
+
end
|
79
|
+
distances
|
80
|
+
end
|
81
|
+
|
82
|
+
# Build up a suggestion string
|
83
|
+
#
|
84
|
+
# @param [Array[String]] suggestions
|
85
|
+
#
|
86
|
+
# @return [String]
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
def evaluate(suggestions)
|
90
|
+
suggestion = ""
|
91
|
+
if suggestions.one?
|
92
|
+
suggestion << single_text + "\n"
|
93
|
+
suggestion << (" " * indent + suggestions.first)
|
94
|
+
else
|
95
|
+
suggestion << plural_text + "\n"
|
96
|
+
suggestion << suggestions.map { |suggestion| " " * indent + suggestion }.join("\n")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end # Suggestion
|
101
|
+
end # Shell
|
102
|
+
end # TTY
|
data/lib/tty/shell.rb
CHANGED
@@ -135,30 +135,57 @@ module TTY
|
|
135
135
|
args.each { |message| say message, options.merge(:color => :red) }
|
136
136
|
end
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
138
|
+
# Takes the string provided by the user and compare it with other possible
|
139
|
+
# matches to suggest an unambigous string
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# shell.suggest('sta', ['status', 'stage', 'commit', 'branch'])
|
143
|
+
# # => "status, stage"
|
144
|
+
#
|
145
|
+
# @param [String] message
|
146
|
+
#
|
147
|
+
# @param [Array] possibilities
|
148
|
+
#
|
149
|
+
# @param [Hash] options
|
150
|
+
# @option options [String] :indent
|
151
|
+
# The number of spaces for indentation
|
152
|
+
# @option options [String] :single_text
|
153
|
+
# The text for a single suggestion
|
154
|
+
# @option options [String] :plural_text
|
155
|
+
# The text for multiple suggestions
|
156
|
+
#
|
157
|
+
# @return [String]
|
158
|
+
#
|
159
|
+
# @api public
|
160
|
+
def suggest(message, possibilities, options={})
|
161
|
+
suggestion = Suggestion.new(options)
|
162
|
+
say(suggestion.suggest(message, possibilities))
|
149
163
|
end
|
150
164
|
|
151
165
|
# Print a table to shell.
|
152
166
|
#
|
167
|
+
# @example of a table with rows rendered with ascii border
|
168
|
+
# rows = [[1], [2], [3]]
|
169
|
+
# TTY.shell.print_table rows, renderer: :ascii
|
170
|
+
#
|
153
171
|
# @return [undefined]
|
154
172
|
#
|
155
173
|
# @api public
|
156
174
|
def print_table(*args, &block)
|
157
|
-
|
158
|
-
|
175
|
+
options = Utils.extract_options!(args)
|
176
|
+
renderer = options.fetch(:renderer) { :basic }
|
177
|
+
table = TTY::Table.new(*args, &block)
|
178
|
+
say table.render(renderer, options)
|
159
179
|
end
|
160
180
|
|
161
|
-
|
181
|
+
# Check if outputing to shell
|
182
|
+
#
|
183
|
+
# @return [Boolean]
|
184
|
+
#
|
185
|
+
# @api public
|
186
|
+
def tty?
|
187
|
+
stdout.tty?
|
188
|
+
end
|
162
189
|
|
163
190
|
def stdin
|
164
191
|
$stdin
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'shellwords'
|
4
|
+
|
5
|
+
module TTY
|
6
|
+
class System
|
7
|
+
|
8
|
+
# A class responsible for launching an editor
|
9
|
+
class Editor
|
10
|
+
|
11
|
+
attr_reader :file
|
12
|
+
|
13
|
+
# Initialize an Editor
|
14
|
+
#
|
15
|
+
# @param [String] file
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def initialize(file)
|
19
|
+
@file = file
|
20
|
+
end
|
21
|
+
|
22
|
+
# List possible executable for editor command
|
23
|
+
#
|
24
|
+
# @return [Array[String]]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def self.executables
|
28
|
+
[ ENV['VISUAL'], ENV['EDITOR'], 'vi', 'emacs' ]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Find available command
|
32
|
+
#
|
33
|
+
# @param [Array[String]] commands
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def self.available(*commands)
|
39
|
+
commands = commands.empty? ? self.executables : commands
|
40
|
+
commands.compact.uniq.find { |cmd| System.exists?(cmd) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Finds command using a configured command(s) or detected shell commands.
|
44
|
+
#
|
45
|
+
# @param [Array[String]] commands
|
46
|
+
#
|
47
|
+
# @return [String]
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def self.command(*commands)
|
51
|
+
@command = if (@command && commands.empty?)
|
52
|
+
@command
|
53
|
+
else
|
54
|
+
available(*commands)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Open file in system editor
|
59
|
+
#
|
60
|
+
# @param [String] file
|
61
|
+
# the name of the file
|
62
|
+
#
|
63
|
+
# @raise [TTY::CommandInvocationError]
|
64
|
+
#
|
65
|
+
# @return [Object]
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def self.open(file)
|
69
|
+
unless self.command
|
70
|
+
raise CommandInvocationError, "Please export $VISUAL or $EDITOR"
|
71
|
+
exit 1
|
72
|
+
end
|
73
|
+
|
74
|
+
new(file).invoke
|
75
|
+
end
|
76
|
+
|
77
|
+
# Build invocation command for editor
|
78
|
+
#
|
79
|
+
# @return [String]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
def build
|
83
|
+
escaped_file = if System.unix?
|
84
|
+
# Escape file string so it can be safely used in a Bourne shell
|
85
|
+
Shellwords.shellescape(file)
|
86
|
+
elsif System.windows?
|
87
|
+
file.gsub(/\//, '\\')
|
88
|
+
else
|
89
|
+
file
|
90
|
+
end
|
91
|
+
"#{Editor.command} #{escaped_file}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Inovke editor command in a shell
|
95
|
+
#
|
96
|
+
# @raise [TTY::CommandInvocationError]
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
def invoke
|
100
|
+
command_invocation = build
|
101
|
+
status = system(*Shellwords.split(command_invocation))
|
102
|
+
|
103
|
+
unless status
|
104
|
+
raise CommandInvocationError, "`#{command_invocation}` failed with status: #{$? ? $?.exitstatus : nil}"
|
105
|
+
exit status
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end # Editor
|
110
|
+
end # System
|
111
|
+
end # TTY
|
data/lib/tty/system/which.rb
CHANGED
@@ -6,6 +6,18 @@ module TTY
|
|
6
6
|
# A class responsible for finding an executable in the PATH
|
7
7
|
class Which
|
8
8
|
|
9
|
+
attr_reader :command
|
10
|
+
|
11
|
+
# Initialize a Which
|
12
|
+
#
|
13
|
+
# @param [String] command
|
14
|
+
# the command to find
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
def initialize(command)
|
18
|
+
@command = command
|
19
|
+
end
|
20
|
+
|
9
21
|
# Find an executable in the PATH
|
10
22
|
#
|
11
23
|
# @param [String] command
|
@@ -18,7 +30,7 @@ module TTY
|
|
18
30
|
# the full path to executable if found, `nil` otherwise
|
19
31
|
#
|
20
32
|
# @api public
|
21
|
-
def which
|
33
|
+
def which
|
22
34
|
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
23
35
|
default_system_path.each do |path|
|
24
36
|
exts.each do |ext|
|
data/lib/tty/system.rb
CHANGED
@@ -5,34 +5,50 @@ require 'rbconfig'
|
|
5
5
|
module TTY
|
6
6
|
class System
|
7
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
|
-
|
8
|
+
# Check if windows platform.
|
9
|
+
#
|
10
|
+
# @return [Boolean]
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def self.windows?
|
14
|
+
RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/
|
15
|
+
end
|
16
|
+
|
17
|
+
# Check if unix platform
|
18
|
+
#
|
19
|
+
# @return [Boolean]
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def self.unix?
|
23
|
+
RbConfig::CONFIG['host_os'] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
24
|
+
end
|
25
|
+
|
26
|
+
# Find an executable in the PATH
|
27
|
+
#
|
28
|
+
# @see TTY::System::Which
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def self.which(command)
|
32
|
+
Which.new(command).which
|
33
|
+
end
|
34
|
+
|
35
|
+
# Check if command is available
|
36
|
+
#
|
37
|
+
# @param [String] name
|
38
|
+
# the command name
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
def self.exists?(name)
|
42
|
+
!!self.which(name)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Proxy to editor object
|
46
|
+
#
|
47
|
+
# @return [TTY::System::Editor]
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def self.editor
|
51
|
+
TTY::System::Editor
|
36
52
|
end
|
37
53
|
|
38
54
|
end # System
|
@@ -26,15 +26,6 @@ module TTY
|
|
26
26
|
border ? super : nil
|
27
27
|
end
|
28
28
|
|
29
|
-
# A line spanning all columns delemited by space character.
|
30
|
-
#
|
31
|
-
# @return [String]
|
32
|
-
#
|
33
|
-
# @api private
|
34
|
-
def row_line
|
35
|
-
(border && !border.characters.empty?) ? super : row.join(SPACE_CHAR)
|
36
|
-
end
|
37
|
-
|
38
29
|
# A stub bottom line
|
39
30
|
#
|
40
31
|
# @api private
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Table
|
5
|
+
class Border
|
6
|
+
|
7
|
+
# A class for a table row line chars manipulation
|
8
|
+
class RowLine < Struct.new(:left, :center, :right)
|
9
|
+
|
10
|
+
# Colorize characters with a given style
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def colorize(style)
|
14
|
+
colorized_chars = Border.set_color(style, right, center, left)
|
15
|
+
self.right, self.center, self.left = colorized_chars
|
16
|
+
end
|
17
|
+
|
18
|
+
end # RowLine
|
19
|
+
end # Border
|
20
|
+
end # Table
|
21
|
+
end # TTY
|
data/lib/tty/table/border.rb
CHANGED
@@ -15,18 +15,12 @@ module TTY
|
|
15
15
|
# Represent a separtor on each row
|
16
16
|
EACH_ROW = :each_row
|
17
17
|
|
18
|
-
# The row
|
18
|
+
# The row field widths
|
19
19
|
#
|
20
20
|
# @api private
|
21
21
|
attr_reader :widths
|
22
22
|
private :widths
|
23
23
|
|
24
|
-
# The table row
|
25
|
-
#
|
26
|
-
# @api private
|
27
|
-
attr_reader :row
|
28
|
-
private :row
|
29
|
-
|
30
24
|
# The table custom border characters
|
31
25
|
attr_reader :border
|
32
26
|
|
@@ -39,19 +33,19 @@ module TTY
|
|
39
33
|
|
40
34
|
# Instantiate a new object
|
41
35
|
#
|
42
|
-
# @param [Array]
|
36
|
+
# @param [Array] column_widths
|
37
|
+
# the table column widths
|
43
38
|
#
|
44
39
|
# @param [BorderOptions] options
|
45
40
|
#
|
46
41
|
# @return [Object]
|
47
42
|
#
|
48
43
|
# @api private
|
49
|
-
def initialize(
|
44
|
+
def initialize(column_widths, options = nil)
|
50
45
|
if self.class == Border
|
51
46
|
raise NotImplementedError, "#{self} is an abstract class"
|
52
47
|
else
|
53
|
-
@
|
54
|
-
@widths = row.map { |cell| cell.chars.to_a.size }
|
48
|
+
@widths = column_widths
|
55
49
|
@border = TTY::Table::BorderOptions.from options
|
56
50
|
end
|
57
51
|
end
|
@@ -65,7 +59,7 @@ module TTY
|
|
65
59
|
#
|
66
60
|
# @api public
|
67
61
|
def self.def_border(characters=(not_set=true), &block)
|
68
|
-
return self.characters = characters
|
62
|
+
return self.characters = characters unless not_set
|
69
63
|
|
70
64
|
dsl = TTY::Table::BorderDSL.new(&block)
|
71
65
|
self.characters = dsl.characters
|
@@ -116,6 +110,15 @@ module TTY
|
|
116
110
|
(result = render(:top)).empty? ? nil : result
|
117
111
|
end
|
118
112
|
|
113
|
+
# A line spannig all columns marking bottom of a table.
|
114
|
+
#
|
115
|
+
# @return [String]
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
def bottom_line
|
119
|
+
(result = render(:bottom)).empty? ? nil : result
|
120
|
+
end
|
121
|
+
|
119
122
|
# A line spanning all columns delemeting rows in a table.
|
120
123
|
#
|
121
124
|
# @return [String]
|
@@ -125,35 +128,61 @@ module TTY
|
|
125
128
|
(result = render(:mid)).empty? ? nil : result
|
126
129
|
end
|
127
130
|
|
128
|
-
# A line spanning all columns delemeting
|
131
|
+
# A line spanning all columns delemeting fields in a row.
|
132
|
+
#
|
133
|
+
# @param [TTY::Table::Row] row
|
134
|
+
# the table row
|
129
135
|
#
|
130
136
|
# @return [String]
|
131
137
|
#
|
132
|
-
# @api
|
133
|
-
def row_line
|
134
|
-
|
135
|
-
|
136
|
-
center_char = self['center']
|
138
|
+
# @api public
|
139
|
+
def row_line(row)
|
140
|
+
line = RowLine.new(self['left'], self['center'], self['right'])
|
141
|
+
line.colorize(border.style) if color?
|
137
142
|
|
138
|
-
|
139
|
-
|
140
|
-
|
143
|
+
result = row_heights(row, line)
|
144
|
+
result.empty? ? EMPTY_CHAR : result
|
145
|
+
end
|
141
146
|
|
142
|
-
|
143
|
-
|
147
|
+
protected
|
148
|
+
|
149
|
+
# Separate multiline string into individual rows with border.
|
150
|
+
#
|
151
|
+
# @param [TTY::Table::Row] row
|
152
|
+
# the table row
|
153
|
+
#
|
154
|
+
# @param [TTY::Table::Border::RowLine] line
|
155
|
+
#
|
156
|
+
# @api private
|
157
|
+
def row_heights(row, line)
|
158
|
+
if row.size > 0
|
159
|
+
row.height.times.map do |line_index|
|
160
|
+
row_height_line(row, line_index, line)
|
161
|
+
end.join("\n")
|
162
|
+
else
|
163
|
+
line.left + line.right
|
164
|
+
end
|
144
165
|
end
|
145
166
|
|
146
|
-
#
|
167
|
+
# Generate border for a given multiline row
|
168
|
+
#
|
169
|
+
# @param [TTY::Table::Row] row
|
170
|
+
# the table row
|
171
|
+
#
|
172
|
+
# @param [Integer] line
|
173
|
+
# the index for current line inside multiline
|
174
|
+
#
|
175
|
+
# @param [TTY::Table::Border::RowLine] line
|
147
176
|
#
|
148
177
|
# @return [String]
|
149
178
|
#
|
150
179
|
# @api private
|
151
|
-
def
|
152
|
-
|
180
|
+
def row_height_line(row, line_index, line)
|
181
|
+
line.left + row.fields.each_with_index.map do |field, index|
|
182
|
+
(field.lines[line_index] || EMPTY_CHAR).ljust(widths[index])
|
183
|
+
end.join(line.center) + line.right
|
153
184
|
end
|
154
185
|
|
155
|
-
protected
|
156
|
-
|
157
186
|
# Generate particular border type
|
158
187
|
#
|
159
188
|
# @param [String] type
|
@@ -164,11 +193,13 @@ module TTY
|
|
164
193
|
type = type.to_s
|
165
194
|
border_char = self[type]
|
166
195
|
line = render_line(border_char,
|
167
|
-
|
168
|
-
|
169
|
-
|
196
|
+
self["#{type}_left"] || border_char,
|
197
|
+
self["#{type}_right"] || border_char,
|
198
|
+
self["#{type}_mid"])
|
170
199
|
|
171
|
-
|
200
|
+
if color? && !line.empty?
|
201
|
+
line = Border.set_color(border.style, line)
|
202
|
+
end
|
172
203
|
line
|
173
204
|
end
|
174
205
|
|
data/lib/tty/table/border_dsl.rb
CHANGED
@@ -22,7 +22,7 @@ module TTY
|
|
22
22
|
def initialize(characters=nil, &block)
|
23
23
|
@options = TTY::Table::BorderOptions.new
|
24
24
|
@options.characters = characters if characters
|
25
|
-
yield_or_eval
|
25
|
+
yield_or_eval(&block) if block_given?
|
26
26
|
end
|
27
27
|
|
28
28
|
# Apply style color to the border
|