toys-core 0.11.5 → 0.12.0
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 +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
|