markdown_exec 3.5.2 → 3.6.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/bats/block-type-shell-context-eval.bats +48 -0
  6. data/bats/block-type-ux-echo.bats +1 -1
  7. data/bats/block-type-ux-force.bats +1 -1
  8. data/bats/block-type-ux-invalid.bats +1 -1
  9. data/bats/block-type-ux-require.bats +1 -1
  10. data/bats/document-shell.bats +2 -2
  11. data/bats/import.bats +1 -1
  12. data/bats/load-vars-state-demo.bats +4 -4
  13. data/bin/tab_completion.sh +3 -3
  14. data/docs/dev/bats-document-configuration.md +1 -1
  15. data/docs/dev/block-type-shell-context-eval.md +52 -0
  16. data/docs/dev/block-type-shell-require-ux.md +6 -2
  17. data/docs/dev/block-type-ux-echo.md +3 -3
  18. data/docs/dev/block-type-ux-force.md +1 -1
  19. data/docs/dev/block-type-ux-require-chained.md +1 -1
  20. data/docs/dev/block-type-ux-require.md +2 -2
  21. data/docs/dev/import-parameter-symbols.md +1 -1
  22. data/docs/dev/linked-file.md +1 -1
  23. data/docs/dev/load-vars-state-demo.md +1 -1
  24. data/docs/dev/requiring-blocks.md +1 -1
  25. data/docs/dev/specs.md +2 -2
  26. data/docs/shell-script-evaluation.md +78 -0
  27. data/examples/link-blocks-vars.md +2 -2
  28. data/examples/linked.md +1 -1
  29. data/examples/linked1.md +2 -9
  30. data/examples/opts-blocks.md +2 -2
  31. data/examples/port-blocks.md +1 -1
  32. data/examples/variable-expansion.md +1 -1
  33. data/lib/cached_nested_file_reader.rb +10 -7
  34. data/lib/hash_delegator.rb +325 -284
  35. data/lib/input_sequencer.rb +4 -3
  36. data/lib/link_history.rb +76 -28
  37. data/lib/markdown_exec/version.rb +1 -1
  38. data/lib/mdoc.rb +93 -65
  39. data/lib/menu.src.yml +5 -5
  40. data/lib/menu.yml +5 -5
  41. data/lib/ww.rb +1 -1
  42. metadata +5 -2
@@ -217,7 +217,7 @@ module HashDelegatorSelf
217
217
  #
218
218
  # @example Basic execution without export
219
219
  # result, exportable, new_lines = execute_bash_script_lines(
220
- # code_lines: ["echo 'Hello'", "echo 'World'"],
220
+ # transient_code: ["echo 'Hello'", "echo 'World'"],
221
221
  # export: nil,
222
222
  # force: false
223
223
  # )
@@ -226,14 +226,14 @@ module HashDelegatorSelf
226
226
  # @example Execution with export
227
227
  # export = OpenStruct.new(name: "MY_VAR", exportable: true)
228
228
  # result, exportable, new_lines = execute_bash_script_lines(
229
- # code_lines: ["echo 'Hello World'"],
229
+ # transient_code: ["echo 'Hello World'"],
230
230
  # export: export,
231
231
  # force: true
232
232
  # )
233
233
  # # => [CommandResult, true, [{name: "MY_VAR", force: true, text: "Hello World\n"}]]
234
234
  #
235
235
  def execute_bash_script_lines(
236
- code_lines: [],
236
+ transient_code: [],
237
237
  export: nil,
238
238
  export_name:,
239
239
  force: false,
@@ -243,7 +243,7 @@ module HashDelegatorSelf
243
243
  archive_time_format: nil # @delegate_object[:archive_time_format]
244
244
  )
245
245
  Tempfile.create('script_exec') do |temp_file|
246
- temp_file.write(join_code_lines(code_lines))
246
+ temp_file.write(join_code_lines(transient_code))
247
247
  temp_file.close # Close the file before chmod and execution
248
248
  File.chmod(0o755, temp_file.path)
249
249
 
@@ -282,20 +282,20 @@ module HashDelegatorSelf
282
282
  exit_status: tsc.exit_code,
283
283
  exportable: exportable_success,
284
284
  new_lines: new_lines,
285
- script: code_lines,
285
+ script: transient_code,
286
286
  stdout: tsc.transformed_output,
287
287
  transformed_shell_command: tsc
288
288
  )
289
289
  end
290
290
  rescue StandardError
291
- wwe $!, 'code_lines:', code_lines, 'export:', export
291
+ wwe $!, 'transient_code:', transient_code, 'export:', export
292
292
  # warn "Error executing script: #{err.message}"
293
293
  # return failure result
294
294
  CommandResult.new(
295
295
  exit_status: CommandResult::EXIT_STATUS_FAIL,
296
296
  exportable: false,
297
297
  new_lines: [],
298
- script: code_lines,
298
+ script: transient_code,
299
299
  stdout: ''
300
300
  )
301
301
  end
@@ -781,7 +781,7 @@ module MarkdownExec
781
781
 
782
782
  @process_mutex = Mutex.new
783
783
  @process_cv = ConditionVariable.new
784
- @dml_link_state = Struct.new(:document_filename, :inherited_lines)
784
+ @dml_link_state = Struct.new(:document_filename, :context_code)
785
785
  .new(@delegate_object[:filename], [])
786
786
  @dml_menu_blocks = []
787
787
  @fcb_store = [] # all fcbs created
@@ -850,7 +850,7 @@ module MarkdownExec
850
850
  add_inherited_lines(
851
851
  link_state: link_state,
852
852
  menu_blocks: menu_blocks
853
- ) if @delegate_object[:menu_with_inherited_lines]
853
+ ) if @delegate_object[:menu_with_context_code]
854
854
 
855
855
  # back before exit
