markdown_exec 3.0.4 → 3.0.6

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/Gemfile.lock +1 -1
  4. data/bats/block-type-ux-act-init.bats +17 -0
  5. data/bats/block-type-ux-echo-hash-transform.bats +8 -0
  6. data/bats/block-type-ux-echo.bats +1 -1
  7. data/bats/block-type-ux-sources.bats +1 -1
  8. data/bats/block-type-ux-transform.bats +1 -1
  9. data/bats/import-conflict.bats +11 -0
  10. data/bats/import-duplicates.bats +53 -0
  11. data/bats/variable-expansion-multiline.bats +1 -1
  12. data/bin/bmde +4 -3
  13. data/docs/dev/block-type-ux-act-init.md +187 -0
  14. data/docs/dev/block-type-ux-auto.md +0 -1
  15. data/docs/dev/block-type-ux-default.md +2 -2
  16. data/docs/dev/block-type-ux-echo-hash-transform.md +40 -0
  17. data/docs/dev/block-type-ux-echo.md +3 -0
  18. data/docs/dev/block-type-ux-exec.md +0 -1
  19. data/docs/dev/block-type-ux-sources.md +1 -1
  20. data/docs/dev/block-type-ux-transform.md +5 -4
  21. data/docs/dev/command-substitution.md +1 -0
  22. data/docs/dev/import-conflict-0.md +12 -0
  23. data/docs/dev/import-conflict-1.md +7 -0
  24. data/docs/dev/import-duplicates-0.md +17 -0
  25. data/docs/dev/import-duplicates-1.md +13 -0
  26. data/docs/dev/load_code.md +1 -0
  27. data/docs/dev/no-active-elements.md +1 -0
  28. data/docs/dev/variable-expansion-multiline.md +4 -1
  29. data/docs/ux-blocks-examples.md +120 -0
  30. data/docs/ux-blocks-init-act.md +100 -0
  31. data/lib/command_result.rb +51 -0
  32. data/lib/command_result_alternatives.rb +233 -0
  33. data/lib/env_interface.rb +57 -0
  34. data/lib/fcb.rb +1 -1
  35. data/lib/hash_delegator.rb +207 -123
  36. data/lib/markdown_exec/version.rb +1 -1
  37. data/lib/resize_terminal.rb +11 -5
  38. data/lib/ww.rb +4 -1
  39. metadata +16 -2
@@ -44,6 +44,7 @@ require_relative 'string_util'
44
44
  require_relative 'table_extractor'
45
45
  require_relative 'text_analyzer'
46
46
  require_relative 'value_or_exception'
47
+ require_relative 'env_interface'
47
48
 
48
49
  $pd = false unless defined?($pd)
49
50
  $table_cell_truncate = true
@@ -96,10 +97,6 @@ module HashDelegatorSelf
96
97
  blocks.select { |item| item.send(msg) == value }
97
98
  end
98
99
 
99
- def code_merge(*bodies)
100
- merge_lists(*bodies)
101
- end
102
-
103
100
  def count_matches_in_lines(lines, regex)
104
101
  lines.count { |line| line.to_s.match(regex) }
105
102
  end
@@ -157,6 +154,14 @@ module HashDelegatorSelf
157
154
  )
158
155
  end
159
156
 
157
+ # Takes multiple arrays as arguments, flattens them into a single array, and removes nil values.
158
+ # @param args [Array<Array>] Variable number of arrays to be processed
159
+ # @return [Array] A single flattened array with nil values removed, or an empty array if the result is empty
160
+ def flatten_and_compact_arrays(*args)
161
+ merged = args.compact.flatten
162
+ merged.empty? ? [] : merged
163
+ end
164
+
160
165
  # Indents all lines in a given string with a specified indentation string.
161
166
  # @param body [String] A multi-line string to be indented.
162
167
  # @param indent [String] The string used for indentation
@@ -177,13 +182,6 @@ module HashDelegatorSelf
177
182
  ((lines || []) + ['']).join("\n")
178
183
  end
179
184
 
180
- def merge_lists(*args)
181
- # Filters out nil values, flattens the arrays, and ensures an
182
- # empty list is returned if no valid lists are provided.
183
- merged = args.compact.flatten
184
- merged.empty? ? [] : merged
185
- end
186
-
187
185
  def next_link_state(
188
186
  block_name_from_cli:, was_using_cli:, block_state:, block_name: nil
189
187
  )
