markdown_exec 2.7.5 → 2.8.1
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +22 -1
- data/bats/block-type-ux-auto.bats +8 -0
- data/bats/block-type-ux-exec.bats +8 -0
- data/bats/block-type-ux-row-format.bats +8 -0
- data/bats/block-type-ux-transform.bats +8 -0
- data/bats/command-substitution.bats +1 -1
- data/bats/line-wrapping.bats +1 -1
- data/bats/table-column-truncate.bats +8 -0
- data/bats/table.bats +1 -1
- data/bin/tab_completion.sh +1 -1
- data/docs/dev/bats-document-configuration.md +3 -0
- data/docs/dev/block-type-ux-auto.md +43 -0
- data/docs/dev/block-type-ux-exec.md +42 -0
- data/docs/dev/block-type-ux-row-format.md +47 -0
- data/docs/dev/block-type-ux-transform.md +41 -0
- data/docs/dev/command-substitution.md +1 -0
- data/docs/dev/table-column-truncate.md +17 -0
- data/docs/dev/table-indent.md +1 -0
- data/examples/colors.md +2 -0
- data/lib/block_types.rb +1 -0
- data/lib/constants.rb +4 -2
- data/lib/evaluate_shell_expressions.rb +29 -24
- data/lib/fcb.rb +47 -37
- data/lib/format_table.rb +8 -7
- data/lib/hash_delegator.rb +332 -69
- data/lib/hierarchy_string.rb +3 -2
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +5 -8
- data/lib/mdoc.rb +52 -21
- data/lib/menu.src.yml +30 -0
- data/lib/menu.yml +27 -0
- metadata +12 -2
data/lib/hash_delegator.rb
CHANGED
@@ -92,6 +92,10 @@ module HashDelegatorSelf
|
|
92
92
|
blocks.find { |item| item.send(msg) == value } || default
|
93
93
|
end
|
94
94
|
|
95
|
+
def block_match(blocks, msg, value, default = nil)
|
96
|
+
blocks.select { |item| value =~ item.send(msg) }
|
97
|
+
end
|
98
|
+
|
95
99
|
def block_select(blocks, msg, value, default = nil)
|
96
100
|
blocks.select { |item| item.send(msg) == value }
|
97
101
|
end
|
@@ -297,14 +301,16 @@ module HashDelegatorSelf
|
|
297
301
|
truncate: $table_cell_truncate
|
298
302
|
)
|
299
303
|
|
300
|
-
|
304
|
+
exceeded_table_cell = false # any cell in table is exceeded
|
305
|
+
truncated_table_cell = false # any cell in table is truncated
|
301
306
|
table__hs.each do |table_hs|
|
302
307
|
table_hs.substrings.each do |substrings|
|
303
308
|
substrings.each do |node|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
309
|
+
next unless node[:text].class == TrackedString
|
310
|
+
|
311
|
+
exceeded_table_cell ||= node[:text].exceeded
|
312
|
+
truncated_table_cell = node[:text].truncated
|
313
|
+
break if truncated_table_cell
|
308
314
|
end
|
309
315
|
break if truncated_table_cell
|
310
316
|
end
|
@@ -337,9 +343,9 @@ module HashDelegatorSelf
|
|
337
343
|
|
338
344
|
if ind.zero?
|
339
345
|
fcb.truncated_table_cell = truncated_table_cell
|
340
|
-
|
341
|
-
|
342
|
-
|
346
|
+
if exceeded_table_cell
|
347
|
+
fcb.delete_key(:disabled)
|
348
|
+
end
|
343
349
|
end
|
344
350
|
end
|
345
351
|
end
|
@@ -588,6 +594,7 @@ module MarkdownExec
|
|
588
594
|
@prompt = HashDelegator.tty_prompt_without_disabled_symbol
|
589
595
|
|
590
596
|
@opts_most_recent_filename = nil
|
597
|
+
@ux_most_recent_filename = nil
|
591
598
|
@vars_most_recent_filename = nil
|
592
599
|
@pass_args = []
|
593
600
|
@run_state = OpenStruct.new(
|
@@ -865,7 +872,6 @@ module MarkdownExec
|
|
865
872
|
blocks = []
|
866
873
|
iter_blocks_from_nested_files do |btype, fcb|
|
867
874
|
count += 1
|
868
|
-
|
869
875
|
case btype
|
870
876
|
when :blocks
|
871
877
|
if @delegate_object[:bash]
|
@@ -873,7 +879,10 @@ module MarkdownExec
|
|
873
879
|
block_calls_scan: @delegate_object[:block_calls_scan],
|
874
880
|
block_name_match: @delegate_object[:block_name_match],
|
875
881
|
block_name_nick_match: @delegate_object[:block_name_nick_match],
|
876
|
-
id: "#{source_id}_bfnf_b_#{count}"
|
882
|
+
id: "#{source_id}_bfnf_b_#{count}",
|
883
|
+
menu_format: @delegate_object[:menu_ux_row_format],
|
884
|
+
prompt: @delegate_object[:prompt_ux_enter_a_value],
|
885
|
+
table_center: @delegate_object[:table_center]
|
877
886
|
) do |oname, color|
|
878
887
|
apply_block_type_color_option(oname, color)
|
879
888
|
end
|
@@ -925,7 +934,12 @@ module MarkdownExec
|
|
925
934
|
end
|
926
935
|
end
|
927
936
|
|
928
|
-
|
937
|
+
def build_menu_options(exit_option, display_mode_option,
|
938
|
+
menu_entries, display_format)
|
939
|
+
[exit_option,
|
940
|
+
display_mode_option,
|
941
|
+
*menu_entries.map(&display_format)].compact
|
942
|
+
end
|
929
943
|
|
930
944
|
def build_replacement_dictionary(
|
931
945
|
commands, link_state,
|
@@ -935,7 +949,7 @@ module MarkdownExec
|
|
935
949
|
(link_state&.inherited_lines_block || ''), commands,
|
936
950
|
initial_code_required: initial_code_required,
|
937
951
|
key_format: key_format
|
938
|
-
)
|
952
|
+
)
|
939
953
|
end
|
940
954
|
|
941
955
|
def calc_logged_stdout_filename(block_name:)
|
@@ -1008,6 +1022,136 @@ module MarkdownExec
|
|
1008
1022
|
]
|
1009
1023
|
end
|
1010
1024
|
|
1025
|
+
def neval(export_exec, inherited_code)
|
1026
|
+
# ww0 export_exec
|
1027
|
+
# ww0 inherited_code
|
1028
|
+
code = (inherited_code || []) + [export_exec]
|
1029
|
+
filespec = generate_temp_filename
|
1030
|
+
File.write filespec, HashDelegator.join_code_lines(code)
|
1031
|
+
File.chmod 0o755, filespec
|
1032
|
+
# ww0 File.read(filespec)
|
1033
|
+
ret = `#{filespec}`
|
1034
|
+
File.delete filespec
|
1035
|
+
ret
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
# sets ENV
|
1039
|
+
def code_from_ux_block_to_set_environment_variables(
|
1040
|
+
selected, mdoc, inherited_code: nil, force: true, only_default: false
|
1041
|
+
)
|
1042
|
+
# ww0 inherited_code
|
1043
|
+
# ww0 mdoc
|
1044
|
+
exit_prompt = @delegate_object[:prompt_filespec_back]
|
1045
|
+
|
1046
|
+
required = mdoc.collect_recursively_required_code(
|
1047
|
+
anyname: selected.pub_name,
|
1048
|
+
label_format_above: @delegate_object[:shell_code_label_format_above],
|
1049
|
+
label_format_below: @delegate_object[:shell_code_label_format_below],
|
1050
|
+
block_source: block_source
|
1051
|
+
)
|
1052
|
+
|
1053
|
+
code_lines = []
|
1054
|
+
case data = YAML.load(selected.body.join("\n"))
|
1055
|
+
when Hash
|
1056
|
+
export = parse_yaml_of_ux_block(
|
1057
|
+
data,
|
1058
|
+
prompt: @delegate_object[:prompt_ux_enter_a_value],
|
1059
|
+
validate: '^(?<name>[^ ].*)$'
|
1060
|
+
)
|
1061
|
+
|
1062
|
+
exportable = true
|
1063
|
+
if only_default
|
1064
|
+
value = case export.default
|
1065
|
+
# exec > default
|
1066
|
+
when :exec
|
1067
|
+
raise unless export.exec.present?
|
1068
|
+
|
1069
|
+
n1 = neval(export.exec,
|
1070
|
+
(inherited_code || []) + required[:code])
|
1071
|
+
|
1072
|
+
if export.transform.present?
|
1073
|
+
if export.transform.is_a? Symbol
|
1074
|
+
n1.send(export.transform)
|
1075
|
+
else
|
1076
|
+
format(
|
1077
|
+
export.transform,
|
1078
|
+
NamedCaptureExtractor.extract_named_groups(
|
1079
|
+
n1, export.validate
|
1080
|
+
)
|
1081
|
+
)
|
1082
|
+
end
|
1083
|
+
else
|
1084
|
+
n1
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
# default
|
1088
|
+
else
|
1089
|
+
export.default.to_s
|
1090
|
+
end
|
1091
|
+
else
|
1092
|
+
caps = nil
|
1093
|
+
value = nil
|
1094
|
+
|
1095
|
+
# exec > allowed
|
1096
|
+
if export.exec
|
1097
|
+
value = neval(export.exec, (inherited_code || []) + required[:code])
|
1098
|
+
caps = NamedCaptureExtractor.extract_named_groups(value,
|
1099
|
+
export.validate)
|
1100
|
+
|
1101
|
+
# allowed > prompt
|
1102
|
+
elsif export.allowed && export.allowed.count.positive?
|
1103
|
+
case (choice = prompt_select_code_filename(
|
1104
|
+
[exit_prompt] + export.allowed,
|
1105
|
+
string: export.prompt,
|
1106
|
+
color_sym: :prompt_color_after_script_execution
|
1107
|
+
))
|
1108
|
+
when exit_prompt
|
1109
|
+
exportable = false
|
1110
|
+
else
|
1111
|
+
value = choice
|
1112
|
+
caps = NamedCaptureExtractor.extract_named_groups(value,
|
1113
|
+
export.validate)
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
# prompt > default
|
1117
|
+
elsif export.prompt.present?
|
1118
|
+
begin
|
1119
|
+
while true
|
1120
|
+
print "#{export.prompt} [#{export.default}]: "
|
1121
|
+
value = gets.chomp
|
1122
|
+
value = export.default.to_s if value.empty?
|
1123
|
+
caps = NamedCaptureExtractor.extract_named_groups(value,
|
1124
|
+
export.validate)
|
1125
|
+
break if caps
|
1126
|
+
|
1127
|
+
# invalid input, retry
|
1128
|
+
|
1129
|
+
end
|
1130
|
+
rescue Interrupt
|
1131
|
+
exportable = false
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
# default
|
1135
|
+
else
|
1136
|
+
value = export.default
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
if exportable && export.transform.present?
|
1140
|
+
value = format(export.transform, caps)
|
1141
|
+
end
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
if exportable
|
1145
|
+
ENV[export.name] = value.to_s
|
1146
|
+
code_lines.push code_line_safe_assign(export.name, value,
|
1147
|
+
force: force)
|
1148
|
+
end
|
1149
|
+
else
|
1150
|
+
raise "Invalid data type: #{data.inspect}"
|
1151
|
+
end
|
1152
|
+
code_lines
|
1153
|
+
end
|
1154
|
+
|
1011
1155
|
# sets ENV
|
1012
1156
|
def code_from_vars_block_to_set_environment_variables(selected)
|
1013
1157
|
code_lines = []
|
@@ -1027,6 +1171,14 @@ module MarkdownExec
|
|
1027
1171
|
code_lines
|
1028
1172
|
end
|
1029
1173
|
|
1174
|
+
def code_line_safe_assign(name, value, force:)
|
1175
|
+
if force
|
1176
|
+
"#{name}=#{Shellwords.escape(value)}"
|
1177
|
+
else
|
1178
|
+
"[[ -z $#{name} ]] && #{name}=#{Shellwords.escape(value)}"
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1030
1182
|
def collect_line_decor_patterns(delegate_object)
|
1031
1183
|
extract_patterns = lambda do |key|
|
1032
1184
|
return [] unless delegate_object[key].present?
|
@@ -1412,7 +1564,7 @@ module MarkdownExec
|
|
1412
1564
|
@delegate_object[criteria[:color]].to_sym,
|
1413
1565
|
decor_patterns:
|
1414
1566
|
@decor_patterns_from_delegate_object_for_block_create,
|
1415
|
-
disabled:
|
1567
|
+
disabled: !(criteria[:collapsible] && @delegate_object[criteria[:collapsible]]),
|
1416
1568
|
fcb: fcb,
|
1417
1569
|
id: "#{id}.#{index}",
|
1418
1570
|
format_option: criteria[:format] &&
|
@@ -1790,6 +1942,18 @@ module MarkdownExec
|
|
1790
1942
|
)
|
1791
1943
|
next_state_set_code(selected, link_state, required_lines)
|
1792
1944
|
|
1945
|
+
elsif selected.type == BlockType::UX
|
1946
|
+
debounce_reset
|
1947
|
+
next_state_append_code(
|
1948
|
+
selected,
|
1949
|
+
link_state,
|
1950
|
+
code_from_ux_block_to_set_environment_variables(
|
1951
|
+
selected,
|
1952
|
+
@dml_mdoc,
|
1953
|
+
inherited_code: @dml_link_state.inherited_lines
|
1954
|
+
)
|
1955
|
+
)
|
1956
|
+
|
1793
1957
|
elsif selected.type == BlockType::VARS
|
1794
1958
|
debounce_reset
|
1795
1959
|
next_state_append_code(selected, link_state,
|
@@ -1822,19 +1986,23 @@ module MarkdownExec
|
|
1822
1986
|
block_source: block_source
|
1823
1987
|
)
|
1824
1988
|
|
1825
|
-
#
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1989
|
+
# dname is not fixed for some block types, use block id
|
1990
|
+
if lfls.load_file != LoadFile::LOAD &&
|
1991
|
+
[BlockType::HEADING, BlockType::TEXT,
|
1992
|
+
BlockType::UX].include?(selected.type)
|
1993
|
+
block_selection = BlockSelection.new(selected.id)
|
1994
|
+
end
|
1995
|
+
|
1996
|
+
{ link_state: lfls.link_state,
|
1997
|
+
block_selection: block_selection,
|
1998
|
+
quit: lfls.load_file == LoadFile::EXIT }
|
1831
1999
|
end
|
1832
2000
|
|
1833
2001
|
def execute_block_in_state(block_name)
|
1834
2002
|
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1835
2003
|
dump_and_warn_block_state(name: block_name,
|
1836
2004
|
selected: @dml_block_state.block)
|
1837
|
-
|
2005
|
+
next_block_state =
|
1838
2006
|
execute_block_for_state_and_name(
|
1839
2007
|
selected: @dml_block_state.block,
|
1840
2008
|
mdoc: @dml_mdoc,
|
@@ -1846,7 +2014,10 @@ module MarkdownExec
|
|
1846
2014
|
)
|
1847
2015
|
}
|
1848
2016
|
)
|
1849
|
-
|
2017
|
+
|
2018
|
+
@dml_link_state = next_block_state[:link_state]
|
2019
|
+
@dml_block_selection = next_block_state[:block_selection]
|
2020
|
+
:break if next_block_state[:quit]
|
1850
2021
|
end
|
1851
2022
|
|
1852
2023
|
def execute_block_type_history_ux(
|
@@ -1993,6 +2164,7 @@ module MarkdownExec
|
|
1993
2164
|
block_data['glob'] || glob
|
1994
2165
|
)
|
1995
2166
|
)
|
2167
|
+
dirs.sort_by! { |f| File.mtime(f) }.reverse!
|
1996
2168
|
|
1997
2169
|
if !contains_glob?(block_data['directory']) &&
|
1998
2170
|
!contains_glob?(block_data['glob'])
|
@@ -2003,7 +2175,7 @@ module MarkdownExec
|
|
2003
2175
|
end
|
2004
2176
|
elsif selected_option = select_option_with_metadata(
|
2005
2177
|
prompt_title,
|
2006
|
-
[exit_prompt] + dirs.
|
2178
|
+
[exit_prompt] + dirs.map do |file|
|
2007
2179
|
{ name: format(
|
2008
2180
|
block_data['view'] || view,
|
2009
2181
|
NamedCaptureExtractor.extract_named_group_match_data(
|
@@ -2167,41 +2339,25 @@ module MarkdownExec
|
|
2167
2339
|
)
|
2168
2340
|
# repeat select+display until user exits
|
2169
2341
|
|
2170
|
-
|
2171
|
-
|
2172
|
-
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
pause_now = false
|
2190
|
-
else
|
2191
|
-
file = files_table_rows.select { |ftr| ftr.row == name }&.first
|
2192
|
-
info = file_info(file.file)
|
2193
|
-
stream.puts "#{file.file} - #{info[:lines]} lines / " \
|
2194
|
-
"#{info[:size]} bytes"
|
2195
|
-
stream.puts(
|
2196
|
-
File.readlines(file.file,
|
2197
|
-
chomp: false).map.with_index do |line, ind|
|
2198
|
-
format(' %s. %s',
|
2199
|
-
AnsiString.new(format('% 4d', ind + 1)).send(:violet),
|
2200
|
-
line)
|
2201
|
-
end
|
2202
|
-
)
|
2203
|
-
pause_now = pause_refresh
|
2204
|
-
end
|
2342
|
+
interactive_menu_with_display_modes(
|
2343
|
+
files_table_rows,
|
2344
|
+
display_formats: [:row, :file],
|
2345
|
+
display_mode_option: @delegate_object[:prompt_filespec_facet],
|
2346
|
+
exit_option: exit_prompt,
|
2347
|
+
menu_title: @delegate_object[:prompt_select_history_file],
|
2348
|
+
pause_after_selection: pause_refresh
|
2349
|
+
) do |file|
|
2350
|
+
info = file_info(file.file)
|
2351
|
+
stream.puts "#{file.file} - #{info[:lines]} lines / " \
|
2352
|
+
"#{info[:size]} bytes"
|
2353
|
+
stream.puts(
|
2354
|
+
File.readlines(file.file,
|
2355
|
+
chomp: false).map.with_index do |line, ind|
|
2356
|
+
format(' %s. %s',
|
2357
|
+
AnsiString.new(format('% 4d', ind + 1)).send(:violet),
|
2358
|
+
line)
|
2359
|
+
end
|
2360
|
+
)
|
2205
2361
|
end
|
2206
2362
|
end
|
2207
2363
|
|
@@ -2296,7 +2452,7 @@ module MarkdownExec
|
|
2296
2452
|
|
2297
2453
|
variable_counts = count_named_group_occurrences(blocks, pattern,
|
2298
2454
|
group_name: group_name)
|
2299
|
-
return if variable_counts.nil?
|
2455
|
+
return if variable_counts.nil? || variable_counts == {}
|
2300
2456
|
|
2301
2457
|
echo_commands = generate_echo_commands(variable_counts, echo_format)
|
2302
2458
|
|
@@ -2307,6 +2463,7 @@ module MarkdownExec
|
|
2307
2463
|
)
|
2308
2464
|
|
2309
2465
|
return if replacements.nil?
|
2466
|
+
return if replacements == EvaluateShellExpression::StatusFail
|
2310
2467
|
|
2311
2468
|
expand_blocks_with_replacements(blocks, replacements)
|
2312
2469
|
end
|
@@ -2519,6 +2676,56 @@ module MarkdownExec
|
|
2519
2676
|
}
|
2520
2677
|
end
|
2521
2678
|
|
2679
|
+
def interactive_menu_with_display_modes(
|
2680
|
+
menu_entries,
|
2681
|
+
display_formats:,
|
2682
|
+
display_mode_option:,
|
2683
|
+
exit_option:,
|
2684
|
+
menu_title:,
|
2685
|
+
pause_after_selection:
|
2686
|
+
)
|
2687
|
+
pause_menu = false
|
2688
|
+
current_display_format = display_formats.first
|
2689
|
+
|
2690
|
+
loop do
|
2691
|
+
break if pause_menu && (prompt_select_continue == MenuState::EXIT)
|
2692
|
+
|
2693
|
+
menu_options = build_menu_options(
|
2694
|
+
exit_option, display_mode_option,
|
2695
|
+
menu_entries, current_display_format
|
2696
|
+
)
|
2697
|
+
|
2698
|
+
selection = prompt_select_code_filename(
|
2699
|
+
menu_options,
|
2700
|
+
string: menu_title,
|
2701
|
+
color_sym: :prompt_color_after_script_execution
|
2702
|
+
)
|
2703
|
+
|
2704
|
+
case selection
|
2705
|
+
when exit_option
|
2706
|
+
break
|
2707
|
+
when display_mode_option
|
2708
|
+
current_display_format = next_item(
|
2709
|
+
display_formats, current_display_format
|
2710
|
+
)
|
2711
|
+
pause_menu = false
|
2712
|
+
else
|
2713
|
+
handle_selection(menu_entries, selection,
|
2714
|
+
current_display_format) do |item|
|
2715
|
+
yield item if block_given?
|
2716
|
+
end
|
2717
|
+
pause_menu = pause_after_selection
|
2718
|
+
end
|
2719
|
+
end
|
2720
|
+
end
|
2721
|
+
|
2722
|
+
def handle_selection(menu_entries, selection, current_display_format)
|
2723
|
+
selected_item = menu_entries.find do |entry|
|
2724
|
+
entry.send(current_display_format) == selection
|
2725
|
+
end
|
2726
|
+
yield selected_item if selected_item
|
2727
|
+
end
|
2728
|
+
|
2522
2729
|
# Iterates through blocks in a file, applying the provided block to each line.
|
2523
2730
|
# The iteration only occurs if the file exists.
|
2524
2731
|
# @yield [Symbol] :filter Yields to obtain selected messages for processing.
|
@@ -2723,6 +2930,37 @@ module MarkdownExec
|
|
2723
2930
|
true
|
2724
2931
|
end
|
2725
2932
|
|
2933
|
+
def load_auto_ux_block(
|
2934
|
+
all_blocks,
|
2935
|
+
mdoc,
|
2936
|
+
block_name: @delegate_object[:document_load_ux_block_name]
|
2937
|
+
)
|
2938
|
+
unless block_name.present? &&
|
2939
|
+
@ux_most_recent_filename != @delegate_object[:filename]
|
2940
|
+
return
|
2941
|
+
end
|
2942
|
+
|
2943
|
+
blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
|
2944
|
+
if blocks.empty?
|
2945
|
+
blocks = HashDelegator.block_match(all_blocks, :nickname,
|
2946
|
+
Regexp.new(block_name))
|
2947
|
+
end
|
2948
|
+
return if blocks.empty?
|
2949
|
+
|
2950
|
+
@ux_most_recent_filename = @delegate_object[:filename]
|
2951
|
+
|
2952
|
+
(blocks.each.with_object([]) do |block, merged_options|
|
2953
|
+
merged_options.push(
|
2954
|
+
code_from_ux_block_to_set_environment_variables(
|
2955
|
+
block,
|
2956
|
+
mdoc,
|
2957
|
+
force: @delegate_object[:ux_auto_load_force_default],
|
2958
|
+
only_default: true
|
2959
|
+
)
|
2960
|
+
)
|
2961
|
+
end).to_a
|
2962
|
+
end
|
2963
|
+
|
2726
2964
|
def load_auto_vars_block(all_blocks,
|
2727
2965
|
block_name: @delegate_object[:document_load_vars_block_name])
|
2728
2966
|
unless block_name.present? &&
|
@@ -2871,6 +3109,16 @@ module MarkdownExec
|
|
2871
3109
|
reload_blocks = true
|
2872
3110
|
end
|
2873
3111
|
|
3112
|
+
# load document ux block
|
3113
|
+
#
|
3114
|
+
if code_lines = load_auto_ux_block(all_blocks, mdoc)
|
3115
|
+
new_code = HashDelegator.code_merge(link_state.inherited_lines,
|
3116
|
+
code_lines)
|
3117
|
+
next_state_set_code(nil, link_state, new_code)
|
3118
|
+
link_state.inherited_lines = new_code
|
3119
|
+
reload_blocks = true
|
3120
|
+
end
|
3121
|
+
|
2874
3122
|
# load document vars block
|
2875
3123
|
#
|
2876
3124
|
if code_lines = load_auto_vars_block(all_blocks)
|
@@ -2924,7 +3172,6 @@ module MarkdownExec
|
|
2924
3172
|
HashDelegator.tables_into_columns!(menu_blocks, @delegate_object,
|
2925
3173
|
screen_width_for_table)
|
2926
3174
|
|
2927
|
-
|
2928
3175
|
[all_blocks, menu_blocks, mdoc]
|
2929
3176
|
end
|
2930
3177
|
|
@@ -2988,7 +3235,6 @@ module MarkdownExec
|
|
2988
3235
|
def menu_toggle_collapsible_block(selected)
|
2989
3236
|
# return true if @compress_ids.key?(fcb.id) && !!@compress_ids[fcb.id]
|
2990
3237
|
# return false if @expand_ids.key?(fcb.id) && !!@expand_ids[fcb.id]
|
2991
|
-
# binding.irb
|
2992
3238
|
if @compressed_ids.key?(selected.id) && !!@compressed_ids[selected.id]
|
2993
3239
|
@compressed_ids.delete(selected.id)
|
2994
3240
|
@expanded_ids[selected.id] = selected.level
|
@@ -3010,6 +3256,13 @@ module MarkdownExec
|
|
3010
3256
|
end
|
3011
3257
|
end
|
3012
3258
|
|
3259
|
+
def next_item(list, current_item)
|
3260
|
+
index = list.index(current_item)
|
3261
|
+
return nil unless index # Return nil if the item is not in the list
|
3262
|
+
|
3263
|
+
list[(index + 1) % list.size] # Get the next item, wrap around if at the end
|
3264
|
+
end
|
3265
|
+
|
3013
3266
|
def next_state_append_code(selected, link_state, code_lines)
|
3014
3267
|
next_state_set_code(
|
3015
3268
|
selected,
|
@@ -3705,15 +3958,17 @@ module MarkdownExec
|
|
3705
3958
|
end
|
3706
3959
|
|
3707
3960
|
def screen_width
|
3708
|
-
|
3709
|
-
|
3961
|
+
width = @delegate_object[:screen_width]
|
3962
|
+
if width && width.positive?
|
3963
|
+
width
|
3710
3964
|
else
|
3711
3965
|
@delegate_object[:console_width]
|
3712
3966
|
end
|
3713
3967
|
end
|
3714
3968
|
|
3715
3969
|
def screen_width_for_table
|
3716
|
-
|
3970
|
+
# menu adds newline after some lines if sized to the edge
|
3971
|
+
screen_width - prompt_margin_left_width - prompt_margin_right_width - 3 # menu prompt symbol (1) + space (1) + gap (1)
|
3717
3972
|
end
|
3718
3973
|
|
3719
3974
|
def screen_width_for_wrapping
|
@@ -3910,7 +4165,7 @@ module MarkdownExec
|
|
3910
4165
|
disabled = if fcb_title_groups.fetch(:type, '') == BlockType::YAML
|
3911
4166
|
TtyMenu::DISABLE
|
3912
4167
|
else
|
3913
|
-
|
4168
|
+
TtyMenu::ENABLE
|
3914
4169
|
end
|
3915
4170
|
|
3916
4171
|
MarkdownExec::FCB.new(
|
@@ -4036,11 +4291,11 @@ module MarkdownExec
|
|
4036
4291
|
@delegate_object.merge!(options)
|
4037
4292
|
end
|
4038
4293
|
|
4039
|
-
def vux_await_user_selection
|
4294
|
+
def vux_await_user_selection(prior_answer: @dml_block_selection)
|
4040
4295
|
@dml_block_state = load_cli_or_user_selected_block(
|
4041
4296
|
all_blocks: @dml_blocks_in_file,
|
4042
4297
|
menu_blocks: @dml_menu_blocks,
|
4043
|
-
prior_answer:
|
4298
|
+
prior_answer: prior_answer
|
4044
4299
|
)
|
4045
4300
|
if !@dml_block_state
|
4046
4301
|
# HashDelegator.error_handler('block_state missing', { abort: true })
|
@@ -4194,7 +4449,7 @@ module MarkdownExec
|
|
4194
4449
|
@dml_link_state.block_name.present?
|
4195
4450
|
@cli_block_name = @dml_link_state.block_name
|
4196
4451
|
@dml_now_using_cli = @run_state.source.block_name_from_cli
|
4197
|
-
@
|
4452
|
+
@dml_block_selection = nil
|
4198
4453
|
@dml_block_state = SelectedBlockMenuState.new
|
4199
4454
|
@doc_saved_lines_files = []
|
4200
4455
|
|
@@ -4512,7 +4767,9 @@ module MarkdownExec
|
|
4512
4767
|
else
|
4513
4768
|
# puts "? - Select a block to execute (or type #{$texit}
|
4514
4769
|
# to exit):"
|
4515
|
-
return :break if vux_await_user_selection
|
4770
|
+
return :break if vux_await_user_selection(
|
4771
|
+
prior_answer: @dml_block_selection
|
4772
|
+
) == :break
|
4516
4773
|
return :break if @dml_block_state.block.nil? # no block matched
|
4517
4774
|
end
|
4518
4775
|
# puts "! - Executing block: #{data}"
|
@@ -4562,7 +4819,13 @@ module MarkdownExec
|
|
4562
4819
|
block.dname.include?(prior_answer)
|
4563
4820
|
end&.name
|
4564
4821
|
when Struct
|
4565
|
-
|
4822
|
+
if prior_answer.id
|
4823
|
+
menu_items.find_index do |block|
|
4824
|
+
block[:id] == prior_answer.id
|
4825
|
+
end + 1
|
4826
|
+
else
|
4827
|
+
prior_answer.index || prior_answer.name
|
4828
|
+
end
|
4566
4829
|
end
|
4567
4830
|
# prior_answer value may not match if color is different from
|
4568
4831
|
# originating menu (opts changed while processing)
|
data/lib/hierarchy_string.rb
CHANGED
data/lib/markdown_exec.rb
CHANGED
@@ -256,7 +256,7 @@ module MarkdownExec
|
|
256
256
|
block_name_nick_match)
|
257
257
|
return unless line.match(fenced_start_and_end_regex)
|
258
258
|
|
259
|
-
bm = NamedCaptureExtractor
|
259
|
+
bm = NamedCaptureExtractor.extract_named_groups(line, block_name_match)
|
260
260
|
return if bm.nil?
|
261
261
|
|
262
262
|
name = bm[:title]
|
@@ -282,7 +282,6 @@ module MarkdownExec
|
|
282
282
|
include StringUtil
|
283
283
|
|
284
284
|
def initialize(options = {})
|
285
|
-
# ww0 'options', options, caller.deref
|
286
285
|
@option_parser = nil
|
287
286
|
|
288
287
|
@options = HashDelegator.new(options)
|
@@ -405,7 +404,7 @@ module MarkdownExec
|
|
405
404
|
## Executes the block specified in the options
|
406
405
|
#
|
407
406
|
def execute_block_with_error_handling
|
408
|
-
@options.register_console_attributes(@options)
|
407
|
+
@options.register_console_attributes(@options)
|
409
408
|
finalize_cli_argument_processing
|
410
409
|
execute_initial_commands_and_main_loop(@options, @options.run_state)
|
411
410
|
rescue FileMissingError
|
@@ -430,11 +429,9 @@ module MarkdownExec
|
|
430
429
|
def execute_simple_commands(options, stage: nil)
|
431
430
|
# !!p stage
|
432
431
|
simple_commands(options).each do |key, (cstage, proc)|
|
433
|
-
if @options[key].is_a?(TrueClass) || @options[key].present?
|
434
|
-
|
435
|
-
|
436
|
-
return true
|
437
|
-
end
|
432
|
+
if (@options[key].is_a?(TrueClass) || @options[key].present?) && (stage && stage == cstage)
|
433
|
+
proc.call
|
434
|
+
return true
|
438
435
|
end
|
439
436
|
end
|
440
437
|
false
|