markdown_exec 3.1.1 → 3.3.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 +46 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +3 -3
- data/bats/block-type-ux-auto.bats +1 -1
- data/bats/block-type-ux-default.bats +1 -1
- data/bats/block-type-ux-echo-hash-transform.bats +1 -1
- data/bats/block-type-ux-echo-hash.bats +2 -2
- data/bats/block-type-ux-exec-hash-transform.bats +8 -0
- data/bats/block-type-ux-exec-hash.bats +15 -0
- data/bats/block-type-ux-exec.bats +1 -1
- data/bats/block-type-ux-force.bats +9 -0
- data/bats/block-type-ux-formats.bats +8 -0
- data/bats/block-type-ux-readonly.bats +1 -1
- data/bats/block-type-ux-row-format.bats +1 -1
- data/bats/block-type-ux-transform.bats +1 -1
- data/bats/import-directive-parameter-symbols.bats +9 -0
- data/bats/import-duplicates.bats +4 -2
- data/bats/import-parameter-symbols.bats +8 -0
- data/bats/markup.bats +1 -1
- data/bats/options.bats +1 -1
- data/bin/tab_completion.sh +5 -1
- data/docs/dev/block-type-ux-echo-hash-transform.md +14 -12
- data/docs/dev/block-type-ux-exec-hash-transform.md +37 -0
- data/docs/dev/block-type-ux-exec-hash.md +93 -0
- data/docs/dev/block-type-ux-force.md +20 -0
- data/docs/dev/block-type-ux-formats.md +58 -0
- data/docs/dev/hexdump_format.md +267 -0
- data/docs/dev/import/parameter-symbols.md +6 -0
- data/docs/dev/import-directive-parameter-symbols.md +9 -0
- data/docs/dev/import-parameter-symbols-template.md +24 -0
- data/docs/dev/import-parameter-symbols.md +6 -0
- data/docs/dev/load-vars-state-demo.md +35 -0
- data/docs/ux-blocks-examples.md +3 -3
- data/examples/import_with_substitution_demo.md +130 -26
- data/examples/imports/organism_template.md +86 -29
- data/lib/cached_nested_file_reader.rb +265 -27
- data/lib/constants.rb +8 -1
- data/lib/env_interface.rb +13 -7
- data/lib/evaluate_shell_expressions.rb +1 -0
- data/lib/fcb.rb +123 -19
- data/lib/format_table.rb +56 -23
- data/lib/fout.rb +5 -0
- data/lib/hash_delegator.rb +1196 -337
- data/lib/markdown_exec/version.rb +2 -1
- data/lib/markdown_exec.rb +2 -0
- data/lib/mdoc.rb +12 -6
- data/lib/menu.src.yml +150 -33
- data/lib/menu.yml +126 -31
- data/lib/string_util.rb +80 -0
- data/lib/table_extractor.rb +170 -64
- data/lib/ww.rb +328 -30
- metadata +18 -2
data/lib/hash_delegator.rb
CHANGED
@@ -97,6 +97,33 @@ module HashDelegatorSelf
|
|
97
97
|
blocks.select { |item| item.send(msg) == value }
|
98
98
|
end
|
99
99
|
|
100
|
+
def chrome_block_criteria
|
101
|
+
[
|
102
|
+
{ center: :table_center, format: :menu_note_format,
|
103
|
+
match: :table_row_multi_line_match, type: BlockType::TEXT },
|
104
|
+
{ case_conversion: :upcase, center: :heading1_center,
|
105
|
+
collapse: :heading1_collapse, collapsible: :heading1_collapsible,
|
106
|
+
color: :menu_heading1_color, format: :menu_heading1_format, level: 1,
|
107
|
+
match: :heading1_match, type: BlockType::HEADING, wrap: true },
|
108
|
+
{ center: :heading2_center,
|
109
|
+
collapse: :heading2_collapse, collapsible: :heading2_collapsible,
|
110
|
+
color: :menu_heading2_color, format: :menu_heading2_format, level: 2,
|
111
|
+
match: :heading2_match, type: BlockType::HEADING, wrap: true },
|
112
|
+
{ case_conversion: :downcase, center: :heading3_center,
|
113
|
+
collapse: :heading3_collapse, collapsible: :heading3_collapsible,
|
114
|
+
color: :menu_heading3_color, format: :menu_heading3_format, level: 3,
|
115
|
+
match: :heading3_match, type: BlockType::HEADING, wrap: true },
|
116
|
+
{ center: :divider4_center,
|
117
|
+
collapse: :divider4_collapse, collapsible: :divider4_collapsible,
|
118
|
+
color: :menu_divider_color, format: :menu_divider_format, level: 4,
|
119
|
+
match: :divider_match, type: BlockType::DIVIDER },
|
120
|
+
{ color: :menu_note_color, format: :menu_note_format,
|
121
|
+
match: :menu_note_match, type: BlockType::TEXT, wrap: true },
|
122
|
+
{ color: :menu_task_color, format: :menu_task_format,
|
123
|
+
match: :menu_task_match, type: BlockType::TEXT, wrap: true }
|
124
|
+
]
|
125
|
+
end
|
126
|
+
|
100
127
|
def count_matches_in_lines(lines, regex)
|
101
128
|
lines.count { |line| line.to_s.match(regex) }
|
102
129
|
end
|
@@ -274,7 +301,9 @@ module HashDelegatorSelf
|
|
274
301
|
lines = blocks_menu.map(&:oname)
|
275
302
|
text_tables = TableExtractor.extract_tables(
|
276
303
|
lines,
|
277
|
-
regexp: delegate_object[:table_parse_regexp]
|
304
|
+
regexp: delegate_object[:table_parse_regexp],
|
305
|
+
multi_line_delimiter: delegate_object[:table_row_multi_line_delimiter],
|
306
|
+
single_line_delimiter: delegate_object[:table_row_single_line_delimiter]
|
278
307
|
)
|
279
308
|
return unless text_tables.count.positive?
|
280
309
|
|
@@ -287,11 +316,16 @@ module HashDelegatorSelf
|
|
287
316
|
column_count: table[:columns],
|
288
317
|
decorate: {
|
289
318
|
border: delegate_object[:table_border_color],
|
290
|
-
header_row:
|
319
|
+
header_row: if table[:rows] == 1
|
320
|
+
delegate_object[:table_row_color]
|
321
|
+
else
|
322
|
+
delegate_object[:table_header_row_color]
|
323
|
+
end,
|
291
324
|
row: delegate_object[:table_row_color],
|
292
325
|
separator_line: delegate_object[:table_separator_line_color]
|
293
326
|
},
|
294
327
|
lines: lines,
|
328
|
+
table: table,
|
295
329
|
table_width: screen_width_for_table,
|
296
330
|
truncate: $table_cell_truncate
|
297
331
|
)
|
@@ -390,11 +424,22 @@ module HashDelegatorSelf
|
|
390
424
|
# @param [String] line The line to be processed.
|
391
425
|
# @param [Array<Symbol>] selected_types A list of message types to check.
|
392
426
|
# @param [Proc] block The block to be called with the line data.
|
393
|
-
def yield_line_if_selected(
|
394
|
-
|
427
|
+
def yield_line_if_selected(
|
428
|
+
line, selected_types, all_fcbs: nil,
|
429
|
+
criteria: nil, source_id: '', &block
|
430
|
+
)
|
395
431
|
return unless block && block_type_selected?(selected_types, :line)
|
396
432
|
|
397
|
-
|
433
|
+
opts = {
|
434
|
+
body: [line],
|
435
|
+
id: source_id
|
436
|
+
}
|
437
|
+
# add style if it is a single line table
|
438
|
+
opts[:criteria] = criteria if criteria
|
439
|
+
|
440
|
+
block.call(:line, persist_fcb_self(all_fcbs, opts))
|
441
|
+
rescue StandardError
|
442
|
+
wwe 'YAML loading error', { body: body, error: $! }
|
398
443
|
end
|
399
444
|
|
400
445
|
def persist_fcb_self(all_fcbs, options)
|
@@ -626,6 +671,8 @@ module MarkdownExec
|
|
626
671
|
|
627
672
|
@compressed_ids = {}
|
628
673
|
@expanded_ids = {}
|
674
|
+
rescue StandardError
|
675
|
+
wwe $!
|
629
676
|
end
|
630
677
|
|
631
678
|
##
|
@@ -709,6 +756,22 @@ module MarkdownExec
|
|
709
756
|
)
|
710
757
|
end
|
711
758
|
|
759
|
+
def annotate_required_lines(name, lines, block_name:)
|
760
|
+
if @delegate_object[:required_lines_with_source_comments] && !lines.empty?
|
761
|
+
formatted = formatted_block_name(block_name,
|
762
|
+
:script_comment_block_name_format)
|
763
|
+
['',
|
764
|
+
"#‡¯¯¯ #{name} ¯¯¯ #{formatted}",
|
765
|
+
'',
|
766
|
+
*lines,
|
767
|
+
'',
|
768
|
+
"#‡___ #{name} ___ #{formatted}",
|
769
|
+
'']
|
770
|
+
else
|
771
|
+
lines || []
|
772
|
+
end
|
773
|
+
end
|
774
|
+
|
712
775
|
# Appends a chrome block, which is a menu option for Back or Exit
|
713
776
|
#
|
714
777
|
# @param all_blocks [Array] The current blocks in the menu
|
@@ -819,6 +882,7 @@ module MarkdownExec
|
|
819
882
|
# @param block_type_color_option [Symbol, nil] The shell color option to apply.
|
820
883
|
# @return [String] The colorized or original name string.
|
821
884
|
def apply_block_type_color_option(name, block_type_color_option)
|
885
|
+
### accept string for color
|
822
886
|
if block_type_color_option && @delegate_object[block_type_color_option].present?
|
823
887
|
string_send_color(name, block_type_color_option)
|
824
888
|
else
|
@@ -866,6 +930,7 @@ module MarkdownExec
|
|
866
930
|
results = {}
|
867
931
|
iter_blocks_from_nested_files do |btype, fcb|
|
868
932
|
count += 1
|
933
|
+
wwt :iter, 'count:', count, 'btype:', btype, 'fcb.id:', fcb&.id
|
869
934
|
case btype
|
870
935
|
when :blocks
|
871
936
|
result = SuccessResult.instance
|
@@ -903,7 +968,11 @@ module MarkdownExec
|
|
903
968
|
center: fcb0.center,
|
904
969
|
chrome: true,
|
905
970
|
collapse: false,
|
906
|
-
disabled: is_enabled_but_inactive
|
971
|
+
disabled: if is_enabled_but_inactive
|
972
|
+
TtyMenu::ENABLE
|
973
|
+
else
|
974
|
+
TtyMenu::DISABLE
|
975
|
+
end,
|
907
976
|
dname: fcb0.indent + menu_line,
|
908
977
|
id: "#{id_prefix}#{index}",
|
909
978
|
indent: fcb0.indent,
|
@@ -922,9 +991,11 @@ module MarkdownExec
|
|
922
991
|
end
|
923
992
|
|
924
993
|
result = fcb.for_menu!(
|
994
|
+
appopts: @delegate_object,
|
925
995
|
block_calls_scan: @delegate_object[:block_calls_scan],
|
926
996
|
block_name_match: @delegate_object[:block_name_match],
|
927
|
-
block_name_nick_match:
|
997
|
+
block_name_nick_match:
|
998
|
+
@delegate_object[:block_name_nick_match],
|
928
999
|
id: fcb.id,
|
929
1000
|
menu_format: @delegate_object[:menu_ux_row_format],
|
930
1001
|
prompt: @delegate_object[:prompt_ux_enter_a_value],
|
@@ -939,9 +1010,11 @@ module MarkdownExec
|
|
939
1010
|
else
|
940
1011
|
# prepare block for menu, may fail and call HashDelegator.error_handler
|
941
1012
|
result = fcb.for_menu!(
|
1013
|
+
appopts: @delegate_object,
|
942
1014
|
block_calls_scan: @delegate_object[:block_calls_scan],
|
943
1015
|
block_name_match: @delegate_object[:block_name_match],
|
944
|
-
block_name_nick_match:
|
1016
|
+
block_name_nick_match:
|
1017
|
+
@delegate_object[:block_name_nick_match],
|
945
1018
|
id: fcb.id,
|
946
1019
|
menu_format: @delegate_object[:menu_ux_row_format],
|
947
1020
|
prompt: @delegate_object[:prompt_ux_enter_a_value],
|
@@ -978,7 +1051,7 @@ module MarkdownExec
|
|
978
1051
|
end
|
979
1052
|
OpenStruct.new(blocks: blocks, results: results)
|
980
1053
|
rescue StandardError
|
981
|
-
wwe 'link_state:', link_state, 'source_id:', source_id, 'btype:', btype,
|
1054
|
+
wwe $!, 'link_state:', link_state, 'source_id:', source_id, 'btype:', btype,
|
982
1055
|
'fcb:', fcb
|
983
1056
|
end
|
984
1057
|
|
@@ -1027,7 +1100,28 @@ module MarkdownExec
|
|
1027
1100
|
|
1028
1101
|
def cfile
|
1029
1102
|
@cfile ||= CachedNestedFileReader.new(
|
1030
|
-
|
1103
|
+
import_directive_line_pattern:
|
1104
|
+
@delegate_object.fetch(:import_directive_line_pattern),
|
1105
|
+
import_directive_parameter_scan:
|
1106
|
+
Regexp.new(
|
1107
|
+
@delegate_object.fetch(:import_directive_parameter_scan, '')
|
1108
|
+
),
|
1109
|
+
import_parameter_variable_assignment:
|
1110
|
+
@delegate_object[:import_parameter_variable_assignment],
|
1111
|
+
shell:
|
1112
|
+
@delegate_object[:shell],
|
1113
|
+
shell_block_name:
|
1114
|
+
@delegate_object[:document_load_shell_block_name],
|
1115
|
+
symbol_command_substitution:
|
1116
|
+
@delegate_object[:import_symbol_command_substitution],
|
1117
|
+
symbol_evaluated_expression:
|
1118
|
+
@delegate_object[:import_symbol_evaluated_expression],
|
1119
|
+
symbol_force_quoted_literal:
|
1120
|
+
@delegate_object[:import_symbol_force_quoted_literal],
|
1121
|
+
symbol_raw_literal:
|
1122
|
+
@delegate_object[:import_symbol_raw_literal],
|
1123
|
+
symbol_variable_reference:
|
1124
|
+
@delegate_object[:import_symbol_variable_reference]
|
1031
1125
|
)
|
1032
1126
|
end
|
1033
1127
|
|
@@ -1045,48 +1139,130 @@ module MarkdownExec
|
|
1045
1139
|
true
|
1046
1140
|
end
|
1047
1141
|
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1142
|
+
# return code resulting from evaluating all automatic blocks in order
|
1143
|
+
def code_from_auto_blocks(all_blocks, mdoc: nil, default_only: true)
|
1144
|
+
shell_block_name = @delegate_object[:document_load_shell_block_name]
|
1145
|
+
vars_block_name = @delegate_object[:document_load_vars_block_name]
|
1146
|
+
|
1147
|
+
# do not reload the same document
|
1148
|
+
read_shell = @shell_most_recent_filename != @delegate_object[:filename]
|
1149
|
+
read_ux = @ux_most_recent_filename != @delegate_object[:filename]
|
1150
|
+
read_vars = @vars_most_recent_filename != @delegate_object[:filename]
|
1151
|
+
@shell_most_recent_filename = @delegate_object[:filename]
|
1152
|
+
@ux_most_recent_filename = @delegate_object[:filename]
|
1153
|
+
@vars_most_recent_filename = @delegate_object[:filename]
|
1154
|
+
|
1155
|
+
all_code = []
|
1156
|
+
all_blocks.each do |fcb|
|
1157
|
+
block_code = []
|
1158
|
+
if fcb.oname == shell_block_name
|
1159
|
+
if read_shell
|
1160
|
+
# collect code from shell block
|
1161
|
+
code = if mdoc
|
1162
|
+
mdoc.collect_recursively_required_code(
|
1163
|
+
anyname: fcb.id,
|
1164
|
+
### anyname: fcb.pub_name,
|
1165
|
+
label_format_above:
|
1166
|
+
@delegate_object[:shell_code_label_format_above],
|
1167
|
+
label_format_below:
|
1168
|
+
@delegate_object[:shell_code_label_format_below],
|
1169
|
+
block_source: block_source
|
1170
|
+
)[:code]
|
1171
|
+
else
|
1172
|
+
fcb.body
|
1173
|
+
end
|
1174
|
+
block_code = annotate_required_lines('blk:SHELL', code,
|
1175
|
+
block_name: fcb.id)
|
1176
|
+
end
|
1177
|
+
elsif fcb.oname == vars_block_name
|
1178
|
+
if read_vars
|
1179
|
+
block_code = code_from_vars_block_to_set_environment_variables(fcb)
|
1180
|
+
end
|
1181
|
+
elsif fcb.type == 'ux'
|
1182
|
+
if !read_ux
|
1183
|
+
# skip
|
1184
|
+
elsif fcb.is_split_rest?
|
1185
|
+
# ignore
|
1186
|
+
else
|
1187
|
+
command_result_w_e_t_nl =
|
1188
|
+
code_from_ux_block_to_set_environment_variables(
|
1189
|
+
fcb,
|
1190
|
+
mdoc,
|
1191
|
+
force: @delegate_object[:ux_auto_load_force_default],
|
1192
|
+
only_default: default_only,
|
1193
|
+
silent: true
|
1194
|
+
)
|
1195
|
+
block_code = if command_result_w_e_t_nl&.success?
|
1196
|
+
command_result_w_e_t_nl.new_lines
|
1197
|
+
else
|
1198
|
+
[]
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
else
|
1203
|
+
# do nothing
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
wwt :code, 'block_code:', block_code unless block_code&.empty?
|
1207
|
+
all_code += block_code
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
all_code.tap { wwt :code, _1 }
|
1211
|
+
rescue StandardError
|
1212
|
+
wwe 'all_blocks.count:', all_blocks.count
|
1073
1213
|
end
|
1074
1214
|
|
1075
|
-
|
1215
|
+
# return code resulting from evaluating all automatic SHELL blocks in order
|
1216
|
+
def code_from_auto_shell_blocks(all_blocks, mdoc: nil)
|
1217
|
+
# a block name is required
|
1218
|
+
# do not reload the most recent filename
|
1219
|
+
block_name = @delegate_object[:document_load_shell_block_name]
|
1220
|
+
unless block_name.present? &&
|
1221
|
+
@shell_most_recent_filename != @delegate_object[:filename]
|
1222
|
+
return
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
@shell_most_recent_filename = @delegate_object[:filename]
|
1226
|
+
|
1227
|
+
# select the first block with the given name
|
1228
|
+
fcb = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1229
|
+
return unless fcb
|
1230
|
+
|
1231
|
+
# collect code from shell block
|
1232
|
+
code = if mdoc
|
1233
|
+
mdoc.collect_recursively_required_code(
|
1234
|
+
anyname: fcb.pub_name,
|
1235
|
+
label_format_above:
|
1236
|
+
@delegate_object[:shell_code_label_format_above],
|
1237
|
+
label_format_below:
|
1238
|
+
@delegate_object[:shell_code_label_format_below],
|
1239
|
+
block_source: block_source
|
1240
|
+
)[:code]
|
1241
|
+
else
|
1242
|
+
fcb.body
|
1243
|
+
end
|
1244
|
+
annotate_required_lines('blk:SHELL', code, block_name: fcb.id)
|
1245
|
+
end
|
1246
|
+
|
1247
|
+
# return code resulting from evaluating all UX blocks in order
|
1248
|
+
def code_from_auto_ux_blocks(
|
1076
1249
|
all_blocks,
|
1077
1250
|
mdoc
|
1078
1251
|
)
|
1252
|
+
# do not reload the most recent filename
|
1079
1253
|
unless @ux_most_recent_filename != @delegate_object[:filename]
|
1080
1254
|
return
|
1081
1255
|
end
|
1082
1256
|
|
1257
|
+
@ux_most_recent_filename = @delegate_object[:filename]
|
1258
|
+
|
1259
|
+
# select all UX blocks, rejecting non-primary split
|
1083
1260
|
blocks = select_automatic_ux_blocks(
|
1084
1261
|
all_blocks.reject(&:is_split_rest?)
|
1085
1262
|
)
|
1086
1263
|
return if blocks.empty?
|
1087
1264
|
|
1088
|
-
|
1089
|
-
|
1265
|
+
# collect code from all ux blocks
|
1090
1266
|
(blocks.each.with_object([]) do |block, merged_options|
|
1091
1267
|
command_result_w_e_t_nl =
|
1092
1268
|
code_from_ux_block_to_set_environment_variables(
|
@@ -1097,6 +1273,7 @@ module MarkdownExec
|
|
1097
1273
|
silent: true
|
1098
1274
|
)
|
1099
1275
|
if command_result_w_e_t_nl.failure?
|
1276
|
+
# if a block fails, proceed with next block
|
1100
1277
|
merged_options
|
1101
1278
|
else
|
1102
1279
|
merged_options.push(command_result_w_e_t_nl.new_lines)
|
@@ -1104,8 +1281,39 @@ module MarkdownExec
|
|
1104
1281
|
end).to_a
|
1105
1282
|
end
|
1106
1283
|
|
1284
|
+
# return code resulting from evaluating all automatic VARS blocks in order
|
1285
|
+
def code_from_auto_vars_blocks(
|
1286
|
+
all_blocks,
|
1287
|
+
block_name: @delegate_object[:document_load_vars_block_name]
|
1288
|
+
)
|
1289
|
+
# a block name is required
|
1290
|
+
# do not reload the most recent filename
|
1291
|
+
unless block_name.present? &&
|
1292
|
+
@vars_most_recent_filename != @delegate_object[:filename]
|
1293
|
+
return
|
1294
|
+
end
|
1295
|
+
|
1296
|
+
@vars_most_recent_filename = @delegate_object[:filename]
|
1297
|
+
|
1298
|
+
# select all blocks with the given name
|
1299
|
+
blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
|
1300
|
+
return if blocks.empty?
|
1301
|
+
|
1302
|
+
# collect code for vars from all blocks
|
1303
|
+
(blocks.each.with_object([]) do |block, merged_options|
|
1304
|
+
merged_options.push(
|
1305
|
+
code_from_vars_block_to_set_environment_variables(block)
|
1306
|
+
)
|
1307
|
+
end).to_a
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
def selected_id_name(selected)
|
1311
|
+
selected.id
|
1312
|
+
end
|
1313
|
+
|
1107
1314
|
# parse YAML body defining the UX for a single variable
|
1108
1315
|
# set ENV value for the variable and return code lines for the same
|
1316
|
+
# for BlockType::UX
|
1109
1317
|
def code_from_ux_block_to_set_environment_variables(
|
1110
1318
|
selected, mdoc, inherited_code: nil, force: true, only_default: false,
|
1111
1319
|
silent:
|
@@ -1115,7 +1323,7 @@ module MarkdownExec
|
|
1115
1323
|
exit_prompt = @delegate_object[:prompt_filespec_back]
|
1116
1324
|
|
1117
1325
|
required = mdoc.collect_recursively_required_code(
|
1118
|
-
anyname: selected
|
1326
|
+
anyname: selected_id_name(selected),
|
1119
1327
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
1120
1328
|
label_format_below: @delegate_object[:shell_code_label_format_below],
|
1121
1329
|
block_source: block_source
|
@@ -1129,7 +1337,8 @@ module MarkdownExec
|
|
1129
1337
|
|
1130
1338
|
wwt :fcb, 'a required block', block
|
1131
1339
|
|
1132
|
-
|
1340
|
+
body1 = block.raw_body || block.body
|
1341
|
+
case data = safe_yaml_load(body1.join("\n"))
|
1133
1342
|
when Hash
|
1134
1343
|
export = parse_yaml_of_ux_block(
|
1135
1344
|
data,
|
@@ -1146,6 +1355,8 @@ module MarkdownExec
|
|
1146
1355
|
export.required&.each do |precondition|
|
1147
1356
|
required_variables.push "[[ -z $#{precondition} ]] && exit #{EXIT_STATUS_REQUIRED_EMPTY}"
|
1148
1357
|
end
|
1358
|
+
wwt :required_variables, 'required_variables',
|
1359
|
+
required_variables
|
1149
1360
|
|
1150
1361
|
eval_code = join_array_of_arrays(
|
1151
1362
|
inherited_code, # inherited code
|
@@ -1153,6 +1364,7 @@ module MarkdownExec
|
|
1153
1364
|
required_variables, # test conditions
|
1154
1365
|
required[:code] # current block code
|
1155
1366
|
)
|
1367
|
+
wwt :eval_code, 'eval_code:', eval_code
|
1156
1368
|
if only_default
|
1157
1369
|
command_result_w_e_t_nl =
|
1158
1370
|
ux_block_export_automatic(eval_code, export)
|
@@ -1163,7 +1375,9 @@ module MarkdownExec
|
|
1163
1375
|
command_result_w_e_t_nl =
|
1164
1376
|
ux_block_export_activated(eval_code, export, exit_prompt)
|
1165
1377
|
if command_result_w_e_t_nl.failure?
|
1166
|
-
|
1378
|
+
if command_result_w_e_t_nl.warning&.present? && !silent
|
1379
|
+
warn command_result_w_e_t_nl.warning
|
1380
|
+
end
|
1167
1381
|
return command_result_w_e_t_nl
|
1168
1382
|
end
|
1169
1383
|
end
|
@@ -1174,25 +1388,35 @@ module MarkdownExec
|
|
1174
1388
|
process_command_result_lines(command_result_w_e_t_nl, export,
|
1175
1389
|
required_lines)
|
1176
1390
|
required_lines.concat(command_result_w_e_t_nl.new_lines)
|
1391
|
+
|
1392
|
+
required_lines = annotate_required_lines(
|
1393
|
+
'blk:UX', required_lines, block_name: selected.id
|
1394
|
+
)
|
1395
|
+
|
1177
1396
|
command_result_w_e_t_nl.new_lines = required_lines
|
1178
1397
|
ret_command_result = command_result_w_e_t_nl
|
1179
1398
|
else
|
1180
1399
|
raise "Invalid data type: #{data.inspect}"
|
1181
1400
|
end
|
1182
1401
|
end
|
1402
|
+
wwt :required_lines, required_lines
|
1183
1403
|
|
1184
|
-
(ret_command_result || CommandResult.new(
|
1185
|
-
|
1404
|
+
(ret_command_result || CommandResult.new(
|
1405
|
+
stdout: annotate_required_lines(
|
1406
|
+
'blk:UX', required_lines, block_name: selected.id
|
1407
|
+
)
|
1408
|
+
)).tap do |ret|
|
1409
|
+
wwt :cr, ret, caller.deref
|
1186
1410
|
end
|
1187
1411
|
rescue StandardError
|
1188
1412
|
wwe 'selected:', selected, 'required:', required, 'block:', block,
|
1189
1413
|
'data:', data
|
1190
1414
|
end
|
1191
1415
|
|
1416
|
+
# def
|
1192
1417
|
# sets ENV
|
1193
1418
|
def code_from_vars_block_to_set_environment_variables(selected)
|
1194
1419
|
code_lines = []
|
1195
|
-
# code_lines << '# code_from_vars_block_to_set_environment_variables'
|
1196
1420
|
case data = YAML.load(selected.body.join("\n"))
|
1197
1421
|
when Hash
|
1198
1422
|
data.each do |key, value|
|
@@ -1201,12 +1425,15 @@ module MarkdownExec
|
|
1201
1425
|
|
1202
1426
|
next unless @delegate_object[:menu_vars_set_format].present?
|
1203
1427
|
|
1428
|
+
# in-menu display
|
1204
1429
|
formatted_string = format(@delegate_object[:menu_vars_set_format],
|
1205
1430
|
{ key: key, value: value })
|
1431
|
+
|
1432
|
+
# activity dump
|
1206
1433
|
print string_send_color(formatted_string, :menu_vars_set_color)
|
1207
1434
|
end
|
1208
1435
|
end
|
1209
|
-
code_lines
|
1436
|
+
annotate_required_lines('blk:VARS', code_lines, block_name: selected.id)
|
1210
1437
|
rescue StandardError
|
1211
1438
|
wwe 'selected:', selected, 'data:', data, 'key:', key, 'value:', value,
|
1212
1439
|
'code_lines:', code_lines, 'formatted_string:', formatted_string
|
@@ -1386,7 +1613,7 @@ module MarkdownExec
|
|
1386
1613
|
|
1387
1614
|
if allow_execution
|
1388
1615
|
execute_required_lines(
|
1389
|
-
blockname: selected
|
1616
|
+
blockname: selected_id_name(selected),
|
1390
1617
|
erls: { play_bin: play_bin,
|
1391
1618
|
shell: selected_shell(selected.shell) },
|
1392
1619
|
required_lines: required_lines,
|
@@ -1513,7 +1740,9 @@ module MarkdownExec
|
|
1513
1740
|
if wrap
|
1514
1741
|
line_caps = line_caps.flat_map do |line_cap|
|
1515
1742
|
text = line_cap[:text]
|
1516
|
-
wrapper = StringWrapper.new(
|
1743
|
+
wrapper = StringWrapper.new(
|
1744
|
+
width: screen_width_for_wrapping - line_cap[:indent].length
|
1745
|
+
)
|
1517
1746
|
|
1518
1747
|
if text.length > screen_width_for_wrapping
|
1519
1748
|
# Wrap this text and create line_cap objects for each part
|
@@ -1559,13 +1788,16 @@ module MarkdownExec
|
|
1559
1788
|
decorated = apply_tree_decorations(
|
1560
1789
|
oname, color_method, decor_patterns
|
1561
1790
|
)
|
1562
|
-
|
1563
1791
|
line_obj[:line] = line_obj[:indent] + line_obj[:text]
|
1564
1792
|
|
1565
1793
|
if use_fcb
|
1566
1794
|
fcb.center = center
|
1567
1795
|
fcb.chrome = true
|
1568
|
-
fcb.collapse = collapse.nil?
|
1796
|
+
fcb.collapse = if collapse.nil?
|
1797
|
+
(line_obj[:collapse] == COLLAPSIBLE_TOKEN_COLLAPSE)
|
1798
|
+
else
|
1799
|
+
collapse
|
1800
|
+
end
|
1569
1801
|
fcb.disabled = disabled ? TtyMenu::DISABLE : nil
|
1570
1802
|
fcb.dname = line_obj[:indent] + decorated
|
1571
1803
|
fcb.id = "#{id}.#{index}"
|
@@ -1583,7 +1815,12 @@ module MarkdownExec
|
|
1583
1815
|
fcb = persist_fcb(
|
1584
1816
|
center: center,
|
1585
1817
|
chrome: true,
|
1586
|
-
collapse:
|
1818
|
+
collapse:
|
1819
|
+
if collapse.nil?
|
1820
|
+
(line_obj[:collapse] == COLLAPSIBLE_TOKEN_COLLAPSE)
|
1821
|
+
else
|
1822
|
+
collapse
|
1823
|
+
end,
|
1587
1824
|
disabled: disabled ? TtyMenu::DISABLE : nil,
|
1588
1825
|
dname: line_obj[:indent] + decorated,
|
1589
1826
|
id: "#{id}.#{index}",
|
@@ -1613,53 +1850,65 @@ module MarkdownExec
|
|
1613
1850
|
# @param use_chrome [Boolean] Indicates if the chrome styling should
|
1614
1851
|
# be applied.
|
1615
1852
|
def create_and_add_chrome_blocks(blocks, fcb, id: '', init_ids: false)
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1853
|
+
index = nil
|
1854
|
+
|
1855
|
+
unless (criteria = fcb.criteria)
|
1856
|
+
HashDelegator.chrome_block_criteria.each_with_index do |criteria1, index1|
|
1857
|
+
# rubocop:disable Lint/UselessAssignment
|
1858
|
+
if !@delegate_object[criteria1[:match]].present? ||
|
1859
|
+
!(match_data = fcb.body[0].match @delegate_object[criteria1[:match]])
|
1860
|
+
next
|
1861
|
+
end
|
1862
|
+
# rubocop:enable Lint/UselessAssignment
|
1863
|
+
|
1864
|
+
criteria = criteria1
|
1865
|
+
index = index1
|
1866
|
+
break
|
1620
1867
|
end
|
1868
|
+
end
|
1621
1869
|
|
1622
|
-
|
1623
|
-
# expand references only if block is recognized (not a comment)
|
1624
|
-
yield if block_given?
|
1870
|
+
return unless criteria
|
1625
1871
|
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
)
|
1630
|
-
end
|
1872
|
+
if block_given?
|
1873
|
+
# expand references only if block is recognized (not a comment)
|
1874
|
+
yield if block_given?
|
1631
1875
|
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
center: criteria[:center] &&
|
1636
|
-
@delegate_object[criteria[:center]],
|
1637
|
-
|
1638
|
-
collapse: case fcb.collapse_token
|
1639
|
-
when COLLAPSIBLE_TOKEN_COLLAPSE
|
1640
|
-
true
|
1641
|
-
when COLLAPSIBLE_TOKEN_EXPAND
|
1642
|
-
false
|
1643
|
-
else
|
1644
|
-
false
|
1645
|
-
end,
|
1646
|
-
|
1647
|
-
color_method: criteria[:color] &&
|
1648
|
-
@delegate_object[criteria[:color]].to_sym,
|
1649
|
-
decor_patterns:
|
1650
|
-
@decor_patterns_from_delegate_object_for_block_create,
|
1651
|
-
disabled: !(criteria[:collapsible] && @delegate_object[criteria[:collapsible]]),
|
1652
|
-
fcb: fcb,
|
1653
|
-
id: "#{id}.#{index}",
|
1654
|
-
format_option: criteria[:format] &&
|
1655
|
-
@delegate_object[criteria[:format]],
|
1656
|
-
level: criteria[:level],
|
1657
|
-
match_data: mbody,
|
1658
|
-
type: criteria[:type],
|
1659
|
-
wrap: criteria[:wrap]
|
1876
|
+
# parse multiline to capture output of variable expansion
|
1877
|
+
match_data = fcb.body[0].match Regexp.new(
|
1878
|
+
@delegate_object[criteria[:match]], Regexp::MULTILINE
|
1660
1879
|
)
|
1661
|
-
break
|
1662
1880
|
end
|
1881
|
+
|
1882
|
+
create_and_add_chrome_block(
|
1883
|
+
blocks: blocks,
|
1884
|
+
case_conversion: criteria[:case_conversion],
|
1885
|
+
center: criteria[:center] &&
|
1886
|
+
@delegate_object[criteria[:center]],
|
1887
|
+
|
1888
|
+
collapse: case fcb.collapse_token
|
1889
|
+
when COLLAPSIBLE_TOKEN_COLLAPSE
|
1890
|
+
true
|
1891
|
+
when COLLAPSIBLE_TOKEN_EXPAND
|
1892
|
+
false
|
1893
|
+
else
|
1894
|
+
false
|
1895
|
+
end,
|
1896
|
+
|
1897
|
+
color_method: criteria[:color] &&
|
1898
|
+
@delegate_object[criteria[:color]].to_sym,
|
1899
|
+
decor_patterns:
|
1900
|
+
@decor_patterns_from_delegate_object_for_block_create,
|
1901
|
+
disabled: !(criteria[:collapsible] &&
|
1902
|
+
@delegate_object[criteria[:collapsible]]),
|
1903
|
+
fcb: fcb,
|
1904
|
+
id: "#{id}.#{index}",
|
1905
|
+
format_option: criteria[:format] &&
|
1906
|
+
@delegate_object[criteria[:format]],
|
1907
|
+
level: criteria[:level],
|
1908
|
+
match_data: match_data,
|
1909
|
+
type: criteria[:type],
|
1910
|
+
wrap: criteria[:wrap]
|
1911
|
+
)
|
1663
1912
|
end
|
1664
1913
|
|
1665
1914
|
def create_divider(position, source_id: '')
|
@@ -1668,8 +1917,10 @@ module MarkdownExec
|
|
1668
1917
|
else
|
1669
1918
|
:menu_final_divider
|
1670
1919
|
end
|
1671
|
-
oname = format(
|
1672
|
-
|
1920
|
+
oname = format(
|
1921
|
+
@delegate_object[:menu_divider_format],
|
1922
|
+
HashDelegator.safeval(@delegate_object[divider_key])
|
1923
|
+
)
|
1673
1924
|
|
1674
1925
|
persist_fcb(
|
1675
1926
|
chrome: true,
|
@@ -1996,11 +2247,6 @@ module MarkdownExec
|
|
1996
2247
|
|
1997
2248
|
LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
1998
2249
|
|
1999
|
-
# from CLI
|
2000
|
-
elsif selected.nickname == @delegate_object[:menu_option_exit_name][:line]
|
2001
|
-
debounce_reset
|
2002
|
-
LoadFileLinkState.new(LoadFile::EXIT, link_state)
|
2003
|
-
|
2004
2250
|
elsif @menu_user_clicked_back_link
|
2005
2251
|
debounce_reset
|
2006
2252
|
LoadFileLinkState.new(
|
@@ -2037,6 +2283,7 @@ module MarkdownExec
|
|
2037
2283
|
selected,
|
2038
2284
|
@dml_mdoc,
|
2039
2285
|
inherited_code: @dml_link_state.inherited_lines,
|
2286
|
+
only_default: false,
|
2040
2287
|
silent: true
|
2041
2288
|
)
|
2042
2289
|
### TBD if command_result_w_e_t_nl.failure?
|
@@ -2154,16 +2401,19 @@ module MarkdownExec
|
|
2154
2401
|
link_state: LinkState.new, block_source: {}
|
2155
2402
|
)
|
2156
2403
|
link_block_data = HashDelegator.parse_yaml_data_from_body(link_block_body)
|
2404
|
+
|
2157
2405
|
## collect blocks specified by block
|
2158
2406
|
#
|
2159
2407
|
if mdoc
|
2160
2408
|
code_info = mdoc.collect_recursively_required_code(
|
2161
|
-
anyname: selected
|
2409
|
+
anyname: selected_id_name(selected),
|
2410
|
+
block_source: block_source,
|
2162
2411
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
2163
|
-
label_format_below: @delegate_object[:shell_code_label_format_below]
|
2164
|
-
|
2412
|
+
label_format_below: @delegate_object[:shell_code_label_format_below]
|
2413
|
+
)
|
2414
|
+
code_lines = annotate_required_lines(
|
2415
|
+
'blk:LINK', code_info[:code], block_name: selected.id
|
2165
2416
|
)
|
2166
|
-
code_lines = code_info[:code]
|
2167
2417
|
block_names = code_info[:block_names]
|
2168
2418
|
dependencies = code_info[:dependencies]
|
2169
2419
|
else
|
@@ -2198,9 +2448,8 @@ module MarkdownExec
|
|
2198
2448
|
|
2199
2449
|
# if an eval link block, evaluate code_lines and return its standard output
|
2200
2450
|
#
|
2201
|
-
if link_block_data.fetch(LinkKeys::EVAL,
|
2202
|
-
|
2203
|
-
false)
|
2451
|
+
if link_block_data.fetch(LinkKeys::EVAL, false) ||
|
2452
|
+
link_block_data.fetch(LinkKeys::EXEC, false)
|
2204
2453
|
code_lines += link_block_data_eval(
|
2205
2454
|
link_state, code_lines, selected, link_block_data,
|
2206
2455
|
block_source: block_source,
|
@@ -2217,6 +2466,10 @@ module MarkdownExec
|
|
2217
2466
|
nil
|
2218
2467
|
) || link_block_data.fetch(LinkKeys::BLOCK, nil) || ''
|
2219
2468
|
|
2469
|
+
code_lines = annotate_required_lines(
|
2470
|
+
'blk:LINK', code_lines, block_name: selected.id
|
2471
|
+
)
|
2472
|
+
|
2220
2473
|
if link_block_data[LinkKeys::RETURN]
|
2221
2474
|
pop_add_current_code_to_head_and_trigger_load(
|
2222
2475
|
link_state, block_names, code_lines,
|
@@ -2229,9 +2482,9 @@ module MarkdownExec
|
|
2229
2482
|
curr_block_name: selected.pub_name,
|
2230
2483
|
curr_document_filename: @delegate_object[:filename],
|
2231
2484
|
inherited_block_names:
|
2232
|
-
|
2485
|
+
((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2233
2486
|
inherited_dependencies:
|
2234
|
-
|
2487
|
+
(link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2235
2488
|
inherited_lines: HashDelegator.flatten_and_compact_arrays(
|
2236
2489
|
link_state&.inherited_lines, code_lines
|
2237
2490
|
),
|
@@ -2239,7 +2492,12 @@ module MarkdownExec
|
|
2239
2492
|
next_block_name: next_block_name,
|
2240
2493
|
next_document_filename: next_document_filename,
|
2241
2494
|
next_keep_code: next_keep_code,
|
2242
|
-
next_load_file:
|
2495
|
+
next_load_file:
|
2496
|
+
if next_document_filename == @delegate_object[:filename]
|
2497
|
+
LoadFile::REUSE
|
2498
|
+
else
|
2499
|
+
LoadFile::LOAD
|
2500
|
+
end
|
2243
2501
|
)
|
2244
2502
|
end
|
2245
2503
|
end
|
@@ -2279,7 +2537,9 @@ module MarkdownExec
|
|
2279
2537
|
block_data['view'] || view,
|
2280
2538
|
NamedCaptureExtractor.extract_named_group_match_data(
|
2281
2539
|
file.match(
|
2282
|
-
Regexp.new(
|
2540
|
+
Regexp.new(
|
2541
|
+
block_data['filename_pattern'] || filename_pattern
|
2542
|
+
)
|
2283
2543
|
)
|
2284
2544
|
)
|
2285
2545
|
),
|
@@ -2306,9 +2566,11 @@ module MarkdownExec
|
|
2306
2566
|
reason = 'default Load mode'
|
2307
2567
|
mode = LoadMode::APPEND
|
2308
2568
|
end
|
2569
|
+
wwt :state, '@dml_block_state:', @dml_block_state
|
2309
2570
|
|
2310
2571
|
OpenStruct.new(
|
2311
|
-
code: code,
|
2572
|
+
code: annotate_required_lines('blk:LOAD', code,
|
2573
|
+
block_name: selected.id),
|
2312
2574
|
mode: mode,
|
2313
2575
|
reason: reason
|
2314
2576
|
)
|
@@ -2325,7 +2587,7 @@ module MarkdownExec
|
|
2325
2587
|
def execute_block_type_port_code_lines(mdoc:, selected:, block_source:,
|
2326
2588
|
link_state: LinkState.new)
|
2327
2589
|
required = mdoc.collect_recursively_required_code(
|
2328
|
-
anyname: selected
|
2590
|
+
anyname: selected_id_name(selected),
|
2329
2591
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
2330
2592
|
label_format_below: @delegate_object[:shell_code_label_format_below],
|
2331
2593
|
block_source: block_source
|
@@ -2356,15 +2618,21 @@ module MarkdownExec
|
|
2356
2618
|
|
2357
2619
|
if selected[:type] == BlockType::OPTS
|
2358
2620
|
# body of blocks is returned as a list of lines to be read an YAML
|
2359
|
-
HashDelegator.flatten_and_compact_arrays(
|
2621
|
+
HashDelegator.flatten_and_compact_arrays(
|
2622
|
+
required[:blocks].map(&:body).flatten(1)
|
2623
|
+
)
|
2360
2624
|
else
|
2361
2625
|
code_lines = if selected.type == BlockType::VARS
|
2362
2626
|
code_from_vars_block_to_set_environment_variables(selected)
|
2363
2627
|
else
|
2364
2628
|
[]
|
2365
2629
|
end
|
2366
|
-
HashDelegator.flatten_and_compact_arrays(
|
2367
|
-
|
2630
|
+
HashDelegator.flatten_and_compact_arrays(
|
2631
|
+
link_state&.inherited_lines,
|
2632
|
+
annotate_required_lines(
|
2633
|
+
'blk:PORT', required[:code] + code_lines, block_name: selected.id
|
2634
|
+
)
|
2635
|
+
)
|
2368
2636
|
end
|
2369
2637
|
end
|
2370
2638
|
|
@@ -2383,6 +2651,11 @@ module MarkdownExec
|
|
2383
2651
|
save_filespec_from_expression(directory_glob).tap do |save_filespec|
|
2384
2652
|
if save_filespec && save_filespec != exit_prompt
|
2385
2653
|
begin
|
2654
|
+
if @delegate_object[:document_save_make_directory]
|
2655
|
+
# make directory if it doesn't exist
|
2656
|
+
FileUtils.mkdir_p(File.dirname(save_filespec))
|
2657
|
+
end
|
2658
|
+
|
2386
2659
|
File.write(save_filespec,
|
2387
2660
|
HashDelegator.join_code_lines(code_lines))
|
2388
2661
|
rescue Errno::ENOENT
|
@@ -2425,8 +2698,10 @@ module MarkdownExec
|
|
2425
2698
|
end
|
2426
2699
|
|
2427
2700
|
# Handle stdin stream
|
2428
|
-
input_thread = handle_stream(
|
2429
|
-
|
2701
|
+
input_thread = handle_stream(
|
2702
|
+
stream: $stdin,
|
2703
|
+
file_type: ExecutionStreams::STD_IN
|
2704
|
+
) do |line|
|
2430
2705
|
stdin.puts(line)
|
2431
2706
|
yield line, nil, nil, exec_thread if block_given?
|
2432
2707
|
end
|
@@ -2555,6 +2830,7 @@ module MarkdownExec
|
|
2555
2830
|
end
|
2556
2831
|
|
2557
2832
|
def expand_references!(fcb, link_state)
|
2833
|
+
wwt :expand_references, 'fcb.id', fcb.id, 'link_state:', link_state
|
2558
2834
|
# options expansions
|
2559
2835
|
expand_variable_references!(
|
2560
2836
|
blocks: [fcb],
|
@@ -2562,8 +2838,9 @@ module MarkdownExec
|
|
2562
2838
|
group_name: :payload,
|
2563
2839
|
initial_code_required: false,
|
2564
2840
|
link_state: link_state,
|
2565
|
-
pattern:
|
2566
|
-
|
2841
|
+
pattern:
|
2842
|
+
@delegate_object[:option_expansion_expression_regexp].present? &&
|
2843
|
+
Regexp.new(@delegate_object[:option_expansion_expression_regexp])
|
2567
2844
|
)
|
2568
2845
|
|
2569
2846
|
# variable expansions
|
@@ -2572,7 +2849,8 @@ module MarkdownExec
|
|
2572
2849
|
echo_formatter: lambda do |variable|
|
2573
2850
|
%(echo "$#{variable}")
|
2574
2851
|
end,
|
2575
|
-
group_name:
|
2852
|
+
group_name:
|
2853
|
+
@delegate_object[:variable_expansion_name_capture_group]&.to_sym,
|
2576
2854
|
initial_code_required: false,
|
2577
2855
|
link_state: link_state,
|
2578
2856
|
pattern: options_variable_expansion_regexp
|
@@ -2582,12 +2860,15 @@ module MarkdownExec
|
|
2582
2860
|
expand_variable_references!(
|
2583
2861
|
blocks: [fcb],
|
2584
2862
|
echo_formatter: lambda { |command| command },
|
2585
|
-
group_name:
|
2863
|
+
group_name:
|
2864
|
+
@delegate_object[:command_substitution_name_capture_group]&.to_sym,
|
2586
2865
|
initial_code_required: false,
|
2587
2866
|
link_state: link_state,
|
2588
2867
|
pattern: options_command_substitution_regexp
|
2589
2868
|
)
|
2590
2869
|
# no return
|
2870
|
+
rescue StandardError
|
2871
|
+
wwe 'fcb:', fcb, 'link_state:', link_state
|
2591
2872
|
end
|
2592
2873
|
|
2593
2874
|
def expand_variable_references!(
|
@@ -2623,55 +2904,88 @@ module MarkdownExec
|
|
2623
2904
|
# no return
|
2624
2905
|
end
|
2625
2906
|
|
2626
|
-
def
|
2627
|
-
bash_script_lines, export,
|
2907
|
+
def ux_block_eval_for_export(
|
2908
|
+
bash_script_lines, export,
|
2909
|
+
data:,
|
2910
|
+
first_only: false,
|
2911
|
+
force:,
|
2912
|
+
printf_expand: false,
|
2913
|
+
silent:,
|
2914
|
+
string: nil
|
2628
2915
|
)
|
2629
|
-
wwp
|
2630
2916
|
exportable = true
|
2631
2917
|
command_result = nil
|
2632
2918
|
new_lines = []
|
2633
|
-
export_string = string.nil? ?
|
2919
|
+
export_string = string.nil? ? data : string
|
2920
|
+
expander = ->(expression) { %(printf '%s' "#{expression}") }
|
2921
|
+
|
2634
2922
|
case export_string
|
2635
2923
|
when String, Integer, Float, TrueClass, FalseClass
|
2636
2924
|
command_result, exportable, = output_from_adhoc_bash_script_file(
|
2637
2925
|
join_array_of_arrays(
|
2638
2926
|
bash_script_lines,
|
2639
|
-
|
2927
|
+
printf_expand ? expander.call(export_string) : [export_string]
|
2640
2928
|
),
|
2641
2929
|
export,
|
2642
2930
|
force: force
|
2643
2931
|
)
|
2644
2932
|
if command_result.exit_status == EXIT_STATUS_REQUIRED_EMPTY
|
2645
2933
|
exportable = false
|
2646
|
-
|
2934
|
+
unless silent
|
2935
|
+
command_result.warning = warning_required_empty(export)
|
2936
|
+
end
|
2647
2937
|
else
|
2938
|
+
# store the transformed value in ENV
|
2648
2939
|
EnvInterface.set(export.name, command_result.stdout.to_s)
|
2940
|
+
|
2649
2941
|
new_lines << { name: export.name, force: force,
|
2650
2942
|
text: command_result.stdout }
|
2651
2943
|
end
|
2652
2944
|
|
2653
2945
|
when Hash
|
2946
|
+
required_lines = []
|
2947
|
+
|
2654
2948
|
# each item in the hash is a variable name and value
|
2655
2949
|
export_string.each do |name, expression|
|
2656
2950
|
command_result, = output_from_adhoc_bash_script_file(
|
2657
2951
|
join_array_of_arrays(
|
2658
2952
|
bash_script_lines,
|
2659
|
-
|
2953
|
+
required_lines,
|
2954
|
+
printf_expand ? expander.call(expression) : [expression]
|
2660
2955
|
),
|
2661
2956
|
export,
|
2662
2957
|
force: force
|
2663
2958
|
)
|
2664
2959
|
if command_result.exit_status == EXIT_STATUS_REQUIRED_EMPTY
|
2665
|
-
|
2960
|
+
unless silent
|
2961
|
+
command_result.warning = warning_required_empty(export)
|
2962
|
+
end
|
2666
2963
|
else
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2964
|
+
transformed = command_result.stdout.to_s
|
2965
|
+
|
2966
|
+
# code for subsequent expression evaluations
|
2967
|
+
required_lines << code_line_to_assign_a_variable(
|
2968
|
+
name, transformed, force: force
|
2969
|
+
)
|
2970
|
+
|
2971
|
+
if variable_is_exportable(name)
|
2972
|
+
# store the transformed value in ENV
|
2973
|
+
EnvInterface.set(name, transformed)
|
2974
|
+
|
2975
|
+
new_lines << { name: name, force: force,
|
2976
|
+
text: command_result.stdout }
|
2977
|
+
end
|
2670
2978
|
end
|
2979
|
+
|
2980
|
+
break if first_only
|
2671
2981
|
end
|
2982
|
+
else
|
2983
|
+
# do nothing
|
2672
2984
|
end
|
2673
2985
|
|
2674
2986
|
[command_result, exportable, new_lines]
|
2987
|
+
rescue StandardError
|
2988
|
+
wwe bash_script_lines, export, force, silent, string
|
2675
2989
|
end
|
2676
2990
|
|
2677
2991
|
# Retrieves a specific data symbol from the delegate object,
|
@@ -2711,8 +3025,13 @@ module MarkdownExec
|
|
2711
3025
|
# fallback to @dml_menu_blocks if not found.
|
2712
3026
|
def find_block_by_name(blocks, block_name)
|
2713
3027
|
match_block = ->(item) do
|
2714
|
-
[
|
2715
|
-
|
3028
|
+
[
|
3029
|
+
selected_id_name(item),
|
3030
|
+
item.pub_name,
|
3031
|
+
item.nickname,
|
3032
|
+
item.oname,
|
3033
|
+
item.s2title
|
3034
|
+
].include?(block_name)
|
2716
3035
|
end
|
2717
3036
|
|
2718
3037
|
@dml_blocks_in_file.find(&match_block) ||
|
@@ -2759,7 +3078,9 @@ module MarkdownExec
|
|
2759
3078
|
end
|
2760
3079
|
|
2761
3080
|
def format_echo_command(payload)
|
2762
|
-
payload_match = payload.match(
|
3081
|
+
payload_match = payload.match(
|
3082
|
+
@delegate_object[:option_expansion_payload_regexp]
|
3083
|
+
)
|
2763
3084
|
variable = payload_match[:option]
|
2764
3085
|
property = payload_match[:property]
|
2765
3086
|
|
@@ -2807,6 +3128,20 @@ module MarkdownExec
|
|
2807
3128
|
string_send_color(formatted_string, color_sym)
|
2808
3129
|
end
|
2809
3130
|
|
3131
|
+
# for inherited code comments
|
3132
|
+
# for external automation
|
3133
|
+
def formatted_block_name(block_name,
|
3134
|
+
format_sym = :publish_block_name_format)
|
3135
|
+
format(
|
3136
|
+
@delegate_object[format_sym],
|
3137
|
+
{ block: block_name,
|
3138
|
+
document: @delegate_object[:filename],
|
3139
|
+
time: Time.now.utc.strftime(
|
3140
|
+
@delegate_object[:publish_time_format]
|
3141
|
+
) }
|
3142
|
+
)
|
3143
|
+
end
|
3144
|
+
|
2810
3145
|
# Expand expression if it contains format specifiers
|
2811
3146
|
def formatted_expression(expr)
|
2812
3147
|
expr.include?('%{') ? format_expression(expr) : expr
|
@@ -2994,6 +3329,7 @@ module MarkdownExec
|
|
2994
3329
|
) do |nested_line|
|
2995
3330
|
next if nested_line.nil?
|
2996
3331
|
|
3332
|
+
wwt :iterlines, 'nested_line:', nested_line
|
2997
3333
|
update_line_and_block_state(
|
2998
3334
|
nested_line, state, selected_types,
|
2999
3335
|
source_id: "ItrBlkFrmNstFls:#{index}¤#{nested_line.filename}:#{nested_line.index}",
|
@@ -3002,6 +3338,8 @@ module MarkdownExec
|
|
3002
3338
|
|
3003
3339
|
index += 1
|
3004
3340
|
end
|
3341
|
+
rescue StandardError
|
3342
|
+
wwe $!, 'state:', state, 'nested_line:', nested_line
|
3005
3343
|
end
|
3006
3344
|
|
3007
3345
|
def iter_source_blocks(source, source_id: nil, &block)
|
@@ -3036,8 +3374,9 @@ module MarkdownExec
|
|
3036
3374
|
|
3037
3375
|
def link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
3038
3376
|
block_source:, shell:)
|
3039
|
-
all_code = HashDelegator.flatten_and_compact_arrays(
|
3040
|
-
|
3377
|
+
all_code = HashDelegator.flatten_and_compact_arrays(
|
3378
|
+
link_state&.inherited_lines, code_lines
|
3379
|
+
)
|
3041
3380
|
output_lines = []
|
3042
3381
|
|
3043
3382
|
Tempfile.open do |file|
|
@@ -3171,9 +3510,10 @@ module MarkdownExec
|
|
3171
3510
|
|
3172
3511
|
# Loads and updates auto options for document blocks if the current filename has changed.
|
3173
3512
|
#
|
3174
|
-
# This method checks if the delegate object specifies a document load
|
3175
|
-
#
|
3176
|
-
#
|
3513
|
+
# This method checks if the delegate object specifies a document load
|
3514
|
+
# options block name and if the filename has been updated. It then
|
3515
|
+
# selects the appropriate blocks, collects their dependencies, processes
|
3516
|
+
# their options, and updates the menu base with the merged options.
|
3177
3517
|
#
|
3178
3518
|
# @param all_blocks [Array] An array of all block elements.
|
3179
3519
|
# @param mdoc [Object] The document object managing dependencies and options.
|
@@ -3211,27 +3551,6 @@ module MarkdownExec
|
|
3211
3551
|
true
|
3212
3552
|
end
|
3213
3553
|
|
3214
|
-
def load_auto_vars_block(
|
3215
|
-
all_blocks,
|
3216
|
-
block_name: @delegate_object[:document_load_vars_block_name]
|
3217
|
-
)
|
3218
|
-
unless block_name.present? &&
|
3219
|
-
@vars_most_recent_filename != @delegate_object[:filename]
|
3220
|
-
return
|
3221
|
-
end
|
3222
|
-
|
3223
|
-
blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
|
3224
|
-
return if blocks.empty?
|
3225
|
-
|
3226
|
-
@vars_most_recent_filename = @delegate_object[:filename]
|
3227
|
-
|
3228
|
-
(blocks.each.with_object([]) do |block, merged_options|
|
3229
|
-
merged_options.push(
|
3230
|
-
code_from_vars_block_to_set_environment_variables(block)
|
3231
|
-
)
|
3232
|
-
end).to_a
|
3233
|
-
end
|
3234
|
-
|
3235
3554
|
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [],
|
3236
3555
|
prior_answer: nil)
|
3237
3556
|
if @delegate_object[:block_name].present?
|
@@ -3252,30 +3571,6 @@ module MarkdownExec
|
|
3252
3571
|
SelectedBlockMenuState.new(block, source, state)
|
3253
3572
|
end
|
3254
3573
|
|
3255
|
-
def load_document_shell_block(all_blocks, mdoc: nil)
|
3256
|
-
block_name = @delegate_object[:document_load_shell_block_name]
|
3257
|
-
unless block_name.present? &&
|
3258
|
-
@shell_most_recent_filename != @delegate_object[:filename]
|
3259
|
-
return
|
3260
|
-
end
|
3261
|
-
|
3262
|
-
fcb = HashDelegator.block_find(all_blocks, :oname, block_name)
|
3263
|
-
return unless fcb
|
3264
|
-
|
3265
|
-
@shell_most_recent_filename = @delegate_object[:filename]
|
3266
|
-
|
3267
|
-
if mdoc
|
3268
|
-
mdoc.collect_recursively_required_code(
|
3269
|
-
anyname: fcb.pub_name,
|
3270
|
-
label_format_above: @delegate_object[:shell_code_label_format_above],
|
3271
|
-
label_format_below: @delegate_object[:shell_code_label_format_below],
|
3272
|
-
block_source: block_source
|
3273
|
-
)[:code]
|
3274
|
-
else
|
3275
|
-
fcb.body
|
3276
|
-
end
|
3277
|
-
end
|
3278
|
-
|
3279
3574
|
# format + glob + select for file in load block
|
3280
3575
|
# name has references to ENV vars and doc and batch vars
|
3281
3576
|
# incl. timestamp
|
@@ -3367,32 +3662,21 @@ module MarkdownExec
|
|
3367
3662
|
reload_blocks = true
|
3368
3663
|
end
|
3369
3664
|
|
3370
|
-
#
|
3665
|
+
# return code resulting from evaluating all SHELL, UX, VARS blocks;
|
3666
|
+
# each set in sequence; with its own order
|
3371
3667
|
#
|
3372
|
-
if (code_lines =
|
3373
|
-
|
3374
|
-
|
3375
|
-
|
3376
|
-
|
3377
|
-
|
3378
|
-
|
3379
|
-
#
|
3380
|
-
if (code_lines = code_from_automatic_ux_blocks(all_blocks, mdoc))
|
3381
|
-
new_code = HashDelegator.flatten_and_compact_arrays(link_state.inherited_lines,
|
3382
|
-
code_lines)
|
3383
|
-
next_state_set_code(nil, link_state, new_code)
|
3384
|
-
link_state.inherited_lines = new_code
|
3385
|
-
reload_blocks = true
|
3386
|
-
end
|
3387
|
-
|
3388
|
-
# load document vars block
|
3389
|
-
#
|
3390
|
-
if (code_lines = load_auto_vars_block(all_blocks))
|
3391
|
-
new_code = HashDelegator.flatten_and_compact_arrays(link_state.inherited_lines,
|
3392
|
-
code_lines)
|
3668
|
+
if (code_lines = code_from_auto_blocks(
|
3669
|
+
all_blocks,
|
3670
|
+
default_only: true,
|
3671
|
+
mdoc: mdoc
|
3672
|
+
))&.select_by(:empty?, false)&.compact&.count&.positive?
|
3673
|
+
new_code = code_lines
|
3674
|
+
wwt :code_lines, 'code_lines:', code_lines
|
3393
3675
|
next_state_set_code(nil, link_state, new_code)
|
3394
3676
|
link_state.inherited_lines = new_code
|
3395
3677
|
reload_blocks = true
|
3678
|
+
else
|
3679
|
+
link_state&.inherited_lines
|
3396
3680
|
end
|
3397
3681
|
|
3398
3682
|
if reload_blocks
|
@@ -3448,6 +3732,7 @@ module MarkdownExec
|
|
3448
3732
|
[all_blocks, menu_blocks, mdoc]
|
3449
3733
|
end
|
3450
3734
|
|
3735
|
+
# enable scroll targets in long sequences of inactive lines
|
3451
3736
|
def handle_consecutive_inactive_items!(menu_blocks)
|
3452
3737
|
consecutive_inactive_count = 0
|
3453
3738
|
menu_blocks.each do |fcb|
|
@@ -3455,7 +3740,10 @@ module MarkdownExec
|
|
3455
3740
|
consecutive_inactive_count = 0
|
3456
3741
|
else
|
3457
3742
|
consecutive_inactive_count += 1
|
3458
|
-
if (consecutive_inactive_count %
|
3743
|
+
if (consecutive_inactive_count %
|
3744
|
+
(@delegate_object[:select_page_height] /
|
3745
|
+
@delegate_object[:select_page_ratio])
|
3746
|
+
).zero?
|
3459
3747
|
fcb.disabled = TtyMenu::ENABLE
|
3460
3748
|
fcb.is_enabled_but_inactive = true
|
3461
3749
|
end
|
@@ -3463,7 +3751,7 @@ module MarkdownExec
|
|
3463
3751
|
end
|
3464
3752
|
end
|
3465
3753
|
|
3466
|
-
def menu_add_disabled_option(document_glob)
|
3754
|
+
def menu_add_disabled_option(document_glob, id)
|
3467
3755
|
raise unless document_glob.present?
|
3468
3756
|
raise if @dml_menu_blocks.nil?
|
3469
3757
|
|
@@ -3473,13 +3761,16 @@ module MarkdownExec
|
|
3473
3761
|
#
|
3474
3762
|
return unless block.nil?
|
3475
3763
|
|
3764
|
+
dname = HashDelegator.new(@delegate_object).string_send_color(
|
3765
|
+
document_glob, :menu_inherited_lines_color
|
3766
|
+
)
|
3767
|
+
|
3476
3768
|
chrome_block = persist_fcb(
|
3477
3769
|
chrome: true,
|
3478
3770
|
disabled: TtyMenu::DISABLE,
|
3479
|
-
dname:
|
3480
|
-
document_glob, :menu_inherited_lines_color
|
3481
|
-
),
|
3771
|
+
dname: dname,
|
3482
3772
|
# 2025-01-03 menu item is disabled ∴ does not need a recall id
|
3773
|
+
id: id,
|
3483
3774
|
oname: formatted_name
|
3484
3775
|
)
|
3485
3776
|
|
@@ -3749,7 +4040,8 @@ module MarkdownExec
|
|
3749
4040
|
end
|
3750
4041
|
end
|
3751
4042
|
|
3752
|
-
# This method handles the back-link operation in
|
4043
|
+
# This method handles the back-link operation in
|
4044
|
+
# the Markdown execution context.
|
3753
4045
|
# It updates the history state for the next block.
|
3754
4046
|
#
|
3755
4047
|
# @return [LinkState] An object indicating the state for
|
@@ -3804,12 +4096,13 @@ module MarkdownExec
|
|
3804
4096
|
multiline = fcb.indented_decorated ||
|
3805
4097
|
(fcb.indent + (fcb.s1decorated || fcb.dname))
|
3806
4098
|
|
3807
|
-
fcb.name = multiline.
|
4099
|
+
fcb.name = multiline.split("\n",
|
4100
|
+
-1).each_with_index.map do |line, index|
|
3808
4101
|
if fcb.fetch(:disabled, nil).nil?
|
3809
4102
|
index.zero? ? active : inactive
|
3810
4103
|
else
|
3811
4104
|
inactive
|
3812
|
-
end + line
|
4105
|
+
end + line
|
3813
4106
|
end.join("\n")
|
3814
4107
|
|
3815
4108
|
fcb.value = fcb.id || fcb.name.split("\n").first
|
@@ -3855,8 +4148,10 @@ module MarkdownExec
|
|
3855
4148
|
raise StandardError, $!
|
3856
4149
|
end
|
3857
4150
|
|
3858
|
-
def process_string_array(
|
3859
|
-
|
4151
|
+
def process_string_array(
|
4152
|
+
arr, begin_pattern: nil, end_pattern: nil, scan1: nil,
|
4153
|
+
format1: nil, name: ''
|
4154
|
+
)
|
3860
4155
|
in_block = !begin_pattern.present?
|
3861
4156
|
collected_lines = []
|
3862
4157
|
|
@@ -3909,6 +4204,9 @@ module MarkdownExec
|
|
3909
4204
|
|
3910
4205
|
@allowed_execution_block = @prior_execution_block
|
3911
4206
|
true
|
4207
|
+
rescue TTY::Reader::InputInterrupt
|
4208
|
+
# treat as denial
|
4209
|
+
false
|
3912
4210
|
end
|
3913
4211
|
|
3914
4212
|
def prompt_for_command(prompt)
|
@@ -3992,6 +4290,9 @@ module MarkdownExec
|
|
3992
4290
|
end
|
3993
4291
|
|
3994
4292
|
sel == MenuOptions::YES
|
4293
|
+
rescue TTY::Reader::InputInterrupt
|
4294
|
+
# treat as denial
|
4295
|
+
false
|
3995
4296
|
end
|
3996
4297
|
|
3997
4298
|
def prompt_margin_left_text
|
@@ -4016,7 +4317,14 @@ module MarkdownExec
|
|
4016
4317
|
menu.choice @delegate_object[:prompt_yes]
|
4017
4318
|
menu.choice @delegate_object[:prompt_exit]
|
4018
4319
|
end
|
4019
|
-
sel == @delegate_object[:prompt_exit]
|
4320
|
+
sel == if @delegate_object[:prompt_exit]
|
4321
|
+
MenuState::EXIT
|
4322
|
+
else
|
4323
|
+
MenuState::CONTINUE
|
4324
|
+
end
|
4325
|
+
rescue TTY::Reader::InputInterrupt
|
4326
|
+
# treat as denial
|
4327
|
+
MenuState::EXIT
|
4020
4328
|
end
|
4021
4329
|
|
4022
4330
|
# public
|
@@ -4045,6 +4353,9 @@ module MarkdownExec
|
|
4045
4353
|
end
|
4046
4354
|
end
|
4047
4355
|
end
|
4356
|
+
rescue TTY::Reader::InputInterrupt
|
4357
|
+
# treat as no selection
|
4358
|
+
nil
|
4048
4359
|
end
|
4049
4360
|
|
4050
4361
|
# user prompt to exit if the menu will be displayed again
|
@@ -4081,15 +4392,6 @@ module MarkdownExec
|
|
4081
4392
|
end
|
4082
4393
|
end
|
4083
4394
|
|
4084
|
-
# Handle expression with wildcard characters
|
4085
|
-
# allow user to select or enter
|
4086
|
-
def puts_gets_oprompt_(filespec)
|
4087
|
-
puts format(@delegate_object[:prompt_show_expr_format],
|
4088
|
-
{ expr: filespec })
|
4089
|
-
puts @delegate_object[:prompt_enter_filespec]
|
4090
|
-
gets.chomp
|
4091
|
-
end
|
4092
|
-
|
4093
4395
|
def read_saved_assets_for_history_table(
|
4094
4396
|
asset: nil,
|
4095
4397
|
filename: nil,
|
@@ -4323,7 +4625,9 @@ module MarkdownExec
|
|
4323
4625
|
required_lines:, selected:, shell:
|
4324
4626
|
)
|
4325
4627
|
write_command_file(
|
4326
|
-
required_lines: required_lines,
|
4628
|
+
required_lines: required_lines,
|
4629
|
+
blockname: selected.pub_name,
|
4630
|
+
shell: selected_shell(shell)
|
4327
4631
|
)
|
4328
4632
|
@fout.fout "File saved: #{@run_state.saved_filespec}"
|
4329
4633
|
end
|
@@ -4371,7 +4675,8 @@ module MarkdownExec
|
|
4371
4675
|
|
4372
4676
|
def screen_width_for_table
|
4373
4677
|
# menu adds newline after some lines if sized to the edge
|
4374
|
-
|
4678
|
+
# menu prompt symbol (1) + space (1) + gap (1)
|
4679
|
+
screen_width - prompt_margin_left_width - prompt_margin_right_width - 3
|
4375
4680
|
end
|
4376
4681
|
|
4377
4682
|
def screen_width_for_wrapping
|
@@ -4472,10 +4777,14 @@ module MarkdownExec
|
|
4472
4777
|
exit 1
|
4473
4778
|
end
|
4474
4779
|
|
4475
|
-
if
|
4780
|
+
if selected.oname == HashDelegator.safeval(
|
4781
|
+
@delegate_object.fetch(:menu_option_back_name, '')
|
4782
|
+
)[:line]
|
4476
4783
|
selected.option = selection
|
4477
4784
|
selected.type = BlockType::LINK
|
4478
|
-
elsif
|
4785
|
+
elsif selected.oname == HashDelegator.safeval(
|
4786
|
+
@delegate_object.fetch(:menu_option_exit_name, '')
|
4787
|
+
)[:line]
|
4479
4788
|
selected.option = selection
|
4480
4789
|
else
|
4481
4790
|
selected.selected = selection
|
@@ -4616,6 +4925,7 @@ module MarkdownExec
|
|
4616
4925
|
# color_sym is not found in @delegate_object.
|
4617
4926
|
# @return [String] The string with the applied color method.
|
4618
4927
|
def string_send_color(string, color_sym)
|
4928
|
+
### accept string with color as well as symbol for color_hash
|
4619
4929
|
HashDelegator.apply_color_from_hash(string, @delegate_object, color_sym)
|
4620
4930
|
end
|
4621
4931
|
|
@@ -4705,12 +5015,23 @@ module MarkdownExec
|
|
4705
5015
|
@delegate_object[:menu_include_imported_notes]
|
4706
5016
|
# add line if it is depth 0 or option allows it
|
4707
5017
|
#
|
5018
|
+
criteria = nil
|
5019
|
+
if @delegate_object[:table_row_single_line_match]&.present? &&
|
5020
|
+
line.match(@delegate_object[:table_row_single_line_match])
|
5021
|
+
criteria = {
|
5022
|
+
center: :table_center,
|
5023
|
+
match: :table_row_single_line_match
|
5024
|
+
}
|
5025
|
+
end
|
4708
5026
|
HashDelegator.yield_line_if_selected(
|
4709
5027
|
line, selected_types,
|
4710
5028
|
all_fcbs: @fcb_store,
|
5029
|
+
criteria: criteria,
|
4711
5030
|
source_id: source_id, &block
|
4712
5031
|
)
|
4713
5032
|
end
|
5033
|
+
rescue StandardError
|
5034
|
+
wwe $!, 'state:', state, 'nested_line:', nested_line
|
4714
5035
|
end
|
4715
5036
|
|
4716
5037
|
## apply options to current state
|
@@ -4743,10 +5064,13 @@ module MarkdownExec
|
|
4743
5064
|
|
4744
5065
|
case export.allow
|
4745
5066
|
when :echo, ExportValueSource::ECHO
|
4746
|
-
command_result, exportable, new_lines =
|
5067
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4747
5068
|
bash_script_lines,
|
4748
5069
|
export,
|
5070
|
+
data: export.echo,
|
5071
|
+
first_only: true,
|
4749
5072
|
force: force,
|
5073
|
+
printf_expand: true,
|
4750
5074
|
silent: silent
|
4751
5075
|
)
|
4752
5076
|
|
@@ -4754,15 +5078,20 @@ module MarkdownExec
|
|
4754
5078
|
command_result
|
4755
5079
|
else
|
4756
5080
|
command_result = CommandResult.new(
|
4757
|
-
stdout: menu_from_list_with_back(
|
5081
|
+
stdout: menu_from_list_with_back(
|
5082
|
+
command_result.stdout.split("\n")
|
5083
|
+
)
|
4758
5084
|
)
|
4759
5085
|
end
|
4760
5086
|
|
4761
5087
|
when :exec, UxActSource::EXEC
|
4762
|
-
command_result, =
|
4763
|
-
|
5088
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
5089
|
+
bash_script_lines,
|
4764
5090
|
export,
|
4765
|
-
|
5091
|
+
data: export.exec,
|
5092
|
+
first_only: true,
|
5093
|
+
force: force,
|
5094
|
+
silent: silent
|
4766
5095
|
)
|
4767
5096
|
|
4768
5097
|
if command_result.exit_status == EXIT_STATUS_REQUIRED_EMPTY
|
@@ -4777,10 +5106,13 @@ module MarkdownExec
|
|
4777
5106
|
|
4778
5107
|
else
|
4779
5108
|
export_init = menu_from_list_with_back(export.allow)
|
4780
|
-
command_result, exportable, new_lines =
|
5109
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4781
5110
|
[assign_key_value_in_bash(export.name, export_init)],
|
4782
5111
|
export,
|
5112
|
+
data: export.echo,
|
5113
|
+
first_only: true,
|
4783
5114
|
force: force,
|
5115
|
+
printf_expand: true,
|
4784
5116
|
silent: silent,
|
4785
5117
|
string: export_init
|
4786
5118
|
)
|
@@ -4788,11 +5120,12 @@ module MarkdownExec
|
|
4788
5120
|
end
|
4789
5121
|
|
4790
5122
|
when :echo, UxActSource::ECHO
|
4791
|
-
|
4792
|
-
command_result, exportable, new_lines = export_echo_with_code(
|
5123
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4793
5124
|
bash_script_lines,
|
4794
5125
|
export,
|
5126
|
+
data: export.echo,
|
4795
5127
|
force: force,
|
5128
|
+
printf_expand: true,
|
4796
5129
|
silent: silent
|
4797
5130
|
)
|
4798
5131
|
|
@@ -4822,10 +5155,12 @@ module MarkdownExec
|
|
4822
5155
|
command_result = CommandResult.new(stdout: output)
|
4823
5156
|
|
4824
5157
|
when :exec, UxActSource::EXEC
|
4825
|
-
command_result, exportable, new_lines =
|
4826
|
-
|
5158
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
5159
|
+
bash_script_lines,
|
4827
5160
|
export,
|
4828
|
-
|
5161
|
+
data: export.exec,
|
5162
|
+
force: force,
|
5163
|
+
silent: silent
|
4829
5164
|
)
|
4830
5165
|
|
4831
5166
|
else
|
@@ -4843,6 +5178,8 @@ module MarkdownExec
|
|
4843
5178
|
command_result.transformable = transformable
|
4844
5179
|
command_result.new_lines = new_lines
|
4845
5180
|
command_result
|
5181
|
+
rescue StandardError
|
5182
|
+
wwe bash_script_lines, export, exit_prompt
|
4846
5183
|
end
|
4847
5184
|
|
4848
5185
|
def ux_block_export_automatic(
|
@@ -4866,36 +5203,47 @@ module MarkdownExec
|
|
4866
5203
|
|
4867
5204
|
case export.allow
|
4868
5205
|
when :echo, ExportValueSource::ECHO
|
4869
|
-
cr_echo, =
|
4870
|
-
|
4871
|
-
bash_script_lines,
|
4872
|
-
%(printf '%s' "#{export.echo}")
|
4873
|
-
),
|
5206
|
+
cr_echo, = ux_block_eval_for_export(
|
5207
|
+
bash_script_lines,
|
4874
5208
|
export,
|
4875
|
-
|
5209
|
+
data: export.echo,
|
5210
|
+
first_only: true,
|
5211
|
+
force: force,
|
5212
|
+
printf_expand: true,
|
5213
|
+
silent: silent
|
4876
5214
|
)
|
4877
5215
|
export_init = cr_echo.stdout.split("\n").first
|
4878
|
-
|
5216
|
+
|
5217
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4879
5218
|
[assign_key_value_in_bash(export.name, export_init)],
|
4880
5219
|
export,
|
5220
|
+
data: export.echo,
|
5221
|
+
first_only: true,
|
4881
5222
|
force: force,
|
5223
|
+
printf_expand: true,
|
4882
5224
|
silent: silent,
|
4883
5225
|
string: export_init
|
4884
5226
|
)
|
4885
5227
|
|
4886
5228
|
when :exec, ExportValueSource::EXEC
|
4887
5229
|
# extract first line from 'exec' output
|
4888
|
-
command_result, exportable, new_lines =
|
4889
|
-
|
5230
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
5231
|
+
bash_script_lines,
|
4890
5232
|
export,
|
4891
|
-
|
5233
|
+
data: export.exec,
|
5234
|
+
first_only: true,
|
5235
|
+
force: force,
|
5236
|
+
silent: silent
|
4892
5237
|
)
|
5238
|
+
|
4893
5239
|
unless command_result.failure?
|
4894
5240
|
export_init = command_result.stdout.split("\n").first
|
4895
|
-
command_result, exportable, new_lines =
|
5241
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4896
5242
|
[assign_key_value_in_bash(export.name, export_init)],
|
4897
5243
|
export,
|
5244
|
+
data: export.exec,
|
4898
5245
|
force: force,
|
5246
|
+
printf_expand: true,
|
4899
5247
|
silent: silent,
|
4900
5248
|
string: export_init
|
4901
5249
|
)
|
@@ -4904,10 +5252,12 @@ module MarkdownExec
|
|
4904
5252
|
else
|
4905
5253
|
# first item from 'allow' list
|
4906
5254
|
export_init = export.allow.first
|
4907
|
-
command_result, exportable, new_lines =
|
5255
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4908
5256
|
[assign_key_value_in_bash(export.name, export_init)],
|
4909
5257
|
export,
|
5258
|
+
data: export.allow,
|
4910
5259
|
force: force,
|
5260
|
+
printf_expand: true,
|
4911
5261
|
silent: silent,
|
4912
5262
|
string: export_init
|
4913
5263
|
)
|
@@ -4921,32 +5271,37 @@ module MarkdownExec
|
|
4921
5271
|
when :echo, UxActSource::ECHO
|
4922
5272
|
raise unless export.echo.present?
|
4923
5273
|
|
4924
|
-
command_result, exportable, new_lines =
|
5274
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4925
5275
|
bash_script_lines,
|
4926
5276
|
export,
|
5277
|
+
data: export.echo,
|
4927
5278
|
force: force,
|
5279
|
+
printf_expand: true,
|
4928
5280
|
silent: silent
|
4929
5281
|
)
|
4930
5282
|
|
4931
5283
|
when :exec, UxActSource::EXEC
|
4932
5284
|
raise unless export.exec.present?
|
4933
5285
|
|
4934
|
-
command_result, exportable, new_lines =
|
4935
|
-
|
5286
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
5287
|
+
bash_script_lines,
|
4936
5288
|
export,
|
4937
|
-
|
5289
|
+
data: export.exec,
|
5290
|
+
force: force,
|
5291
|
+
silent: silent
|
4938
5292
|
)
|
4939
5293
|
|
4940
5294
|
else
|
4941
5295
|
export_init = export.init.to_s
|
4942
|
-
command_result, exportable, new_lines =
|
5296
|
+
command_result, exportable, new_lines = ux_block_eval_for_export(
|
4943
5297
|
[assign_key_value_in_bash(export.name, export_init)],
|
4944
5298
|
export,
|
5299
|
+
data: export.exec,
|
4945
5300
|
force: force,
|
5301
|
+
printf_expand: true,
|
4946
5302
|
silent: silent,
|
4947
5303
|
string: export_init
|
4948
5304
|
)
|
4949
|
-
# raise "Unknown FCB.init_source(export) #{FCB.init_source(export)}"
|
4950
5305
|
end
|
4951
5306
|
|
4952
5307
|
# add message for required variables
|
@@ -4959,10 +5314,19 @@ module MarkdownExec
|
|
4959
5314
|
command_result.transformable = transformable
|
4960
5315
|
command_result.new_lines = new_lines
|
4961
5316
|
command_result
|
5317
|
+
rescue StandardError
|
5318
|
+
wwe bash_script_lines, export
|
4962
5319
|
end
|
4963
5320
|
|
4964
|
-
|
4965
|
-
|
5321
|
+
# true if the variable is exported in a series of evaluations
|
5322
|
+
def variable_is_exportable(name)
|
5323
|
+
local_name_pattern = @delegate_object.fetch(:local_name_pattern, '')
|
5324
|
+
|
5325
|
+
# export all if rule is empty
|
5326
|
+
return true if local_name_pattern.empty?
|
5327
|
+
|
5328
|
+
# export if it its name does not match the rule
|
5329
|
+
name !~ Regexp.new(local_name_pattern)
|
4966
5330
|
end
|
4967
5331
|
|
4968
5332
|
def vux_await_user_selection(prior_answer: @dml_block_selection)
|
@@ -4981,17 +5345,119 @@ module MarkdownExec
|
|
4981
5345
|
end
|
4982
5346
|
|
4983
5347
|
def vux_clear_menu_state
|
5348
|
+
@dml_block_selection = @dml_block_state.block
|
4984
5349
|
@dml_block_state = SelectedBlockMenuState.new
|
4985
5350
|
@delegate_object[:block_name] = nil
|
4986
5351
|
end
|
4987
5352
|
|
4988
5353
|
def vux_edit_inherited
|
4989
5354
|
edited = edit_text(@dml_link_state.inherited_lines_block)
|
4990
|
-
|
5355
|
+
return unless edited
|
5356
|
+
|
5357
|
+
@dml_link_state.inherited_lines =
|
5358
|
+
annotate_required_lines(
|
5359
|
+
'blk:EDIT', edited.split("\n"), block_name: 'EDIT'
|
5360
|
+
)
|
5361
|
+
end
|
5362
|
+
|
5363
|
+
def block_is_back(fcb)
|
5364
|
+
fcb.oname == HashDelegator.safeval(
|
5365
|
+
@delegate_object[:menu_option_back_name]
|
5366
|
+
)[:line]
|
5367
|
+
end
|
5368
|
+
|
5369
|
+
def block_is_edit(fcb)
|
5370
|
+
fcb.oname == HashDelegator.safeval(
|
5371
|
+
@delegate_object[:menu_option_edit_name]
|
5372
|
+
)[:line]
|
5373
|
+
end
|
5374
|
+
|
5375
|
+
def block_is_exit(fcb)
|
5376
|
+
fcb.oname == HashDelegator.safeval(
|
5377
|
+
@delegate_object[:menu_option_exit_name]
|
5378
|
+
)[:line]
|
5379
|
+
end
|
5380
|
+
|
5381
|
+
def block_is_history(fcb)
|
5382
|
+
fcb.oname == HashDelegator.safeval(
|
5383
|
+
@delegate_object[:menu_option_history_name]
|
5384
|
+
)[:line]
|
5385
|
+
end
|
5386
|
+
|
5387
|
+
def block_is_load(fcb)
|
5388
|
+
fcb.oname == HashDelegator.safeval(
|
5389
|
+
@delegate_object[:menu_option_load_name]
|
5390
|
+
)[:line]
|
5391
|
+
end
|
5392
|
+
|
5393
|
+
def block_is_save(fcb)
|
5394
|
+
fcb.oname == HashDelegator.safeval(
|
5395
|
+
@delegate_object[:menu_option_save_name]
|
5396
|
+
)[:line]
|
5397
|
+
end
|
5398
|
+
|
5399
|
+
def block_is_shell(fcb)
|
5400
|
+
fcb.oname == HashDelegator.safeval(
|
5401
|
+
@delegate_object[:menu_option_shell_name]
|
5402
|
+
)[:line]
|
5403
|
+
end
|
5404
|
+
|
5405
|
+
def block_is_view(fcb)
|
5406
|
+
fcb.oname == HashDelegator.safeval(
|
5407
|
+
@delegate_object[:menu_option_view_name]
|
5408
|
+
)[:line]
|
4991
5409
|
end
|
4992
5410
|
|
4993
5411
|
def vux_execute_and_prompt(block_name)
|
4994
5412
|
@dml_block_state = find_block_state_by_name(block_name)
|
5413
|
+
|
5414
|
+
if @dml_block_state.block
|
5415
|
+
if block_is_back(@dml_block_state.block)
|
5416
|
+
debounce_reset
|
5417
|
+
vux_navigate_back_for_ls
|
5418
|
+
return
|
5419
|
+
|
5420
|
+
elsif block_is_edit(@dml_block_state.block)
|
5421
|
+
debounce_reset
|
5422
|
+
vux_edit_inherited
|
5423
|
+
return pause_user_exit ? :break : nil
|
5424
|
+
|
5425
|
+
elsif block_is_exit(@dml_block_state.block)
|
5426
|
+
debounce_reset
|
5427
|
+
### LoadFileLinkState.new(LoadFile::EXIT, link_state)
|
5428
|
+
return :break
|
5429
|
+
|
5430
|
+
elsif block_is_history(@dml_block_state.block)
|
5431
|
+
debounce_reset
|
5432
|
+
return :break unless (files_table_rows = vux_history_files_table_rows)
|
5433
|
+
|
5434
|
+
execute_history_select(files_table_rows, stream: $stderr)
|
5435
|
+
return :break if pause_user_exit
|
5436
|
+
|
5437
|
+
return
|
5438
|
+
|
5439
|
+
elsif block_is_load(@dml_block_state.block)
|
5440
|
+
debounce_reset
|
5441
|
+
vux_load_inherited
|
5442
|
+
return pause_user_exit ? :break : nil
|
5443
|
+
|
5444
|
+
elsif block_is_save(@dml_block_state.block)
|
5445
|
+
debounce_reset
|
5446
|
+
return execute_inherited_save == :break ? :break : nil
|
5447
|
+
|
5448
|
+
elsif block_is_shell(@dml_block_state.block)
|
5449
|
+
debounce_reset
|
5450
|
+
vux_input_and_execute_shell_commands(stream: $stderr, shell: shell)
|
5451
|
+
return pause_user_exit ? :break : nil
|
5452
|
+
|
5453
|
+
elsif block_is_view(@dml_block_state.block)
|
5454
|
+
debounce_reset
|
5455
|
+
vux_view_inherited(stream: $stderr)
|
5456
|
+
return pause_user_exit ? :break : nil
|
5457
|
+
|
5458
|
+
end
|
5459
|
+
end
|
5460
|
+
|
4995
5461
|
if @dml_block_state.block &&
|
4996
5462
|
@dml_block_state.block.type == BlockType::OPTS
|
4997
5463
|
debounce_reset
|
@@ -5032,62 +5498,12 @@ module MarkdownExec
|
|
5032
5498
|
end
|
5033
5499
|
|
5034
5500
|
def vux_execute_block_per_type(block_name, formatted_choice_ostructs)
|
5035
|
-
|
5036
|
-
when formatted_choice_ostructs[:back].pub_name
|
5037
|
-
debounce_reset
|
5038
|
-
vux_navigate_back_for_ls
|
5501
|
+
return :break if vux_execute_and_prompt(block_name) == :break
|
5039
5502
|
|
5040
|
-
|
5041
|
-
|
5042
|
-
|
5043
|
-
|
5044
|
-
|
5045
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
5046
|
-
|
5047
|
-
when formatted_choice_ostructs[:history].pub_name
|
5048
|
-
debounce_reset
|
5049
|
-
return :break unless (files_table_rows = vux_history_files_table_rows)
|
5050
|
-
|
5051
|
-
execute_history_select(files_table_rows, stream: $stderr)
|
5052
|
-
return :break if pause_user_exit
|
5053
|
-
|
5054
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
5055
|
-
|
5056
|
-
when formatted_choice_ostructs[:load].pub_name
|
5057
|
-
debounce_reset
|
5058
|
-
vux_load_inherited
|
5059
|
-
return :break if pause_user_exit
|
5060
|
-
|
5061
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
5062
|
-
|
5063
|
-
when formatted_choice_ostructs[:save].pub_name
|
5064
|
-
debounce_reset
|
5065
|
-
return :break if execute_inherited_save == :break
|
5066
|
-
|
5067
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
5068
|
-
|
5069
|
-
when formatted_choice_ostructs[:shell].pub_name
|
5070
|
-
debounce_reset
|
5071
|
-
vux_input_and_execute_shell_commands(stream: $stderr, shell: shell)
|
5072
|
-
return :break if pause_user_exit
|
5073
|
-
|
5074
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
5075
|
-
|
5076
|
-
when formatted_choice_ostructs[:view].pub_name
|
5077
|
-
debounce_reset
|
5078
|
-
vux_view_inherited(stream: $stderr)
|
5079
|
-
return :break if pause_user_exit
|
5080
|
-
|
5081
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
5082
|
-
|
5083
|
-
else
|
5084
|
-
return :break if vux_execute_and_prompt(block_name) == :break
|
5085
|
-
|
5086
|
-
InputSequencer.next_link_state(
|
5087
|
-
block_name: @dml_link_state.block_name,
|
5088
|
-
prior_block_was_link: @dml_block_state.block.type != BlockType::SHELL
|
5089
|
-
)
|
5090
|
-
end
|
5503
|
+
InputSequencer.next_link_state(
|
5504
|
+
block_name: @dml_link_state.block_name,
|
5505
|
+
prior_block_was_link: @dml_block_state.block.type != BlockType::SHELL
|
5506
|
+
)
|
5091
5507
|
end
|
5092
5508
|
|
5093
5509
|
def vux_formatted_names_for_state_chrome_blocks(
|
@@ -5237,10 +5653,13 @@ module MarkdownExec
|
|
5237
5653
|
block_list
|
5238
5654
|
).run do |msg, data|
|
5239
5655
|
count += 1
|
5656
|
+
wwt :id, 'count:', count, 'msg:', msg, 'data:', data
|
5240
5657
|
case msg
|
5241
5658
|
when :parse_document # once for each menu
|
5242
5659
|
count = 0
|
5243
|
-
vux_parse_document(
|
5660
|
+
vux_parse_document(
|
5661
|
+
source_id: "#{@delegate_object[:filename]}¤VuxMainLoop®PrsDoc"
|
5662
|
+
)
|
5244
5663
|
vux_menu_append_history_files(
|
5245
5664
|
formatted_choice_ostructs,
|
5246
5665
|
source_id: "#{@delegate_object[:filename]}¤VuxMainLoop®HstFls"
|
@@ -5254,8 +5673,19 @@ module MarkdownExec
|
|
5254
5673
|
when :end_of_cli
|
5255
5674
|
# yield :end_of_cli, @delegate_object
|
5256
5675
|
|
5257
|
-
if @delegate_object[:
|
5258
|
-
|
5676
|
+
if @delegate_object[:blocks].present?
|
5677
|
+
@delegate_object[:list_blocks_message] =
|
5678
|
+
@delegate_object[:blocks].to_sym
|
5679
|
+
@delegate_object[:list_blocks_type] = 3
|
5680
|
+
|
5681
|
+
list_blocks(
|
5682
|
+
source_id: "#{@delegate_object[:filename]}¤VuxMainLoop®EndCLI"
|
5683
|
+
)
|
5684
|
+
:exit
|
5685
|
+
elsif @delegate_object[:list_blocks]
|
5686
|
+
list_blocks(
|
5687
|
+
source_id: "#{@delegate_object[:filename]}¤VuxMainLoop®EndCLI"
|
5688
|
+
)
|
5259
5689
|
:exit
|
5260
5690
|
end
|
5261
5691
|
|
@@ -5263,9 +5693,14 @@ module MarkdownExec
|
|
5263
5693
|
vux_user_selected_block_name
|
5264
5694
|
|
5265
5695
|
when :execute_block
|
5266
|
-
|
5267
|
-
|
5268
|
-
|
5696
|
+
begin
|
5697
|
+
ret = vux_execute_block_per_type(data, formatted_choice_ostructs)
|
5698
|
+
vux_publish_block_name_for_external_automation(data)
|
5699
|
+
ret
|
5700
|
+
rescue StandardError
|
5701
|
+
# error executing block, do not abort
|
5702
|
+
InputSequencer.next_link_state(prior_block_was_link: false)
|
5703
|
+
end
|
5269
5704
|
|
5270
5705
|
when :close_ux
|
5271
5706
|
if @vux_pipe_open.present? && File.exist?(@vux_pipe_open)
|
@@ -5321,7 +5756,7 @@ module MarkdownExec
|
|
5321
5756
|
|
5322
5757
|
# add menu items (glob, load, save) and enable selectively
|
5323
5758
|
if files.count.positive? || lines_count.positive?
|
5324
|
-
menu_add_disabled_option(document_glob)
|
5759
|
+
menu_add_disabled_option(document_glob, "#{source_id}_vmahf_glob")
|
5325
5760
|
end
|
5326
5761
|
if files.count.positive?
|
5327
5762
|
dml_menu_append_chrome_item(
|
@@ -5402,14 +5837,7 @@ module MarkdownExec
|
|
5402
5837
|
|
5403
5838
|
def vux_publish_block_name_for_external_automation(block_name)
|
5404
5839
|
publish_for_external_automation(
|
5405
|
-
message:
|
5406
|
-
@delegate_object[:publish_block_name_format],
|
5407
|
-
{ block: block_name,
|
5408
|
-
document: @delegate_object[:filename],
|
5409
|
-
time: Time.now.utc.strftime(
|
5410
|
-
@delegate_object[:publish_time_format]
|
5411
|
-
) }
|
5412
|
-
)
|
5840
|
+
message: formatted_block_name(block_name)
|
5413
5841
|
)
|
5414
5842
|
end
|
5415
5843
|
|
@@ -5445,7 +5873,7 @@ module MarkdownExec
|
|
5445
5873
|
return :break if @dml_block_state.block.nil? # no block matched
|
5446
5874
|
end
|
5447
5875
|
# puts "! - Executing block: #{data}"
|
5448
|
-
@dml_block_state.block&.
|
5876
|
+
@dml_block_state.block&.id
|
5449
5877
|
end
|
5450
5878
|
|
5451
5879
|
def vux_view_inherited(stream:)
|
@@ -5488,11 +5916,12 @@ module MarkdownExec
|
|
5488
5916
|
nil
|
5489
5917
|
when String
|
5490
5918
|
menu_blocks.find do |block|
|
5491
|
-
block.
|
5919
|
+
block.id == prior_answer
|
5492
5920
|
end&.name
|
5493
5921
|
when Struct, MarkdownExec::FCB
|
5494
5922
|
if prior_answer.id
|
5495
|
-
# when switching documents,
|
5923
|
+
# when switching documents,
|
5924
|
+
# the prior answer will not be found
|
5496
5925
|
(menu_blocks.find_index do |block|
|
5497
5926
|
block[:id] == prior_answer.id
|
5498
5927
|
end || 0) + 1
|
@@ -5519,6 +5948,10 @@ module MarkdownExec
|
|
5519
5948
|
determine_block_state(selected_option)
|
5520
5949
|
end
|
5521
5950
|
|
5951
|
+
def warning_required_empty(export)
|
5952
|
+
"A value must exist for: #{export.required.join(', ')}"
|
5953
|
+
end
|
5954
|
+
|
5522
5955
|
# Handles the core logic for generating the command
|
5523
5956
|
# file's metadata and content.
|
5524
5957
|
def write_command_file(required_lines:, blockname:, shell: nil)
|
@@ -5590,8 +6023,10 @@ module MarkdownExec
|
|
5590
6023
|
if save_expr.present?
|
5591
6024
|
save_filespec = save_filespec_from_expression(save_expr)
|
5592
6025
|
if save_filespec.present?
|
5593
|
-
File.write(
|
5594
|
-
|
6026
|
+
File.write(
|
6027
|
+
save_filespec,
|
6028
|
+
HashDelegator.join_code_lines(link_state&.inherited_lines)
|
6029
|
+
)
|
5595
6030
|
@delegate_object[:filename]
|
5596
6031
|
else
|
5597
6032
|
link_block_data[LinkKeys::FILE] || @delegate_object[:filename]
|
@@ -5602,6 +6037,7 @@ module MarkdownExec
|
|
5602
6037
|
end
|
5603
6038
|
|
5604
6039
|
def safe_yaml_load(body)
|
6040
|
+
caller.deref(12)
|
5605
6041
|
return {} unless body&.present?
|
5606
6042
|
|
5607
6043
|
YAML.load(body.to_s)
|
@@ -6725,4 +7161,427 @@ module MarkdownExec
|
|
6725
7161
|
end
|
6726
7162
|
end
|
6727
7163
|
end
|
7164
|
+
|
7165
|
+
# Comprehensive tests for ux_block_eval_for_export function
|
7166
|
+
class TestUxBlockEvalForExport < Minitest::Test
|
7167
|
+
def setup
|
7168
|
+
@hd = HashDelegator.new
|
7169
|
+
@bash_script_lines = ['#!/bin/bash', 'set -e']
|
7170
|
+
@export = OpenStruct.new(name: 'TEST_VAR', required: ['TEST_VAR'])
|
7171
|
+
@mock_result = OpenStruct.new(
|
7172
|
+
exit_status: 0,
|
7173
|
+
stdout: 'test_output',
|
7174
|
+
stderr: '',
|
7175
|
+
warning: nil
|
7176
|
+
)
|
7177
|
+
end
|
7178
|
+
|
7179
|
+
def teardown
|
7180
|
+
# Clean up environment variables set during tests
|
7181
|
+
ENV.delete('TEST_VAR')
|
7182
|
+
ENV.delete('VAR1')
|
7183
|
+
ENV.delete('VAR2')
|
7184
|
+
end
|
7185
|
+
|
7186
|
+
# Test string input - typical case
|
7187
|
+
def test_string_input_success
|
7188
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7189
|
+
true])
|
7190
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7191
|
+
|
7192
|
+
result = @hd.ux_block_eval_for_export(
|
7193
|
+
@bash_script_lines, @export,
|
7194
|
+
data: 'echo "hello"',
|
7195
|
+
force: false,
|
7196
|
+
silent: false
|
7197
|
+
)
|
7198
|
+
|
7199
|
+
command_result, exportable, new_lines = result
|
7200
|
+
assert_equal @mock_result, command_result
|
7201
|
+
assert_equal true, exportable
|
7202
|
+
assert_equal 1, new_lines.length
|
7203
|
+
assert_equal 'TEST_VAR', new_lines.first[:name]
|
7204
|
+
assert_equal 'test_output', new_lines.first[:text]
|
7205
|
+
end
|
7206
|
+
|
7207
|
+
# Test string input with printf_expand
|
7208
|
+
def test_string_input_with_printf_expand
|
7209
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7210
|
+
true])
|
7211
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7212
|
+
|
7213
|
+
@hd.ux_block_eval_for_export(
|
7214
|
+
@bash_script_lines, @export,
|
7215
|
+
data: 'test_value',
|
7216
|
+
force: false,
|
7217
|
+
printf_expand: true,
|
7218
|
+
silent: false
|
7219
|
+
)
|
7220
|
+
|
7221
|
+
# Verify that join_array_of_arrays was called with printf wrapped expression
|
7222
|
+
# This tests that the expander lambda is applied correctly
|
7223
|
+
end
|
7224
|
+
|
7225
|
+
# Test integer input
|
7226
|
+
def test_integer_input
|
7227
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7228
|
+
true])
|
7229
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7230
|
+
|
7231
|
+
result = @hd.ux_block_eval_for_export(
|
7232
|
+
@bash_script_lines, @export,
|
7233
|
+
data: 42,
|
7234
|
+
force: true,
|
7235
|
+
silent: false
|
7236
|
+
)
|
7237
|
+
|
7238
|
+
command_result, exportable, new_lines = result
|
7239
|
+
assert_equal @mock_result, command_result
|
7240
|
+
assert_equal true, exportable
|
7241
|
+
assert_equal 1, new_lines.length
|
7242
|
+
end
|
7243
|
+
|
7244
|
+
# Test boolean inputs
|
7245
|
+
def test_boolean_true_input
|
7246
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7247
|
+
true])
|
7248
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7249
|
+
|
7250
|
+
result = @hd.ux_block_eval_for_export(
|
7251
|
+
@bash_script_lines, @export,
|
7252
|
+
data: true,
|
7253
|
+
force: false,
|
7254
|
+
silent: false
|
7255
|
+
)
|
7256
|
+
|
7257
|
+
command_result, exportable, = result
|
7258
|
+
assert_equal @mock_result, command_result
|
7259
|
+
assert_equal true, exportable
|
7260
|
+
end
|
7261
|
+
|
7262
|
+
def test_boolean_false_input
|
7263
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7264
|
+
true])
|
7265
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7266
|
+
|
7267
|
+
result = @hd.ux_block_eval_for_export(
|
7268
|
+
@bash_script_lines, @export,
|
7269
|
+
data: false,
|
7270
|
+
force: false,
|
7271
|
+
silent: false
|
7272
|
+
)
|
7273
|
+
|
7274
|
+
command_result, exportable, = result
|
7275
|
+
assert_equal @mock_result, command_result
|
7276
|
+
assert_equal true, exportable
|
7277
|
+
end
|
7278
|
+
|
7279
|
+
# Test float input
|
7280
|
+
def test_float_input
|
7281
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7282
|
+
true])
|
7283
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7284
|
+
|
7285
|
+
result = @hd.ux_block_eval_for_export(
|
7286
|
+
@bash_script_lines, @export,
|
7287
|
+
data: 3.14,
|
7288
|
+
force: false,
|
7289
|
+
silent: false
|
7290
|
+
)
|
7291
|
+
|
7292
|
+
command_result, exportable, = result
|
7293
|
+
assert_equal @mock_result, command_result
|
7294
|
+
assert_equal true, exportable
|
7295
|
+
end
|
7296
|
+
|
7297
|
+
# Test hash input - typical case
|
7298
|
+
def test_hash_input_success
|
7299
|
+
hash_data = { 'VAR1' => 'value1', 'VAR2' => 'value2' }
|
7300
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7301
|
+
true])
|
7302
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7303
|
+
@hd.stubs(:code_line_to_assign_a_variable).returns('VAR1=value1')
|
7304
|
+
|
7305
|
+
result = @hd.ux_block_eval_for_export(
|
7306
|
+
@bash_script_lines, @export,
|
7307
|
+
data: hash_data,
|
7308
|
+
force: false,
|
7309
|
+
silent: false
|
7310
|
+
)
|
7311
|
+
|
7312
|
+
command_result, exportable, new_lines = result
|
7313
|
+
assert_equal @mock_result, command_result
|
7314
|
+
assert_equal true, exportable
|
7315
|
+
assert_equal 2, new_lines.length
|
7316
|
+
assert_equal 'VAR1', new_lines.first[:name]
|
7317
|
+
assert_equal 'VAR2', new_lines.last[:name]
|
7318
|
+
end
|
7319
|
+
|
7320
|
+
# Test hash input with first_only flag
|
7321
|
+
def test_hash_input_first_only
|
7322
|
+
hash_data = { 'VAR1' => 'value1', 'VAR2' => 'value2' }
|
7323
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7324
|
+
true])
|
7325
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7326
|
+
@hd.stubs(:code_line_to_assign_a_variable).returns('VAR1=value1')
|
7327
|
+
|
7328
|
+
result = @hd.ux_block_eval_for_export(
|
7329
|
+
@bash_script_lines, @export,
|
7330
|
+
data: hash_data,
|
7331
|
+
first_only: true,
|
7332
|
+
force: false,
|
7333
|
+
silent: false
|
7334
|
+
)
|
7335
|
+
|
7336
|
+
command_result, _, new_lines = result
|
7337
|
+
assert_equal @mock_result, command_result
|
7338
|
+
assert_equal 1, new_lines.length
|
7339
|
+
assert_equal 'VAR1', new_lines.first[:name]
|
7340
|
+
end
|
7341
|
+
|
7342
|
+
# Test hash with non-exportable variables
|
7343
|
+
def test_hash_input_non_exportable_variables
|
7344
|
+
hash_data = { 'LOCAL_VAR' => 'value1' }
|
7345
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7346
|
+
true])
|
7347
|
+
@hd.stubs(:variable_is_exportable).returns(false)
|
7348
|
+
@hd.stubs(:code_line_to_assign_a_variable).returns('LOCAL_VAR=value1')
|
7349
|
+
|
7350
|
+
result = @hd.ux_block_eval_for_export(
|
7351
|
+
@bash_script_lines, @export,
|
7352
|
+
data: hash_data,
|
7353
|
+
force: false,
|
7354
|
+
silent: false
|
7355
|
+
)
|
7356
|
+
|
7357
|
+
command_result, _, new_lines = result
|
7358
|
+
assert_equal @mock_result, command_result
|
7359
|
+
assert_equal 0, new_lines.length # No exportable variables
|
7360
|
+
end
|
7361
|
+
|
7362
|
+
# Test EXIT_STATUS_REQUIRED_EMPTY handling
|
7363
|
+
def test_exit_status_required_empty_with_warning
|
7364
|
+
failed_result = OpenStruct.new(
|
7365
|
+
exit_status: 248, # EXIT_STATUS_REQUIRED_EMPTY
|
7366
|
+
stdout: '',
|
7367
|
+
stderr: 'Required variable empty',
|
7368
|
+
warning: nil
|
7369
|
+
)
|
7370
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([failed_result,
|
7371
|
+
false])
|
7372
|
+
@hd.stubs(:warning_required_empty).returns('Warning: required empty')
|
7373
|
+
|
7374
|
+
result = @hd.ux_block_eval_for_export(
|
7375
|
+
@bash_script_lines, @export,
|
7376
|
+
data: 'echo ""',
|
7377
|
+
force: false,
|
7378
|
+
silent: false
|
7379
|
+
)
|
7380
|
+
|
7381
|
+
command_result, exportable, new_lines = result
|
7382
|
+
assert_equal failed_result, command_result
|
7383
|
+
assert_equal false, exportable
|
7384
|
+
assert_equal 0, new_lines.length
|
7385
|
+
assert_equal 'Warning: required empty', command_result.warning
|
7386
|
+
end
|
7387
|
+
|
7388
|
+
# Test EXIT_STATUS_REQUIRED_EMPTY handling with silent flag
|
7389
|
+
def test_exit_status_required_empty_silent
|
7390
|
+
failed_result = OpenStruct.new(
|
7391
|
+
exit_status: 248,
|
7392
|
+
stdout: '',
|
7393
|
+
stderr: 'Required variable empty',
|
7394
|
+
warning: nil
|
7395
|
+
)
|
7396
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([failed_result,
|
7397
|
+
false])
|
7398
|
+
|
7399
|
+
result = @hd.ux_block_eval_for_export(
|
7400
|
+
@bash_script_lines, @export,
|
7401
|
+
data: 'echo ""',
|
7402
|
+
force: false,
|
7403
|
+
silent: true
|
7404
|
+
)
|
7405
|
+
|
7406
|
+
command_result, exportable, = result
|
7407
|
+
assert_equal failed_result, command_result
|
7408
|
+
assert_equal false, exportable
|
7409
|
+
assert_nil command_result.warning # No warning when silent
|
7410
|
+
end
|
7411
|
+
|
7412
|
+
# Test string parameter override
|
7413
|
+
def test_string_parameter_override
|
7414
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7415
|
+
true])
|
7416
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7417
|
+
|
7418
|
+
result = @hd.ux_block_eval_for_export(
|
7419
|
+
@bash_script_lines, @export,
|
7420
|
+
data: 'original_data',
|
7421
|
+
string: 'override_string',
|
7422
|
+
force: false,
|
7423
|
+
silent: false
|
7424
|
+
)
|
7425
|
+
|
7426
|
+
# The function should use string parameter instead of data
|
7427
|
+
command_result, exportable, = result
|
7428
|
+
assert_equal @mock_result, command_result
|
7429
|
+
assert_equal true, exportable
|
7430
|
+
end
|
7431
|
+
|
7432
|
+
# Edge case: empty string
|
7433
|
+
def test_empty_string_input
|
7434
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7435
|
+
true])
|
7436
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7437
|
+
|
7438
|
+
result = @hd.ux_block_eval_for_export(
|
7439
|
+
@bash_script_lines, @export,
|
7440
|
+
data: '',
|
7441
|
+
force: false,
|
7442
|
+
silent: false
|
7443
|
+
)
|
7444
|
+
|
7445
|
+
command_result, exportable, = result
|
7446
|
+
assert_equal @mock_result, command_result
|
7447
|
+
assert_equal true, exportable
|
7448
|
+
end
|
7449
|
+
|
7450
|
+
# Edge case: nil data (uses string.nil? check)
|
7451
|
+
def test_nil_data_input
|
7452
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7453
|
+
true])
|
7454
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7455
|
+
|
7456
|
+
result = @hd.ux_block_eval_for_export(
|
7457
|
+
@bash_script_lines, @export,
|
7458
|
+
data: 'd1',
|
7459
|
+
force: false,
|
7460
|
+
silent: false
|
7461
|
+
)
|
7462
|
+
|
7463
|
+
command_result, exportable, = result
|
7464
|
+
assert_equal @mock_result, command_result
|
7465
|
+
assert_equal true, exportable
|
7466
|
+
end
|
7467
|
+
|
7468
|
+
# Edge case: empty hash
|
7469
|
+
def test_empty_hash_input
|
7470
|
+
result = @hd.ux_block_eval_for_export(
|
7471
|
+
@bash_script_lines, @export,
|
7472
|
+
data: {},
|
7473
|
+
force: false,
|
7474
|
+
silent: false
|
7475
|
+
)
|
7476
|
+
|
7477
|
+
command_result, exportable, new_lines = result
|
7478
|
+
assert_nil command_result # No iterations, so command_result remains nil
|
7479
|
+
assert_equal true, exportable # Initial value
|
7480
|
+
assert_equal 0, new_lines.length
|
7481
|
+
end
|
7482
|
+
|
7483
|
+
# Edge case: hash with nil values
|
7484
|
+
def test_hash_with_nil_values
|
7485
|
+
hash_data = { 'VAR1' => nil, 'VAR2' => 'value2' }
|
7486
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7487
|
+
true])
|
7488
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7489
|
+
@hd.stubs(:code_line_to_assign_a_variable).returns('VAR1=')
|
7490
|
+
|
7491
|
+
result = @hd.ux_block_eval_for_export(
|
7492
|
+
@bash_script_lines, @export,
|
7493
|
+
data: hash_data,
|
7494
|
+
force: false,
|
7495
|
+
silent: false
|
7496
|
+
)
|
7497
|
+
|
7498
|
+
command_result, exportable, new_lines = result
|
7499
|
+
assert_equal @mock_result, command_result
|
7500
|
+
assert_equal true, exportable
|
7501
|
+
assert_equal 2, new_lines.length
|
7502
|
+
end
|
7503
|
+
|
7504
|
+
# Edge case: unsupported input type (Array)
|
7505
|
+
def test_unsupported_input_type_array
|
7506
|
+
result = @hd.ux_block_eval_for_export(
|
7507
|
+
@bash_script_lines, @export,
|
7508
|
+
data: %w[item1 item2],
|
7509
|
+
force: false,
|
7510
|
+
silent: false
|
7511
|
+
)
|
7512
|
+
|
7513
|
+
command_result, exportable, new_lines = result
|
7514
|
+
assert_nil command_result # No processing for unsupported types
|
7515
|
+
assert_equal true, exportable # Initial value
|
7516
|
+
assert_equal 0, new_lines.length
|
7517
|
+
end
|
7518
|
+
|
7519
|
+
# Edge case: unsupported input type (custom object)
|
7520
|
+
def test_unsupported_input_type_object
|
7521
|
+
custom_object = Object.new
|
7522
|
+
result = @hd.ux_block_eval_for_export(
|
7523
|
+
@bash_script_lines, @export,
|
7524
|
+
data: custom_object,
|
7525
|
+
force: false,
|
7526
|
+
silent: false
|
7527
|
+
)
|
7528
|
+
|
7529
|
+
command_result, exportable, new_lines = result
|
7530
|
+
assert_nil command_result # No processing for unsupported types
|
7531
|
+
assert_equal true, exportable # Initial value
|
7532
|
+
assert_equal 0, new_lines.length
|
7533
|
+
end
|
7534
|
+
|
7535
|
+
# Test error handling - StandardError rescue
|
7536
|
+
def test_standard_error_rescue
|
7537
|
+
# Should not raise, but return nil due to rescue block
|
7538
|
+
result = @hd.ux_block_eval_for_export(
|
7539
|
+
@bash_script_lines, @export,
|
7540
|
+
data: 'test_data',
|
7541
|
+
force: false,
|
7542
|
+
silent: false
|
7543
|
+
)
|
7544
|
+
|
7545
|
+
command_result, = result
|
7546
|
+
assert_equal 127, command_result.exit_status
|
7547
|
+
end
|
7548
|
+
|
7549
|
+
# Test environment variable setting
|
7550
|
+
def test_environment_variable_setting
|
7551
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7552
|
+
true])
|
7553
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7554
|
+
|
7555
|
+
# Mock EnvInterface.set to verify it's called
|
7556
|
+
EnvInterface.expects(:set).with('TEST_VAR', 'test_output')
|
7557
|
+
|
7558
|
+
@hd.ux_block_eval_for_export(
|
7559
|
+
@bash_script_lines, @export,
|
7560
|
+
data: 'echo "test"',
|
7561
|
+
force: false,
|
7562
|
+
silent: false
|
7563
|
+
)
|
7564
|
+
end
|
7565
|
+
|
7566
|
+
# Test join_array_of_arrays is called correctly
|
7567
|
+
def test_join_array_of_arrays_called
|
7568
|
+
@hd.stubs(:output_from_adhoc_bash_script_file).returns([@mock_result,
|
7569
|
+
true])
|
7570
|
+
@hd.stubs(:variable_is_exportable).returns(true)
|
7571
|
+
|
7572
|
+
# Mock join_array_of_arrays to verify it's called with correct parameters
|
7573
|
+
@hd.expects(:join_array_of_arrays).with(
|
7574
|
+
@bash_script_lines,
|
7575
|
+
['test_data']
|
7576
|
+
).returns(['combined_script_lines'])
|
7577
|
+
|
7578
|
+
@hd.ux_block_eval_for_export(
|
7579
|
+
@bash_script_lines, @export,
|
7580
|
+
data: 'test_data',
|
7581
|
+
force: false,
|
7582
|
+
printf_expand: false,
|
7583
|
+
silent: false
|
7584
|
+
)
|
7585
|
+
end
|
7586
|
+
end
|
6728
7587
|
end # module MarkdownExec
|