@@ -501,10 +499,6 @@ class BashCommentFormatter
501
499
  end
502
500
  formatted.join("\n")
503
501
  end
504
- # # fit oname in single bash comment
505
- # def oname_for_bash_comment(oname)
506
- # oname.gsub("\n", ' ~ ').gsub(/ +/, ' ')
507
- # end
508
502
  end
509
503
 
510
504
  class StringWrapper
@@ -1094,17 +1088,18 @@ module MarkdownExec
1094
1088
  @ux_most_recent_filename = @delegate_object[:filename]
1095
1089
 
1096
1090
  (blocks.each.with_object([]) do |block, merged_options|
1097
- command_result_w_e_t_nl = code_from_ux_block_to_set_environment_variables(
1098
- block,
1099
- mdoc,
1100
- force: @delegate_object[:ux_auto_load_force_default],
1101
- only_default: true,
1102
- silent: true
1103
- )
1091
+ command_result_w_e_t_nl =
1092
+ code_from_ux_block_to_set_environment_variables(
1093
+ block,
1094
+ mdoc,
1095
+ force: @delegate_object[:ux_auto_load_force_default],
1096
+ only_default: true,
1097
+ silent: true
1098
+ )
1104
1099
  if command_result_w_e_t_nl.failure?
1105
1100
  merged_options
1106
1101
  else
1107
- merged_options.push(command_result_w_e_t_nl.stdout)
1102
+ merged_options.push(command_result_w_e_t_nl.new_lines)
1108
1103
  end
1109
1104
  end).to_a
1110
1105
  end
@@ -1115,6 +1110,7 @@ module MarkdownExec
1115
1110
  selected, mdoc, inherited_code: nil, force: true, only_default: false,
1116
1111
  silent:
1117
1112
  )
1113
+ ret_command_result = nil
1118
1114
  exit_prompt = @delegate_object[:prompt_filespec_back]
1119
1115
 
