toys-core 0.11.5 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +1 -1
- data/lib/toys-core.rb +4 -1
- data/lib/toys/acceptor.rb +3 -3
- data/lib/toys/arg_parser.rb +6 -7
- data/lib/toys/cli.rb +44 -14
- data/lib/toys/compat.rb +19 -22
- data/lib/toys/completion.rb +3 -1
- data/lib/toys/context.rb +2 -2
- data/lib/toys/core.rb +1 -1
- data/lib/toys/dsl/base.rb +85 -0
- data/lib/toys/dsl/flag.rb +3 -3
- data/lib/toys/dsl/flag_group.rb +7 -7
- data/lib/toys/dsl/internal.rb +206 -0
- data/lib/toys/dsl/positional_arg.rb +3 -3
- data/lib/toys/dsl/tool.rb +174 -216
- data/lib/toys/errors.rb +1 -0
- data/lib/toys/flag.rb +15 -18
- data/lib/toys/flag_group.rb +5 -4
- data/lib/toys/input_file.rb +4 -4
- data/lib/toys/loader.rb +189 -50
- data/lib/toys/middleware.rb +1 -1
- data/lib/toys/mixin.rb +2 -2
- data/lib/toys/positional_arg.rb +3 -3
- data/lib/toys/settings.rb +900 -0
- data/lib/toys/source_info.rb +121 -18
- data/lib/toys/standard_middleware/apply_config.rb +5 -4
- data/lib/toys/standard_middleware/set_default_descriptions.rb +18 -18
- data/lib/toys/standard_middleware/show_help.rb +17 -5
- data/lib/toys/standard_mixins/exec.rb +12 -14
- data/lib/toys/standard_mixins/git_cache.rb +48 -0
- data/lib/toys/standard_mixins/xdg.rb +56 -0
- data/lib/toys/template.rb +2 -2
- data/lib/toys/{tool.rb → tool_definition.rb} +100 -41
- data/lib/toys/utils/exec.rb +4 -5
- data/lib/toys/utils/gems.rb +8 -7
- data/lib/toys/utils/git_cache.rb +184 -0
- data/lib/toys/utils/help_text.rb +90 -34
- data/lib/toys/utils/terminal.rb +1 -1
- data/lib/toys/utils/xdg.rb +293 -0
- metadata +14 -7
data/lib/toys/utils/gems.rb
CHANGED
@@ -132,8 +132,8 @@ module Toys
|
|
132
132
|
end
|
133
133
|
@on_conflict = on_conflict || :error
|
134
134
|
@terminal = terminal
|
135
|
-
@input = input ||
|
136
|
-
@output = output ||
|
135
|
+
@input = input || $stdin
|
136
|
+
@output = output || $stdout
|
137
137
|
end
|
138
138
|
|
139
139
|
##
|
@@ -185,6 +185,7 @@ module Toys
|
|
185
185
|
gemfile_path = Gems.find_gemfile(dir, gemfile_names: gemfile_names)
|
186
186
|
end
|
187
187
|
raise GemfileNotFoundError, "Gemfile not found" unless gemfile_path
|
188
|
+
gemfile_path = ::File.absolute_path(gemfile_path)
|
188
189
|
Gems.synchronize do
|
189
190
|
if configure_gemfile(gemfile_path)
|
190
191
|
activate("bundler", "~> 2.1")
|
@@ -296,7 +297,7 @@ module Toys
|
|
296
297
|
if ::File.basename(gemfile_path) == "gems.rb"
|
297
298
|
::File.join(::File.dirname(gemfile_path), "gems.locked")
|
298
299
|
else
|
299
|
-
gemfile_path
|
300
|
+
"#{gemfile_path}.lock"
|
300
301
|
end
|
301
302
|
end
|
302
303
|
|
@@ -325,14 +326,14 @@ module Toys
|
|
325
326
|
end
|
326
327
|
|
327
328
|
def restore_old_lockfile(lockfile_path, contents)
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
end
|
329
|
+
return unless contents
|
330
|
+
::File.open(lockfile_path, "w") do |file|
|
331
|
+
file.write(contents)
|
332
332
|
end
|
333
333
|
end
|
334
334
|
|
335
335
|
def modify_bundle_definition(gemfile_path, lockfile_path)
|
336
|
+
::Bundler.configure
|
336
337
|
builder = ::Bundler::Dsl.new
|
337
338
|
builder.eval_gemfile(gemfile_path)
|
338
339
|
toys_gems = ["toys-core"]
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest"
|
4
|
+
require "fileutils"
|
5
|
+
require "toys/utils/exec"
|
6
|
+
require "toys/utils/xdg"
|
7
|
+
|
8
|
+
module Toys
|
9
|
+
module Utils
|
10
|
+
##
|
11
|
+
# This object provides cached access to remote git data. Given a remote
|
12
|
+
# repository, a path, and a commit, it makes the files availble in the
|
13
|
+
# local filesystem. Access is cached, so repeated requests do not hit the
|
14
|
+
# remote repository again.
|
15
|
+
#
|
16
|
+
# This class is used by the Loader to load tools from git. Tools can also
|
17
|
+
# use the `:git_cache` mixin for direct access to this class.
|
18
|
+
#
|
19
|
+
class GitCache
|
20
|
+
##
|
21
|
+
# GitCache encountered a failure
|
22
|
+
#
|
23
|
+
class Error < ::StandardError
|
24
|
+
##
|
25
|
+
# Create a GitCache::Error.
|
26
|
+
#
|
27
|
+
# @param message [String] The error message
|
28
|
+
# @param result [Toys::Utils::Exec::Result] The result of a git
|
29
|
+
# command execution, or `nil` if this error was not due to a git
|
30
|
+
# command error.
|
31
|
+
#
|
32
|
+
def initialize(message, result)
|
33
|
+
super(message)
|
34
|
+
@exec_result = result
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# @return [Toys::Utils::Exec::Result] The result of a git command
|
39
|
+
# execution, or `nil` if this error was not due to a git command
|
40
|
+
# error.
|
41
|
+
#
|
42
|
+
attr_reader :exec_result
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Access a git cache.
|
47
|
+
#
|
48
|
+
# @param cache_dir [String] The path to the cache directory. Defaults to
|
49
|
+
# a specific directory in the user's XDG cache.
|
50
|
+
#
|
51
|
+
def initialize(cache_dir: nil)
|
52
|
+
@cache_dir = ::File.expand_path(cache_dir || default_cache_dir)
|
53
|
+
@exec = Utils::Exec.new(out: :capture, err: :capture)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Find the given git-based files from the git cache, loading from the
|
58
|
+
# remote repo if necessary.
|
59
|
+
#
|
60
|
+
# @param remote [String] The URL of the git repo. Required.
|
61
|
+
# @param path [String] The path to the file or directory within the repo.
|
62
|
+
# Optional. Defaults to the entire repo.
|
63
|
+
# @param commit [String] The commit reference, which may be a SHA or any
|
64
|
+
# git ref such as a branch or tag. Optional. Defaults to `HEAD`.
|
65
|
+
# @param update [Boolean] Force update of non-SHA commit references, even
|
66
|
+
# if it has previously been loaded.
|
67
|
+
#
|
68
|
+
# @return [String] The full path to the cached files.
|
69
|
+
#
|
70
|
+
def find(remote, path: nil, commit: nil, update: false)
|
71
|
+
path ||= ""
|
72
|
+
commit ||= "HEAD"
|
73
|
+
dir = ensure_dir(remote)
|
74
|
+
lock_repo(dir) do
|
75
|
+
ensure_repo(dir, remote)
|
76
|
+
sha = ensure_commit(dir, commit, update)
|
77
|
+
ensure_source(dir, sha, path.to_s)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# The cache directory.
|
83
|
+
#
|
84
|
+
# @return [String]
|
85
|
+
#
|
86
|
+
attr_reader :cache_dir
|
87
|
+
|
88
|
+
# @private Used for testing
|
89
|
+
def repo_dir_for(remote)
|
90
|
+
::File.join(@cache_dir, remote_dir_name(remote), "repo")
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def remote_dir_name(remote)
|
96
|
+
::Digest::MD5.hexdigest(remote)
|
97
|
+
end
|
98
|
+
|
99
|
+
def source_name(sha, path)
|
100
|
+
digest = ::Digest::MD5.hexdigest("#{sha}#{path}")
|
101
|
+
"#{digest}#{::File.extname(path)}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def repo_dir_name
|
105
|
+
"repo"
|
106
|
+
end
|
107
|
+
|
108
|
+
def default_cache_dir
|
109
|
+
::File.join(XDG.new.cache_home, "toys", "git")
|
110
|
+
end
|
111
|
+
|
112
|
+
def git(dir, cmd, error_message: nil)
|
113
|
+
result = @exec.exec(["git"] + cmd, chdir: dir)
|
114
|
+
if result.failed?
|
115
|
+
raise GitCache::Error.new("Could not run git command line", result)
|
116
|
+
end
|
117
|
+
if block_given?
|
118
|
+
yield result
|
119
|
+
elsif result.error? && error_message
|
120
|
+
raise GitCache::Error.new(error_message, result)
|
121
|
+
else
|
122
|
+
result
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def ensure_dir(remote)
|
127
|
+
dir = ::File.join(@cache_dir, remote_dir_name(remote))
|
128
|
+
::FileUtils.mkdir_p(dir)
|
129
|
+
dir
|
130
|
+
end
|
131
|
+
|
132
|
+
def lock_repo(dir)
|
133
|
+
lock_path = ::File.join(dir, "repo.lock")
|
134
|
+
::File.open(lock_path, ::File::RDWR | ::File::CREAT) do |file|
|
135
|
+
file.flock(::File::LOCK_EX)
|
136
|
+
yield
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def ensure_repo(dir, remote)
|
141
|
+
repo_dir = ::File.join(dir, repo_dir_name)
|
142
|
+
::FileUtils.mkdir_p(repo_dir)
|
143
|
+
result = git(repo_dir, ["remote", "get-url", "origin"])
|
144
|
+
unless result.success? && result.captured_out.strip == remote
|
145
|
+
::FileUtils.rm_rf(repo_dir)
|
146
|
+
::FileUtils.mkdir_p(repo_dir)
|
147
|
+
git(repo_dir, ["init"],
|
148
|
+
error_message: "Unable to initialize git repository")
|
149
|
+
git(repo_dir, ["remote", "add", "origin", remote],
|
150
|
+
error_message: "Unable to add git remote")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def ensure_commit(dir, commit, update = false)
|
155
|
+
local_commit = "toys-git-cache/#{commit}"
|
156
|
+
repo_dir = ::File.join(dir, repo_dir_name)
|
157
|
+
is_sha = commit =~ /^[0-9a-f]{40}$/
|
158
|
+
if update && !is_sha || !commit_exists?(repo_dir, local_commit)
|
159
|
+
git(repo_dir, ["fetch", "--depth=1", "origin", "#{commit}:#{local_commit}"],
|
160
|
+
error_message: "Unable to to fetch commit: #{commit}")
|
161
|
+
end
|
162
|
+
result = git(repo_dir, ["rev-parse", local_commit],
|
163
|
+
error_message: "Unable to retrieve commit: #{local_commit}")
|
164
|
+
result.captured_out.strip
|
165
|
+
end
|
166
|
+
|
167
|
+
def commit_exists?(repo_dir, commit)
|
168
|
+
result = git(repo_dir, ["cat-file", "-t", commit])
|
169
|
+
result.success? && result.captured_out.strip == "commit"
|
170
|
+
end
|
171
|
+
|
172
|
+
def ensure_source(dir, sha, path)
|
173
|
+
source_path = ::File.join(dir, source_name(sha, path))
|
174
|
+
unless ::File.exist?(source_path)
|
175
|
+
repo_dir = ::File.join(dir, repo_dir_name)
|
176
|
+
git(repo_dir, ["checkout", sha])
|
177
|
+
from_path = ::File.join(repo_dir, path)
|
178
|
+
::FileUtils.cp_r(from_path, source_path)
|
179
|
+
end
|
180
|
+
source_path
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/lib/toys/utils/help_text.rb
CHANGED
@@ -44,11 +44,12 @@ module Toys
|
|
44
44
|
##
|
45
45
|
# Create a usage helper.
|
46
46
|
#
|
47
|
-
# @param tool [Toys::
|
47
|
+
# @param tool [Toys::ToolDefinition] The tool to document.
|
48
48
|
# @param loader [Toys::Loader] A loader that can provide subcommands.
|
49
49
|
# @param executable_name [String] The name of the executable.
|
50
50
|
# e.g. `"toys"`.
|
51
|
-
# @param delegates [Array<Toys::
|
51
|
+
# @param delegates [Array<Toys::ToolDefinition>] The delegation path to
|
52
|
+
# the tool.
|
52
53
|
#
|
53
54
|
# @return [Toys::Utils::HelpText]
|
54
55
|
#
|
@@ -60,8 +61,8 @@ module Toys
|
|
60
61
|
end
|
61
62
|
|
62
63
|
##
|
63
|
-
# The
|
64
|
-
# @return [Toys::
|
64
|
+
# The ToolDefinition being documented.
|
65
|
+
# @return [Toys::ToolDefinition]
|
65
66
|
#
|
66
67
|
attr_reader :tool
|
67
68
|
|
@@ -72,6 +73,8 @@ module Toys
|
|
72
73
|
# display all subtools recursively. Defaults to false.
|
73
74
|
# @param include_hidden [Boolean] Include hidden subtools (i.e. whose
|
74
75
|
# names begin with underscore.) Default is false.
|
76
|
+
# @param separate_sources [Boolean] Split up tool list by source root.
|
77
|
+
# Defaults to false.
|
75
78
|
# @param left_column_width [Integer] Width of the first column. Default
|
76
79
|
# is {DEFAULT_LEFT_COLUMN_WIDTH}.
|
77
80
|
# @param indent [Integer] Indent width. Default is {DEFAULT_INDENT}.
|
@@ -80,13 +83,14 @@ module Toys
|
|
80
83
|
#
|
81
84
|
# @return [String] A usage string.
|
82
85
|
#
|
83
|
-
def usage_string(recursive: false, include_hidden: false,
|
86
|
+
def usage_string(recursive: false, include_hidden: false, separate_sources: false,
|
84
87
|
left_column_width: nil, indent: nil, wrap_width: nil)
|
85
88
|
left_column_width ||= DEFAULT_LEFT_COLUMN_WIDTH
|
86
89
|
indent ||= DEFAULT_INDENT
|
87
|
-
subtools =
|
90
|
+
subtools = collect_subtool_info(recursive, nil, include_hidden, separate_sources)
|
88
91
|
assembler = UsageStringAssembler.new(
|
89
|
-
@tool, @executable_name, subtools,
|
92
|
+
@tool, @executable_name, subtools, separate_sources,
|
93
|
+
indent, left_column_width, wrap_width
|
90
94
|
)
|
91
95
|
assembler.result
|
92
96
|
end
|
@@ -102,6 +106,8 @@ module Toys
|
|
102
106
|
# names begin with underscore.) Default is false.
|
103
107
|
# @param show_source_path [Boolean] If true, shows the source path
|
104
108
|
# section. Defaults to false.
|
109
|
+
# @param separate_sources [Boolean] Split up tool list by source root.
|
110
|
+
# Defaults to false.
|
105
111
|
# @param indent [Integer] Indent width. Default is {DEFAULT_INDENT}.
|
106
112
|
# @param indent2 [Integer] Second indent width. Default is
|
107
113
|
# {DEFAULT_INDENT}.
|
@@ -112,13 +118,14 @@ module Toys
|
|
112
118
|
# @return [String] A usage string.
|
113
119
|
#
|
114
120
|
def help_string(recursive: false, search: nil, include_hidden: false,
|
115
|
-
show_source_path: false,
|
121
|
+
show_source_path: false, separate_sources: false,
|
116
122
|
indent: nil, indent2: nil, wrap_width: nil, styled: true)
|
117
123
|
indent ||= DEFAULT_INDENT
|
118
124
|
indent2 ||= DEFAULT_INDENT
|
119
|
-
subtools =
|
125
|
+
subtools = collect_subtool_info(recursive, search, include_hidden, separate_sources)
|
120
126
|
assembler = HelpStringAssembler.new(
|
121
|
-
@tool, @executable_name, @delegates, subtools, search,
|
127
|
+
@tool, @executable_name, @delegates, subtools, search,
|
128
|
+
show_source_path, separate_sources,
|
122
129
|
indent, indent2, wrap_width, styled
|
123
130
|
)
|
124
131
|
assembler.result
|
@@ -133,6 +140,8 @@ module Toys
|
|
133
140
|
# listing subtools. Defaults to `nil` which finds all subtools.
|
134
141
|
# @param include_hidden [Boolean] Include hidden subtools (i.e. whose
|
135
142
|
# names begin with underscore.) Default is false.
|
143
|
+
# @param separate_sources [Boolean] Split up tool list by source root.
|
144
|
+
# Defaults to false.
|
136
145
|
# @param indent [Integer] Indent width. Default is {DEFAULT_INDENT}.
|
137
146
|
# @param wrap_width [Integer,nil] Wrap width of the column, or `nil` to
|
138
147
|
# disable wrap. Default is `nil`.
|
@@ -141,17 +150,23 @@ module Toys
|
|
141
150
|
# @return [String] A usage string.
|
142
151
|
#
|
143
152
|
def list_string(recursive: false, search: nil, include_hidden: false,
|
144
|
-
indent: nil, wrap_width: nil, styled: true)
|
153
|
+
separate_sources: false, indent: nil, wrap_width: nil, styled: true)
|
145
154
|
indent ||= DEFAULT_INDENT
|
146
|
-
subtools =
|
147
|
-
assembler = ListStringAssembler.new(@tool, subtools, recursive, search,
|
155
|
+
subtools = collect_subtool_info(recursive, search, include_hidden, separate_sources)
|
156
|
+
assembler = ListStringAssembler.new(@tool, subtools, recursive, search, separate_sources,
|
148
157
|
indent, wrap_width, styled)
|
149
158
|
assembler.result
|
150
159
|
end
|
151
160
|
|
152
161
|
private
|
153
162
|
|
154
|
-
def
|
163
|
+
def collect_subtool_info(recursive, search, include_hidden, separate_sources)
|
164
|
+
subtools_by_name = list_subtools(recursive, include_hidden)
|
165
|
+
filter_subtools(subtools_by_name, search)
|
166
|
+
arrange_subtools(subtools_by_name, separate_sources)
|
167
|
+
end
|
168
|
+
|
169
|
+
def list_subtools(recursive, include_hidden)
|
155
170
|
subtools_by_name = {}
|
156
171
|
([@tool] + @delegates).each do |tool|
|
157
172
|
name_len = tool.full_name.length
|
@@ -162,20 +177,37 @@ module Toys
|
|
162
177
|
subtools_by_name[local_name] = subtool
|
163
178
|
end
|
164
179
|
end
|
180
|
+
subtools_by_name
|
181
|
+
end
|
182
|
+
|
183
|
+
def filter_subtools(subtools_by_name, search)
|
184
|
+
if !search.nil? && !search.empty?
|
185
|
+
regex = ::Regexp.new(search, ::Regexp::IGNORECASE)
|
186
|
+
subtools_by_name.delete_if do |local_name, tool|
|
187
|
+
!regex.match?(local_name) && !regex.match?(tool.desc.to_s)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def arrange_subtools(subtools_by_name, separate_sources)
|
165
193
|
subtool_list = subtools_by_name.sort_by { |(local_name, _tool)| local_name }
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
194
|
+
result = {}
|
195
|
+
subtool_list.each do |(local_name, subtool)|
|
196
|
+
key = separate_sources ? subtool.source_root : nil
|
197
|
+
(result[key] ||= []) << [local_name, subtool]
|
170
198
|
end
|
199
|
+
result.sort_by { |source, _subtools| -(source&.priority || -999_999) }
|
200
|
+
.map { |source, subtools| [source&.source_name || "unknown source", subtools] }
|
171
201
|
end
|
172
202
|
|
173
203
|
## @private
|
174
204
|
class UsageStringAssembler
|
175
|
-
def initialize(tool, executable_name, subtools,
|
205
|
+
def initialize(tool, executable_name, subtools, separate_sources,
|
206
|
+
indent, left_column_width, wrap_width)
|
176
207
|
@tool = tool
|
177
208
|
@executable_name = executable_name
|
178
209
|
@subtools = subtools
|
210
|
+
@separate_sources = separate_sources
|
179
211
|
@indent = indent
|
180
212
|
@left_column_width = left_column_width
|
181
213
|
@wrap_width = wrap_width
|
@@ -193,7 +225,8 @@ module Toys
|
|
193
225
|
add_flag_group_sections
|
194
226
|
add_positional_arguments_section if @tool.runnable?
|
195
227
|
add_subtool_list_section
|
196
|
-
|
228
|
+
joined_lines = @lines.join("\n")
|
229
|
+
@result = "#{joined_lines}\n"
|
197
230
|
end
|
198
231
|
|
199
232
|
def add_synopsis_section
|
@@ -226,7 +259,7 @@ module Toys
|
|
226
259
|
@lines << ""
|
227
260
|
desc_str = group.desc.to_s
|
228
261
|
desc_str = "Flags" if desc_str.empty?
|
229
|
-
@lines << desc_str
|
262
|
+
@lines << "#{desc_str}:"
|
230
263
|
group.flags.each do |flag|
|
231
264
|
add_flag(flag)
|
232
265
|
end
|
@@ -254,11 +287,12 @@ module Toys
|
|
254
287
|
end
|
255
288
|
|
256
289
|
def add_subtool_list_section
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
290
|
+
@subtools.each do |source_name, subtool_list|
|
291
|
+
@lines << ""
|
292
|
+
@lines << (@separate_sources ? "Tools from #{source_name}:" : "Tools:")
|
293
|
+
subtool_list.each do |local_name, subtool|
|
294
|
+
add_right_column_desc(local_name, wrap_desc(subtool.desc))
|
295
|
+
end
|
262
296
|
end
|
263
297
|
end
|
264
298
|
|
@@ -299,7 +333,7 @@ module Toys
|
|
299
333
|
## @private
|
300
334
|
class HelpStringAssembler
|
301
335
|
def initialize(tool, executable_name, delegates, subtools, search_term,
|
302
|
-
show_source_path, indent, indent2, wrap_width, styled)
|
336
|
+
show_source_path, separate_sources, indent, indent2, wrap_width, styled)
|
303
337
|
require "toys/utils/terminal"
|
304
338
|
@tool = tool
|
305
339
|
@executable_name = executable_name
|
@@ -307,6 +341,7 @@ module Toys
|
|
307
341
|
@subtools = subtools
|
308
342
|
@search_term = search_term
|
309
343
|
@show_source_path = show_source_path
|
344
|
+
@separate_sources = separate_sources
|
310
345
|
@indent = indent
|
311
346
|
@indent2 = indent2
|
312
347
|
@wrap_width = wrap_width
|
@@ -532,8 +567,17 @@ module Toys
|
|
532
567
|
@lines << indent_str("Showing search results for \"#{@search_term}\"")
|
533
568
|
@lines << ""
|
534
569
|
end
|
535
|
-
|
536
|
-
|
570
|
+
first_section = true
|
571
|
+
@subtools.each do |source_name, subtool_list|
|
572
|
+
@lines << "" unless first_section
|
573
|
+
if @separate_sources
|
574
|
+
@lines << indent_str(underline("From #{source_name}"))
|
575
|
+
@lines << ""
|
576
|
+
end
|
577
|
+
subtool_list.each do |local_name, subtool|
|
578
|
+
add_prefix_with_desc(bold(local_name), subtool.desc)
|
579
|
+
end
|
580
|
+
first_section = false
|
537
581
|
end
|
538
582
|
end
|
539
583
|
|
@@ -596,12 +640,14 @@ module Toys
|
|
596
640
|
|
597
641
|
## @private
|
598
642
|
class ListStringAssembler
|
599
|
-
def initialize(tool, subtools, recursive, search_term,
|
643
|
+
def initialize(tool, subtools, recursive, search_term, separate_sources,
|
644
|
+
indent, wrap_width, styled)
|
600
645
|
require "toys/utils/terminal"
|
601
646
|
@tool = tool
|
602
647
|
@subtools = subtools
|
603
648
|
@recursive = recursive
|
604
649
|
@search_term = search_term
|
650
|
+
@separate_sources = separate_sources
|
605
651
|
@indent = indent
|
606
652
|
@wrap_width = wrap_width
|
607
653
|
assemble(styled)
|
@@ -626,16 +672,22 @@ module Toys
|
|
626
672
|
else
|
627
673
|
"#{top_line} under #{bold(@tool.display_name)}:"
|
628
674
|
end
|
629
|
-
@lines << ""
|
630
675
|
if @search_term
|
631
|
-
@lines << "Showing search results for \"#{@search_term}\""
|
632
676
|
@lines << ""
|
677
|
+
@lines << "Showing search results for \"#{@search_term}\""
|
633
678
|
end
|
634
679
|
end
|
635
680
|
|
636
681
|
def add_list
|
637
|
-
@subtools.each do |
|
638
|
-
|
682
|
+
@subtools.each do |source_name, subtool_list|
|
683
|
+
@lines << ""
|
684
|
+
if @separate_sources
|
685
|
+
@lines << underline("From: #{source_name}")
|
686
|
+
@lines << ""
|
687
|
+
end
|
688
|
+
subtool_list.each do |local_name, subtool|
|
689
|
+
add_prefix_with_desc(bold(local_name), subtool.desc)
|
690
|
+
end
|
639
691
|
end
|
640
692
|
end
|
641
693
|
|
@@ -662,6 +714,10 @@ module Toys
|
|
662
714
|
@lines.apply_styles(str, :bold)
|
663
715
|
end
|
664
716
|
|
717
|
+
def underline(str)
|
718
|
+
@lines.apply_styles(str, :underline)
|
719
|
+
end
|
720
|
+
|
665
721
|
def indent_str(str)
|
666
722
|
"#{' ' * @indent}#{str}"
|
667
723
|
end
|