markdown_exec 2.1.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +23 -1
- data/Gemfile +3 -3
- data/Gemfile.lock +134 -92
- data/README.md +13 -13
- data/bin/tab_completion.sh +14 -3
- data/bin/tab_completion.sh.erb +0 -1
- data/examples/bash-blocks.md +58 -0
- data/examples/block-names.md +62 -0
- data/examples/indent.md +43 -2
- data/examples/link-blocks-block.md +5 -0
- data/examples/link-blocks-load-save.md +59 -0
- data/examples/link-blocks-vars.md +56 -0
- data/examples/linked.md +6 -101
- data/examples/opts-blocks-require.md +28 -0
- data/examples/{port.md → port-blocks.md} +18 -9
- data/examples/save.md +76 -4
- data/examples/vars-blocks.md +38 -0
- data/lib/colorize.rb +13 -0
- data/lib/constants.rb +1 -1
- data/lib/fcb.rb +202 -16
- data/lib/filter.rb +12 -12
- data/lib/hash_delegator.rb +695 -326
- data/lib/hierarchy_string.rb +133 -0
- data/lib/input_sequencer.rb +4 -2
- data/lib/link_history.rb +34 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +67 -79
- data/lib/mdoc.rb +122 -60
- data/lib/menu.src.yml +71 -21
- data/lib/menu.yml +59 -19
- data/lib/namer.rb +50 -0
- data/lib/poly.rb +152 -0
- data/lib/saved_assets.rb +4 -11
- data/lib/string_util.rb +0 -1
- data/lib/text_analyzer.rb +100 -0
- metadata +16 -6
- data/examples/vars.md +0 -20
- /data/examples/{opts.md → opts-blocks.md} +0 -0
- /data/examples/{pass-through.md → pass-through-arguments.md} +0 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Class representing a hierarchy of substrings stored as Hash nodes
|
4
|
+
class HierarchyString
|
5
|
+
attr_accessor :substrings
|
6
|
+
|
7
|
+
# Initialize with a single hash or an array of hashes
|
8
|
+
def initialize(substrings)
|
9
|
+
@substrings = parse_substrings(substrings)
|
10
|
+
end
|
11
|
+
|
12
|
+
def map_substring_text_yield(tree, &block)
|
13
|
+
case tree
|
14
|
+
when Array
|
15
|
+
tree.each.with_index do |node, ind|
|
16
|
+
case node
|
17
|
+
when String
|
18
|
+
tree[ind] = yield node
|
19
|
+
else
|
20
|
+
map_substring_text_yield(node, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
when Hash
|
24
|
+
text = yield tree[:text]
|
25
|
+
tree[:text] = text
|
26
|
+
|
27
|
+
tree
|
28
|
+
when String
|
29
|
+
yield tree
|
30
|
+
else
|
31
|
+
raise ArgumentError, 'Invalid type.'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# operate on substring
|
36
|
+
def replace_text!
|
37
|
+
map_substring_text_yield(@substrings) do |node|
|
38
|
+
case node
|
39
|
+
when Hash
|
40
|
+
text = yield node[:text]
|
41
|
+
node[:text] = text
|
42
|
+
when String
|
43
|
+
yield node
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Method to concatenate all substrings into a single string
|
49
|
+
def concatenate
|
50
|
+
concatenate_substrings(@substrings)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Method to decorate all substrings into a single string
|
54
|
+
def decorate
|
55
|
+
decorate_substrings(@substrings)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Handle string inspection methods and pass them to the concatenated string
|
59
|
+
def method_missing(method_name, *arguments, &block)
|
60
|
+
if ''.respond_to?(method_name)
|
61
|
+
concatenate.send(method_name, *arguments, &block)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Ensure proper handling of method checks
|
68
|
+
def respond_to_missing?(method_name, include_private = false)
|
69
|
+
''.respond_to?(method_name) || super
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Parse the input substrings into a nested array of hashes structure
|
75
|
+
def parse_substrings(substrings)
|
76
|
+
case substrings
|
77
|
+
when Hash
|
78
|
+
[substrings]
|
79
|
+
when Array
|
80
|
+
substrings.map { |s| parse_substrings(s) }
|
81
|
+
else
|
82
|
+
substrings
|
83
|
+
# raise ArgumentError, 'Invalid input type. Expected Hash or Array.'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Recursively concatenate substrings
|
88
|
+
def concatenate_substrings(substrings)
|
89
|
+
substrings.map do |s|
|
90
|
+
case s
|
91
|
+
when Hash
|
92
|
+
s[:text]
|
93
|
+
when Array
|
94
|
+
concatenate_substrings(s)
|
95
|
+
end
|
96
|
+
end.join
|
97
|
+
end
|
98
|
+
|
99
|
+
# Recursively decorate substrings
|
100
|
+
def decorate_substrings(substrings, prior_color = '')
|
101
|
+
substrings.map do |s|
|
102
|
+
case s
|
103
|
+
when Hash
|
104
|
+
if s[:color]
|
105
|
+
s[:text].send(s[:color]) + prior_color
|
106
|
+
else
|
107
|
+
s[:text]
|
108
|
+
end
|
109
|
+
when Array
|
110
|
+
decorate_substrings(s, prior_color)
|
111
|
+
end
|
112
|
+
end.join
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
return if $PROGRAM_NAME != __FILE__
|
117
|
+
|
118
|
+
# require 'bundler/setup'
|
119
|
+
# Bundler.require(:default)
|
120
|
+
|
121
|
+
# require 'fcb'
|
122
|
+
# require 'minitest/autorun'
|
123
|
+
|
124
|
+
# Usage
|
125
|
+
hierarchy = HierarchyString.new([{ text: 'Hello ', color: :red },
|
126
|
+
[{ text: 'World', color: :upcase },
|
127
|
+
{ text: '!' }]])
|
128
|
+
puts hierarchy.decorate
|
129
|
+
puts hierarchy.length
|
130
|
+
# puts hierarchy.concatenate # Outputs: Hello World!
|
131
|
+
# puts hierarchy.upcase # Outputs: HELLO WORLD!
|
132
|
+
# puts hierarchy.length # Outputs: 12
|
133
|
+
# puts hierarchy.gsub('World', 'Ruby') # Outputs: Hello Ruby!
|
data/lib/input_sequencer.rb
CHANGED
@@ -79,7 +79,8 @@ class InputSequencer
|
|
79
79
|
)
|
80
80
|
exit_when_bq_empty = !bq_is_empty? # true when running blocks from cli; unless "stay" is used
|
81
81
|
loop do
|
82
|
-
break if run_yield(:parse_document, now_menu.document_filename,
|
82
|
+
break if run_yield(:parse_document, now_menu.document_filename,
|
83
|
+
&block) == :break
|
83
84
|
|
84
85
|
# self.imw_ins now_menu, 'now_menu'
|
85
86
|
|
@@ -92,7 +93,8 @@ class InputSequencer
|
|
92
93
|
choice = run_yield :user_choice, &block
|
93
94
|
|
94
95
|
raise 'Block not recognized.' if choice.nil?
|
95
|
-
|
96
|
+
# Exit loop and method to terminate the app
|
97
|
+
break if run_yield(:exit?, choice&.downcase, &block)
|
96
98
|
|
97
99
|
next_state = run_yield :execute_block, choice, &block
|
98
100
|
# imw_ins next_state, 'next_state'
|
data/lib/link_history.rb
CHANGED
@@ -2,10 +2,13 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
|
+
|
6
|
+
$pd = false unless defined?($pd)
|
7
|
+
|
5
8
|
module MarkdownExec
|
6
9
|
class LinkState
|
7
10
|
attr_accessor :block_name, :display_menu, :document_filename,
|
8
|
-
:inherited_block_names, :inherited_dependencies,
|
11
|
+
:inherited_block_names, :inherited_dependencies,
|
9
12
|
:prior_block_was_link
|
10
13
|
|
11
14
|
# Initialize the LinkState with keyword arguments for each attribute.
|
@@ -45,6 +48,36 @@ module MarkdownExec
|
|
45
48
|
other.inherited_lines == inherited_lines &&
|
46
49
|
other.prior_block_was_link == prior_block_was_link
|
47
50
|
end
|
51
|
+
|
52
|
+
def inherited_lines
|
53
|
+
@inherited_lines.tap { |ret| pp ['LinkState.inherited_lines() ->', ret] if $pd }
|
54
|
+
end
|
55
|
+
|
56
|
+
def inherited_lines=(value)
|
57
|
+
@inherited_lines = value.tap { |ret| pp ['LinkState.inherited_lines=() ->', ret] if $pd }
|
58
|
+
end
|
59
|
+
|
60
|
+
def inherited_lines_append(value)
|
61
|
+
@inherited_lines = ((@inherited_lines || []) + value).tap { |ret| pp ['LinkState.inherited_lines_append() ->', ret] if $pd }
|
62
|
+
end
|
63
|
+
|
64
|
+
def inherited_lines_block
|
65
|
+
@inherited_lines.join("\n").tap { |ret| pp ['LinkState.inherited_lines_block() ->', ret] if $pd }
|
66
|
+
end
|
67
|
+
|
68
|
+
def inherited_lines_count
|
69
|
+
(@inherited_lines&.count || 0).tap { |ret| pp ['LinkState.inherited_lines_count() ->', ret] if $pd }
|
70
|
+
end
|
71
|
+
|
72
|
+
def inherited_lines_map
|
73
|
+
@inherited_lines.map do |line|
|
74
|
+
yield line
|
75
|
+
end.tap { |ret| pp ['LinkState.inherited_lines_map() ->', ret] if $pd }
|
76
|
+
end
|
77
|
+
|
78
|
+
def inherited_lines_present?
|
79
|
+
@inherited_lines.present?.tap { |ret| pp ['LinkState.inherited_lines_present?() ->', ret] if $pd }
|
80
|
+
end
|
48
81
|
end
|
49
82
|
|
50
83
|
class LinkHistory
|
data/lib/markdown_exec.rb
CHANGED
@@ -45,6 +45,8 @@ tap_config envvar: MarkdownExec::TAP_DEBUG
|
|
45
45
|
$stderr.sync = true
|
46
46
|
$stdout.sync = true
|
47
47
|
|
48
|
+
$pd = false unless defined?($pd)
|
49
|
+
|
48
50
|
ARGV_SEP = '--'
|
49
51
|
|
50
52
|
# custom error: file specified is missing
|
@@ -86,20 +88,6 @@ def extract_named_captures_from_option(str, option)
|
|
86
88
|
str.match(Regexp.new(option))&.named_captures&.sym_keys
|
87
89
|
end
|
88
90
|
|
89
|
-
# :reek:UtilityFunction
|
90
|
-
def list_recent_output(saved_stdout_folder, saved_stdout_glob,
|
91
|
-
list_count)
|
92
|
-
SavedFilesMatcher.most_recent_list(saved_stdout_folder,
|
93
|
-
saved_stdout_glob, list_count)
|
94
|
-
end
|
95
|
-
|
96
|
-
# :reek:UtilityFunction
|
97
|
-
def list_recent_scripts(saved_script_folder, saved_script_glob,
|
98
|
-
list_count)
|
99
|
-
SavedFilesMatcher.most_recent_list(saved_script_folder,
|
100
|
-
saved_script_glob, list_count)
|
101
|
-
end
|
102
|
-
|
103
91
|
# execute markdown documents
|
104
92
|
#
|
105
93
|
module MarkdownExec
|
@@ -137,7 +125,10 @@ module MarkdownExec
|
|
137
125
|
return if max <= min # Ensure the range is valid
|
138
126
|
|
139
127
|
# Normalize the value within the range 0 to 1
|
140
|
-
normalized_value = [
|
128
|
+
normalized_value = [
|
129
|
+
0,
|
130
|
+
[(integer_value - min).to_f / (max - min), 1].min
|
131
|
+
].max
|
141
132
|
|
142
133
|
# Calculate how many characters should be filled
|
143
134
|
filled_length = (normalized_value * width).round
|
@@ -158,21 +149,25 @@ module MarkdownExec
|
|
158
149
|
@o_color = :red
|
159
150
|
end
|
160
151
|
|
161
|
-
def build_menu(file_names, directory_names, found_in_block_names,
|
152
|
+
def build_menu(file_names, directory_names, found_in_block_names,
|
153
|
+
files_in_directories, vbn)
|
162
154
|
choices = []
|
163
155
|
|
164
156
|
# Adding section title and data for file names
|
165
|
-
choices << { disabled: '',
|
157
|
+
choices << { disabled: '',
|
158
|
+
name: "in #{file_names[:section_title]}".send(@chrome_color) }
|
166
159
|
choices += file_names[:data].map { |str| FileInMenu.for_menu(str) }
|
167
160
|
|
168
161
|
# Conditionally add directory names if data is present
|
169
162
|
unless directory_names[:data].count.zero?
|
170
|
-
choices << { disabled: '',
|
163
|
+
choices << { disabled: '',
|
164
|
+
name: "in #{directory_names[:section_title]}".send(@chrome_color) }
|
171
165
|
choices += files_in_directories
|
172
166
|
end
|
173
167
|
|
174
168
|
# Adding found in block names
|
175
|
-
choices << { disabled: '',
|
169
|
+
choices << { disabled: '',
|
170
|
+
name: "in #{found_in_block_names[:section_title]}".send(@chrome_color) }
|
176
171
|
|
177
172
|
choices += vbn
|
178
173
|
|
@@ -186,16 +181,22 @@ module MarkdownExec
|
|
186
181
|
{
|
187
182
|
section_title: 'directory names',
|
188
183
|
data: matched_directories,
|
189
|
-
formatted_text: [{ content: AnsiFormatter.new(search_options).format_and_highlight_array(
|
184
|
+
formatted_text: [{ content: AnsiFormatter.new(search_options).format_and_highlight_array(
|
185
|
+
matched_directories, highlight: [highlight_value]
|
186
|
+
) }]
|
190
187
|
}
|
191
188
|
end
|
192
189
|
|
193
|
-
def found_in_block_names(search_options, highlight_value,
|
190
|
+
def found_in_block_names(search_options, highlight_value,
|
191
|
+
formspec: '=%<index>4.d: %<line>s')
|
194
192
|
matched_contents = (find_file_contents do |line|
|
195
|
-
read_block_name(line, search_options[:fenced_start_and_end_regex],
|
193
|
+
read_block_name(line, search_options[:fenced_start_and_end_regex],
|
194
|
+
search_options[:block_name_match], search_options[:block_name_nick_match])
|
196
195
|
end).map.with_index do |(file, contents), index|
|
197
196
|
# [file, contents.map { |detail| format(formspec, detail.index, detail.line) }, index]
|
198
|
-
[file, contents.map
|
197
|
+
[file, contents.map do |detail|
|
198
|
+
format(formspec, { index: detail.index, line: detail.line })
|
199
|
+
end, index]
|
199
200
|
end
|
200
201
|
{
|
201
202
|
section_title: 'block names',
|
@@ -222,7 +223,8 @@ module MarkdownExec
|
|
222
223
|
}
|
223
224
|
end
|
224
225
|
|
225
|
-
def read_block_name(line, fenced_start_and_end_regex, block_name_match,
|
226
|
+
def read_block_name(line, fenced_start_and_end_regex, block_name_match,
|
227
|
+
block_name_nick_match)
|
226
228
|
return unless line.match(fenced_start_and_end_regex)
|
227
229
|
|
228
230
|
bm = extract_named_captures_from_option(line, block_name_match)
|
@@ -241,7 +243,6 @@ module MarkdownExec
|
|
241
243
|
##
|
242
244
|
#
|
243
245
|
# :reek:DuplicateMethodCall { allow_calls: ['block', 'item', 'lm', 'opts', 'option', '@options', 'required_blocks'] }
|
244
|
-
# rubocop:enable Layout/LineLength
|
245
246
|
# :reek:MissingSafeMethod { exclude: [ read_configuration_file! ] }
|
246
247
|
# :reek:TooManyInstanceVariables ### temp
|
247
248
|
# :reek:TooManyMethods ### temp
|
@@ -267,6 +268,20 @@ module MarkdownExec
|
|
267
268
|
)
|
268
269
|
end
|
269
270
|
|
271
|
+
# :reek:UtilityFunction
|
272
|
+
def list_recent_output(saved_stdout_folder, saved_stdout_glob,
|
273
|
+
list_count)
|
274
|
+
SavedFilesMatcher.most_recent_list(saved_stdout_folder,
|
275
|
+
saved_stdout_glob, list_count)
|
276
|
+
end
|
277
|
+
|
278
|
+
# :reek:UtilityFunction
|
279
|
+
def list_recent_scripts(saved_script_folder, saved_script_glob,
|
280
|
+
list_count)
|
281
|
+
SavedFilesMatcher.most_recent_list(saved_script_folder,
|
282
|
+
saved_script_glob, list_count)
|
283
|
+
end
|
284
|
+
|
270
285
|
def warn_format(name, message, opts = {})
|
271
286
|
Exceptions.warn_format(
|
272
287
|
"CachedNestedFileReader.#{name} -- #{message}",
|
@@ -390,8 +405,6 @@ module MarkdownExec
|
|
390
405
|
},
|
391
406
|
pwd: -> { @fout.fout File.expand_path('..', __dir__) },
|
392
407
|
run_last_script: -> { run_last_script },
|
393
|
-
select_recent_output: -> { select_recent_output },
|
394
|
-
select_recent_script: -> { select_recent_script },
|
395
408
|
tab_completions: -> { @fout.fout tab_completions },
|
396
409
|
menu_export: -> { @fout.fout menu_export }
|
397
410
|
}
|
@@ -456,7 +469,8 @@ module MarkdownExec
|
|
456
469
|
:menu_chrome_color)}"
|
457
470
|
searcher = SearchResultsReport.new(value, [find_path])
|
458
471
|
file_names = searcher.file_names(options, value)
|
459
|
-
found_in_block_names = searcher.found_in_block_names(options, value,
|
472
|
+
found_in_block_names = searcher.found_in_block_names(options, value,
|
473
|
+
formspec: '%<line>s')
|
460
474
|
directory_names = searcher.directory_names(options, value)
|
461
475
|
|
462
476
|
### search in file contents (block names, chrome, or text)
|
@@ -480,7 +494,9 @@ module MarkdownExec
|
|
480
494
|
find_files('*', [dn], exclude_dirs: true)
|
481
495
|
end.flatten(1).map { |str| FileInMenu.for_menu(str) }
|
482
496
|
|
483
|
-
|
497
|
+
unless file_names[:data]&.count.positive? || files_in_directories&.count.positive? || found_in_block_names[:data]&.count.positive?
|
498
|
+
return { exit: true }
|
499
|
+
end
|
484
500
|
|
485
501
|
vbn = found_in_block_names[:matched_contents].map do |matched_contents|
|
486
502
|
filename, details, = matched_contents
|
@@ -488,10 +504,14 @@ module MarkdownExec
|
|
488
504
|
details,
|
489
505
|
highlight: [value]
|
490
506
|
)
|
491
|
-
[FileInMenu.for_menu(filename)] +
|
507
|
+
[FileInMenu.for_menu(filename)] +
|
508
|
+
nexo.map do |str|
|
509
|
+
{ disabled: '', name: (' ' * 20) + str }
|
510
|
+
end
|
492
511
|
end.flatten
|
493
512
|
|
494
|
-
choices = MenuBuilder.new.build_menu(file_names, directory_names, found_in_block_names,
|
513
|
+
choices = MenuBuilder.new.build_menu(file_names, directory_names, found_in_block_names,
|
514
|
+
files_in_directories, vbn)
|
495
515
|
|
496
516
|
@options[:filename] = FileInMenu.from_menu(
|
497
517
|
select_document_if_multiple(
|
@@ -545,7 +565,8 @@ module MarkdownExec
|
|
545
565
|
->(_) { exit }
|
546
566
|
when 'find', 'open'
|
547
567
|
->(value) {
|
548
|
-
exit if find_value(value, execute_chosen_found: procname == 'open').fetch(:exit,
|
568
|
+
exit if find_value(value, execute_chosen_found: procname == 'open').fetch(:exit,
|
569
|
+
false)
|
549
570
|
}
|
550
571
|
when 'help'
|
551
572
|
->(_) {
|
@@ -571,9 +592,9 @@ module MarkdownExec
|
|
571
592
|
value.instance_of?(::String) ? (value.chomp != '0') : value
|
572
593
|
}
|
573
594
|
when 'val_as_int'
|
574
|
-
|
595
|
+
lambda(&:to_i)
|
575
596
|
when 'val_as_str'
|
576
|
-
|
597
|
+
lambda(&:to_s)
|
577
598
|
when 'version'
|
578
599
|
lambda { |_|
|
579
600
|
@fout.fout MarkdownExec::VERSION
|
@@ -734,59 +755,26 @@ module MarkdownExec
|
|
734
755
|
@options[:saved_filename_replacement])
|
735
756
|
end
|
736
757
|
|
737
|
-
def select_document_if_multiple(files = list_markdown_files_in_path,
|
758
|
+
def select_document_if_multiple(files = list_markdown_files_in_path,
|
759
|
+
prompt: options[:prompt_select_md].to_s)
|
738
760
|
return files[0] if (count = files.count) == 1
|
739
761
|
|
740
762
|
return unless count >= 2
|
741
763
|
|
742
764
|
opts = options.dup
|
743
|
-
select_option_or_exit(
|
744
|
-
|
745
|
-
opts.merge(per_page: opts[:select_page_height]))
|
746
|
-
end
|
747
|
-
|
748
|
-
# Presents a TTY prompt to select an option or exit, returns selected option or nil
|
749
|
-
def select_option_or_exit(prompt_text, strings, opts = {})
|
750
|
-
result = @options.select_option_with_metadata(prompt_text, strings,
|
751
|
-
opts)
|
752
|
-
### 2024-04-20 what for?
|
753
|
-
# return unless result.fetch(:option, nil)
|
754
|
-
|
755
|
-
result[:selected]
|
756
|
-
end
|
757
|
-
|
758
|
-
def select_recent_output
|
759
|
-
filename = select_option_or_exit(
|
760
|
-
HashDelegator.new(@options).string_send_color(@options[:prompt_select_output].to_s,
|
765
|
+
select_option_or_exit(
|
766
|
+
HashDelegator.new(@options).string_send_color(prompt,
|
761
767
|
:prompt_color_after_script_execution),
|
762
|
-
|
763
|
-
|
764
|
-
@options[:saved_stdout_glob],
|
765
|
-
@options[:list_count]
|
766
|
-
),
|
767
|
-
@options.merge({ per_page: @options[:select_page_height] })
|
768
|
+
files,
|
769
|
+
opts.merge(per_page: opts[:select_page_height])
|
768
770
|
)
|
769
|
-
return unless filename.present?
|
770
|
-
|
771
|
-
`open #{filename} #{options[:output_viewer_options]}`
|
772
771
|
end
|
773
772
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
@options[:saved_script_folder],
|
780
|
-
@options[:saved_script_glob],
|
781
|
-
@options[:list_count]
|
782
|
-
),
|
783
|
-
@options.merge({ per_page: @options[:select_page_height] })
|
784
|
-
)
|
785
|
-
return if filename.nil?
|
786
|
-
|
787
|
-
saved_name_split(filename)
|
788
|
-
|
789
|
-
@options.document_inpseq ### ({ save_executed_script: false })
|
773
|
+
# Presents a TTY prompt to select an option or exit, returns selected option or nil
|
774
|
+
def select_option_or_exit(prompt_text, strings, opts = {})
|
775
|
+
@options.select_option_with_metadata(
|
776
|
+
prompt_text, strings, opts
|
777
|
+
)&.fetch(:selected)
|
790
778
|
end
|
791
779
|
|
792
780
|
public
|
@@ -827,4 +815,4 @@ if $PROGRAM_NAME == __FILE__
|
|
827
815
|
assert_equal MenuState::CONTINUE, state
|
828
816
|
end
|
829
817
|
end # module MarkdownExec
|
830
|
-
end
|
818
|
+
end # if
|