markdown_exec 2.8.3 → 2.8.5
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 +41 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +33 -23
- data/bats/{block-types.bats → block-type-bash.bats} +0 -25
- data/bats/block-type-link.bats +9 -0
- data/bats/block-type-port.bats +16 -0
- data/bats/block-type-ux-allowed.bats +29 -0
- data/bats/block-type-ux-auto.bats +1 -1
- data/bats/block-type-ux-chained.bats +9 -0
- data/bats/block-type-ux-default.bats +8 -0
- data/bats/block-type-ux-echo-hash.bats +14 -0
- data/bats/block-type-ux-echo.bats +2 -2
- data/bats/block-type-ux-exec.bats +1 -1
- data/bats/block-type-ux-hidden.bats +9 -0
- data/bats/block-type-ux-invalid.bats +8 -0
- data/bats/block-type-ux-transform.bats +1 -1
- data/bats/indented-block-type-vars.bats +9 -0
- data/bats/line-decor-dynamic.bats +1 -1
- data/bats/test_helper.bash +9 -2
- data/bats/variable-expansion-multiline.bats +8 -0
- data/bats/variable-expansion.bats +1 -1
- data/docs/dev/block-type-ux-allowed.md +82 -0
- data/docs/dev/block-type-ux-auto.md +2 -1
- data/docs/dev/block-type-ux-chained.md +21 -0
- data/docs/dev/block-type-ux-default.md +42 -0
- data/docs/dev/block-type-ux-echo-hash.md +78 -0
- data/docs/dev/block-type-ux-echo.md +3 -1
- data/docs/dev/block-type-ux-exec.md +1 -0
- data/docs/dev/block-type-ux-hidden.md +21 -0
- data/docs/dev/block-type-ux-invalid.md +5 -0
- data/docs/dev/block-type-ux-require.md +9 -18
- data/docs/dev/indented-block-type-vars.md +6 -0
- data/docs/dev/line-decor-dynamic.md +2 -1
- data/docs/dev/variable-expansion-multiline.md +31 -0
- data/lib/ansi_formatter.rb +0 -1
- data/lib/ansi_string.rb +1 -1
- data/lib/array.rb +0 -1
- data/lib/array_util.rb +0 -1
- data/lib/block_label.rb +1 -1
- data/lib/cached_nested_file_reader.rb +1 -1
- data/lib/constants.rb +18 -0
- data/lib/directory_searcher.rb +1 -1
- data/lib/exceptions.rb +0 -1
- data/lib/fcb.rb +52 -9
- data/lib/filter.rb +1 -2
- data/lib/format_table.rb +1 -0
- data/lib/fout.rb +1 -1
- data/lib/hash.rb +0 -1
- data/lib/hash_delegator.rb +404 -224
- data/lib/link_history.rb +17 -17
- data/lib/logged_struct.rb +429 -0
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +3 -3
- data/lib/mdoc.rb +21 -31
- data/lib/menu.src.yml +15 -7
- data/lib/menu.yml +11 -6
- data/lib/namer.rb +3 -6
- data/lib/null_result.rb +131 -0
- data/lib/object_present.rb +1 -1
- data/lib/option_value.rb +1 -1
- data/lib/resize_terminal.rb +1 -2
- data/lib/saved_assets.rb +1 -1
- data/lib/saved_files_matcher.rb +1 -1
- data/lib/shell_session.rb +439 -0
- data/lib/streams_out.rb +0 -1
- data/lib/string_util.rb +11 -1
- data/lib/success_result.rb +112 -0
- data/lib/text_analyzer.rb +1 -0
- data/lib/ww.rb +9 -7
- metadata +25 -3
data/lib/hash_delegator.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env bundle exec ruby
|
1
|
+
#!/usr/bin/env -S bundle exec ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# encoding=utf-8
|
@@ -45,14 +45,6 @@ require_relative 'text_analyzer'
|
|
45
45
|
$pd = false unless defined?($pd)
|
46
46
|
$table_cell_truncate = true
|
47
47
|
|
48
|
-
class String
|
49
|
-
# Checks if the string is not empty.
|
50
|
-
# @return [Boolean] Returns true if the string is not empty, false otherwise.
|
51
|
-
def non_empty?
|
52
|
-
!empty?
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
48
|
module HashDelegatorSelf
|
57
49
|
# Applies an ANSI color method to a string using a specified color key.
|
58
50
|
# The method retrieves the color method from the provided hash. If the
|
@@ -166,7 +158,7 @@ module HashDelegatorSelf
|
|
166
158
|
# (default is an empty string).
|
167
159
|
# @return [String] A single string with each line indented as specified.
|
168
160
|
def indent_all_lines(body, indent = nil)
|
169
|
-
return body unless indent&.
|
161
|
+
return body unless indent&.present?
|
170
162
|
|
171
163
|
body.lines.map { |line| indent + line.chomp }.join("\n")
|
172
164
|
end
|
@@ -862,12 +854,15 @@ module MarkdownExec
|
|
862
854
|
|
863
855
|
count = 0
|
864
856
|
blocks = []
|
857
|
+
results = {}
|
865
858
|
iter_blocks_from_nested_files do |btype, fcb|
|
866
859
|
count += 1
|
867
860
|
case btype
|
868
861
|
when :blocks
|
862
|
+
result = SuccessResult.instance
|
869
863
|
if @delegate_object[:bash]
|
870
|
-
|
864
|
+
# prepare block for menu, may fail and call HashDelegator.error_handler
|
865
|
+
result = fcb.for_menu!(
|
871
866
|
block_calls_scan: @delegate_object[:block_calls_scan],
|
872
867
|
block_name_match: @delegate_object[:block_name_match],
|
873
868
|
block_name_nick_match: @delegate_object[:block_name_nick_match],
|
@@ -878,10 +873,11 @@ module MarkdownExec
|
|
878
873
|
) do |oname, color|
|
879
874
|
apply_block_type_color_option(oname, color)
|
880
875
|
end
|
876
|
+
results[fcb.id] = result if result.failure?
|
881
877
|
else
|
882
878
|
expand_references!(fcb, link_state)
|
883
879
|
end
|
884
|
-
blocks << fcb
|
880
|
+
blocks << fcb unless result.failure?
|
885
881
|
when :filter # types accepted
|
886
882
|
%i[blocks line]
|
887
883
|
when :line
|
@@ -896,9 +892,9 @@ module MarkdownExec
|
|
896
892
|
end
|
897
893
|
end
|
898
894
|
end
|
899
|
-
|
900
|
-
blocks
|
895
|
+
OpenStruct.new(blocks: blocks, results: results)
|
901
896
|
rescue StandardError
|
897
|
+
# ww $@, $!,
|
902
898
|
HashDelegator.error_handler('blocks_from_nested_files')
|
903
899
|
end
|
904
900
|
|
@@ -914,7 +910,8 @@ module MarkdownExec
|
|
914
910
|
initial_code_required: false, key_format:
|
915
911
|
)
|
916
912
|
evaluate_shell_expressions(
|
917
|
-
(link_state&.inherited_lines_block || ''),
|
913
|
+
(link_state&.inherited_lines_block || ''),
|
914
|
+
commands,
|
918
915
|
initial_code_required: initial_code_required,
|
919
916
|
key_format: key_format
|
920
917
|
)
|
@@ -990,6 +987,52 @@ module MarkdownExec
|
|
990
987
|
]
|
991
988
|
end
|
992
989
|
|
990
|
+
# Executes the allowed exec command and processes the output
|
991
|
+
# @param export [Object] The export configuration object
|
992
|
+
# @param inherited_code [Array] The inherited code lines
|
993
|
+
# @param code_lines [Array] The code lines to append to
|
994
|
+
# @param required [Hash] Required code information
|
995
|
+
# @return [String, Symbol] The command output or :ux_exec_prohibited if execution failed
|
996
|
+
def process_allowed_exec(export, inherited_code, code_lines, required)
|
997
|
+
output = export_exec_with_code(
|
998
|
+
export, inherited_code, code_lines, required
|
999
|
+
)
|
1000
|
+
return :ux_exec_prohibited if output == :invalidated
|
1001
|
+
|
1002
|
+
output.split("\n")
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
def code_from_automatic_ux_blocks(
|
1006
|
+
all_blocks,
|
1007
|
+
mdoc
|
1008
|
+
)
|
1009
|
+
unless @ux_most_recent_filename != @delegate_object[:filename]
|
1010
|
+
return
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
blocks = select_automatic_ux_blocks(all_blocks)
|
1014
|
+
if blocks.empty?
|
1015
|
+
blocks = select_automatic_ux_blocks(all_blocks)
|
1016
|
+
end
|
1017
|
+
return if blocks.empty?
|
1018
|
+
|
1019
|
+
@ux_most_recent_filename = @delegate_object[:filename]
|
1020
|
+
|
1021
|
+
(blocks.each.with_object([]) do |block, merged_options|
|
1022
|
+
code = code_from_ux_block_to_set_environment_variables(
|
1023
|
+
block,
|
1024
|
+
mdoc,
|
1025
|
+
force: @delegate_object[:ux_auto_load_force_default],
|
1026
|
+
only_default: true
|
1027
|
+
)
|
1028
|
+
if code == :ux_exec_prohibited
|
1029
|
+
merged_options
|
1030
|
+
else
|
1031
|
+
merged_options.push(code)
|
1032
|
+
end
|
1033
|
+
end).to_a
|
1034
|
+
end
|
1035
|
+
|
993
1036
|
# parse YAML body defining the UX for a single variable
|
994
1037
|
# set ENV value for the variable and return code lines for the same
|
995
1038
|
def code_from_ux_block_to_set_environment_variables(
|
@@ -1023,105 +1066,30 @@ module MarkdownExec
|
|
1023
1066
|
code_lines.push "[[ -z $#{precondition} ]] && exit 1"
|
1024
1067
|
end
|
1025
1068
|
|
1026
|
-
exportable = true
|
1027
1069
|
if only_default
|
1028
|
-
value
|
1029
|
-
|
1030
|
-
when :echo
|
1031
|
-
raise unless export.echo.present?
|
1032
|
-
|
1033
|
-
output = export_echo_with_code(
|
1034
|
-
export, inherited_code, code_lines, required
|
1035
|
-
)
|
1036
|
-
if output == :invalidated
|
1037
|
-
return :ux_exec_prohibited
|
1038
|
-
end
|
1039
|
-
|
1040
|
-
transform_export_value(output, export)
|
1041
|
-
|
1042
|
-
# exec > default
|
1043
|
-
when :exec
|
1044
|
-
raise unless export.exec.present?
|
1045
|
-
|
1046
|
-
output = export_exec_with_code(
|
1047
|
-
export, inherited_code, code_lines, required
|
1048
|
-
)
|
1049
|
-
if output == :invalidated
|
1050
|
-
return :ux_exec_prohibited
|
1051
|
-
end
|
1052
|
-
|
1053
|
-
transform_export_value(output, export)
|
1054
|
-
|
1055
|
-
# default
|
1056
|
-
else
|
1057
|
-
export.default.to_s
|
1058
|
-
end
|
1059
|
-
else
|
1060
|
-
value = nil
|
1061
|
-
|
1062
|
-
# echo > exec
|
1063
|
-
if export.echo
|
1064
|
-
value = export_echo_with_code(
|
1070
|
+
value, exportable, transformable =
|
1071
|
+
ux_block_export_automatic(
|
1065
1072
|
export, inherited_code, code_lines, required
|
1066
1073
|
)
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
# exec > allowed
|
1072
|
-
elsif export.exec
|
1073
|
-
value = export_exec_with_code(
|
1074
|
-
export, inherited_code, code_lines, required
|
1074
|
+
else
|
1075
|
+
value, exportable, transformable =
|
1076
|
+
ux_block_export_activated(
|
1077
|
+
export, inherited_code, code_lines, required, exit_prompt
|
1075
1078
|
)
|
1076
|
-
|
1077
|
-
|
1078
|
-
end
|
1079
|
-
|
1080
|
-
# allowed > prompt
|
1081
|
-
elsif export.allowed && export.allowed.count.positive?
|
1082
|
-
case (choice = prompt_select_code_filename(
|
1083
|
-
[exit_prompt] + export.allowed,
|
1084
|
-
string: export.prompt,
|
1085
|
-
color_sym: :prompt_color_after_script_execution
|
1086
|
-
))
|
1087
|
-
when exit_prompt
|
1088
|
-
exportable = false
|
1089
|
-
else
|
1090
|
-
value = choice
|
1091
|
-
end
|
1092
|
-
|
1093
|
-
# prompt > default
|
1094
|
-
elsif export.prompt.present?
|
1095
|
-
begin
|
1096
|
-
loop do
|
1097
|
-
print "#{export.prompt} [#{export.default}]: "
|
1098
|
-
value = gets.chomp
|
1099
|
-
value = export.default.to_s if value.empty?
|
1100
|
-
caps = NamedCaptureExtractor.extract_named_groups(value,
|
1101
|
-
export.validate)
|
1102
|
-
break if caps
|
1103
|
-
|
1104
|
-
# invalid input, retry
|
1105
|
-
end
|
1106
|
-
rescue Interrupt
|
1107
|
-
exportable = false
|
1108
|
-
end
|
1079
|
+
end
|
1080
|
+
return :ux_exec_prohibited if value == :ux_exec_prohibited
|
1109
1081
|
|
1110
|
-
|
1111
|
-
|
1112
|
-
value = export
|
1082
|
+
if SelectResponse.continue?(value)
|
1083
|
+
if transformable
|
1084
|
+
value = transform_export_value(value, export)
|
1113
1085
|
end
|
1114
1086
|
|
1115
1087
|
if exportable
|
1116
|
-
|
1088
|
+
ENV[export.name] = value.to_s
|
1089
|
+
code_lines.push code_line_safe_assign(export.name, value,
|
1090
|
+
force: force)
|
1117
1091
|
end
|
1118
1092
|
end
|
1119
|
-
|
1120
|
-
if exportable
|
1121
|
-
ENV[export.name] = value.to_s
|
1122
|
-
code_lines.push code_line_safe_assign(export.name, value,
|
1123
|
-
force: force)
|
1124
|
-
end
|
1125
1093
|
else
|
1126
1094
|
raise "Invalid data type: #{data.inspect}"
|
1127
1095
|
end
|
@@ -1363,7 +1331,7 @@ module MarkdownExec
|
|
1363
1331
|
)
|
1364
1332
|
# Initialize a counter for named group occurrences
|
1365
1333
|
occurrence_count = Hash.new(0)
|
1366
|
-
return occurrence_count if pattern == //
|
1334
|
+
return occurrence_count if pattern.nil? || pattern == //
|
1367
1335
|
|
1368
1336
|
blocks.each do |block|
|
1369
1337
|
# Skip processing for shell-type blocks
|
@@ -1381,7 +1349,7 @@ module MarkdownExec
|
|
1381
1349
|
|
1382
1350
|
def count_named_group_occurrences_block_body_fix_indent(block)
|
1383
1351
|
### actually double the entries, but not a problem since it's used as a boolean
|
1384
|
-
([block.oname || ''] + block.body).join("\n")
|
1352
|
+
([block.oname || ''] + (block.body || [''])).join("\n")
|
1385
1353
|
end
|
1386
1354
|
|
1387
1355
|
##
|
@@ -1425,10 +1393,30 @@ module MarkdownExec
|
|
1425
1393
|
line_cap[:line] ||= ''
|
1426
1394
|
|
1427
1395
|
line_caps = [line_cap]
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1396
|
+
|
1397
|
+
# split text with newlines, from variable expansion
|
1398
|
+
if line_cap[:text].include?("\n")
|
1399
|
+
lines = line_cap[:text].split("\n")
|
1400
|
+
line_caps = lines.map do |line|
|
1401
|
+
line_cap.dup.merge(text: line)
|
1402
|
+
end.to_a
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
# wrap text on multiple lines to screen width, replacing line_caps
|
1406
|
+
if wrap
|
1407
|
+
line_caps = line_caps.flat_map do |line_cap|
|
1408
|
+
text = line_cap[:text]
|
1409
|
+
wrapper = StringWrapper.new(width: screen_width_for_wrapping - line_cap[:indent].length)
|
1410
|
+
|
1411
|
+
if text.length > screen_width_for_wrapping
|
1412
|
+
# Wrap this text and create line_cap objects for each part
|
1413
|
+
wrapper.wrap(text).map do |wrapped_text|
|
1414
|
+
line_cap.dup.merge(text: wrapped_text)
|
1415
|
+
end
|
1416
|
+
else
|
1417
|
+
# No change needed for this line
|
1418
|
+
line_cap
|
1419
|
+
end
|
1432
1420
|
end
|
1433
1421
|
end
|
1434
1422
|
|
@@ -1527,7 +1515,11 @@ module MarkdownExec
|
|
1527
1515
|
if block_given?
|
1528
1516
|
# expand references only if block is recognized (not a comment)
|
1529
1517
|
yield if block_given?
|
1530
|
-
|
1518
|
+
|
1519
|
+
# parse multiline to capture output of variable expansion
|
1520
|
+
mbody = fcb.body[0].match Regexp.new(
|
1521
|
+
@delegate_object[criteria[:match]], Regexp::MULTILINE
|
1522
|
+
)
|
1531
1523
|
end
|
1532
1524
|
|
1533
1525
|
create_and_add_chrome_block(
|
@@ -2432,7 +2424,8 @@ module MarkdownExec
|
|
2432
2424
|
# update blocks
|
2433
2425
|
#
|
2434
2426
|
Regexp.union(replacements.keys.map do |word|
|
2435
|
-
|
2427
|
+
# match multiline text from variable expansion
|
2428
|
+
Regexp.new(Regexp.escape(word), Regexp::MULTILINE)
|
2436
2429
|
end).tap do |pattern|
|
2437
2430
|
menu_blocks.each do |block|
|
2438
2431
|
next if exclude_types.include?(block.type)
|
@@ -2446,14 +2439,16 @@ module MarkdownExec
|
|
2446
2439
|
expand_variable_references!(
|
2447
2440
|
blocks: [fcb],
|
2448
2441
|
initial_code_required: false,
|
2449
|
-
|
2442
|
+
key_format: @delegate_object[:variable_expression_format],
|
2443
|
+
link_state: link_state,
|
2444
|
+
pattern: options_variable_expression_regexp
|
2450
2445
|
)
|
2451
2446
|
expand_variable_references!(
|
2452
2447
|
blocks: [fcb],
|
2453
2448
|
echo_format: '%s',
|
2454
2449
|
group_name: :command,
|
2455
2450
|
initial_code_required: false,
|
2456
|
-
key_format:
|
2451
|
+
key_format: @delegate_object[:command_substitution_format],
|
2457
2452
|
link_state: link_state,
|
2458
2453
|
pattern: options_command_substitution_regexp
|
2459
2454
|
)
|
@@ -2461,16 +2456,13 @@ module MarkdownExec
|
|
2461
2456
|
|
2462
2457
|
def expand_variable_references!(
|
2463
2458
|
blocks:,
|
2464
|
-
echo_format: 'echo $%s',
|
2459
|
+
echo_format: 'echo "$%s"',
|
2465
2460
|
group_name: :variable,
|
2466
2461
|
initial_code_required: false,
|
2467
|
-
key_format
|
2462
|
+
key_format:,
|
2468
2463
|
link_state:,
|
2469
|
-
pattern:
|
2464
|
+
pattern:
|
2470
2465
|
)
|
2471
|
-
pattern ||= options_variable_expression_regexp
|
2472
|
-
return if pattern.nil?
|
2473
|
-
|
2474
2466
|
variable_counts = count_named_group_occurrences(blocks, pattern,
|
2475
2467
|
group_name: group_name)
|
2476
2468
|
return if variable_counts.nil? || variable_counts == {}
|
@@ -2489,9 +2481,11 @@ module MarkdownExec
|
|
2489
2481
|
expand_blocks_with_replacements(blocks, replacements)
|
2490
2482
|
end
|
2491
2483
|
|
2492
|
-
def
|
2484
|
+
def export_echo_with_code_single(export_echo, inherited_code, code_lines,
|
2485
|
+
required)
|
2486
|
+
code = %(printf '%s' "#{export_echo}")
|
2493
2487
|
value = execute_temporary_script(
|
2494
|
-
|
2488
|
+
code,
|
2495
2489
|
(inherited_code || []) +
|
2496
2490
|
code_lines + required[:code]
|
2497
2491
|
)
|
@@ -2501,6 +2495,26 @@ module MarkdownExec
|
|
2501
2495
|
value
|
2502
2496
|
end
|
2503
2497
|
|
2498
|
+
def export_echo_with_code(export, inherited_code, code_lines, required,
|
2499
|
+
force:)
|
2500
|
+
exportable = true
|
2501
|
+
case export.echo
|
2502
|
+
when String, Integer, Float, TrueClass, FalseClass
|
2503
|
+
value = export_echo_with_code_single(export.echo.to_s, inherited_code,
|
2504
|
+
code_lines, required)
|
2505
|
+
when Hash
|
2506
|
+
# each item in the hash is a variable name and value
|
2507
|
+
export.echo.each do |name, expression|
|
2508
|
+
value = export_echo_with_code_single(expression, inherited_code,
|
2509
|
+
code_lines, required)
|
2510
|
+
ENV[name] = value.to_s
|
2511
|
+
code_lines.push code_line_safe_assign(name, value, force: force)
|
2512
|
+
end
|
2513
|
+
exportable = false
|
2514
|
+
end
|
2515
|
+
[value, exportable]
|
2516
|
+
end
|
2517
|
+
|
2504
2518
|
def export_exec_with_code(export, inherited_code, code_lines, required)
|
2505
2519
|
value = execute_temporary_script(
|
2506
2520
|
export.exec,
|
@@ -2555,7 +2569,7 @@ module MarkdownExec
|
|
2555
2569
|
end
|
2556
2570
|
|
2557
2571
|
@dml_blocks_in_file.find(&match_block) ||
|
2558
|
-
|
2572
|
+
@dml_menu_blocks.find(&match_block)
|
2559
2573
|
end
|
2560
2574
|
|
2561
2575
|
# find a block by its original (undecorated) name or nickname (not visible in menu)
|
@@ -2763,7 +2777,7 @@ module MarkdownExec
|
|
2763
2777
|
menu_entries, current_display_format
|
2764
2778
|
)
|
2765
2779
|
|
2766
|
-
selection =
|
2780
|
+
selection = prompt_select_from_list(
|
2767
2781
|
menu_options,
|
2768
2782
|
string: menu_title,
|
2769
2783
|
color_sym: :prompt_color_after_script_execution
|
@@ -2819,7 +2833,7 @@ module MarkdownExec
|
|
2819
2833
|
def iter_source_blocks(source, source_id: nil, &block)
|
2820
2834
|
case source
|
2821
2835
|
when 1
|
2822
|
-
blocks_from_nested_files(source_id: source_id).each(&block)
|
2836
|
+
blocks_from_nested_files(source_id: source_id).blocks.each(&block)
|
2823
2837
|
when 2
|
2824
2838
|
@dml_blocks_in_file.each(&block)
|
2825
2839
|
when 3
|
@@ -2862,7 +2876,8 @@ module MarkdownExec
|
|
2862
2876
|
nil),
|
2863
2877
|
end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
|
2864
2878
|
scan1: @delegate_object.fetch(:output_assignment_match, nil),
|
2865
|
-
format1: @delegate_object.fetch(:output_assignment_format, nil)
|
2879
|
+
format1: @delegate_object.fetch(:output_assignment_format, nil),
|
2880
|
+
name: ''
|
2866
2881
|
)
|
2867
2882
|
|
2868
2883
|
else
|
@@ -2969,69 +2984,45 @@ module MarkdownExec
|
|
2969
2984
|
@fout.fout_list(list)
|
2970
2985
|
end
|
2971
2986
|
|
2972
|
-
# Loads auto blocks
|
2973
|
-
#
|
2974
|
-
#
|
2975
|
-
#
|
2976
|
-
#
|
2987
|
+
# Loads and updates auto options for document blocks if the current filename has changed.
|
2988
|
+
#
|
2989
|
+
# This method checks if the delegate object specifies a document load options block name and if the filename
|
2990
|
+
# has been updated. It then selects the appropriate blocks, collects their dependencies, processes their
|
2991
|
+
# options, and updates the menu base with the merged options.
|
2992
|
+
#
|
2993
|
+
# @param all_blocks [Array] An array of all block elements.
|
2994
|
+
# @param mdoc [Object] The document object managing dependencies and options.
|
2995
|
+
# @return [Boolean, nil] Returns true if options were updated; nil otherwise.
|
2977
2996
|
def load_auto_opts_block(all_blocks, mdoc:)
|
2978
|
-
|
2979
|
-
|
2980
|
-
@opts_most_recent_filename != @delegate_object[:filename]
|
2981
|
-
return
|
2982
|
-
end
|
2997
|
+
opts_block_name = @delegate_object[:document_load_opts_block_name]
|
2998
|
+
current_filename = @delegate_object[:filename]
|
2983
2999
|
|
2984
|
-
|
2985
|
-
|
3000
|
+
return unless opts_block_name.present? &&
|
3001
|
+
@opts_most_recent_filename != current_filename
|
3002
|
+
|
3003
|
+
selected_blocks = HashDelegator.block_select(all_blocks, :oname,
|
3004
|
+
opts_block_name)
|
3005
|
+
return if selected_blocks.empty?
|
3006
|
+
|
3007
|
+
dependency_map = {}
|
3008
|
+
selected_blocks.each do |block|
|
3009
|
+
mdoc.collect_dependencies(memo: dependency_map, block: block)
|
3010
|
+
end
|
2986
3011
|
|
2987
|
-
|
2988
|
-
|
3012
|
+
collected_options =
|
3013
|
+
dependency_map.each.with_object({}) do |(block_id, _), merged_options|
|
3014
|
+
matching_block = HashDelegator.block_find(all_blocks, :id, block_id)
|
2989
3015
|
options_state = read_show_options_and_trigger_reuse(
|
2990
|
-
mdoc: mdoc,
|
2991
|
-
selected: block
|
3016
|
+
mdoc: mdoc, selected: matching_block
|
2992
3017
|
)
|
2993
3018
|
merged_options.merge!(options_state.options)
|
2994
3019
|
end
|
2995
|
-
)
|
2996
3020
|
|
2997
|
-
|
3021
|
+
update_menu_base(collected_options)
|
3022
|
+
@opts_most_recent_filename = current_filename
|
2998
3023
|
true
|
2999
3024
|
end
|
3000
3025
|
|
3001
|
-
def load_auto_ux_block(
|
3002
|
-
all_blocks,
|
3003
|
-
mdoc,
|
3004
|
-
block_name: @delegate_object[:document_load_ux_block_name]
|
3005
|
-
)
|
3006
|
-
unless block_name.present? &&
|
3007
|
-
@ux_most_recent_filename != @delegate_object[:filename]
|
3008
|
-
return
|
3009
|
-
end
|
3010
|
-
|
3011
|
-
blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
|
3012
|
-
if blocks.empty?
|
3013
|
-
blocks = HashDelegator.block_match(all_blocks, :nickname,
|
3014
|
-
Regexp.new(block_name))
|
3015
|
-
end
|
3016
|
-
return if blocks.empty?
|
3017
|
-
|
3018
|
-
@ux_most_recent_filename = @delegate_object[:filename]
|
3019
|
-
|
3020
|
-
(blocks.each.with_object([]) do |block, merged_options|
|
3021
|
-
code = code_from_ux_block_to_set_environment_variables(
|
3022
|
-
block,
|
3023
|
-
mdoc,
|
3024
|
-
force: @delegate_object[:ux_auto_load_force_default],
|
3025
|
-
only_default: true
|
3026
|
-
)
|
3027
|
-
if code == :ux_exec_prohibited
|
3028
|
-
merged_options
|
3029
|
-
else
|
3030
|
-
merged_options.push(code)
|
3031
|
-
end
|
3032
|
-
end).to_a
|
3033
|
-
end
|
3034
|
-
|
3035
3026
|
def load_auto_vars_block(
|
3036
3027
|
all_blocks,
|
3037
3028
|
block_name: @delegate_object[:document_load_vars_block_name]
|
@@ -3123,7 +3114,7 @@ module MarkdownExec
|
|
3123
3114
|
else
|
3124
3115
|
## user selects from existing files or other
|
3125
3116
|
#
|
3126
|
-
case (name =
|
3117
|
+
case (name = prompt_select_from_list(
|
3127
3118
|
[@delegate_object[:prompt_filespec_back]] + files,
|
3128
3119
|
string: @delegate_object[:prompt_select_code_file],
|
3129
3120
|
color_sym: :prompt_color_after_script_execution
|
@@ -3154,11 +3145,19 @@ module MarkdownExec
|
|
3154
3145
|
end
|
3155
3146
|
|
3156
3147
|
def mdoc_and_blocks_from_nested_files(source_id: nil)
|
3157
|
-
|
3158
|
-
|
3148
|
+
blocks_results = blocks_from_nested_files(source_id: source_id)
|
3149
|
+
|
3150
|
+
blocks_results.results.select do |_id, result|
|
3151
|
+
result.failure?
|
3152
|
+
end.each do |id, result|
|
3153
|
+
HashDelegator.error_handler("#{id} - #{result.to_yaml}")
|
3154
|
+
end
|
3155
|
+
|
3156
|
+
mdoc = MDoc.new(blocks_results.blocks) do |nopts|
|
3159
3157
|
@delegate_object.merge!(nopts)
|
3160
3158
|
end
|
3161
|
-
|
3159
|
+
|
3160
|
+
[blocks_results.blocks, mdoc]
|
3162
3161
|
end
|
3163
3162
|
|
3164
3163
|
## Handles the file loading and returns the blocks
|
@@ -3184,7 +3183,7 @@ module MarkdownExec
|
|
3184
3183
|
|
3185
3184
|
# load document ux block
|
3186
3185
|
#
|
3187
|
-
if (code_lines =
|
3186
|
+
if (code_lines = code_from_automatic_ux_blocks(all_blocks, mdoc))
|
3188
3187
|
new_code = HashDelegator.code_merge(link_state.inherited_lines,
|
3189
3188
|
code_lines)
|
3190
3189
|
next_state_set_code(nil, link_state, new_code)
|
@@ -3305,6 +3304,19 @@ module MarkdownExec
|
|
3305
3304
|
end
|
3306
3305
|
end
|
3307
3306
|
|
3307
|
+
def menu_from_list_with_back(list)
|
3308
|
+
case (name = prompt_select_from_list(
|
3309
|
+
[@delegate_object[:prompt_filespec_back]] + list,
|
3310
|
+
string: @delegate_object[:prompt_select_code_file],
|
3311
|
+
color_sym: :prompt_color_after_script_execution
|
3312
|
+
))
|
3313
|
+
when @delegate_object[:prompt_filespec_back]
|
3314
|
+
SelectResponse::BACK
|
3315
|
+
else
|
3316
|
+
name
|
3317
|
+
end
|
3318
|
+
end
|
3319
|
+
|
3308
3320
|
def menu_toggle_collapsible_block(selected)
|
3309
3321
|
# return true if @compress_ids.key?(fcb.id) && !!@compress_ids[fcb.id]
|
3310
3322
|
# return false if @expand_ids.key?(fcb.id) && !!@expand_ids[fcb.id]
|
@@ -3487,6 +3499,11 @@ module MarkdownExec
|
|
3487
3499
|
fout_execution_report if @delegate_object[:output_execution_report]
|
3488
3500
|
end
|
3489
3501
|
|
3502
|
+
# all UX blocks are automatic for the document
|
3503
|
+
def select_automatic_ux_blocks(blocks)
|
3504
|
+
blocks.select { |item| item.type == 'ux' }
|
3505
|
+
end
|
3506
|
+
|
3490
3507
|
# Filter blocks per block_name_include_match, block_name_wrapper_match.
|
3491
3508
|
#
|
3492
3509
|
# @param all_blocks [Array<Hash>] The list of blocks from the file.
|
@@ -3538,7 +3555,7 @@ module MarkdownExec
|
|
3538
3555
|
# private
|
3539
3556
|
|
3540
3557
|
def process_string_array(arr, begin_pattern: nil, end_pattern: nil, scan1: nil,
|
3541
|
-
format1: nil)
|
3558
|
+
format1: nil, name: '')
|
3542
3559
|
in_block = !begin_pattern.present?
|
3543
3560
|
collected_lines = []
|
3544
3561
|
|
@@ -3560,6 +3577,9 @@ module MarkdownExec
|
|
3560
3577
|
collected_lines << formatted
|
3561
3578
|
end
|
3562
3579
|
end
|
3580
|
+
elsif format1.present?
|
3581
|
+
formatted = format(format1, { value: line })
|
3582
|
+
collected_lines << formatted
|
3563
3583
|
else
|
3564
3584
|
collected_lines << line
|
3565
3585
|
end
|
@@ -3685,9 +3705,22 @@ module MarkdownExec
|
|
3685
3705
|
0
|
3686
3706
|
end
|
3687
3707
|
|
3708
|
+
def prompt_select_continue(filter: true, quiet: true)
|
3709
|
+
sel = @prompt.select(
|
3710
|
+
string_send_color(@delegate_object[:prompt_after_script_execution],
|
3711
|
+
:prompt_color_after_script_execution),
|
3712
|
+
filter: filter,
|
3713
|
+
quiet: quiet
|
3714
|
+
) do |menu|
|
3715
|
+
menu.choice @delegate_object[:prompt_yes]
|
3716
|
+
menu.choice @delegate_object[:prompt_exit]
|
3717
|
+
end
|
3718
|
+
sel == @delegate_object[:prompt_exit] ? MenuState::EXIT : MenuState::CONTINUE
|
3719
|
+
end
|
3720
|
+
|
3688
3721
|
# public
|
3689
3722
|
|
3690
|
-
def
|
3723
|
+
def prompt_select_from_list(
|
3691
3724
|
filenames,
|
3692
3725
|
color_sym: :prompt_color_after_script_execution,
|
3693
3726
|
cycle: true,
|
@@ -3713,19 +3746,6 @@ module MarkdownExec
|
|
3713
3746
|
end
|
3714
3747
|
end
|
3715
3748
|
|
3716
|
-
def prompt_select_continue(filter: true, quiet: true)
|
3717
|
-
sel = @prompt.select(
|
3718
|
-
string_send_color(@delegate_object[:prompt_after_script_execution],
|
3719
|
-
:prompt_color_after_script_execution),
|
3720
|
-
filter: filter,
|
3721
|
-
quiet: quiet
|
3722
|
-
) do |menu|
|
3723
|
-
menu.choice @delegate_object[:prompt_yes]
|
3724
|
-
menu.choice @delegate_object[:prompt_exit]
|
3725
|
-
end
|
3726
|
-
sel == @delegate_object[:prompt_exit] ? MenuState::EXIT : MenuState::CONTINUE
|
3727
|
-
end
|
3728
|
-
|
3729
3749
|
# user prompt to exit if the menu will be displayed again
|
3730
3750
|
#
|
3731
3751
|
def prompt_user_exit(block_name_from_cli:, selected:)
|
@@ -3799,27 +3819,6 @@ module MarkdownExec
|
|
3799
3819
|
end&.compact
|
3800
3820
|
end
|
3801
3821
|
|
3802
|
-
def saved_asset_for_history(
|
3803
|
-
file:, form:, match_info:
|
3804
|
-
)
|
3805
|
-
OpenStruct.new(
|
3806
|
-
file: file[(Dir.pwd.length + 1)..-1],
|
3807
|
-
full: file,
|
3808
|
-
row: format(
|
3809
|
-
form,
|
3810
|
-
# default '*' so unknown parameters are given a wildcard
|
3811
|
-
match_info.names.each_with_object(Hash.new('*')) do |name, hash|
|
3812
|
-
hash[name.to_sym] = match_info[name]
|
3813
|
-
end
|
3814
|
-
)
|
3815
|
-
)
|
3816
|
-
rescue KeyError
|
3817
|
-
# pp $!, $@
|
3818
|
-
warn "Cannot format with: #{@delegate_object[:saved_history_format]}"
|
3819
|
-
error_handler('saved_history_format')
|
3820
|
-
:break
|
3821
|
-
end
|
3822
|
-
|
3823
3822
|
# Processes YAML data from the selected menu item, updating delegate
|
3824
3823
|
# objects and optionally printing formatted output.
|
3825
3824
|
# @param selected [Hash] Selected item from the menu containing a YAML body.
|
@@ -3874,8 +3873,8 @@ module MarkdownExec
|
|
3874
3873
|
# console [height, width]. If not provided or if the terminal
|
3875
3874
|
# is resized, it will be set to the current console dimensions.
|
3876
3875
|
# - :select_page_height [Integer, nil] The height of the page for
|
3877
|
-
# selection. If not provided or if not positive, it
|
3878
|
-
# to the maximum of (console height - 3) or 4.
|
3876
|
+
# selection. If not provided or if not positive, it
|
3877
|
+
# will be set to the maximum of (console height - 3) or 4.
|
3879
3878
|
# - :per_page [Integer, nil] The number of items per page. If
|
3880
3879
|
# :select_page_height is not provided or if not positive, it
|
3881
3880
|
# will be set to the maximum of (console height - 3) or 4.
|
@@ -4002,7 +4001,7 @@ module MarkdownExec
|
|
4002
4001
|
## user selects from existing files or other
|
4003
4002
|
# input into path with wildcard for easy entry
|
4004
4003
|
#
|
4005
|
-
case (name =
|
4004
|
+
case (name = prompt_select_from_list(
|
4006
4005
|
[@delegate_object[:prompt_filespec_back],
|
4007
4006
|
@delegate_object[:prompt_filespec_other]] + files,
|
4008
4007
|
string: @delegate_object[:prompt_select_code_file],
|
@@ -4039,6 +4038,27 @@ module MarkdownExec
|
|
4039
4038
|
).generate_name
|
4040
4039
|
end
|
4041
4040
|
|
4041
|
+
def saved_asset_for_history(
|
4042
|
+
file:, form:, match_info:
|
4043
|
+
)
|
4044
|
+
OpenStruct.new(
|
4045
|
+
file: file[(Dir.pwd.length + 1)..-1],
|
4046
|
+
full: file,
|
4047
|
+
row: format(
|
4048
|
+
form,
|
4049
|
+
# default '*' so unknown parameters are given a wildcard
|
4050
|
+
match_info.names.each_with_object(Hash.new('*')) do |name, hash|
|
4051
|
+
hash[name.to_sym] = match_info[name]
|
4052
|
+
end
|
4053
|
+
)
|
4054
|
+
)
|
4055
|
+
rescue KeyError
|
4056
|
+
# pp $!, $@
|
4057
|
+
warn "Cannot format with: #{@delegate_object[:saved_history_format]}"
|
4058
|
+
error_handler('saved_history_format')
|
4059
|
+
:break
|
4060
|
+
end
|
4061
|
+
|
4042
4062
|
def screen_width
|
4043
4063
|
width = @delegate_object[:screen_width]
|
4044
4064
|
if width&.positive?
|
@@ -4387,6 +4407,166 @@ module MarkdownExec
|
|
4387
4407
|
@delegate_object.merge!(options)
|
4388
4408
|
end
|
4389
4409
|
|
4410
|
+
def ux_block_export_activated(export, inherited_code, code_lines, required,
|
4411
|
+
exit_prompt)
|
4412
|
+
exportable = true
|
4413
|
+
transformable = true
|
4414
|
+
[if export.allowed.present?
|
4415
|
+
if export.allowed == :echo
|
4416
|
+
output, exportable = export_echo_with_code(
|
4417
|
+
export, inherited_code, code_lines, required, force: true
|
4418
|
+
)
|
4419
|
+
return :ux_exec_prohibited if output == :invalidated
|
4420
|
+
|
4421
|
+
menu_from_list_with_back(output.split("\n"))
|
4422
|
+
|
4423
|
+
elsif export.allowed == :exec
|
4424
|
+
output = process_allowed_exec(export, inherited_code,
|
4425
|
+
code_lines, required)
|
4426
|
+
return :ux_exec_prohibited if output == :ux_exec_prohibited
|
4427
|
+
|
4428
|
+
menu_from_list_with_back(output)
|
4429
|
+
|
4430
|
+
else
|
4431
|
+
menu_from_list_with_back(export.allowed)
|
4432
|
+
end
|
4433
|
+
|
4434
|
+
# echo > exec
|
4435
|
+
elsif export.echo
|
4436
|
+
output, exportable = export_echo_with_code(
|
4437
|
+
export, inherited_code, code_lines, required, force: true
|
4438
|
+
)
|
4439
|
+
return :ux_exec_prohibited if output == :invalidated
|
4440
|
+
|
4441
|
+
output
|
4442
|
+
|
4443
|
+
# exec > allowed
|
4444
|
+
elsif export.exec
|
4445
|
+
output = export_exec_with_code(
|
4446
|
+
export, inherited_code, code_lines, required
|
4447
|
+
)
|
4448
|
+
return :ux_exec_prohibited if output == :invalidated
|
4449
|
+
|
4450
|
+
output
|
4451
|
+
|
4452
|
+
# allowed > prompt
|
4453
|
+
elsif export.allowed && export.allowed.count.positive?
|
4454
|
+
case (choice = prompt_select_from_list(
|
4455
|
+
[exit_prompt] + export.allowed,
|
4456
|
+
string: export.prompt,
|
4457
|
+
color_sym: :prompt_color_after_script_execution
|
4458
|
+
))
|
4459
|
+
when exit_prompt
|
4460
|
+
exportable = false
|
4461
|
+
transformable = false
|
4462
|
+
nil
|
4463
|
+
else
|
4464
|
+
choice
|
4465
|
+
end
|
4466
|
+
|
4467
|
+
# prompt > default
|
4468
|
+
elsif export.prompt.present?
|
4469
|
+
begin
|
4470
|
+
loop do
|
4471
|
+
print "#{export.prompt} [#{export.default}]: "
|
4472
|
+
output = gets.chomp
|
4473
|
+
output = export.default.to_s if output.empty?
|
4474
|
+
caps = NamedCaptureExtractor.extract_named_groups(output,
|
4475
|
+
export.validate)
|
4476
|
+
break if caps
|
4477
|
+
|
4478
|
+
# invalid input, retry
|
4479
|
+
end
|
4480
|
+
rescue Interrupt
|
4481
|
+
exportable = false
|
4482
|
+
transformable = false
|
4483
|
+
end
|
4484
|
+
|
4485
|
+
output
|
4486
|
+
|
4487
|
+
# default
|
4488
|
+
else
|
4489
|
+
transformable = false
|
4490
|
+
export.default
|
4491
|
+
end, exportable, transformable]
|
4492
|
+
end
|
4493
|
+
|
4494
|
+
def ux_block_export_automatic(export, inherited_code, code_lines, required)
|
4495
|
+
transformable = true
|
4496
|
+
exportable = true
|
4497
|
+
|
4498
|
+
if export.default == false
|
4499
|
+
exportable = false
|
4500
|
+
transformable = false
|
4501
|
+
value = nil
|
4502
|
+
else
|
4503
|
+
if export.default.nil?
|
4504
|
+
if export.echo.present?
|
4505
|
+
export.default = :echo
|
4506
|
+
elsif export.exec.present?
|
4507
|
+
export.default = :exec
|
4508
|
+
elsif export.allowed.present?
|
4509
|
+
export.default = export.allowed.first
|
4510
|
+
end
|
4511
|
+
end
|
4512
|
+
|
4513
|
+
value = case export.default
|
4514
|
+
when :allowed
|
4515
|
+
raise unless export.allowed.present?
|
4516
|
+
|
4517
|
+
if export.allowed == :echo
|
4518
|
+
output, exportable = export_echo_with_code(
|
4519
|
+
export, inherited_code, code_lines, required, force: false
|
4520
|
+
)
|
4521
|
+
return :ux_exec_prohibited if output == :invalidated
|
4522
|
+
|
4523
|
+
exportable && output.split("\n").first
|
4524
|
+
|
4525
|
+
elsif export.allowed == :exec
|
4526
|
+
output = process_allowed_exec(export, inherited_code,
|
4527
|
+
code_lines, required)
|
4528
|
+
return :ux_exec_prohibited if output == :ux_exec_prohibited
|
4529
|
+
|
4530
|
+
output.first
|
4531
|
+
|
4532
|
+
else
|
4533
|
+
export.allowed.first
|
4534
|
+
end
|
4535
|
+
|
4536
|
+
# echo > default
|
4537
|
+
when :echo
|
4538
|
+
raise unless export.echo.present?
|
4539
|
+
|
4540
|
+
output, exportable = export_echo_with_code(
|
4541
|
+
export, inherited_code, code_lines, required, force: false
|
4542
|
+
)
|
4543
|
+
return :ux_exec_prohibited if output == :invalidated
|
4544
|
+
|
4545
|
+
output
|
4546
|
+
|
4547
|
+
# exec > default
|
4548
|
+
when :exec
|
4549
|
+
raise unless export.exec.present?
|
4550
|
+
|
4551
|
+
output = export_exec_with_code(
|
4552
|
+
export, inherited_code, code_lines, required
|
4553
|
+
)
|
4554
|
+
return :ux_exec_prohibited if output == :invalidated
|
4555
|
+
|
4556
|
+
output
|
4557
|
+
|
4558
|
+
# default
|
4559
|
+
else
|
4560
|
+
transformable = false
|
4561
|
+
export.default.to_s
|
4562
|
+
end
|
4563
|
+
end
|
4564
|
+
|
4565
|
+
[value,
|
4566
|
+
exportable,
|
4567
|
+
transformable]
|
4568
|
+
end
|
4569
|
+
|
4390
4570
|
def vux_await_user_selection(prior_answer: @dml_block_selection)
|
4391
4571
|
@dml_block_state = load_cli_or_user_selected_block(
|
4392
4572
|
all_blocks: @dml_blocks_in_file,
|
@@ -5324,7 +5504,7 @@ module MarkdownExec
|
|
5324
5504
|
end
|
5325
5505
|
|
5326
5506
|
def test_blocks_from_nested_files
|
5327
|
-
result = @hd.blocks_from_nested_files
|
5507
|
+
result = @hd.blocks_from_nested_files.blocks
|
5328
5508
|
assert_kind_of Array, result
|
5329
5509
|
assert_kind_of FCB, result.first
|
5330
5510
|
end
|
@@ -5333,7 +5513,7 @@ module MarkdownExec
|
|
5333
5513
|
@hd = HashDelegator.new(no_chrome: true)
|
5334
5514
|
@hd.expects(:create_and_add_chrome_blocks).never
|
5335
5515
|
|
5336
|
-
result = @hd.blocks_from_nested_files
|
5516
|
+
result = @hd.blocks_from_nested_files.blocks
|
5337
5517
|
|
5338
5518
|
assert_kind_of Array, result
|
5339
5519
|
end
|