856
856
  add_back_option(
@@ -969,10 +969,10 @@ module MarkdownExec
969
969
  # @param menu_blocks [Array] The array of menu block elements.
970
970
  # @param position [Symbol] The position to insert the divider (:initial or :final).
971
971
  def append_inherited_lines(link_state:, menu_blocks:, position: top)
972
- return unless link_state.inherited_lines_present?
972
+ return unless link_state.context_code_present?
973
973
 
974
974
  insert_at_top = @delegate_object[:menu_inherited_lines_at_top]
975
- chrome_blocks = link_state.inherited_lines_map do |line|
975
+ chrome_blocks = link_state.context_code_map do |line|
976
976
  formatted = format(@delegate_object[:menu_inherited_lines_format],
977
977
  { line: line })
978
978
  persist_fcb(
@@ -1190,7 +1190,7 @@ module MarkdownExec
1190
1190
  occurrence_expressions: nil
1191
1191
  )
1192
1192
  evaluate_shell_expressions(
1193
- (link_state&.inherited_lines_block || ''),
1193
+ (link_state&.context_code_block || ''),
1194
1194
  commands,
1195
1195
  initial_code_required: initial_code_required,
1196
1196
  occurrence_expressions: occurrence_expressions
@@ -1209,7 +1209,7 @@ module MarkdownExec
1209
1209
  exts: '.out.txt',
1210
1210
  saved_asset_format:
1211
1211
  shell_escape_asset_format(
1212
- code_lines: @dml_link_state.inherited_lines,
1212
+ transient_code: @dml_link_state.context_code,
1213
1213
  shell: ShellType::BASH
1214
1214
  )
1215
1215
  ).generate_name
@@ -1264,8 +1264,8 @@ module MarkdownExec
1264
1264
  end
1265
1265
 
1266
1266
  # return code resulting from evaluating all automatic blocks in order
1267
- def code_from_auto_blocks(
1268
- all_blocks, mdoc: nil, default_only: true, inherited_lines: []
1267
+ def inherited_lines_from_auto_blocks(
1268
+ all_blocks, mdoc: nil, default_only: true, context_code: []
1269
1269
  )
1270
1270
  shell_block_name = @delegate_object[:document_load_shell_block_name]
1271
1271
  vars_block_name = @delegate_object[:document_load_vars_block_name]
@@ -1287,18 +1287,18 @@ module MarkdownExec
1287
1287
  if read_shell
1288
1288
  # collect code from shell block
1289
1289
  code = if mdoc
1290
- reqinfo = mdoc.collect_recursively_required_code(
1290
+ required_code = mdoc.collect_recursively_required_code(
1291
1291
  anyname: fcb.id,
1292
1292
  label_format_above:
1293
1293
  @delegate_object[:shell_code_label_format_above],
1294
1294
  label_format_below:
1295
1295
  @delegate_object[:shell_code_label_format_below],
1296
1296
  block_source: block_source,
1297
- inherited_lines: inherited_lines
1297
+ context_code: context_code
1298
1298
  )
1299
- block_inherit = reqinfo[:inherit]
1299
+ block_inherit = required_code[:context_code]
1300
1300
 
1301
- reqinfo[:code]
1301
+ required_code[:transient_code]
1302
1302
  else
1303
1303
  fcb.body
1304
1304
  end
@@ -1339,48 +1339,11 @@ module MarkdownExec
1339
1339
  all_inherit += block_inherit
1340
1340
  end
1341
1341
 
1342
- [all_code, all_inherit].tap { wwr _1 }
1342
+ all_code.tap { wwr _1 }
1343
1343
  rescue StandardError
1344
1344
  wwe $!, 'all_blocks.count:', all_blocks.count
1345
1345
  end
1346
1346
 
1347
- # return code resulting from evaluating all UX blocks in order
1348
- def code_from_auto_ux_blocks(
1349
- all_blocks,
1350
- mdoc
1351
- )
1352
- # do not reload the most recent filename
1353
- unless @ux_most_recent_filename != @delegate_object[:filename]
1354
- return
1355
- end
1356
-
1357
- @ux_most_recent_filename = @delegate_object[:filename]
1358
-
1359
- # select all UX blocks, rejecting non-primary split
1360
- blocks = select_automatic_ux_blocks(
1361
- all_blocks.reject(&:is_split_rest?)
1362
- )
1363
- return if blocks.empty?
1364
-
1365
- # collect code from all ux blocks
1366
- (blocks.each.with_object([]) do |block, merged_options|
1367
- command_result_w_e_t_nl =
1368
- code_from_ux_block_to_set_environment_variables(
1369
- block,
1370
- mdoc,
1371
- force: @delegate_object[:ux_auto_load_force_default],
1372
- only_default: true,
1373
- silent: true
1374
- )
1375
- if command_result_w_e_t_nl.failure?
1376
- # if a block fails, proceed with next block
1377
- merged_options
1378
- else
1379
- merged_options.push(command_result_w_e_t_nl.new_lines)
1380
- end
1381
- end).to_a
1382
- end
1383
-
1384
1347
  # return code resulting from evaluating all automatic VARS blocks in order
1385
1348
  def code_from_auto_vars_blocks(
1386
1349
  all_blocks,
@@ -1415,91 +1378,97 @@ module MarkdownExec
1415
1378
  # set ENV value for the variable and return code lines for the same
1416
1379
  # for BlockType::UX
1417
1380
  def code_from_ux_block_to_set_environment_variables(
1418
- selected, mdoc, inherited_code: nil, force: true, only_default: false,
1419
- required: nil, silent:
1381
+ selected, mdoc, context_code: nil, force: true, only_default: false,
1382
+ required: OpenStruct.new(context_code: [], transient_code: []),
1383
+ silent:
1420
1384
  )
1421
1385
  wwt :fcb, 'selected:', selected
1422
- wwt :inherited_code, inherited_code
1386
+ wwt :context_code, context_code
1423
1387
  ret_command_result = nil
1424
1388
  exit_prompt = @delegate_object[:prompt_filespec_back]
1425
1389
 
1426
- required ||= mdoc.collect_recursively_required_code(
1390
+ wwt :required, required
1391
+ required_code = mdoc&.collect_recursively_required_code(
1427
1392
  anyname: selected_id_name(selected),
1428
1393
  label_format_above: @delegate_object[:shell_code_label_format_above],
1429
1394
  label_format_below: @delegate_object[:shell_code_label_format_below],
1430
1395
  block_source: block_source,
1431
- inherited_lines: inherited_code
1396
+ context_code: context_code
1432
1397
  )
1433
- wwt :required, required
1398
+ wwt :required_code, required_code
1434
1399
  # new_inherited_lines = []
1435
1400
 
1436
1401
  # process each ux block in sequence, setting ENV and collecting lines
1437
1402
  concatenated_code_from_required_blocks = []
1438
- required[:blocks]&.each do |block|
1439
- next if block.type != BlockType::UX
1440
-
1441
- wwt :fcb, 'a required block', block
1442
-
1443
- body1 = block.raw_body || block.body
1444
- case data = safe_yaml_load(body1.join("\n"))
1445
- when Hash
1446
- export = parse_yaml_of_ux_block(
1447
- data,
1448
- prompt: @delegate_object[:prompt_ux_enter_a_value],
1449
- validate: '^(?<name>[^ ].*)$'
1450
- )
1451
- block.export = export
1452
- block.export_act = FCB.act_source(export)
1453
- block.export_init = FCB.init_source(export)
1454
-
1455
- # required are variable names that must be set before the UX block is executed.
1456
- # if any precondition is not set, the sequence is aborted.
1457
- required_variables = []
1458
- export.required&.each do |precondition|
1459
- required_variables.push "[[ -z $#{precondition} ]] && exit #{CommandResult::EXIT_STATUS_REQUIRED_EMPTY}"
1460
- end
1461
- wwt :required_variables, 'required_variables',
1462
- required_variables
1463
-
1464
- eval_code = join_array_of_arrays(
1465
- inherited_code, # inherited code
1466
- concatenated_code_from_required_blocks, # current block requirements
1467
- required_variables, # test conditions
1468
- required[:code] # required by selected
1469
- )
1470
- wwt :eval_code, 'eval_code:', eval_code
1471
- if only_default
1472
- command_result_w_e_t_nl =
1473
- ux_block_export_automatic(eval_code, export)
1474
- # do not display warnings on initializing call
1475
- return command_result_w_e_t_nl if command_result_w_e_t_nl.failure?
1403
+ if required_code # exclude for tests
1404
+ required_code[:blocks]&.each do |block|
1405
+ next if block.type != BlockType::UX
1406
+
1407
+ wwt :fcb, 'a required block', block
1408
+
1409
+ body1 = block.raw_body || block.body
1410
+ case data = safe_yaml_load(body1.join("\n"))
1411
+ when Hash
1412
+ export = parse_yaml_of_ux_block(
1413
+ data,
1414
+ prompt: @delegate_object[:prompt_ux_enter_a_value],
1415
+ validate: '^(?<name>[^ ].*)$'
1416
+ )
1417
+ block.export = export
1418
+ block.export_act = FCB.act_source(export)
1419
+ block.export_init = FCB.init_source(export)
1420
+
1421
+ # required_code are variable names that must be set before the UX block is executed.
1422
+ # if any precondition is not set, the sequence is aborted.
1423
+ required_variables = []
1424
+ export.required&.each do |precondition|
1425
+ required_variables.push "[[ -z $#{precondition} ]] && exit #{CommandResult::EXIT_STATUS_REQUIRED_EMPTY}"
1426
+ end
1427
+ wwt :required_variables, 'required_variables',
1428
+ required_variables
1429
+
1430
+ eval_code = join_array_of_arrays(
1431
+ required[:context_code],
1432
+ context_code, # inherited code
1433
+ concatenated_code_from_required_blocks, # current block requirements
1434
+ required_variables, # test conditions
1435
+ required[:transient_code],
1436
+ required_code[:transient_code] # required by selected
1437
+ )
1438
+ wwt :eval_code, 'eval_code:', eval_code
1439
+ if only_default
1440
+ command_result_w_e_t_nl =
1441
+ ux_block_export_automatic(eval_code, export)
1442
+ # do not display warnings on initializing call
1443
+ return command_result_w_e_t_nl if command_result_w_e_t_nl.failure?
1476
1444
 
1477
- else
1478
- command_result_w_e_t_nl =
1479
- ux_block_export_activated(eval_code, export, exit_prompt)
1480
- if command_result_w_e_t_nl.failure?
1481
- if command_result_w_e_t_nl.warning&.present? && !silent
1482
- warn command_result_w_e_t_nl.warning
1445
+ else
1446
+ command_result_w_e_t_nl =
1447
+ ux_block_export_activated(eval_code, export, exit_prompt)
1448
+ if command_result_w_e_t_nl.failure?
1449
+ if command_result_w_e_t_nl.warning&.present? && !silent
1450
+ warn command_result_w_e_t_nl.warning
1451
+ end
1452
+ return command_result_w_e_t_nl
1483
1453
  end
1484
- return command_result_w_e_t_nl
1485
1454
  end
1486
- end
1487
- return command_result_w_e_t_nl if command_result_w_e_t_nl.failure?
1455
+ return command_result_w_e_t_nl if command_result_w_e_t_nl.failure?
1488
1456
 
1489
- # update the required lines for this and subsequent blocks
1490
- command_result_w_e_t_nl.new_lines =
1491
- process_command_result_lines(command_result_w_e_t_nl, export,
1492
- concatenated_code_from_required_blocks)
1493
- concatenated_code_from_required_blocks.concat(command_result_w_e_t_nl.new_lines)
1457
+ # update the required lines for this and subsequent blocks
1458
+ command_result_w_e_t_nl.new_lines =
1459
+ process_command_result_lines(command_result_w_e_t_nl, export,
1460
+ concatenated_code_from_required_blocks)
1461
+ concatenated_code_from_required_blocks.concat(command_result_w_e_t_nl.new_lines)
1494
1462
 
1495
- concatenated_code_from_required_blocks = annotate_required_lines(
1496
- 'blk:UX', concatenated_code_from_required_blocks, block_name: selected.id
1497
- )
1463
+ concatenated_code_from_required_blocks = annotate_required_lines(
1464
+ 'blk:UX', concatenated_code_from_required_blocks, block_name: selected.id
1465
+ )
1498
1466
 
1499
- command_result_w_e_t_nl.new_lines = concatenated_code_from_required_blocks
1500
- ret_command_result = command_result_w_e_t_nl
1501
- else
1502
- raise "Invalid data type: #{data.inspect}"
1467
+ command_result_w_e_t_nl.new_lines = concatenated_code_from_required_blocks
1468
+ ret_command_result = command_result_w_e_t_nl
1469
+ else
1470
+ raise "Invalid data type: #{data.inspect}"
1471
+ end
1503
1472
  end
1504
1473
  end
1505
1474
  wwt :concatenated_code_from_required_blocks,
@@ -1513,19 +1482,19 @@ module MarkdownExec
1513
1482
  wwt :cr, ret, caller.deref
1514
1483
  end
1515
1484
  rescue StandardError
1516
- wwe $!, 'selected:', selected, 'required:', required, 'block:', block,
1485
+ wwe $!, 'selected:', selected, 'required_code:', required_code, 'block:', block,
1517
1486
  'data:', data
1518
1487
  end
1519
1488
 
1520
1489
  # def
1521
1490
  # sets ENV
1522
1491
  def code_from_vars_block_to_set_environment_variables(selected)
1523
- code_lines = []
1492
+ transient_code = []
1524
1493
  case data = YAML.load(selected.body.join("\n"))
1525
1494
  when Hash
1526
1495
  data.each do |key, value|
1527
1496
  EnvInterface.set(key, value.to_s)
1528
- code_lines << assign_key_value_in_bash(key, value)
1497
+ transient_code << assign_key_value_in_bash(key, value)
1529
1498
 
1530
1499
  next unless @delegate_object[:menu_vars_set_format].present?
1531
1500
 
@@ -1537,10 +1506,10 @@ module MarkdownExec
1537
1506
  print string_send_color(formatted_string, :menu_vars_set_color)
1538
1507
  end
1539
1508
  end
1540
- annotate_required_lines('blk:VARS', code_lines, block_name: selected.id)
1509
+ annotate_required_lines('blk:VARS', transient_code, block_name: selected.id)
1541
1510
  rescue StandardError
1542
1511
  wwe 'selected:', selected, 'data:', data, 'key:', key, 'value:', value,
1543
- 'code_lines:', code_lines, 'formatted_string:', formatted_string
1512
+ 'transient_code:', transient_code, 'formatted_string:', formatted_string
1544
1513
  end
1545
1514
 
1546
1515
  # make a single line of shell code to assign an escaped value to a variable
@@ -1597,7 +1566,8 @@ module MarkdownExec
1597
1566
  else
1598
1567
  @run_state.in_own_window = false
1599
1568
  command_execute_in_process(
1600
- args: args, command: command,
1569
+ args: args,
1570
+ command: command,
1601
1571
  erls: erls,
1602
1572
  filename: @delegate_object[:filename],
1603
1573
  shell: shell
@@ -1679,8 +1649,7 @@ module MarkdownExec
1679
1649
  # containing code blocks.
1680
1650
  # @param selected [Hash] The selected item from the menu
1681
1651
  # to be executed.
1682
- # @return [LoadFileLinkState] An object indicating whether to load
1683
- # the next block or reuse the current one.
1652
+ # @return [Array] context_code
1684
1653
  def compile_execute_and_trigger_reuse(
1685
1654
  mdoc:, selected:, block_source:, link_state:
1686
1655
  )
@@ -1697,18 +1666,18 @@ module MarkdownExec
1697
1666
  end
1698
1667
  end
1699
1668
 
1700
- required_lines = execute_block_type_port_code_lines(
1669
+ required_code = execute_block_type_port_code_lines(
1701
1670
  mdoc: mdoc, selected: selected,
1702
1671
  link_state: link_state, block_source: block_source
1703
1672
  )
1704
1673
  output_or_approval = @delegate_object[:output_script] ||
1705
1674
  @delegate_object[:user_must_approve]
1706
1675
  if output_or_approval
1707
- display_required_code(required_lines: required_lines)
1676
+ display_required_code(required_lines: required_code[:transient_code])
1708
1677
  end
1709
1678
  allow_execution = if @delegate_object[:user_must_approve]
1710
1679
  prompt_for_user_approval(
1711
- required_lines: required_lines,
1680
+ required_lines: required_code[:transient_code],
1712
1681
  selected: selected
1713
1682
  )
1714
1683
  else
@@ -1716,16 +1685,28 @@ module MarkdownExec
1716
1685
  end
1717
1686
 
1718
1687
  if allow_execution
1688
+ script_lines = ( #HashDelegator.join_code_lines(
1689
+ # ['# prior context'] +
1690
+ (link_state&.context_code || []) +
1691
+ # ['# new context'] +
1692
+ required_code[:context_code] +
1693
+ # ['# new transient'] +
1694
+ required_code[:transient_code]
1695
+ )
1719
1696
  execute_required_lines(
1720
1697
  blockname: selected_id_name(selected),
1721
1698
  erls: { play_bin: play_bin,
1722
1699
  shell: selected_shell(selected.shell) },
1723
- required_lines: required_lines,
1700
+ script_lines: script_lines,
1724
1701
  shell: selected_shell(selected.shell)
1725
1702
  )
1726
1703
  end
1727
1704
 
1728
1705
  link_state.block_name = nil
1706
+
1707
+ required_code[:context_code]
1708
+ rescue StandardError
1709
+ wwe $!
1729
1710
  end
1730
1711
 
1731
1712
  # Check if the expression contains wildcard characters
@@ -2036,6 +2017,8 @@ module MarkdownExec
2036
2017
  # filter block if selected in menu
2037
2018
  return true if @run_state.source.block_name_from_cli
2038
2019
 
2020
+ return true if @delegate_object[:block_name].empty?
2021
+
2039
2022
  # return false if @prior_execution_block == @delegate_object[:block_name]
2040
2023
  if @prior_execution_block == @delegate_object[:block_name]
2041
2024
  return @allowed_execution_block == @prior_execution_block ||
@@ -2212,10 +2195,10 @@ module MarkdownExec
2212
2195
  warn format_and_highlight_lines(link_state.inherited_dependencies,
2213
2196
  label: 'inherited_dependencies')
2214
2197
  end
2215
- return unless @delegate_object[:dump_inherited_lines]
2198
+ return unless @delegate_object[:dump_context_code]
2216
2199
 
2217
- warn format_and_highlight_lines(link_state.inherited_lines,
2218
- label: 'inherited_lines')
2200
+ warn format_and_highlight_lines(link_state.context_code,
2201
+ label: 'context_code')
2219
2202
  end
2220
2203
 
2221
2204
  # Opens text in an editor for user modification and
@@ -2301,7 +2284,7 @@ module MarkdownExec
2301
2284
  vux_edit_inherited
2302
2285
  return :break if pause_user_exit
2303
2286
 
2304
- next_state_append_code(selected, link_state, [])
2287
+ next_state_append_code(selected, link_state, context_code: [])
2305
2288
 
2306
2289
  elsif selected.type == BlockType::HISTORY
2307
2290
  debounce_reset
@@ -2314,23 +2297,25 @@ module MarkdownExec
2314
2297
 
2315
2298
  elsif selected.type == BlockType::LINK
2316
2299
  debounce_reset
2317
- execute_block_type_link_with_state(link_block_body: selected.body,
2318
- mdoc: mdoc,
2319
- selected: selected,
2320
- link_state: link_state,
2321
- block_source: block_source)
2300
+ execute_block_type_link_with_state(
2301
+ link_block_body: selected.body,
2302
+ mdoc: mdoc,
2303
+ selected: selected,
2304
+ link_state: link_state,
2305
+ block_source: block_source
2306
+ )
2322
2307
 
2323
2308
  elsif selected.type == BlockType::LOAD
2324
2309
  debounce_reset
2325
2310
  load_result = execute_block_type_load_code_lines(selected)
2326
- next_state_append_code(selected, link_state, load_result.code,
2327
- mode: load_result.mode)
2311
+ next_state_append_code(selected, link_state, context_code: load_result.code,
2312
+ mode: load_result.mode)
2328
2313
 
2329
2314
  elsif selected.type == BlockType::SAVE
2330
2315
  debounce_reset
2331
2316
 
2332
2317
  execute_block_type_save(
2333
- code_lines: link_state&.inherited_lines,
2318
+ transient_code: link_state&.context_code,
2334
2319
  selected: selected
2335
2320
  )
2336
2321
 
@@ -2352,7 +2337,7 @@ module MarkdownExec
2352
2337
 
2353
2338
  elsif selected.type == BlockType::OPTS
2354
2339
  debounce_reset
2355
- code_lines = []
2340
+ transient_code = []
2356
2341
  options_state = read_show_options_and_trigger_reuse(
2357
2342
  link_state: link_state,
2358
2343
  mdoc: @dml_mdoc,
@@ -2361,7 +2346,7 @@ module MarkdownExec
2361
2346
  update_menu_base(options_state.options)
2362
2347
 
2363
2348
  link_state = LinkState.new
2364
- next_state_append_code(selected, link_state, code_lines)
2349
+ next_state_append_code(selected, link_state, context_code: transient_code)
2365
2350
 
2366
2351
  elsif selected.type == BlockType::PORT
2367
2352
  debounce_reset
@@ -2370,22 +2355,22 @@ module MarkdownExec
2370
2355
  selected: selected,
2371
2356
  link_state: link_state,
2372
2357
  block_source: block_source
2373
- )
2374
- next_state_append_code(selected, link_state, required_lines)
2358
+ )[:context_code]
2359
+ next_state_append_code(selected, link_state, context_code: required_lines)
2375
2360
 
2376
2361
  elsif selected.type == BlockType::UX
2377
2362
  debounce_reset
2378
2363
  command_result_w_e_t_nl = code_from_ux_block_to_set_environment_variables(
2379
2364
  selected,
2380
2365
  @dml_mdoc,
2381
- inherited_code: @dml_link_state.inherited_lines,
2366
+ context_code: @dml_link_state.context_code,
2382
2367
  only_default: false,
2383
2368
  silent: true
2384
2369
  )
2385
2370
  next_state_append_code(
2386
2371
  selected,
2387
2372
  link_state,
2388
- command_result_w_e_t_nl.failure? ? [] : command_result_w_e_t_nl.new_lines
2373
+ context_code: command_result_w_e_t_nl.failure? ? [] : command_result_w_e_t_nl.new_lines
2389
2374
  )
2390
2375
 
2391
2376
  elsif selected.type == BlockType::VARS
@@ -2393,7 +2378,7 @@ module MarkdownExec
2393
2378
  next_state_append_code(
2394
2379
  selected,
2395
2380
  link_state,
2396
- code_from_vars_block_to_set_environment_variables(selected)
2381
+ context_code: code_from_vars_block_to_set_environment_variables(selected)
2397
2382
  )
2398
2383
 
2399
2384
  elsif COLLAPSIBLE_TYPES.include?(selected.type)
@@ -2403,11 +2388,13 @@ module MarkdownExec
2403
2388
 
2404
2389
  elsif debounce_allows
2405
2390
  # SHELL type
2406
- compile_execute_and_trigger_reuse(mdoc: mdoc,
2407
- selected: selected,
2408
- link_state: link_state,
2409
- block_source: block_source)
2410
- LoadFileLinkState.new(LoadFile::REUSE, link_state)
2391
+ context_code = compile_execute_and_trigger_reuse(
2392
+ mdoc: mdoc,
2393
+ selected: selected,
2394
+ link_state: link_state,
2395
+ block_source: block_source
2396
+ )
2397
+ next_state_set_code(selected, link_state, context_code)
2411
2398
 
2412
2399
  else
2413
2400
  LoadFileLinkState.new(LoadFile::REUSE, link_state)
@@ -2501,30 +2488,31 @@ module MarkdownExec
2501
2488
  ## collect blocks specified by block
2502
2489
  #
2503
2490
  if mdoc
2504
- code_info = mdoc.collect_recursively_required_code(
2491
+ required_code = mdoc.collect_recursively_required_code(
2505
2492
  anyname: selected_id_name(selected),
2506
2493
  block_source: block_source,
2507
2494
  label_format_above: @delegate_object[:shell_code_label_format_above],
2508
2495
  label_format_below: @delegate_object[:shell_code_label_format_below],
2509
- inherited_lines: link_state&.inherited_lines || []
2496
+ context_code: link_state&.context_code || []
2510
2497
  )
2511
- code_lines = annotate_required_lines(
2512
- 'blk:LINK', code_info[:code], block_name: selected.id
2498
+
2499
+ context_code = annotate_required_lines(
2500
+ 'blk:LINK', required_code[:context_code], block_name: selected.id
2513
2501
  )
2514
- block_names = code_info[:block_names]
2515
- dependencies = code_info[:dependencies]
2502
+ block_names = required_code[:block_names]
2503
+ dependencies = required_code[:dependencies]
2516
2504
  else
2517
2505
  block_names = []
2518
- code_lines = []
2506
+ context_code = []
2519
2507
  dependencies = {}
2520
2508
  end
2521
2509
 
2522
2510
  # load key and values from link block into current environment
2523
2511
  #
2524
2512
  if link_block_data[LinkKeys::VARS]
2525
- code_lines << BashCommentFormatter.format_comment(selected.pub_name)
2513
+ context_code << BashCommentFormatter.format_comment(selected.pub_name)
2526
2514
  link_block_data[LinkKeys::VARS].each do |key, value|
2527
- code_lines << assign_key_value_in_bash(key, value)
2515
+ context_code << assign_key_value_in_bash(key, value)
2528
2516
  EnvInterface.set(key, value.to_s)
2529
2517
  end
2530
2518
  end
@@ -2535,20 +2523,20 @@ module MarkdownExec
2535
2523
  load_filespec = load_filespec_from_expression(load_expr)
2536
2524
  if load_filespec
2537
2525
  begin
2538
- code_lines += File.readlines(load_filespec,
2539
- chomp: true)
2526
+ context_code += File.readlines(load_filespec,
2527
+ chomp: true)
2540
2528
  rescue Errno::ENOENT
2541
2529
  report_error($ERROR_INFO)
2542
2530
  end
2543
2531
  end
2544
2532
  end
2545
2533
 
2546
- # if an eval link block, evaluate code_lines and return its standard output
2534
+ # if an eval link block, evaluate context_code and return its standard output
2547
2535
  #
2548
2536
  if link_block_data.fetch(LinkKeys::EVAL, false) ||
2549
2537
  link_block_data.fetch(LinkKeys::EXEC, false)
2550
- code_lines = link_block_data_eval(
2551
- link_state, code_lines, selected, link_block_data,
2538
+ context_code = link_block_data_eval(
2539
+ link_state, context_code, selected, link_block_data,
2552
2540
  block_source: block_source,
2553
2541
  shell: @delegate_object[:block_type_default]
2554
2542
  )
@@ -2563,13 +2551,16 @@ module MarkdownExec
2563
2551
  nil
2564
2552
  ) || link_block_data.fetch(LinkKeys::BLOCK, nil) || ''
2565
2553
 
2566
- code_lines = annotate_required_lines(
2567
- 'blk:LINK', code_lines, block_name: selected.id
2554
+ context_code = annotate_required_lines(
2555
+ 'blk:LINK', context_code, block_name: selected.id
2556
+ )
2557
+ context_code = annotate_required_lines(
2558
+ 'blk:LINK', context_code, block_name: selected.id
2568
2559
  )
2569
2560
 
2570
2561
  if link_block_data[LinkKeys::RETURN]
2571
2562
  pop_add_current_code_to_head_and_trigger_load(
2572
- link_state, block_names, code_lines,
2563
+ link_state, block_names, context_code,
2573
2564
  dependencies, selected, next_block_name: next_block_name
2574
2565
  )
2575
2566
 
@@ -2582,8 +2573,8 @@ module MarkdownExec
2582
2573
  ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
2583
2574
  inherited_dependencies:
2584
2575
  (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
2585
- inherited_lines: HashDelegator.flatten_and_compact_arrays(
2586
- link_state&.inherited_lines, code_lines
2576
+ context_code: HashDelegator.flatten_and_compact_arrays(
2577
+ link_state&.context_code, context_code
2587
2578
  ),
2588
2579
  keep_code: link_state&.keep_code,
2589
2580
  next_block_name: next_block_name,
@@ -2680,32 +2671,34 @@ module MarkdownExec
2680
2671
  #
2681
2672
  # @param mdoc [YourMDocClass] An instance of the MDoc class.
2682
2673
  # @param selected [Hash] The selected block.
2683
- # @return [Array<String>] Required code blocks as an array of lines.
2674
+ # @return [OpenStruct] context and transient code
2684
2675
  def execute_block_type_port_code_lines(mdoc:, selected:, block_source:,
2685
2676
  link_state: LinkState.new)
2686
- required = mdoc.collect_recursively_required_code(
2677
+ required_code = mdoc.collect_recursively_required_code(
2687
2678
  anyname: selected_id_name(selected),
2688
2679
  label_format_above: @delegate_object[:shell_code_label_format_above],
2689
2680
  label_format_below: @delegate_object[:shell_code_label_format_below],
2690
2681
  block_source: block_source,
2691
- inherited_lines: link_state&.inherited_lines || []
2692
- ) # !!t 'required'
2682
+ context_code: link_state&.context_code || []
2683
+ ) # !!t 'required_code'
2693
2684
  dependencies = (
2694
2685
  link_state&.inherited_dependencies || {}
2695
- ).merge(required[:dependencies] || {})
2696
- required[:unmet_dependencies] = (
2697
- required[:unmet_dependencies] || []
2686
+ ).merge(required_code[:dependencies] || {})
2687
+
2688
+ required_code[:unmet_dependencies] = (
2689
+ required_code[:unmet_dependencies] || []
2698
2690
  ) - (link_state&.inherited_block_names || [])
2699
- if required[:unmet_dependencies].present?
2691
+
2692
+ if required_code[:unmet_dependencies].present?
2700
2693
  ### filter against link_state.inherited_block_names
2701
2694
 
2702
2695
  warn format_and_highlight_dependencies(
2703
- dependencies, highlight: required[:unmet_dependencies]
2696
+ dependencies, highlight: required_code[:unmet_dependencies]
2704
2697
  )
2705
2698
  runtime_exception(
2706
2699
  :runtime_exception_error_level,
2707
2700
  'unmet_dependencies, flag: runtime_exception_error_level',
2708
- required[:unmet_dependencies]
2701
+ required_code[:unmet_dependencies]
2709
2702
  )
2710
2703
  elsif @delegate_object[:dump_dependencies]
2711
2704
  warn format_and_highlight_dependencies(
@@ -2716,8 +2709,11 @@ module MarkdownExec
2716
2709
 
2717
2710
  if selected[:type] == BlockType::OPTS
2718
2711
  # body of blocks is returned as a list of lines to be read an YAML
2719
- HashDelegator.flatten_and_compact_arrays(
2720
- required[:blocks].map(&:body).flatten(1)
2712
+ OpenStruct.new(
2713
+ context_code: HashDelegator.flatten_and_compact_arrays(
2714
+ required_code[:blocks].map(&:body).flatten(1)
2715
+ ),
2716
+ transient_code: []
2721
2717
  )
2722
2718
  else
2723
2719
  # code from the selected VARS block
@@ -2727,31 +2723,41 @@ module MarkdownExec
2727
2723
  []
2728
2724
  end
2729
2725
 
2730
- # activate UX blocks in the required list
2726
+ # activate UX blocks in the required_code list
2731
2727
  command_result_w_e_t_nl = code_from_ux_block_to_set_environment_variables(
2732
2728
  selected,
2733
2729
  @dml_mdoc,
2734
- inherited_code: vars_code,
2730
+ context_code: required_code[:context_code] + required_code[:transient_code],
2735
2731
  only_default: false,
2736
- required: required,
2732
+ required:
2733
+ OpenStruct.new(context_code: [], transient_code: vars_code),
2737
2734
  silent: false
2738
2735
  )
2739
2736
  ux_code = command_result_w_e_t_nl.failure? ? [] : command_result_w_e_t_nl.new_lines
2740
2737
 
2741
- HashDelegator.flatten_and_compact_arrays(
2742
- link_state&.inherited_lines,
2743
- annotate_required_lines(
2744
- 'blk:PORT',
2745
- required[:code] + vars_code + ux_code,
2746
- block_name: selected.id
2738
+ OpenStruct.new(
2739
+ context_code: HashDelegator.flatten_and_compact_arrays(
2740
+ link_state&.context_code,
2741
+ annotate_required_lines(
2742
+ 'blk:PORT',
2743
+ (required_code[:context_code] || []) + vars_code + ux_code,
2744
+ block_name: selected.id
2745
+ )
2746
+ ),
2747
+ transient_code: HashDelegator.flatten_and_compact_arrays(
2748
+ annotate_required_lines(
2749
+ 'blk:PORT',
2750
+ required_code[:transient_code],
2751
+ block_name: selected.id
2752
+ )
2747
2753
  )
2748
2754
  )
2749
2755
  end
2750
2756
  rescue StandardError
2751
- wwe(required[:code], ux_code, { error: $!, callback: $@[0] })
2757
+ wwe(required_code, ux_code, { error: $!, callback: $@[0] })
2752
2758
  end
2753
2759
 
2754
- def execute_block_type_save(code_lines:, selected:)
2760
+ def execute_block_type_save(transient_code:, selected:)
2755
2761
  block_data = HashDelegator.parse_yaml_data_from_body(selected.body)
2756
2762
  directory_glob = if block_data['directory']
2757
2763
  File.join(
@@ -2772,7 +2778,7 @@ module MarkdownExec
2772
2778
  end
2773
2779
 
2774
2780
  File.write(save_filespec,
2775
- HashDelegator.join_code_lines(code_lines))
2781
+ HashDelegator.join_code_lines(transient_code))
2776
2782
  rescue Errno::ENOENT
2777
2783
  report_error($ERROR_INFO)
2778
2784
  end
@@ -2867,14 +2873,14 @@ module MarkdownExec
2867
2873
  end
2868
2874
 
2869
2875
  def execute_inherited_save(
2870
- code_lines: @dml_link_state.inherited_lines
2876
+ transient_code: @dml_link_state.context_code
2871
2877
  )
2872
2878
  return unless (save_filespec = save_filespec_from_expression(
2873
2879
  document_name_in_glob_as_file_name
2874
2880
  ))
2875
2881
 
2876
2882
  unless write_file_with_directory_creation(
2877
- content: HashDelegator.join_code_lines(code_lines),
2883
+ content: HashDelegator.join_code_lines(transient_code),
2878
2884
  filespec: save_filespec
2879
2885
  )
2880
2886
  :break
@@ -2885,14 +2891,14 @@ module MarkdownExec
2885
2891
  @menu_user_clicked_back_link = true
2886
2892
 
2887
2893
  keep_code = @dml_link_state.keep_code
2888
- inherited_lines = keep_code ? @dml_link_state.inherited_lines_block : nil
2894
+ context_code = keep_code ? @dml_link_state.context_code_block : nil
2889
2895
 
2890
2896
  @dml_link_state = pop_link_history_new_state
2891
2897
 
2892
2898
  {
2893
2899
  block_name: @dml_link_state.block_name,
2894
2900
  document_filename: @dml_link_state.document_filename,
2895
- inherited_lines: inherited_lines,
2901
+ context_code: context_code,
2896
2902
  keep_code: keep_code
2897
2903
  }
2898
2904
  end
@@ -2908,23 +2914,25 @@ module MarkdownExec
2908
2914
  def execute_required_lines(
2909
2915
  blockname: '',
2910
2916
  erls: {},
2911
- required_lines: [],
2917
+ script_lines: [],
2912
2918
  shell:
2913
2919
  )
2914
2920
  if @delegate_object[:save_executed_script]
2915
2921
  write_command_file(blockname: blockname,
2916
- required_lines: required_lines,
2922
+ required_lines: script_lines,
2917
2923
  shell: selected_shell(shell))
2918
2924
  end
2919
2925
  if @dml_block_state
2920
2926
  calc_logged_stdout_filename(block_name: @dml_block_state.block.oname)
2921
2927
  end
2922
2928
  format_and_execute_command(
2923
- code_lines: required_lines,
2929
+ script_lines: script_lines,
2924
2930
  erls: erls,
2925
2931
  shell: selected_shell(shell)
2926
2932
  )
2927
2933
  post_execution_process
2934
+ rescue StandardError
2935
+ wwe $!
2928
2936
  end
2929
2937
 
2930
2938
  def expand_blocks_with_replacements(
@@ -3039,7 +3047,7 @@ module MarkdownExec
3039
3047
  case export_string
3040
3048
  when String, Integer, Float, TrueClass, FalseClass
3041
3049
  command_result = HashDelegator.execute_bash_script_lines(
3042
- code_lines: join_array_of_arrays(
3050
+ transient_code: join_array_of_arrays(
3043
3051
  bash_script_lines,
3044
3052
  printf_expand ? expander.call(export_string) : [export_string]
3045
3053
  ),
@@ -3080,7 +3088,7 @@ module MarkdownExec
3080
3088
  # each item in the hash is a variable name and value
3081
3089
  export_string.each do |name, expression|
3082
3090
  command_result = HashDelegator.execute_bash_script_lines(
3083
- code_lines: join_array_of_arrays(
3091
+ transient_code: join_array_of_arrays(
3084
3092
  bash_script_lines,
3085
3093
  required_lines,
3086
3094
  printf_expand ? expander.call(expression) : [expression]
@@ -3211,11 +3219,11 @@ module MarkdownExec
3211
3219
  end
3212
3220
 
3213
3221
  def format_and_execute_command(
3214
- code_lines:,
3222
+ script_lines:,
3215
3223
  erls:,
3216
3224
  shell:
3217
3225
  )
3218
- formatted_command = code_lines.flatten.join("\n")
3226
+ formatted_command = script_lines.flatten.join("\n")
3219
3227
  @fout.fout fetch_color(data_sym: :script_execution_head,
3220
3228
  color_sym: :script_execution_frame_color)
3221
3229
 
@@ -3484,7 +3492,7 @@ module MarkdownExec
3484
3492
  wwt :iterlines, 'nested_line:', nested_line
3485
3493
  update_line_and_block_state(
3486
3494
  nested_line, state, selected_types,
3487
- source_id: "ItrBlkFrmNstFls:#{index}¤#{nested_line.filename}:#{nested_line.index}",
3495
+ source_id: "IBNF:#{index}¤#{nested_line.filename}:#{nested_line.index}",
3488
3496
  &block
3489
3497
  )
3490
3498
 
@@ -3524,10 +3532,10 @@ module MarkdownExec
3524
3532
  end.compact.flatten(1)
3525
3533
  end
3526
3534
 
3527
- def link_block_data_eval(link_state, code_lines, selected, link_block_data,
3535
+ def link_block_data_eval(link_state, transient_code, selected, link_block_data,
3528
3536
  block_source:, shell:)
3529
3537
  all_code = HashDelegator.flatten_and_compact_arrays(
3530
- link_state&.inherited_lines, code_lines
3538
+ link_state&.context_code, transient_code
3531
3539
  )
3532
3540
  output_lines = []
3533
3541
 
@@ -3546,34 +3554,34 @@ module MarkdownExec
3546
3554
  output_lines.push(line) if line
3547
3555
  end
3548
3556
 
3549
- if link_block_data.fetch(LinkKeys::EVAL, true)
3550
- # eval: true
3551
-
3552
- ## select output_lines that look like assignment or match other specs
3553
- #
3554
- output_lines = process_string_array(
3555
- output_lines,
3556
- begin_pattern: @delegate_object.fetch(:output_assignment_begin,
3557
- nil),
3558
- end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
3559
- scan1: @delegate_object.fetch(:output_assignment_match, nil),
3560
- format1: @delegate_object.fetch(:output_assignment_format, nil),
3561
- name: ''
3562
- )
3557
+ output_lines = if link_block_data.fetch(LinkKeys::EVAL, true)
3558
+ # eval: true
3559
+
3560
+ ## select output_lines that look like assignment or match other specs
3561
+ #
3562
+ process_string_array(
3563
+ output_lines,
3564
+ begin_pattern: @delegate_object.fetch(:output_assignment_begin,
3565
+ nil),
3566
+ end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
3567
+ scan1: @delegate_object.fetch(:output_assignment_match, nil),
3568
+ format1: @delegate_object.fetch(:output_assignment_format, nil),
3569
+ name: ''
3570
+ )
3563
3571
 
3564
- else
3565
- # eval: false
3566
-
3567
- ## select all output_lines
3568
- #
3569
- output_lines = process_string_array(
3570
- output_lines,
3571
- begin_pattern: @delegate_object.fetch(:output_assignment_begin,
3572
- nil),
3573
- end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
3574
- name: ''
3575
- )
3576
- end
3572
+ else
3573
+ # eval: false
3574
+
3575
+ ## select all output_lines
3576
+ #
3577
+ process_string_array(
3578
+ output_lines,
3579
+ begin_pattern: @delegate_object.fetch(:output_assignment_begin,
3580
+ nil),
3581
+ end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
3582
+ name: ''
3583
+ )
3584
+ end
3577
3585
  else
3578
3586
  output_lines = `bash #{file.path}`.split("\n")
3579
3587
  end
@@ -3620,7 +3628,7 @@ module MarkdownExec
3620
3628
 
3621
3629
  def link_history_push_and_next(
3622
3630
  curr_block_name:, curr_document_filename:,
3623
- inherited_block_names:, inherited_dependencies:, inherited_lines:,
3631
+ inherited_block_names:, inherited_dependencies:, context_code:,
3624
3632
  keep_code:,
3625
3633
  next_block_name:, next_document_filename:,
3626
3634
  next_keep_code:,
@@ -3632,7 +3640,7 @@ module MarkdownExec
3632
3640
  document_filename: curr_document_filename,
3633
3641
  inherited_block_names: inherited_block_names,
3634
3642
  inherited_dependencies: inherited_dependencies,
3635
- inherited_lines: inherited_lines,
3643
+ context_code: context_code,
3636
3644
  keep_code: keep_code
3637
3645
  )
3638
3646
  )
@@ -3643,7 +3651,7 @@ module MarkdownExec
3643
3651
  document_filename: next_document_filename,
3644
3652
  inherited_block_names: inherited_block_names,
3645
3653
  inherited_dependencies: inherited_dependencies,
3646
- inherited_lines: inherited_lines,
3654
+ context_code: context_code,
3647
3655
  keep_code: next_keep_code
3648
3656
  )
3649
3657
  )
@@ -3833,27 +3841,27 @@ module MarkdownExec
3833
3841
  reload_blocks = true
3834
3842
  end
3835
3843
 
3836
- link_state_inherited_lines = link_state&.inherited_lines || []
3844
+ link_state_context_code = link_state&.context_code || []
3837
3845
 
3838
3846
  # return code resulting from evaluating all SHELL, UX, VARS blocks;
3839
3847
  # each set in sequence; with its own order
3840
3848
  #
3841
- if (code_lines, _inherit_lines = code_from_auto_blocks(
3849
+ if (transient_code = inherited_lines_from_auto_blocks(
3842
3850
  all_blocks,
3843
3851
  default_only: true,
3844
3852
  mdoc: mdoc,
3845
- inherited_lines: link_state_inherited_lines
3853
+ context_code: link_state_context_code
3846
3854
  ))&.select_by(:empty?, false)&.compact&.count&.positive?
3847
- wwt :code_lines, 'code_lines:', code_lines
3855
+ wwt :transient_code, 'transient_code:', transient_code
3848
3856
 
3849
- # prepend inherited lines to new code lines
3850
- new_code = link_state_inherited_lines + code_lines
3857
+ # prepend context code to new transient code
3858
+ new_code = link_state_context_code + transient_code
3851
3859
  next_state_set_code(nil, link_state, new_code)
3852
- link_state.inherited_lines = new_code
3860
+ link_state.context_code = new_code
3853
3861
 
3854
3862
  reload_blocks = true
3855
3863
  else
3856
- link_state&.inherited_lines
3864
+ link_state&.context_code
3857
3865
  end
3858
3866
 
3859
3867
  if reload_blocks
@@ -4040,19 +4048,19 @@ module MarkdownExec
4040
4048
  list[(index + 1) % list.size] # Get the next item, wrap around if at the end
4041
4049
  end
4042
4050
 
4043
- def next_state_append_code(selected, link_state, code_lines,
4051
+ def next_state_append_code(selected, link_state, context_code:,
4044
4052
  mode: LoadMode::APPEND)
4045
4053
  next_state_set_code(
4046
4054
  selected,
4047
4055
  link_state,
4048
4056
  HashDelegator.flatten_and_compact_arrays(
4049
- mode == LoadMode::APPEND ? link_state&.inherited_lines : [],
4050
- code_lines.is_a?(Array) ? code_lines : [] # no code for :ux_exec_prohibited
4057
+ mode == LoadMode::APPEND ? link_state&.context_code : [],
4058
+ context_code.is_a?(Array) ? context_code : [] # no code for :ux_exec_prohibited
4051
4059
  )
4052
4060
  )
4053
4061
  end
4054
4062
 
4055
- def next_state_set_code(selected, link_state, code_lines)
4063
+ def next_state_set_code(selected, link_state, context_code)
4056
4064
  block_names = []
4057
4065
  dependencies = {}
4058
4066
  link_history_push_and_next(
@@ -4062,7 +4070,7 @@ module MarkdownExec
4062
4070
  ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
4063
4071
  inherited_dependencies:
4064
4072
  (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
4065
- inherited_lines: HashDelegator.flatten_and_compact_arrays(code_lines),
4073
+ context_code: HashDelegator.flatten_and_compact_arrays(context_code),
4066
4074
  keep_code: link_state&.keep_code,
4067
4075
  next_block_name: '',
4068
4076
  next_document_filename: @delegate_object[:filename],
@@ -4127,7 +4135,7 @@ module MarkdownExec
4127
4135
  end
4128
4136
 
4129
4137
  def pop_add_current_code_to_head_and_trigger_load(
4130
- link_state, block_names, code_lines,
4138
+ link_state, block_names, transient_code,
4131
4139
  dependencies, selected, next_block_name: nil
4132
4140
  )
4133
4141
  pop = @link_history.pop # updatable
@@ -4139,9 +4147,9 @@ module MarkdownExec
4139
4147
  (pop.inherited_block_names + block_names).sort.uniq,
4140
4148
  inherited_dependencies:
4141
4149
  dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data
4142
- inherited_lines:
4143
- HashDelegator.flatten_and_compact_arrays(pop.inherited_lines,
4144
- code_lines)
4150
+ context_code:
4151
+ HashDelegator.flatten_and_compact_arrays(pop.context_code,
4152
+ transient_code)
4145
4153
  )
4146
4154
  @link_history.push(next_state)
4147
4155
 
@@ -4157,9 +4165,9 @@ module MarkdownExec
4157
4165
  ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
4158
4166
  inherited_dependencies:
4159
4167
  (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
4160
- inherited_lines:
4168
+ context_code:
4161
4169
  HashDelegator.flatten_and_compact_arrays(
4162
- link_state&.inherited_lines, code_lines
4170
+ link_state&.context_code, transient_code
4163
4171
  ),
4164
4172
  keep_code: link_state&.keep_code,
4165
4173
  next_block_name: next_block_name,
@@ -4184,7 +4192,7 @@ module MarkdownExec
4184
4192
  document_filename: pop.document_filename,
4185
4193
  inherited_block_names: peek.inherited_block_names,
4186
4194
  inherited_dependencies: peek.inherited_dependencies,
4187
- inherited_lines: peek.inherited_lines
4195
+ context_code: peek.context_code
4188
4196
  )
4189
4197
  end
4190
4198
 
@@ -4560,11 +4568,13 @@ module MarkdownExec
4560
4568
  obj = {}
4561
4569
 
4562
4570
  # concatenated body of all required blocks loaded a YAML
4571
+
4572
+ rc = execute_block_type_port_code_lines(
4573
+ mdoc: mdoc, selected: selected,
4574
+ link_state: link_state, block_source: {}
4575
+ )
4563
4576
  data = (YAML.load(
4564
- execute_block_type_port_code_lines(
4565
- mdoc: mdoc, selected: selected,
4566
- link_state: link_state, block_source: {}
4567
- ).join("\n")
4577
+ rc[:context_code].join("\n")
4568
4578
  ) || {}).transform_keys(&:to_sym)
4569
4579
 
4570
4580
  if selected.type == BlockType::OPTS
@@ -4764,7 +4774,7 @@ module MarkdownExec
4764
4774
  filename: filename,
4765
4775
  saved_asset_format:
4766
4776
  shell_escape_asset_format(
4767
- code_lines: link_state&.inherited_lines,
4777
+ transient_code: link_state&.context_code,
4768
4778
  shell: selected_shell(@delegate_object[:shell])
4769
4779
  )
4770
4780
  ).generate_name
@@ -4933,7 +4943,7 @@ module MarkdownExec
4933
4943
  end
4934
4944
 
4935
4945
  def shell_escape_asset_format(
4936
- code_lines:,
4946
+ transient_code:,
4937
4947
  enable: @delegate_object[:shell_parameter_expansion],
4938
4948
  raw: @delegate_object[:saved_asset_format],
4939
4949
  shell:
@@ -4948,7 +4958,7 @@ module MarkdownExec
4948
4958
 
4949
4959
  marker = Random.new.rand.to_s
4950
4960
 
4951
- code = (code_lines || []) + ["echo -n \"#{marker}#{raw}\""]
4961
+ code = (transient_code || []) + ["echo -n \"#{marker}#{raw}\""]
4952
4962
  File.write filespec, HashDelegator.join_code_lines(code)
4953
4963
  File.chmod 0o755, filespec
4954
4964
 
@@ -5484,10 +5494,10 @@ module MarkdownExec
5484
5494
  end
5485
5495
 
5486
5496
  def vux_edit_inherited
5487
- edited = edit_text(@dml_link_state.inherited_lines_block)
5497
+ edited = edit_text(@dml_link_state.context_code_block)
5488
5498
  return unless edited
5489
5499
 
5490
- @dml_link_state.inherited_lines =
5500
+ @dml_link_state.context_code =
5491
5501
  annotate_required_lines(
5492
5502
  'blk:EDIT', edited.split("\n"), block_name: 'EDIT'
5493
5503
  )
@@ -5707,7 +5717,7 @@ module MarkdownExec
5707
5717
  def vux_load_code_files_into_state
5708
5718
  return unless @menu_base_options[:load_code].present?
5709
5719
 
5710
- @dml_link_state.inherited_lines =
5720
+ @dml_link_state.context_code =
5711
5721
  @menu_base_options[:load_code].split(':').map do |path|
5712
5722
  File.readlines(path, chomp: true)
5713
5723
  end.flatten(1)
@@ -5718,7 +5728,7 @@ module MarkdownExec
5718
5728
 
5719
5729
  pop_add_current_code_to_head_and_trigger_load(
5720
5730
  @dml_link_state, inherited_block_names,
5721
- code_lines, inherited_dependencies, selected
5731
+ transient_code, inherited_dependencies, selected
5722
5732
  )
5723
5733
  end
5724
5734
 
@@ -5727,7 +5737,7 @@ module MarkdownExec
5727
5737
  document_name_in_glob_as_file_name
5728
5738
  ))
5729
5739
 
5730
- @dml_link_state.inherited_lines_append(
5740
+ @dml_link_state.context_code_append(
5731
5741
  File.readlines(filespec, chomp: true)
5732
5742
  )
5733
5743
  end
@@ -5886,7 +5896,7 @@ module MarkdownExec
5886
5896
  files = document_glob ? Dir.glob(document_glob) : []
5887
5897
  @doc_saved_lines_files = files.count.positive? ? files : []
5888
5898
 
5889
- lines_count = @dml_link_state.inherited_lines_count
5899
+ lines_count = @dml_link_state.context_code_count
5890
5900
 
5891
5901
  # add menu items (glob, load, save) and enable selectively
5892
5902
  if files.count.positive? || lines_count.positive?
@@ -6011,7 +6021,7 @@ module MarkdownExec
6011
6021
  end
6012
6022
 
6013
6023
  def vux_view_inherited(stream:)
6014
- stream.puts @dml_link_state.inherited_lines_block
6024
+ stream.puts @dml_link_state.context_code_block
6015
6025
  end
6016
6026
 
6017
6027
  def wait_for_stream_processing
@@ -6104,7 +6114,7 @@ module MarkdownExec
6104
6114
  prefix: @delegate_object[:saved_script_filename_prefix],
6105
6115
  saved_asset_format:
6106
6116
  shell_escape_asset_format(
6107
- code_lines: @dml_link_state.inherited_lines,
6117
+ transient_code: @dml_link_state.context_code,
6108
6118
  shell: shell
6109
6119
  ),
6110
6120
  time: time_now
@@ -6163,7 +6173,7 @@ module MarkdownExec
6163
6173
  if save_filespec.present?
6164
6174
  File.write(
6165
6175
  save_filespec,
6166
- HashDelegator.join_code_lines(link_state&.inherited_lines)
6176
+ HashDelegator.join_code_lines(link_state&.context_code)
6167
6177
  )
6168
6178
  @delegate_object[:filename]
6169
6179
  else
@@ -6346,7 +6356,7 @@ module MarkdownExec
6346
6356
  LinkState.new(block_name: 'sample_block',
6347
6357
  document_filename: 'sample_file',
6348
6358
  inherited_dependencies: {},
6349
- inherited_lines: ['# ', 'KEY="VALUE"'])
6359
+ context_code: ['# ', 'KEY="VALUE"'])
6350
6360
  )
6351
6361
  assert_equal expected_result,
6352
6362
  @hd.execute_block_type_link_with_state(
@@ -6522,12 +6532,43 @@ module MarkdownExec
6522
6532
  def test_execute_block_type_port_code_lines_with_vars
6523
6533
  YAML.stubs(:load).returns({ 'key' => 'value' })
6524
6534
  @mdoc.stubs(:collect_recursively_required_code)
6525
- .returns({ code: ['code line'] })
6535
+ .returns({ context_code: [], transient_code: ['code line'] })
6526
6536
  result = @hd.execute_block_type_port_code_lines(
6527
6537
  mdoc: @mdoc, selected: @selected, block_source: {}
6528
6538
  )
6529
6539
 
6530
- assert_equal ['code line', 'key="value"'], result
6540
+ assert_equal ['key="value"'], result[:context_code]
6541
+ assert_equal ['code line'], result[:transient_code]
6542
+ end
6543
+
6544
+ def test_transient_code_parameter_usage
6545
+ # Test that transient_code parameter is used correctly in execute_bash_script_lines
6546
+ transient_code = ["echo 'test'", "echo 'transient'"]
6547
+ export = OpenStruct.new(exportable: false, validate: //, transform: ->(x) { x })
6548
+ result = HashDelegator.execute_bash_script_lines(
6549
+ transient_code: transient_code,
6550
+ export: export,
6551
+ export_name: 'TEST',
6552
+ shell: '/bin/bash'
6553
+ )
6554
+
6555
+ assert result.is_a?(CommandResult)
6556
+ assert_equal transient_code, result.script
6557
+ end
6558
+
6559
+ def test_transient_code_vs_context_code_separation
6560
+ # Test that transient_code is separate from context_code
6561
+ context_code = ['CONTEXT_VAR="context_value"']
6562
+ transient_code = ['TRANSIENT_VAR="transient_value"']
6563
+
6564
+ # Simulate combining them
6565
+ all_code = HashDelegator.flatten_and_compact_arrays(
6566
+ context_code, transient_code
6567
+ )
6568
+
6569
+ assert_equal 2, all_code.length
6570
+ assert_includes all_code, 'CONTEXT_VAR="context_value"'
6571
+ assert_includes all_code, 'TRANSIENT_VAR="transient_value"'
6531
6572
  end
6532
6573
  end
6533
6574