1120
1116
  required = mdoc.collect_recursively_required_code(
@@ -1169,26 +1165,32 @@ module MarkdownExec
1169
1165
  end
1170
1166
  return command_result_w_e_t_nl if command_result_w_e_t_nl.failure?
1171
1167
 
1172
- required_lines.concat(command_result_w_e_t_nl.new_lines)
1173
- if SelectResponse.continue?(command_result_w_e_t_nl.stdout)
1174
- if command_result_w_e_t_nl.transformable
1175
- command_result_w_e_t_nl.stdout = transform_export_value(
1176
- command_result_w_e_t_nl.stdout, export
1177
- )
1178
- end
1168
+ command_result_w_e_t_nl.new_lines =
1169
+ command_result_w_e_t_nl.new_lines.map do |name_force|
1170
+ transformed = if command_result_w_e_t_nl.transformable
1171
+ transform_export_value(name_force[:text], export)
1172
+ else
1173
+ name_force[:text]
1179
1174
 
1180
- if command_result_w_e_t_nl.exportable
1181
- ENV[export.name] = command_result_w_e_t_nl.stdout.to_s
1182
- required_lines.push code_line_safe_assign(export.name, command_result_w_e_t_nl.stdout,
1183
- force: force)
1175
+ end
1176
+ EnvInterface.set(name_force[:name], transformed)
1177
+
1178
+ code_line_safe_assign(
1179
+ name_force[:name], transformed, force: name_force[:force]
1180
+ )
1184
1181
  end
1185
- end
1182
+ required_lines.concat(command_result_w_e_t_nl.new_lines)
1183
+ ret_command_result = command_result_w_e_t_nl
1186
1184
  else
1187
1185
  raise "Invalid data type: #{data.inspect}"
1188
1186
  end
1189
1187
  end
1190
1188
 
1191
- CommandResult.new(stdout: required_lines)
1189
+ ret_command_result || CommandResult.new(stdout: required_lines)
1190
+ end
1191
+
1192
+ def env_set(name, value)
1193
+ EnvInterface.set(name, value)
1192
1194
  end
1193
1195
 
1194
1196
  # sets ENV
@@ -1197,7 +1199,7 @@ module MarkdownExec
1197
1199
  case data = YAML.load(selected.body.join("\n"))
1198
1200
  when Hash
1199
1201
  data.each do |key, value|
1200
- ENV[key] = value.to_s
1202
+ EnvInterface.set(key, value.to_s)
1201
1203
  code_lines.push "#{key}=#{Shellwords.escape(value)}"
1202
1204
 
1203
1205
  next unless @delegate_object[:menu_vars_set_format].present?
@@ -1891,7 +1893,7 @@ module MarkdownExec
1891
1893
  before_mtime = temp_file.mtime
1892
1894
 
1893
1895
  # Open the temporary file in the default editor
1894
- system("#{ENV['EDITOR'] || 'vi'} #{temp_file.path}")
1896
+ system("#{EnvInterface.get('EDITOR', default: 'vi')} #{temp_file.path}")
1895
1897
 
1896
1898
  # Capture the exit status of the editor
1897
1899
  editor_exit_status = $?.exitstatus
@@ -2034,13 +2036,16 @@ module MarkdownExec
2034
2036
  next_state_append_code(
2035
2037
  selected,
2036
2038
  link_state,
2037
- command_result_w_e_t_nl.failure? ? [] : command_result_w_e_t_nl.stdout
2039
+ command_result_w_e_t_nl.failure? ? [] : command_result_w_e_t_nl.new_lines
2038
2040
  )
2039
2041
 
2040
2042
  elsif selected.type == BlockType::VARS
2041
2043
  debounce_reset
2042
- next_state_append_code(selected, link_state,
2043
- code_from_vars_block_to_set_environment_variables(selected))
2044
+ next_state_append_code(
2045
+ selected,
2046
+ link_state,
2047
+ code_from_vars_block_to_set_environment_variables(selected)
2048
+ )
2044
2049
 
2045
2050
  elsif COLLAPSIBLE_TYPES.include?(selected.type)
2046
2051
  debounce_reset
@@ -2165,7 +2170,7 @@ module MarkdownExec
2165
2170
  if link_block_data[LinkKeys::VARS]
2166
2171
  code_lines.push BashCommentFormatter.format_comment(selected.pub_name)
2167
2172
  (link_block_data[LinkKeys::VARS] || []).each do |(key, value)|
2168
- ENV[key] = value.to_s
2173
+ EnvInterface.set(key, value.to_s)
2169
2174
  code_lines.push(assign_key_value_in_bash(key, value))
2170
2175
  end
2171
2176
  end
@@ -2220,7 +2225,7 @@ module MarkdownExec
2220
2225
  ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
2221
2226
  inherited_dependencies:
2222
2227
  (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
2223
- inherited_lines: HashDelegator.code_merge(
2228
+ inherited_lines: HashDelegator.flatten_and_compact_arrays(
2224
2229
  link_state&.inherited_lines, code_lines
2225
2230
  ),
2226
2231
  keep_code: link_state&.keep_code,
@@ -2328,15 +2333,15 @@ module MarkdownExec
2328
2333
 
2329
2334
  if selected[:type] == BlockType::OPTS
2330
2335
  # body of blocks is returned as a list of lines to be read an YAML
2331
- HashDelegator.code_merge(required[:blocks].map(&:body).flatten(1))
2336
+ HashDelegator.flatten_and_compact_arrays(required[:blocks].map(&:body).flatten(1))
2332
2337
  else
2333
2338
  code_lines = if selected.type == BlockType::VARS
2334
2339
  code_from_vars_block_to_set_environment_variables(selected)
2335
2340
  else
2336
2341
  []
2337
2342
  end
2338
- HashDelegator.code_merge(link_state&.inherited_lines,
2339
- required[:code] + code_lines)
2343
+ HashDelegator.flatten_and_compact_arrays(link_state&.inherited_lines,
2344
+ required[:code] + code_lines)
2340
2345
  end
2341
2346
  end
2342
2347
 
@@ -2558,6 +2563,7 @@ module MarkdownExec
2558
2563
  link_state: link_state,
2559
2564
  pattern: options_command_substitution_regexp
2560
2565
  )
2566
+ # no return
2561
2567
  end
2562
2568
 
2563
2569
  def expand_variable_references!(
@@ -2587,31 +2593,37 @@ module MarkdownExec
2587
2593
  return if replacements == EvaluateShellExpression::StatusFail
2588
2594
 
2589
2595
  expand_blocks_with_replacements(blocks, replacements)
2596
+ # no return
2590
2597
  end
2591
2598
 
2592
2599
  def export_echo_with_code(
2593
- bash_script_lines, export, force:, silent:
2600
+ bash_script_lines, export, force:, silent:, string: nil
2594
2601
  )
2595
2602
  exportable = true
2596
2603
  command_result = nil
2597
2604
  new_lines = []
2598
- case export.echo
2605
+ export_string = string || export.echo
2606
+ case export_string
2599
2607
  when String, Integer, Float, TrueClass, FalseClass
2600
- command_result = output_from_adhoc_bash_script_file(
2608
+ command_result, = output_from_adhoc_bash_script_file(
2601
2609
  join_array_of_arrays(
2602
2610
  bash_script_lines,
2603
- %(printf '%s' "#{export.echo}")
2611
+ %(printf '%s' "#{export_string}")
2604
2612
  )
2605
2613
  )
2606
2614
  if command_result.exit_status == EXIT_STATUS_REQUIRED_EMPTY
2607
2615
  exportable = false
2608
2616
  command_result.warning = warning_required_empty(export) unless silent
2617
+ else
2618
+ EnvInterface.set(export.name, command_result.stdout.to_s)
2619
+ new_lines << { name: export.name, force: force,
2620
+ text: command_result.stdout }
2609
2621
  end
2610
2622
 
2611
2623
  when Hash
2612
2624
  # each item in the hash is a variable name and value
2613
- export.echo.each do |name, expression|
2614
- command_result = output_from_adhoc_bash_script_file(
2625
+ export_string.each do |name, expression|
2626
+ command_result, = output_from_adhoc_bash_script_file(
2615
2627
  join_array_of_arrays(
2616
2628
  bash_script_lines,
2617
2629
  %(printf '%s' "#{expression}")
@@ -2620,14 +2632,11 @@ module MarkdownExec
2620
2632
  if command_result.exit_status == EXIT_STATUS_REQUIRED_EMPTY
2621
2633
  command_result.warning = warning_required_empty(export) unless silent
2622
2634
  else
2623
- ENV[name] = command_result.stdout.to_s
2624
- new_lines << code_line_safe_assign(name, command_result.stdout,
2625
- force: force)
2635
+ EnvInterface.set(name, command_result.stdout.to_s)
2636
+ new_lines << { name: name, force: force,
2637
+ text: command_result.stdout }
2626
2638
  end
2627
2639
  end
2628
-
2629
- # individual items have been exported, none remain
2630
- exportable = false
2631
2640
  end
2632
2641
 
2633
2642
  [command_result, exportable, new_lines]
@@ -2738,7 +2747,7 @@ module MarkdownExec
2738
2747
  # Format expression using environment variables and run state
2739
2748
  def format_expression(expr)
2740
2749
  data = link_load_format_data
2741
- ENV.each { |key, value| data[key.to_sym] = value }
2750
+ EnvInterface.each { |key, value| data[key.to_sym] = value }
2742
2751
  format(expr, data)
2743
2752
  end
2744
2753
 
@@ -2991,8 +3000,8 @@ module MarkdownExec
2991
3000
 
2992
3001
  def link_block_data_eval(link_state, code_lines, selected, link_block_data,
2993
3002
  block_source:, shell:)
2994
- all_code = HashDelegator.code_merge(link_state&.inherited_lines,
2995
- code_lines)
3003
+ all_code = HashDelegator.flatten_and_compact_arrays(link_state&.inherited_lines,
3004
+ code_lines)
2996
3005
  output_lines = []
2997
3006
 
2998
3007
  Tempfile.open do |file|
@@ -3287,8 +3296,11 @@ module MarkdownExec
3287
3296
  [block_name_from_cli, now_using_cli]
3288
3297
  end
3289
3298
 
3290
- def mdoc_and_blocks_from_nested_files(source_id: nil)
3291
- blocks_results = blocks_from_nested_files(source_id: source_id)
3299
+ def mdoc_and_blocks_from_nested_files(source_id: nil, link_state: nil)
3300
+ blocks_results = blocks_from_nested_files(
3301
+ link_state: link_state,
3302
+ source_id: source_id
3303
+ )
3292
3304
 
3293
3305
  blocks_results.results.select do |_id, result|
3294
3306
  result.failure?
@@ -3311,7 +3323,10 @@ module MarkdownExec
3311
3323
  #
3312
3324
  reload_blocks = false
3313
3325
 
3314
- all_blocks, mdoc = mdoc_and_blocks_from_nested_files(source_id: source_id)
3326
+ all_blocks, mdoc = mdoc_and_blocks_from_nested_files(
3327
+ link_state: link_state,
3328
+ source_id: source_id
3329
+ )
3315
3330
  if load_auto_opts_block(all_blocks, mdoc: mdoc)
3316
3331
  reload_blocks = true
3317
3332
  end
@@ -3327,8 +3342,8 @@ module MarkdownExec
3327
3342
  # load document ux block
3328
3343
  #
3329
3344
  if (code_lines = code_from_automatic_ux_blocks(all_blocks, mdoc))
3330
- new_code = HashDelegator.code_merge(link_state.inherited_lines,
3331
- code_lines)
3345
+ new_code = HashDelegator.flatten_and_compact_arrays(link_state.inherited_lines,
3346
+ code_lines)
3332
3347
  next_state_set_code(nil, link_state, new_code)
3333
3348
  link_state.inherited_lines = new_code
3334
3349
  reload_blocks = true
@@ -3337,15 +3352,18 @@ module MarkdownExec
3337
3352
  # load document vars block
3338
3353
  #
3339
3354
  if (code_lines = load_auto_vars_block(all_blocks))
3340
- new_code = HashDelegator.code_merge(link_state.inherited_lines,
3341
- code_lines)
3355
+ new_code = HashDelegator.flatten_and_compact_arrays(link_state.inherited_lines,
3356
+ code_lines)
3342
3357
  next_state_set_code(nil, link_state, new_code)
3343
3358
  link_state.inherited_lines = new_code
3344
3359
  reload_blocks = true
3345
3360
  end
3346
3361
 
3347
3362
  if reload_blocks
3348
- all_blocks, mdoc = mdoc_and_blocks_from_nested_files(source_id: source_id)
3363
+ all_blocks, mdoc = mdoc_and_blocks_from_nested_files(
3364
+ link_state: link_state,
3365
+ source_id: source_id
3366
+ )
3349
3367
  end
3350
3368
 
3351
3369
  # filter by name, collapsed
@@ -3514,7 +3532,7 @@ module MarkdownExec
3514
3532
  next_state_set_code(
3515
3533
  selected,
3516
3534
  link_state,
3517
- HashDelegator.code_merge(
3535
+ HashDelegator.flatten_and_compact_arrays(
3518
3536
  link_state&.inherited_lines,
3519
3537
  code_lines.is_a?(Array) ? code_lines : [] # no code for :ux_exec_prohibited
3520
3538
  )
@@ -3531,7 +3549,7 @@ module MarkdownExec
3531
3549
  ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
3532
3550
  inherited_dependencies:
3533
3551
  (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
3534
- inherited_lines: HashDelegator.code_merge(code_lines),
3552
+ inherited_lines: HashDelegator.flatten_and_compact_arrays(code_lines),
3535
3553
  keep_code: link_state&.keep_code,
3536
3554
  next_block_name: '',
3537
3555
  next_document_filename: @delegate_object[:filename],
@@ -3575,7 +3593,10 @@ module MarkdownExec
3575
3593
  }
3576
3594
  end
3577
3595
 
3578
- def output_from_adhoc_bash_script_file(bash_script_lines)
3596
+ def output_from_adhoc_bash_script_file(
3597
+ bash_script_lines,
3598
+ export = nil
3599
+ )
3579
3600
  Tempfile.create('script_exec') do |temp_file|
3580
3601
  temp_file.write(
3581
3602
  HashDelegator.join_code_lines(
@@ -3595,7 +3616,32 @@ module MarkdownExec
3595
3616
 
3596
3617
  output = `#{shell} #{temp_file.path}`
3597
3618
 
3598
- CommandResult.new(stdout: output, exit_status: $?.exitstatus)
3619
+ exportable = export ? export.exportable : false
3620
+ new_lines = []
3621
+ if export
3622
+ new_lines << "#{export.name}="
3623
+ export_value = output
3624
+ ### transform?
3625
+
3626
+ command_result, exportable, new_lines = export_echo_with_code(
3627
+ ["#{export.name}=#{Shellwords.escape(export_value)}"],
3628
+ export,
3629
+ force: force,
3630
+ silent: silent,
3631
+ string: export_value
3632
+ )
3633
+ else
3634
+ command_result = CommandResult.new(
3635
+ stdout: output,
3636
+ exit_status: $?.exitstatus
3637
+ )
3638
+ end
3639
+
3640
+ [
3641
+ command_result,
3642
+ exportable,
3643
+ new_lines
3644
+ ]
3599
3645
  end
3600
3646
  rescue StandardError => err
3601
3647
  warn "Error executing script: #{err.message}"
@@ -3636,7 +3682,8 @@ module MarkdownExec
3636
3682
  inherited_dependencies:
3637
3683
  dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data
3638
3684
  inherited_lines:
3639
- HashDelegator.code_merge(pop.inherited_lines, code_lines)
3685
+ HashDelegator.flatten_and_compact_arrays(pop.inherited_lines,
3686
+ code_lines)
3640
3687
  )
3641
3688
  @link_history.push(next_state)
3642
3689
 
@@ -3653,7 +3700,9 @@ module MarkdownExec
3653
3700
  inherited_dependencies:
3654
3701
  (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
3655
3702
  inherited_lines:
3656
- HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
3703
+ HashDelegator.flatten_and_compact_arrays(
3704
+ link_state&.inherited_lines, code_lines
3705
+ ),
3657
3706
  keep_code: link_state&.keep_code,
3658
3707
  next_block_name: next_block_name,
3659
3708
  next_document_filename: @delegate_object[:filename], # not next_document_filename
@@ -4395,7 +4444,6 @@ module MarkdownExec
4395
4444
  marker = Random.new.rand.to_s
4396
4445
 
4397
4446
  code = (code_lines || []) + ["echo -n \"#{marker}#{raw}\""]
4398
- # !!t code
4399
4447
  File.write filespec, HashDelegator.join_code_lines(code)
4400
4448
  File.chmod 0o755, filespec
4401
4449
 
@@ -4506,6 +4554,7 @@ module MarkdownExec
4506
4554
  return value unless export.transform.present?
4507
4555
 
4508
4556
  if export.transform.is_a? Symbol
4557
+ ### TBD validate for symbol
4509
4558
  value.send(export.transform)
4510
4559
  else
4511
4560
  format(
@@ -4607,16 +4656,21 @@ module MarkdownExec
4607
4656
  def ux_block_export_activated(
4608
4657
  bash_script_lines, export, exit_prompt
4609
4658
  )
4659
+ command_result = nil
4610
4660
  exportable = true
4611
- transformable = true
4661
+ force = true
4612
4662
  new_lines = []
4613
- command_result = nil
4663
+ silent = false
4664
+ transformable = true
4614
4665
 
4615
4666
  case FCB.act_source(export)
4616
4667
  when false, UxActSource::FALSE
4617
- raise 'Should not be reached.'
4668
+ # read-only
4669
+ command_result = CommandResult.new
4670
+ exportable = false
4671
+ transformable = false
4618
4672
 
4619
- when ':allow', UxActSource::ALLOW
4673
+ when :allow, UxActSource::ALLOW
4620
4674
  raise unless export.allow.present?
4621
4675
 
4622
4676
  case export.allow
@@ -4624,9 +4678,10 @@ module MarkdownExec
4624
4678
  command_result, exportable, new_lines = export_echo_with_code(
4625
4679
  bash_script_lines,
4626
4680
  export,
4627
- force: true,
4628
- silent: false
4681
+ force: force,
4682
+ silent: silent
4629
4683
  )
4684
+
4630
4685
  if command_result.failure?
4631
4686
  command_result
4632
4687
  else
@@ -4635,8 +4690,8 @@ module MarkdownExec
4635
4690
  )
4636
4691
  end
4637
4692
 
4638
- when ':exec', UxActSource::EXEC
4639
- command_result = output_from_adhoc_bash_script_file(
4693
+ when :exec, UxActSource::EXEC
4694
+ command_result, = output_from_adhoc_bash_script_file(
4640
4695
  join_array_of_arrays(bash_script_lines, export.exec)
4641
4696
  )
4642
4697
 
@@ -4651,22 +4706,26 @@ module MarkdownExec
4651
4706
  end
4652
4707
 
4653
4708
  else
4654
- command_result = CommandResult.new(
4655
- stdout: menu_from_list_with_back(export.allow)
4709
+ export_init = menu_from_list_with_back(export.allow)
4710
+ command_result, exportable, new_lines = export_echo_with_code(
4711
+ ["#{export.name}=#{Shellwords.escape(export_init)}"],
4712
+ export,
4713
+ force: force,
4714
+ silent: silent,
4715
+ string: export_init
4656
4716
  )
4717
+
4657
4718
  end
4658
4719
 
4659
- when ':echo', UxActSource::ECHO
4720
+ when :echo, UxActSource::ECHO
4660
4721
  command_result, exportable, new_lines = export_echo_with_code(
4661
4722
  bash_script_lines,
4662
4723
  export,
4663
- force: true,
4664
- silent: false
4724
+ force: force,
4725
+ silent: silent
4665
4726
  )
4666
4727
 
4667
- command_result
4668
-
4669
- when ':edit', UxActSource::EDIT
4728
+ when :edit, UxActSource::EDIT
4670
4729
  output = nil
4671
4730
  begin
4672
4731
  loop do
@@ -4686,13 +4745,11 @@ module MarkdownExec
4686
4745
 
4687
4746
  command_result = CommandResult.new(stdout: output)
4688
4747
 
4689
- when ':exec', UxActSource::EXEC
4690
- command_result = output_from_adhoc_bash_script_file(
4748
+ when :exec, UxActSource::EXEC
4749
+ command_result, = output_from_adhoc_bash_script_file(
4691
4750
  join_array_of_arrays(bash_script_lines, export.exec)
4692
4751
  )
4693
4752
 
4694
- command_result
4695
-
4696
4753
  else
4697
4754
  transformable = false
4698
4755
  command_result = CommandResult.new(stdout: export.default.to_s)
@@ -4701,7 +4758,7 @@ module MarkdownExec
4701
4758
  # add message for required variables
4702
4759
  if command_result.exit_status == EXIT_STATUS_REQUIRED_EMPTY
4703
4760
  command_result.warning = warning_required_empty(export)
4704
- # warn command_result.warning
4761
+ warn command_result.warning unless silent
4705
4762
  end
4706
4763
 
4707
4764
  command_result.exportable = exportable
@@ -4710,12 +4767,15 @@ module MarkdownExec
4710
4767
  command_result
4711
4768
  end
4712
4769
 
4713
- def ux_block_export_automatic(bash_script_lines, export)
4714
- transformable = true
4770
+ def ux_block_export_automatic(
4771
+ bash_script_lines, export
4772
+ )
4773
+ command_result = nil
4715
4774
  exportable = true
4775
+ force = false
4716
4776
  new_lines = []
4717
- command_result = nil
4718
4777
  silent = true
4778
+ transformable = true
4719
4779
 
4720
4780
  case FCB.init_source(export)
4721
4781
  when false, UxActSource::FALSE
@@ -4723,57 +4783,85 @@ module MarkdownExec
4723
4783
  transformable = false
4724
4784
  command_result = CommandResult.new
4725
4785
 
4726
- when ':allow', UxActSource::ALLOW
4786
+ when :allow, UxActSource::ALLOW
4727
4787
  raise unless export.allow.present?
4728
4788
 
4729
4789
  case export.allow
4730
4790
  when :echo, ExportValueSource::ECHO
4791
+ cr_echo, = output_from_adhoc_bash_script_file(
4792
+ join_array_of_arrays(
4793
+ bash_script_lines,
4794
+ %(printf '%s' "#{export.echo}")
4795
+ )
4796
+ )
4797
+ export_init = cr_echo.stdout.split("\n").first
4731
4798
  command_result, exportable, new_lines = export_echo_with_code(
4732
- bash_script_lines,
4799
+ ["#{export.name}=#{Shellwords.escape(export_init)}"],
4733
4800
  export,
4734
- force: false,
4735
- silent: silent
4801
+ force: force,
4802
+ silent: silent,
4803
+ string: export_init
4736
4804
  )
4737
- unless command_result.failure?
4738
- command_result.stdout = (exportable && command_result.stdout.split("\n").first) || ''
4739
- end
4740
4805
 
4741
4806
  when :exec, ExportValueSource::EXEC
4742
- command_result = output_from_adhoc_bash_script_file(
4807
+ # extract first line from 'exec' output
4808
+ command_result, = output_from_adhoc_bash_script_file(
4743
4809
  join_array_of_arrays(bash_script_lines, export.exec)
4744
4810
  )
4745
4811
  unless command_result.failure?
4746
- command_result.stdout = command_result.stdout.split("\n").first
4812
+ export_init = command_result.stdout.split("\n").first
4813
+ command_result, exportable, new_lines = export_echo_with_code(
4814
+ ["#{export.name}=#{Shellwords.escape(export_init)}"],
4815
+ export,
4816
+ force: force,
4817
+ silent: silent,
4818
+ string: export_init
4819
+ )
4747
4820
  end
4748
4821
 
4749
4822
  else
4750
- # must be a list
4751
- command_result = CommandResult.new(stdout: export.allow.first)
4823
+ # first item from 'allow' list
4824
+ export_init = export.allow.first
4825
+ command_result, exportable, new_lines = export_echo_with_code(
4826
+ ["#{export.name}=#{Shellwords.escape(export_init)}"],
4827
+ export,
4828
+ force: force,
4829
+ silent: silent,
4830
+ string: export_init
4831
+ )
4832
+
4752
4833
  end
4753
4834
 
4754
- when ':default', UxActSource::DEFAULT
4835
+ when :default, UxActSource::DEFAULT
4755
4836
  transformable = false
4756
4837
  command_result = CommandResult.new(stdout: export.default.to_s)
4757
4838
 
4758
- when ':echo', UxActSource::ECHO
4839
+ when :echo, UxActSource::ECHO
4759
4840
  raise unless export.echo.present?
4760
4841
 
4761
4842
  command_result, exportable, new_lines = export_echo_with_code(
4762
4843
  bash_script_lines,
4763
4844
  export,
4764
- force: false,
4845
+ force: force,
4765
4846
  silent: silent
4766
4847
  )
4767
-
4768
- when ':exec', UxActSource::EXEC
4848
+ when :exec, UxActSource::EXEC
4769
4849
  raise unless export.exec.present?
4770
4850
 
4771
- command_result = output_from_adhoc_bash_script_file(
4772
- join_array_of_arrays(bash_script_lines, export.exec)
4851
+ command_result, exportable, new_lines = output_from_adhoc_bash_script_file(
4852
+ join_array_of_arrays(bash_script_lines, export.exec),
4853
+ export
4773
4854
  )
4774
4855
 
4775
4856
  else
4776
- command_result = CommandResult.new(stdout: export.init.to_s)
4857
+ export_init = export.init.to_s
4858
+ command_result, exportable, new_lines = export_echo_with_code(
4859
+ ["#{export.name}=#{Shellwords.escape(export_init)}"],
4860
+ export,
4861
+ force: force,
4862
+ silent: silent,
4863
+ string: export_init
4864
+ )
4777
4865
  # raise "Unknown FCB.init_source(export) #{FCB.init_source(export)}"
4778
4866
  end
4779
4867
 
@@ -5189,9 +5277,6 @@ module MarkdownExec
5189
5277
  )
5190
5278
  end
5191
5279
  # rubocop:enable Style/GuardClause
5192
-
5193
- # # reflect new menu items
5194
- # @dml_mdoc = MDoc.new(@dml_menu_blocks)
5195
5280
  end
5196
5281
 
5197
5282
  def vux_navigate_back_for_ls
@@ -5228,7 +5313,6 @@ module MarkdownExec
5228
5313
  mdoc_menu_and_blocks_from_nested_files(
5229
5314
  @dml_link_state, source_id: source_id
5230
5315
  )
5231
-
5232
5316
  dump_delobj(@dml_blocks_in_file, @dml_menu_blocks, @dml_link_state)
5233
5317
  end
5234
5318