markdown_exec 2.8.1 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +27 -0
- data/Gemfile.lock +1 -1
- data/bats/block-hide.bats +8 -0
- data/bats/block-type-ux-require.bats +8 -0
- data/bin/tab_completion.sh +1 -1
- data/docs/dev/block-hide.md +18 -0
- data/docs/dev/block-type-ux-require.md +28 -0
- data/lib/fcb.rb +4 -1
- data/lib/hash_delegator.rb +242 -213
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +11 -28
- data/lib/mdoc.rb +5 -6
- data/lib/menu.src.yml +1 -0
- data/lib/menu.yml +1 -0
- metadata +6 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 066c72f2f85462a89163b7834669dee6526e516ee3ebfe4be2e8b269cb4ece36
         | 
| 4 | 
            +
              data.tar.gz: 48c2bce9ac82cda2cbecca5bea4564b28013cdbab7005e249e8a856d0280afa0
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: fe1270b8cf11efc8ad9e81cb43052bc75cfc217e362c7d6e30acb6981a6d0be749f290b9b15ce1a2655d6a7e157177c4cd975aa61de22a6f6bafe2a835285228
         | 
| 7 | 
            +
              data.tar.gz: 9445285db86af55fe5ba0b784a24d30dd418ac3d1dc551183a5a1b3b865df27a6b314ddc08b4a013de5e926e023439753fe08cd4ea8d6c6da0c0d9547e4a9546
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,32 @@ | |
| 1 1 | 
             
            # Changelog
         | 
| 2 2 |  | 
| 3 | 
            +
            ## [2.8.2] - 2025-02-19
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ### Added
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            - UX blocks can add preconditions. Preconditions are variable names that must be set before the UX block is executed. If any preconditions are not set, a warning is displayed, and the sequence is aborted.
         | 
| 8 | 
            +
            - UX blocks can require shell an other UX blocks.
         | 
| 9 | 
            +
            - UX blocks are evaluated in order and calculation can depend on prior variables in the same sequence.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ### Changed
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            - Hide all blocks per their initial title instead of `oname`.
         | 
| 14 | 
            +
            - Make menu blocks for list of files found to fix crash.
         | 
| 15 | 
            +
            - Use a block ID to recall the selected block.
         | 
| 16 | 
            +
            - UX blocks are hidden similar to the rest.
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ## [2.8.1] - 2025-02-13
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ### Added
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            - BATS tests for UX block type.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ### Changed
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            - Improve persistence of position in menu on reload
         | 
| 27 | 
            +
            - Update block-type-ux-exec BATS test.
         | 
| 28 | 
            +
            - Refactor menu for selecting items with facets.
         | 
| 29 | 
            +
             | 
| 3 30 | 
             
            ## [2.8.0] - 2025-02-10
         | 
| 4 31 |  | 
| 5 32 | 
             
            ### Added
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
| @@ -0,0 +1,8 @@ | |
| 1 | 
            +
            #!/usr/bin/env bats
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            load 'test_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            @test 'Output of executed commands as initial value' {
         | 
| 6 | 
            +
              spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-ux-require.md \
         | 
| 7 | 
            +
               'SPECIES=Pongo tapanuliensis_GENUS=Pongo_NAME=Pongo tapanuliensis - Pongo_NAME2=Pongo tapanuliensis - Pongo'
         | 
| 8 | 
            +
            }
         | 
    
        data/bin/tab_completion.sh
    CHANGED
    
    
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            ``` :(hidden)
         | 
| 2 | 
            +
            ```
         | 
| 3 | 
            +
            ``` :visible
         | 
| 4 | 
            +
            ```
         | 
| 5 | 
            +
            / ux block is displayed differently than other types
         | 
| 6 | 
            +
            ```ux :()
         | 
| 7 | 
            +
            name: name
         | 
| 8 | 
            +
            ```
         | 
| 9 | 
            +
            @import bats-document-configuration.md
         | 
| 10 | 
            +
            ```opts :(document_opts)
         | 
| 11 | 
            +
            # Pattern for blocks to hide from user-selection
         | 
| 12 | 
            +
            block_name_include_match:
         | 
| 13 | 
            +
              ^\(.*\)$
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            # Pattern for the block name in the line defining the block
         | 
| 16 | 
            +
            block_name_match: |
         | 
| 17 | 
            +
              :(?<title>\S+)( |$)
         | 
| 18 | 
            +
            ```
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            / an automatic UX block requires a shell block and another UX block
         | 
| 2 | 
            +
            ``` :(shell)
         | 
| 3 | 
            +
            ENTITY='Pongo tapanuliensis,Pongo'
         | 
| 4 | 
            +
            ```
         | 
| 5 | 
            +
            ```ux :[document_ux_SPECIES] +(shell) +[ux_GENUS]
         | 
| 6 | 
            +
            default: :exec
         | 
| 7 | 
            +
            exec: printf "${ENTITY%%,*}"
         | 
| 8 | 
            +
            name: SPECIES
         | 
| 9 | 
            +
            ```
         | 
| 10 | 
            +
            / required ux block requires another
         | 
| 11 | 
            +
            ```ux :[ux_GENUS] +[ux_NAME]
         | 
| 12 | 
            +
            default: :exec
         | 
| 13 | 
            +
            exec: printf "${ENTITY##*,}"
         | 
| 14 | 
            +
            name: GENUS
         | 
| 15 | 
            +
            ```
         | 
| 16 | 
            +
            / executed in context of prior ux blocks, uses their initial values
         | 
| 17 | 
            +
            ```ux :[ux_NAME]
         | 
| 18 | 
            +
            default: :exec
         | 
| 19 | 
            +
            exec: printf "$SPECIES - $GENUS"
         | 
| 20 | 
            +
            name: NAME
         | 
| 21 | 
            +
            ```
         | 
| 22 | 
            +
            / executed after other ux blocks, uses their initial values
         | 
| 23 | 
            +
            ```ux :[document_ux_NAME2]
         | 
| 24 | 
            +
            default: :exec
         | 
| 25 | 
            +
            exec: printf "$NAME"
         | 
| 26 | 
            +
            name: NAME2
         | 
| 27 | 
            +
            ```
         | 
| 28 | 
            +
            @import bats-document-configuration.md
         | 
    
        data/lib/fcb.rb
    CHANGED
    
    | @@ -14,7 +14,8 @@ def parse_yaml_of_ux_block( | |
| 14 14 | 
             
              export = data['export']
         | 
| 15 15 | 
             
              export = data if export.nil?
         | 
| 16 16 | 
             
              name = export['name']
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 | 
            +
              raise "Name is missing in UX block: #{data.inspect}" unless name.present?
         | 
| 18 19 |  | 
| 19 20 | 
             
              OpenStruct.new(
         | 
| 20 21 | 
             
                allowed: export['allowed'],
         | 
| @@ -22,6 +23,7 @@ def parse_yaml_of_ux_block( | |
| 22 23 | 
             
                exec: export['exec'],
         | 
| 23 24 | 
             
                menu_format: export['menu_format'] || menu_format,
         | 
| 24 25 | 
             
                name: name,
         | 
| 26 | 
            +
                preconditions: export['preconditions'],
         | 
| 25 27 | 
             
                prompt: export['prompt'] || prompt,
         | 
| 26 28 | 
             
                transform: export['transform'],
         | 
| 27 29 | 
             
                validate: export['validate'] || validate
         | 
| @@ -136,6 +138,7 @@ module MarkdownExec | |
| 136 138 | 
             
                      @attrs[:center] = table_center
         | 
| 137 139 | 
             
                      oname = @attrs[:oname] = format(export.menu_format, export.to_h)
         | 
| 138 140 | 
             
                    else
         | 
| 141 | 
            +
                      # triggered by an empty block
         | 
| 139 142 | 
             
                      raise "Invalid data type: #{data.inspect}"
         | 
| 140 143 | 
             
                    end
         | 
| 141 144 | 
             
                  end
         | 
    
        data/lib/hash_delegator.rb
    CHANGED
    
    | @@ -306,7 +306,7 @@ module HashDelegatorSelf | |
| 306 306 | 
             
                  table__hs.each do |table_hs|
         | 
| 307 307 | 
             
                    table_hs.substrings.each do |substrings|
         | 
| 308 308 | 
             
                      substrings.each do |node|
         | 
| 309 | 
            -
                        next unless node[:text]. | 
| 309 | 
            +
                        next unless node[:text].instance_of?(TrackedString)
         | 
| 310 310 |  | 
| 311 311 | 
             
                        exceeded_table_cell ||= node[:text].exceeded
         | 
| 312 312 | 
             
                        truncated_table_cell = node[:text].truncated
         | 
| @@ -606,6 +606,9 @@ module MarkdownExec | |
| 606 606 |  | 
| 607 607 | 
             
                  @process_mutex = Mutex.new
         | 
| 608 608 | 
             
                  @process_cv = ConditionVariable.new
         | 
| 609 | 
            +
                  @dml_link_state = Struct.new(:document_filename, :inherited_lines)
         | 
| 610 | 
            +
                                          .new(@delegate_object[:filename], [])
         | 
| 611 | 
            +
                  @dml_menu_blocks = []
         | 
| 609 612 |  | 
| 610 613 | 
             
                  @p_all_arguments = []
         | 
| 611 614 | 
             
                  @p_options_parsed = []
         | 
| @@ -1022,25 +1025,11 @@ module MarkdownExec | |
| 1022 1025 | 
             
                  ]
         | 
| 1023 1026 | 
             
                end
         | 
| 1024 1027 |  | 
| 1025 | 
            -
                 | 
| 1026 | 
            -
             | 
| 1027 | 
            -
                  # ww0 inherited_code
         | 
| 1028 | 
            -
                  code = (inherited_code || []) + [export_exec]
         | 
| 1029 | 
            -
                  filespec = generate_temp_filename
         | 
| 1030 | 
            -
                  File.write filespec, HashDelegator.join_code_lines(code)
         | 
| 1031 | 
            -
                  File.chmod 0o755, filespec
         | 
| 1032 | 
            -
                  # ww0 File.read(filespec)
         | 
| 1033 | 
            -
                  ret = `#{filespec}`
         | 
| 1034 | 
            -
                  File.delete filespec
         | 
| 1035 | 
            -
                  ret
         | 
| 1036 | 
            -
                end
         | 
| 1037 | 
            -
             | 
| 1038 | 
            -
                # sets ENV
         | 
| 1028 | 
            +
                # parse YAML body defining the UX for a single variable
         | 
| 1029 | 
            +
                # set ENV value for the variable and return code lines for the same
         | 
| 1039 1030 | 
             
                def code_from_ux_block_to_set_environment_variables(
         | 
| 1040 1031 | 
             
                  selected, mdoc, inherited_code: nil, force: true, only_default: false
         | 
| 1041 1032 | 
             
                )
         | 
| 1042 | 
            -
                  # ww0 inherited_code
         | 
| 1043 | 
            -
                  # ww0 mdoc
         | 
| 1044 1033 | 
             
                  exit_prompt = @delegate_object[:prompt_filespec_back]
         | 
| 1045 1034 |  | 
| 1046 1035 | 
             
                  required = mdoc.collect_recursively_required_code(
         | 
| @@ -1050,105 +1039,106 @@ module MarkdownExec | |
| 1050 1039 | 
             
                    block_source: block_source
         | 
| 1051 1040 | 
             
                  )
         | 
| 1052 1041 |  | 
| 1042 | 
            +
                  # process each ux block in sequence, setting ENV and collecting lines
         | 
| 1053 1043 | 
             
                  code_lines = []
         | 
| 1054 | 
            -
                   | 
| 1055 | 
            -
             | 
| 1056 | 
            -
             | 
| 1057 | 
            -
             | 
| 1058 | 
            -
             | 
| 1059 | 
            -
                       | 
| 1060 | 
            -
             | 
| 1061 | 
            -
             | 
| 1062 | 
            -
             | 
| 1063 | 
            -
             | 
| 1064 | 
            -
                      value = case export.default
         | 
| 1065 | 
            -
                              # exec > default
         | 
| 1066 | 
            -
                              when :exec
         | 
| 1067 | 
            -
                                raise unless export.exec.present?
         | 
| 1044 | 
            +
                  required[:blocks].each do |block|
         | 
| 1045 | 
            +
                    next unless block.type == BlockType::UX
         | 
| 1046 | 
            +
             | 
| 1047 | 
            +
                    case data = YAML.load(block.body.join("\n"))
         | 
| 1048 | 
            +
                    when Hash
         | 
| 1049 | 
            +
                      export = parse_yaml_of_ux_block(
         | 
| 1050 | 
            +
                        data,
         | 
| 1051 | 
            +
                        prompt: @delegate_object[:prompt_ux_enter_a_value],
         | 
| 1052 | 
            +
                        validate: '^(?<name>[^ ].*)$'
         | 
| 1053 | 
            +
                      )
         | 
| 1068 1054 |  | 
| 1069 | 
            -
             | 
| 1070 | 
            -
             | 
| 1055 | 
            +
                      # preconditions are variable names that must be set before the UX block is executed.
         | 
| 1056 | 
            +
                      # if any precondition is not set, the sequence is aborted.
         | 
| 1057 | 
            +
                      export.preconditions&.each do |precondition|
         | 
| 1058 | 
            +
                        code_lines.push "[[ -z $#{precondition} ]] && exit 1"
         | 
| 1059 | 
            +
                      end
         | 
| 1071 1060 |  | 
| 1072 | 
            -
             | 
| 1073 | 
            -
             | 
| 1074 | 
            -
             | 
| 1075 | 
            -
             | 
| 1076 | 
            -
             | 
| 1077 | 
            -
             | 
| 1078 | 
            -
             | 
| 1079 | 
            -
             | 
| 1080 | 
            -
             | 
| 1081 | 
            -
             | 
| 1061 | 
            +
                      exportable = true
         | 
| 1062 | 
            +
                      if only_default
         | 
| 1063 | 
            +
                        value = case export.default
         | 
| 1064 | 
            +
                                # exec > default
         | 
| 1065 | 
            +
                                when :exec
         | 
| 1066 | 
            +
                                  raise unless export.exec.present?
         | 
| 1067 | 
            +
             | 
| 1068 | 
            +
                                  output = export_exec_with_code(
         | 
| 1069 | 
            +
                                    export, inherited_code, code_lines, required
         | 
| 1070 | 
            +
                                  )
         | 
| 1071 | 
            +
                                  if output == :invalidated
         | 
| 1072 | 
            +
                                    return :ux_exec_prohibited
         | 
| 1082 1073 | 
             
                                  end
         | 
| 1074 | 
            +
             | 
| 1075 | 
            +
                                  transform_export_value(output, export)
         | 
| 1076 | 
            +
                                # default
         | 
| 1083 1077 | 
             
                                else
         | 
| 1084 | 
            -
                                   | 
| 1078 | 
            +
                                  export.default.to_s
         | 
| 1085 1079 | 
             
                                end
         | 
| 1080 | 
            +
                      else
         | 
| 1081 | 
            +
                        value = nil
         | 
| 1086 1082 |  | 
| 1087 | 
            -
             | 
| 1088 | 
            -
             | 
| 1089 | 
            -
             | 
| 1090 | 
            -
             | 
| 1091 | 
            -
             | 
| 1092 | 
            -
             | 
| 1093 | 
            -
             | 
| 1094 | 
            -
             | 
| 1095 | 
            -
                      # exec > allowed
         | 
| 1096 | 
            -
                      if export.exec
         | 
| 1097 | 
            -
                        value = neval(export.exec, (inherited_code || []) + required[:code])
         | 
| 1098 | 
            -
                        caps = NamedCaptureExtractor.extract_named_groups(value,
         | 
| 1099 | 
            -
                                                                          export.validate)
         | 
| 1100 | 
            -
             | 
| 1101 | 
            -
                      # allowed > prompt
         | 
| 1102 | 
            -
                      elsif export.allowed && export.allowed.count.positive?
         | 
| 1103 | 
            -
                        case (choice = prompt_select_code_filename(
         | 
| 1104 | 
            -
                          [exit_prompt] + export.allowed,
         | 
| 1105 | 
            -
                          string: export.prompt,
         | 
| 1106 | 
            -
                          color_sym: :prompt_color_after_script_execution
         | 
| 1107 | 
            -
                        ))
         | 
| 1108 | 
            -
                        when exit_prompt
         | 
| 1109 | 
            -
                          exportable = false
         | 
| 1110 | 
            -
                        else
         | 
| 1111 | 
            -
                          value = choice
         | 
| 1112 | 
            -
                          caps = NamedCaptureExtractor.extract_named_groups(value,
         | 
| 1113 | 
            -
                                                                            export.validate)
         | 
| 1114 | 
            -
                        end
         | 
| 1115 | 
            -
             | 
| 1116 | 
            -
                      # prompt > default
         | 
| 1117 | 
            -
                      elsif export.prompt.present?
         | 
| 1118 | 
            -
                        begin
         | 
| 1119 | 
            -
                          while true
         | 
| 1120 | 
            -
                            print "#{export.prompt} [#{export.default}]: "
         | 
| 1121 | 
            -
                            value = gets.chomp
         | 
| 1122 | 
            -
                            value = export.default.to_s if value.empty?
         | 
| 1123 | 
            -
                            caps = NamedCaptureExtractor.extract_named_groups(value,
         | 
| 1124 | 
            -
                                                                              export.validate)
         | 
| 1125 | 
            -
                            break if caps
         | 
| 1083 | 
            +
                        # exec > allowed
         | 
| 1084 | 
            +
                        if export.exec
         | 
| 1085 | 
            +
                          value = export_exec_with_code(
         | 
| 1086 | 
            +
                            export, inherited_code, code_lines, required
         | 
| 1087 | 
            +
                          )
         | 
| 1088 | 
            +
                          if value == :invalidated
         | 
| 1089 | 
            +
                            return :ux_exec_prohibited
         | 
| 1090 | 
            +
                          end
         | 
| 1126 1091 |  | 
| 1127 | 
            -
             | 
| 1092 | 
            +
                        # allowed > prompt
         | 
| 1093 | 
            +
                        elsif export.allowed && export.allowed.count.positive?
         | 
| 1094 | 
            +
                          case (choice = prompt_select_code_filename(
         | 
| 1095 | 
            +
                            [exit_prompt] + export.allowed,
         | 
| 1096 | 
            +
                            string: export.prompt,
         | 
| 1097 | 
            +
                            color_sym: :prompt_color_after_script_execution
         | 
| 1098 | 
            +
                          ))
         | 
| 1099 | 
            +
                          when exit_prompt
         | 
| 1100 | 
            +
                            exportable = false
         | 
| 1101 | 
            +
                          else
         | 
| 1102 | 
            +
                            value = choice
         | 
| 1103 | 
            +
                          end
         | 
| 1128 1104 |  | 
| 1105 | 
            +
                        # prompt > default
         | 
| 1106 | 
            +
                        elsif export.prompt.present?
         | 
| 1107 | 
            +
                          begin
         | 
| 1108 | 
            +
                            loop do
         | 
| 1109 | 
            +
                              print "#{export.prompt} [#{export.default}]: "
         | 
| 1110 | 
            +
                              value = gets.chomp
         | 
| 1111 | 
            +
                              value = export.default.to_s if value.empty?
         | 
| 1112 | 
            +
                              caps = NamedCaptureExtractor.extract_named_groups(value,
         | 
| 1113 | 
            +
                                                                                export.validate)
         | 
| 1114 | 
            +
                              break if caps
         | 
| 1115 | 
            +
             | 
| 1116 | 
            +
                              # invalid input, retry
         | 
| 1117 | 
            +
                            end
         | 
| 1118 | 
            +
                          rescue Interrupt
         | 
| 1119 | 
            +
                            exportable = false
         | 
| 1129 1120 | 
             
                          end
         | 
| 1130 | 
            -
             | 
| 1131 | 
            -
             | 
| 1121 | 
            +
             | 
| 1122 | 
            +
                        # default
         | 
| 1123 | 
            +
                        else
         | 
| 1124 | 
            +
                          value = export.default
         | 
| 1132 1125 | 
             
                        end
         | 
| 1133 1126 |  | 
| 1134 | 
            -
             | 
| 1135 | 
            -
             | 
| 1136 | 
            -
                         | 
| 1127 | 
            +
                        if exportable
         | 
| 1128 | 
            +
                          value = transform_export_value(value, export)
         | 
| 1129 | 
            +
                        end
         | 
| 1137 1130 | 
             
                      end
         | 
| 1138 1131 |  | 
| 1139 | 
            -
                      if exportable | 
| 1140 | 
            -
                         | 
| 1132 | 
            +
                      if exportable
         | 
| 1133 | 
            +
                        ENV[export.name] = value.to_s
         | 
| 1134 | 
            +
                        code_lines.push code_line_safe_assign(export.name, value,
         | 
| 1135 | 
            +
                                                              force: force)
         | 
| 1141 1136 | 
             
                      end
         | 
| 1137 | 
            +
                    else
         | 
| 1138 | 
            +
                      raise "Invalid data type: #{data.inspect}"
         | 
| 1142 1139 | 
             
                    end
         | 
| 1143 | 
            -
             | 
| 1144 | 
            -
                    if exportable
         | 
| 1145 | 
            -
                      ENV[export.name] = value.to_s
         | 
| 1146 | 
            -
                      code_lines.push code_line_safe_assign(export.name, value,
         | 
| 1147 | 
            -
                                                            force: force)
         | 
| 1148 | 
            -
                    end
         | 
| 1149 | 
            -
                  else
         | 
| 1150 | 
            -
                    raise "Invalid data type: #{data.inspect}"
         | 
| 1151 1140 | 
             
                  end
         | 
| 1141 | 
            +
             | 
| 1152 1142 | 
             
                  code_lines
         | 
| 1153 1143 | 
             
                end
         | 
| 1154 1144 |  | 
| @@ -1221,7 +1211,8 @@ module MarkdownExec | |
| 1221 1211 | 
             
                    command_execute_in_process(
         | 
| 1222 1212 | 
             
                      args: args, command: command,
         | 
| 1223 1213 | 
             
                      erls: erls,
         | 
| 1224 | 
            -
                      filename: @delegate_object[:filename], | 
| 1214 | 
            +
                      filename: @delegate_object[:filename],
         | 
| 1215 | 
            +
                      shell: shell
         | 
| 1225 1216 | 
             
                    )
         | 
| 1226 1217 | 
             
                  end
         | 
| 1227 1218 |  | 
| @@ -1285,7 +1276,8 @@ module MarkdownExec | |
| 1285 1276 | 
             
                )
         | 
| 1286 1277 | 
             
                  execute_command_with_streams(
         | 
| 1287 1278 | 
             
                    [shell, '-c', command,
         | 
| 1288 | 
            -
                     @delegate_object[:filename], | 
| 1279 | 
            +
                     @delegate_object[:filename],
         | 
| 1280 | 
            +
                     *args]
         | 
| 1289 1281 | 
             
                  )
         | 
| 1290 1282 | 
             
                end
         | 
| 1291 1283 |  | 
| @@ -1987,9 +1979,7 @@ module MarkdownExec | |
| 1987 1979 | 
             
                  )
         | 
| 1988 1980 |  | 
| 1989 1981 | 
             
                  # dname is not fixed for some block types, use block id
         | 
| 1990 | 
            -
                  if lfls.load_file != LoadFile::LOAD | 
| 1991 | 
            -
                     [BlockType::HEADING, BlockType::TEXT,
         | 
| 1992 | 
            -
                      BlockType::UX].include?(selected.type)
         | 
| 1982 | 
            +
                  if lfls.load_file != LoadFile::LOAD
         | 
| 1993 1983 | 
             
                    block_selection = BlockSelection.new(selected.id)
         | 
| 1994 1984 | 
             
                  end
         | 
| 1995 1985 |  | 
| @@ -2173,24 +2163,24 @@ module MarkdownExec | |
| 2173 2163 | 
             
                    else
         | 
| 2174 2164 | 
             
                      warn 'No matching file found.'
         | 
| 2175 2165 | 
             
                    end
         | 
| 2176 | 
            -
                  elsif selected_option = select_option_with_metadata(
         | 
| 2166 | 
            +
                  elsif (selected_option = select_option_with_metadata(
         | 
| 2177 2167 | 
             
                    prompt_title,
         | 
| 2178 2168 | 
             
                    [exit_prompt] + dirs.map do |file|
         | 
| 2179 | 
            -
                      { name: | 
| 2180 | 
            -
             | 
| 2181 | 
            -
             | 
| 2182 | 
            -
             | 
| 2183 | 
            -
             | 
| 2184 | 
            -
             | 
| 2185 | 
            -
             | 
| 2186 | 
            -
             | 
| 2187 | 
            -
             | 
| 2169 | 
            +
                      { name:
         | 
| 2170 | 
            +
                          format(
         | 
| 2171 | 
            +
                            block_data['view'] || view,
         | 
| 2172 | 
            +
                            NamedCaptureExtractor.extract_named_group_match_data(
         | 
| 2173 | 
            +
                              file.match(
         | 
| 2174 | 
            +
                                Regexp.new(block_data['filename_pattern'] || filename_pattern)
         | 
| 2175 | 
            +
                              )
         | 
| 2176 | 
            +
                            )
         | 
| 2177 | 
            +
                          ),
         | 
| 2188 2178 | 
             
                        oname: file }
         | 
| 2189 2179 | 
             
                    end,
         | 
| 2190 2180 | 
             
                    menu_options.merge(
         | 
| 2191 2181 | 
             
                      cycle: true
         | 
| 2192 2182 | 
             
                    )
         | 
| 2193 | 
            -
                  )
         | 
| 2183 | 
            +
                  ))
         | 
| 2194 2184 | 
             
                    if selected_option.dname != exit_prompt
         | 
| 2195 2185 | 
             
                      File.readlines(selected_option.oname, chomp: true)
         | 
| 2196 2186 | 
             
                    end
         | 
| @@ -2341,7 +2331,7 @@ module MarkdownExec | |
| 2341 2331 |  | 
| 2342 2332 | 
             
                  interactive_menu_with_display_modes(
         | 
| 2343 2333 | 
             
                    files_table_rows,
         | 
| 2344 | 
            -
                    display_formats: [ | 
| 2334 | 
            +
                    display_formats: %i[row file],
         | 
| 2345 2335 | 
             
                    display_mode_option: @delegate_object[:prompt_filespec_facet],
         | 
| 2346 2336 | 
             
                    exit_option: exit_prompt,
         | 
| 2347 2337 | 
             
                    menu_title: @delegate_object[:prompt_select_history_file],
         | 
| @@ -2364,9 +2354,9 @@ module MarkdownExec | |
| 2364 2354 | 
             
                def execute_inherited_save(
         | 
| 2365 2355 | 
             
                  code_lines: @dml_link_state.inherited_lines
         | 
| 2366 2356 | 
             
                )
         | 
| 2367 | 
            -
                  return unless save_filespec = save_filespec_from_expression | 
| 2368 | 
            -
             | 
| 2369 | 
            -
                   | 
| 2357 | 
            +
                  return unless (save_filespec = save_filespec_from_expression)
         | 
| 2358 | 
            +
             | 
| 2359 | 
            +
                  document_name_in_glob_as_file_name
         | 
| 2370 2360 |  | 
| 2371 2361 | 
             
                  unless write_file_with_directory_creation(
         | 
| 2372 2362 | 
             
                    content: HashDelegator.join_code_lines(code_lines),
         | 
| @@ -2422,6 +2412,27 @@ module MarkdownExec | |
| 2422 2412 | 
             
                  post_execution_process
         | 
| 2423 2413 | 
             
                end
         | 
| 2424 2414 |  | 
| 2415 | 
            +
                def execute_temporary_script(script_code, additional_code = [])
         | 
| 2416 | 
            +
                  full_code = (additional_code || []) + [script_code]
         | 
| 2417 | 
            +
             | 
| 2418 | 
            +
                  Tempfile.create('script_exec') do |temp_file|
         | 
| 2419 | 
            +
                    temp_file.write(HashDelegator.join_code_lines(full_code))
         | 
| 2420 | 
            +
                    temp_file.flush
         | 
| 2421 | 
            +
                    File.chmod(0o755, temp_file.path)
         | 
| 2422 | 
            +
             | 
| 2423 | 
            +
                    output = `#{temp_file.path}`
         | 
| 2424 | 
            +
             | 
| 2425 | 
            +
                    if $?.exitstatus != 0
         | 
| 2426 | 
            +
                      return :invalidated
         | 
| 2427 | 
            +
                    end
         | 
| 2428 | 
            +
             | 
| 2429 | 
            +
                    output
         | 
| 2430 | 
            +
                  end
         | 
| 2431 | 
            +
                rescue StandardError => err
         | 
| 2432 | 
            +
                  warn "Error executing script: #{err.message}"
         | 
| 2433 | 
            +
                  nil
         | 
| 2434 | 
            +
                end
         | 
| 2435 | 
            +
             | 
| 2425 2436 | 
             
                def expand_blocks_with_replacements(
         | 
| 2426 2437 | 
             
                  menu_blocks, replacements, exclude_types: [BlockType::SHELL]
         | 
| 2427 2438 | 
             
                )
         | 
| @@ -2468,6 +2479,18 @@ module MarkdownExec | |
| 2468 2479 | 
             
                  expand_blocks_with_replacements(blocks, replacements)
         | 
| 2469 2480 | 
             
                end
         | 
| 2470 2481 |  | 
| 2482 | 
            +
                def export_exec_with_code(export, inherited_code, code_lines, required)
         | 
| 2483 | 
            +
                  value = execute_temporary_script(
         | 
| 2484 | 
            +
                    export.exec,
         | 
| 2485 | 
            +
                    (inherited_code || []) +
         | 
| 2486 | 
            +
                     code_lines + required[:code]
         | 
| 2487 | 
            +
                  )
         | 
| 2488 | 
            +
                  if value == :invalidated
         | 
| 2489 | 
            +
                    warn "A value must exist for: #{export.preconditions.join(', ')}"
         | 
| 2490 | 
            +
                  end
         | 
| 2491 | 
            +
                  value
         | 
| 2492 | 
            +
                end
         | 
| 2493 | 
            +
             | 
| 2471 2494 | 
             
                # Retrieves a specific data symbol from the delegate object,
         | 
| 2472 2495 | 
             
                # converts it to a string, and applies a color style
         | 
| 2473 2496 | 
             
                # based on the specified color symbol.
         | 
| @@ -2580,7 +2603,7 @@ module MarkdownExec | |
| 2580 2603 | 
             
                  # commands to echo variables
         | 
| 2581 2604 | 
             
                  #
         | 
| 2582 2605 | 
             
                  commands = {}
         | 
| 2583 | 
            -
                  variable_counts. | 
| 2606 | 
            +
                  variable_counts.each_key do |variable|
         | 
| 2584 2607 | 
             
                    command = format(echo_format, variable)
         | 
| 2585 2608 | 
             
                    commands[variable] = command
         | 
| 2586 2609 | 
             
                  end
         | 
| @@ -2637,7 +2660,6 @@ module MarkdownExec | |
| 2637 2660 | 
             
                end
         | 
| 2638 2661 |  | 
| 2639 2662 | 
             
                def history_files(
         | 
| 2640 | 
            -
                  link_state,
         | 
| 2641 2663 | 
             
                  direction: :reverse,
         | 
| 2642 2664 | 
             
                  filename: nil,
         | 
| 2643 2665 | 
             
                  home: Dir.pwd,
         | 
| @@ -2950,19 +2972,24 @@ module MarkdownExec | |
| 2950 2972 | 
             
                  @ux_most_recent_filename = @delegate_object[:filename]
         | 
| 2951 2973 |  | 
| 2952 2974 | 
             
                  (blocks.each.with_object([]) do |block, merged_options|
         | 
| 2953 | 
            -
                     | 
| 2954 | 
            -
                       | 
| 2955 | 
            -
             | 
| 2956 | 
            -
             | 
| 2957 | 
            -
             | 
| 2958 | 
            -
                        only_default: true
         | 
| 2959 | 
            -
                      )
         | 
| 2975 | 
            +
                    code = code_from_ux_block_to_set_environment_variables(
         | 
| 2976 | 
            +
                      block,
         | 
| 2977 | 
            +
                      mdoc,
         | 
| 2978 | 
            +
                      force: @delegate_object[:ux_auto_load_force_default],
         | 
| 2979 | 
            +
                      only_default: true
         | 
| 2960 2980 | 
             
                    )
         | 
| 2981 | 
            +
                    if code == :ux_exec_prohibited
         | 
| 2982 | 
            +
                      merged_options
         | 
| 2983 | 
            +
                    else
         | 
| 2984 | 
            +
                      merged_options.push(code)
         | 
| 2985 | 
            +
                    end
         | 
| 2961 2986 | 
             
                  end).to_a
         | 
| 2962 2987 | 
             
                end
         | 
| 2963 2988 |  | 
| 2964 | 
            -
                def load_auto_vars_block( | 
| 2965 | 
            -
             | 
| 2989 | 
            +
                def load_auto_vars_block(
         | 
| 2990 | 
            +
                  all_blocks,
         | 
| 2991 | 
            +
                  block_name: @delegate_object[:document_load_vars_block_name]
         | 
| 2992 | 
            +
                )
         | 
| 2966 2993 | 
             
                  unless block_name.present? &&
         | 
| 2967 2994 | 
             
                         @vars_most_recent_filename != @delegate_object[:filename]
         | 
| 2968 2995 | 
             
                    return
         | 
| @@ -3103,7 +3130,7 @@ module MarkdownExec | |
| 3103 3130 |  | 
| 3104 3131 | 
             
                  # load document shell block
         | 
| 3105 3132 | 
             
                  #
         | 
| 3106 | 
            -
                  if code_lines = load_document_shell_block(all_blocks, mdoc: mdoc)
         | 
| 3133 | 
            +
                  if (code_lines = load_document_shell_block(all_blocks, mdoc: mdoc))
         | 
| 3107 3134 | 
             
                    next_state_set_code(nil, link_state, code_lines)
         | 
| 3108 3135 | 
             
                    link_state.inherited_lines = code_lines
         | 
| 3109 3136 | 
             
                    reload_blocks = true
         | 
| @@ -3111,7 +3138,7 @@ module MarkdownExec | |
| 3111 3138 |  | 
| 3112 3139 | 
             
                  # load document ux block
         | 
| 3113 3140 | 
             
                  #
         | 
| 3114 | 
            -
                  if code_lines = load_auto_ux_block(all_blocks, mdoc)
         | 
| 3141 | 
            +
                  if (code_lines = load_auto_ux_block(all_blocks, mdoc))
         | 
| 3115 3142 | 
             
                    new_code = HashDelegator.code_merge(link_state.inherited_lines,
         | 
| 3116 3143 | 
             
                                                        code_lines)
         | 
| 3117 3144 | 
             
                    next_state_set_code(nil, link_state, new_code)
         | 
| @@ -3121,7 +3148,7 @@ module MarkdownExec | |
| 3121 3148 |  | 
| 3122 3149 | 
             
                  # load document vars block
         | 
| 3123 3150 | 
             
                  #
         | 
| 3124 | 
            -
                  if code_lines = load_auto_vars_block(all_blocks)
         | 
| 3151 | 
            +
                  if (code_lines = load_auto_vars_block(all_blocks))
         | 
| 3125 3152 | 
             
                    new_code = HashDelegator.code_merge(link_state.inherited_lines,
         | 
| 3126 3153 | 
             
                                                        code_lines)
         | 
| 3127 3154 | 
             
                    next_state_set_code(nil, link_state, new_code)
         | 
| @@ -3267,7 +3294,10 @@ module MarkdownExec | |
| 3267 3294 | 
             
                  next_state_set_code(
         | 
| 3268 3295 | 
             
                    selected,
         | 
| 3269 3296 | 
             
                    link_state,
         | 
| 3270 | 
            -
                    HashDelegator.code_merge( | 
| 3297 | 
            +
                    HashDelegator.code_merge(
         | 
| 3298 | 
            +
                      link_state&.inherited_lines,
         | 
| 3299 | 
            +
                      code_lines.is_a?(Array) ? code_lines : [] # no code for :ux_exec_prohibited
         | 
| 3300 | 
            +
                    )
         | 
| 3271 3301 | 
             
                  )
         | 
| 3272 3302 | 
             
                end
         | 
| 3273 3303 |  | 
| @@ -3409,8 +3439,8 @@ module MarkdownExec | |
| 3409 3439 | 
             
                #
         | 
| 3410 3440 | 
             
                # @param all_blocks [Array<Hash>] The list of blocks from the file.
         | 
| 3411 3441 | 
             
                def select_blocks(menu_blocks)
         | 
| 3412 | 
            -
                  menu_blocks. | 
| 3413 | 
            -
                     | 
| 3442 | 
            +
                  menu_blocks.reject do |fcb|
         | 
| 3443 | 
            +
                    Filter.prepared_not_in_menu?(
         | 
| 3414 3444 | 
             
                      @delegate_object,
         | 
| 3415 3445 | 
             
                      fcb,
         | 
| 3416 3446 | 
             
                      %i[block_name_include_match block_name_wrapper_match]
         | 
| @@ -3659,16 +3689,16 @@ module MarkdownExec | |
| 3659 3689 |  | 
| 3660 3690 | 
             
                  case @delegate_object[:publish_document_file_mode]
         | 
| 3661 3691 | 
             
                  when 'append'
         | 
| 3662 | 
            -
                    File.write(pipe_path, message | 
| 3692 | 
            +
                    File.write(pipe_path, "#{message}\n", mode: 'a')
         | 
| 3663 3693 | 
             
                  when 'fifo'
         | 
| 3664 3694 | 
             
                    unless @vux_pipe_open
         | 
| 3665 3695 | 
             
                      unless File.exist?(pipe_path)
         | 
| 3666 | 
            -
                         | 
| 3696 | 
            +
                        File.mkfifo(pipe_path)
         | 
| 3667 3697 | 
             
                        @vux_pipe_created = pipe_path
         | 
| 3668 3698 | 
             
                      end
         | 
| 3669 3699 | 
             
                      @vux_pipe_open = File.open(pipe_path, 'w')
         | 
| 3670 3700 | 
             
                    end
         | 
| 3671 | 
            -
                    @vux_pipe_open.puts(message | 
| 3701 | 
            +
                    @vux_pipe_open.puts("#{message}\n")
         | 
| 3672 3702 | 
             
                    @vux_pipe_open.flush
         | 
| 3673 3703 | 
             
                  when 'write'
         | 
| 3674 3704 | 
             
                    File.write(pipe_path, message)
         | 
| @@ -3695,7 +3725,6 @@ module MarkdownExec | |
| 3695 3725 | 
             
                  regexp: @delegate_object[:saved_asset_match]
         | 
| 3696 3726 | 
             
                )
         | 
| 3697 3727 | 
             
                  history_files(
         | 
| 3698 | 
            -
                    @dml_link_state,
         | 
| 3699 3728 | 
             
                    filename:
         | 
| 3700 3729 | 
             
                      if asset.present?
         | 
| 3701 3730 | 
             
                        saved_asset_filename(asset, @dml_link_state)
         | 
| @@ -3710,7 +3739,8 @@ module MarkdownExec | |
| 3710 3739 | 
             
                    end
         | 
| 3711 3740 |  | 
| 3712 3741 | 
             
                    saved_asset = saved_asset_for_history(
         | 
| 3713 | 
            -
                      file: file, | 
| 3742 | 
            +
                      file: file,
         | 
| 3743 | 
            +
                      form: form,
         | 
| 3714 3744 | 
             
                      match_info: $LAST_MATCH_INFO
         | 
| 3715 3745 | 
             
                    )
         | 
| 3716 3746 | 
             
                    saved_asset == :break ? nil : saved_asset
         | 
| @@ -3959,7 +3989,7 @@ module MarkdownExec | |
| 3959 3989 |  | 
| 3960 3990 | 
             
                def screen_width
         | 
| 3961 3991 | 
             
                  width = @delegate_object[:screen_width]
         | 
| 3962 | 
            -
                  if width | 
| 3992 | 
            +
                  if width&.positive?
         | 
| 3963 3993 | 
             
                    width
         | 
| 3964 3994 | 
             
                  else
         | 
| 3965 3995 | 
             
                    @delegate_object[:console_width]
         | 
| @@ -3976,7 +4006,7 @@ module MarkdownExec | |
| 3976 4006 | 
             
                end
         | 
| 3977 4007 |  | 
| 3978 4008 | 
             
                def select_document_if_multiple(options, files, prompt:)
         | 
| 3979 | 
            -
                  return files if files. | 
| 4009 | 
            +
                  return files if files.instance_of?(String)
         | 
| 3980 4010 | 
             
                  return files[0] if (count = files.count) == 1
         | 
| 3981 4011 |  | 
| 3982 4012 | 
             
                  return unless count >= 2
         | 
| @@ -3994,7 +4024,11 @@ module MarkdownExec | |
| 3994 4024 |  | 
| 3995 4025 | 
             
                # Presents a TTY prompt to select an option or exit,
         | 
| 3996 4026 | 
             
                #  returns metadata including option and selected
         | 
| 3997 | 
            -
                def select_option_with_metadata( | 
| 4027 | 
            +
                def select_option_with_metadata(
         | 
| 4028 | 
            +
                  prompt_text, menu_items, opts = {}, menu_blocks: nil
         | 
| 4029 | 
            +
                )
         | 
| 4030 | 
            +
                  @dml_menu_blocks = menu_blocks if menu_blocks
         | 
| 4031 | 
            +
             | 
| 3998 4032 | 
             
                  ## configure to environment
         | 
| 3999 4033 | 
             
                  #
         | 
| 4000 4034 | 
             
                  register_console_attributes(opts)
         | 
| @@ -4039,23 +4073,16 @@ module MarkdownExec | |
| 4039 4073 | 
             
                    return
         | 
| 4040 4074 | 
             
                  end
         | 
| 4041 4075 |  | 
| 4042 | 
            -
                  selected =  | 
| 4076 | 
            +
                  selected = @dml_menu_blocks.find do |item|
         | 
| 4043 4077 | 
             
                    if item.instance_of?(Hash)
         | 
| 4044 4078 | 
             
                      [item[:id], item[:name], item[:dname]].include?(selection)
         | 
| 4045 4079 | 
             
                    elsif item.instance_of?(MarkdownExec::FCB)
         | 
| 4046 | 
            -
                      item. | 
| 4080 | 
            +
                      item.id == selection
         | 
| 4047 4081 | 
             
                    else
         | 
| 4048 4082 | 
             
                      item == selection
         | 
| 4049 4083 | 
             
                    end
         | 
| 4050 4084 | 
             
                  end
         | 
| 4051 4085 |  | 
| 4052 | 
            -
                  # new FCB if selected is not an object
         | 
| 4053 | 
            -
                  if selected.instance_of?(String)
         | 
| 4054 | 
            -
                    selected = FCB.new(dname: selected)
         | 
| 4055 | 
            -
                  elsif selected.instance_of?(Hash)
         | 
| 4056 | 
            -
                    selected = FCB.new(selected)
         | 
| 4057 | 
            -
                  end
         | 
| 4058 | 
            -
             | 
| 4059 4086 | 
             
                  unless selected
         | 
| 4060 4087 | 
             
                    HashDelegator.error_handler('select_option_with_metadata',
         | 
| 4061 4088 | 
             
                                                error: 'menu item not found')
         | 
| @@ -4206,6 +4233,21 @@ module MarkdownExec | |
| 4206 4233 | 
             
                  HashDelegator.apply_color_from_hash(string, @delegate_object, color_sym)
         | 
| 4207 4234 | 
             
                end
         | 
| 4208 4235 |  | 
| 4236 | 
            +
                def transform_export_value(value, export)
         | 
| 4237 | 
            +
                  return value unless export.transform.present?
         | 
| 4238 | 
            +
             | 
| 4239 | 
            +
                  if export.transform.is_a? Symbol
         | 
| 4240 | 
            +
                    value.send(export.transform)
         | 
| 4241 | 
            +
                  else
         | 
| 4242 | 
            +
                    format(
         | 
| 4243 | 
            +
                      export.transform,
         | 
| 4244 | 
            +
                      NamedCaptureExtractor.extract_named_groups(
         | 
| 4245 | 
            +
                        value, export.validate
         | 
| 4246 | 
            +
                      )
         | 
| 4247 | 
            +
                    )
         | 
| 4248 | 
            +
                  end
         | 
| 4249 | 
            +
                end
         | 
| 4250 | 
            +
             | 
| 4209 4251 | 
             
                ##
         | 
| 4210 4252 | 
             
                # Processes an individual line within a loop, updating headings
         | 
| 4211 4253 | 
             
                #  and handling fenced code blocks.
         | 
| @@ -4372,7 +4414,7 @@ module MarkdownExec | |
| 4372 4414 |  | 
| 4373 4415 | 
             
                  when formatted_choice_ostructs[:history].pub_name
         | 
| 4374 4416 | 
             
                    debounce_reset
         | 
| 4375 | 
            -
                    return :break unless files_table_rows = vux_history_files_table_rows
         | 
| 4417 | 
            +
                    return :break unless (files_table_rows = vux_history_files_table_rows)
         | 
| 4376 4418 |  | 
| 4377 4419 | 
             
                    execute_history_select(files_table_rows, stream: $stderr)
         | 
| 4378 4420 | 
             
                    return :break if pause_user_exit
         | 
| @@ -4498,9 +4540,9 @@ module MarkdownExec | |
| 4498 4540 | 
             
                end
         | 
| 4499 4541 |  | 
| 4500 4542 | 
             
                def vux_load_inherited
         | 
| 4501 | 
            -
                  return unless filespec = load_filespec_from_expression(
         | 
| 4543 | 
            +
                  return unless (filespec = load_filespec_from_expression(
         | 
| 4502 4544 | 
             
                    document_name_in_glob_as_file_name
         | 
| 4503 | 
            -
                  )
         | 
| 4545 | 
            +
                  ))
         | 
| 4504 4546 |  | 
| 4505 4547 | 
             
                  @dml_link_state.inherited_lines_append(
         | 
| 4506 4548 | 
             
                    File.readlines(filespec, chomp: true)
         | 
| @@ -4619,7 +4661,6 @@ module MarkdownExec | |
| 4619 4661 | 
             
                )
         | 
| 4620 4662 | 
             
                  if @delegate_object[:menu_for_history]
         | 
| 4621 4663 | 
             
                    history_files(
         | 
| 4622 | 
            -
                      @dml_link_state,
         | 
| 4623 4664 | 
             
                      filename: saved_asset_filename(@delegate_object[:filename],
         | 
| 4624 4665 | 
             
                                                     @dml_link_state),
         | 
| 4625 4666 | 
             
                      path: @delegate_object[:saved_script_folder]
         | 
| @@ -4818,15 +4859,17 @@ module MarkdownExec | |
| 4818 4859 | 
             
                                      menu_blocks.find do |block|
         | 
| 4819 4860 | 
             
                                        block.dname.include?(prior_answer)
         | 
| 4820 4861 | 
             
                                      end&.name
         | 
| 4821 | 
            -
                                    when Struct
         | 
| 4862 | 
            +
                                    when Struct, MarkdownExec::FCB
         | 
| 4822 4863 | 
             
                                      if prior_answer.id
         | 
| 4823 | 
            -
                                         | 
| 4864 | 
            +
                                        # when switching documents, the prior answer will not be found
         | 
| 4865 | 
            +
                                        (menu_blocks.find_index do |block|
         | 
| 4824 4866 | 
             
                                          block[:id] == prior_answer.id
         | 
| 4825 | 
            -
                                        end + 1
         | 
| 4867 | 
            +
                                        end || 0) + 1
         | 
| 4826 4868 | 
             
                                      else
         | 
| 4827 4869 | 
             
                                        prior_answer.index || prior_answer.name
         | 
| 4828 4870 | 
             
                                      end
         | 
| 4829 4871 | 
             
                                    end
         | 
| 4872 | 
            +
             | 
| 4830 4873 | 
             
                  # prior_answer value may not match if color is different from
         | 
| 4831 4874 | 
             
                  # originating menu (opts changed while processing)
         | 
| 4832 4875 | 
             
                  selection_opts = if selected_answer
         | 
| @@ -5157,13 +5200,12 @@ module MarkdownExec | |
| 5157 5200 |  | 
| 5158 5201 | 
             
              class TestHashDelegatorAppendDivider < Minitest::Test
         | 
| 5159 5202 | 
             
                def setup
         | 
| 5160 | 
            -
                  @hd = HashDelegator.new
         | 
| 5161 | 
            -
             | 
| 5162 | 
            -
             | 
| 5163 | 
            -
             | 
| 5164 | 
            -
             | 
| 5165 | 
            -
             | 
| 5166 | 
            -
                                            })
         | 
| 5203 | 
            +
                  @hd = HashDelegator.new(
         | 
| 5204 | 
            +
                    menu_divider_color: :color,
         | 
| 5205 | 
            +
                    menu_divider_format: 'Format',
         | 
| 5206 | 
            +
                    menu_final_divider: 'Final Divider',
         | 
| 5207 | 
            +
                    menu_initial_divider: 'Initial Divider'
         | 
| 5208 | 
            +
                  )
         | 
| 5167 5209 | 
             
                  @hd.stubs(:string_send_color).returns('Formatted Divider')
         | 
| 5168 5210 | 
             
                  HashDelegator.stubs(:safeval).returns('Safe Value')
         | 
| 5169 5211 | 
             
                end
         | 
| @@ -5185,7 +5227,7 @@ module MarkdownExec | |
| 5185 5227 | 
             
                end
         | 
| 5186 5228 |  | 
| 5187 5229 | 
             
                def test_append_divider_without_format
         | 
| 5188 | 
            -
                  @hd. | 
| 5230 | 
            +
                  @hd = HashDelegator.new
         | 
| 5189 5231 | 
             
                  menu_blocks = []
         | 
| 5190 5232 | 
             
                  @hd.append_divider(menu_blocks: menu_blocks, position: :initial)
         | 
| 5191 5233 |  | 
| @@ -5223,7 +5265,6 @@ module MarkdownExec | |
| 5223 5265 | 
             
                  @hd = HashDelegator.new
         | 
| 5224 5266 | 
             
                  @hd.stubs(:iter_blocks_from_nested_files).yields(:blocks, FCB.new)
         | 
| 5225 5267 | 
             
                  @hd.stubs(:create_and_add_chrome_blocks)
         | 
| 5226 | 
            -
                  @hd.instance_variable_set(:@delegate_object, {})
         | 
| 5227 5268 | 
             
                  HashDelegator.stubs(:error_handler)
         | 
| 5228 5269 | 
             
                end
         | 
| 5229 5270 |  | 
| @@ -5234,7 +5275,7 @@ module MarkdownExec | |
| 5234 5275 | 
             
                end
         | 
| 5235 5276 |  | 
| 5236 5277 | 
             
                def test_blocks_from_nested_files_with_no_chrome
         | 
| 5237 | 
            -
                  @hd. | 
| 5278 | 
            +
                  @hd = HashDelegator.new(no_chrome: true)
         | 
| 5238 5279 | 
             
                  @hd.expects(:create_and_add_chrome_blocks).never
         | 
| 5239 5280 |  | 
| 5240 5281 | 
             
                  result = @hd.blocks_from_nested_files
         | 
| @@ -5246,7 +5287,6 @@ module MarkdownExec | |
| 5246 5287 | 
             
              class TestHashDelegatorCollectRequiredCodeLines < Minitest::Test
         | 
| 5247 5288 | 
             
                def setup
         | 
| 5248 5289 | 
             
                  @hd = HashDelegator.new
         | 
| 5249 | 
            -
                  @hd.instance_variable_set(:@delegate_object, {})
         | 
| 5250 5290 | 
             
                  @mdoc = mock('YourMDocClass')
         | 
| 5251 5291 | 
             
                  @selected = FCB.new(
         | 
| 5252 5292 | 
             
                    body: ['key: value'],
         | 
| @@ -5272,15 +5312,13 @@ module MarkdownExec | |
| 5272 5312 | 
             
              class TestHashDelegatorCommandOrUserSelectedBlock < Minitest::Test
         | 
| 5273 5313 | 
             
                def setup
         | 
| 5274 5314 | 
             
                  @hd = HashDelegator.new
         | 
| 5275 | 
            -
                  @hd.instance_variable_set(:@delegate_object, {})
         | 
| 5276 5315 | 
             
                  HashDelegator.stubs(:error_handler)
         | 
| 5277 5316 | 
             
                  @hd.stubs(:wait_for_user_selected_block)
         | 
| 5278 5317 | 
             
                end
         | 
| 5279 5318 |  | 
| 5280 5319 | 
             
                def test_command_selected_block
         | 
| 5281 5320 | 
             
                  all_blocks = [{ oname: 'block1' }, { oname: 'block2' }]
         | 
| 5282 | 
            -
                  @hd. | 
| 5283 | 
            -
                                            { block_name: 'block1' })
         | 
| 5321 | 
            +
                  @hd = HashDelegator.new(block_name: 'block1')
         | 
| 5284 5322 |  | 
| 5285 5323 | 
             
                  result = @hd.load_cli_or_user_selected_block(all_blocks: all_blocks)
         | 
| 5286 5324 |  | 
| @@ -5309,10 +5347,10 @@ module MarkdownExec | |
| 5309 5347 |  | 
| 5310 5348 | 
             
              class TestHashDelegatorCountBlockInFilename < Minitest::Test
         | 
| 5311 5349 | 
             
                def setup
         | 
| 5312 | 
            -
                  @hd = HashDelegator.new
         | 
| 5313 | 
            -
             | 
| 5314 | 
            -
             | 
| 5315 | 
            -
             | 
| 5350 | 
            +
                  @hd = HashDelegator.new(
         | 
| 5351 | 
            +
                    fenced_start_and_end_regex: '^```',
         | 
| 5352 | 
            +
                    filename: '/path/to/file'
         | 
| 5353 | 
            +
                  )
         | 
| 5316 5354 | 
             
                  @hd.stubs(:cfile).returns(mock('cfile'))
         | 
| 5317 5355 | 
             
                end
         | 
| 5318 5356 |  | 
| @@ -5421,7 +5459,6 @@ module MarkdownExec | |
| 5421 5459 | 
             
                def setup
         | 
| 5422 5460 | 
             
                  @hd = HashDelegator.new
         | 
| 5423 5461 | 
             
                  @hd.instance_variable_set(:@fout, mock('fout'))
         | 
| 5424 | 
            -
                  @hd.instance_variable_set(:@delegate_object, {})
         | 
| 5425 5462 | 
             
                  @hd.stubs(:string_send_color)
         | 
| 5426 5463 | 
             
                end
         | 
| 5427 5464 |  | 
| @@ -5443,7 +5480,6 @@ module MarkdownExec | |
| 5443 5480 | 
             
              class TestHashDelegatorFetchColor < Minitest::Test
         | 
| 5444 5481 | 
             
                def setup
         | 
| 5445 5482 | 
             
                  @hd = HashDelegator.new
         | 
| 5446 | 
            -
                  @hd.instance_variable_set(:@delegate_object, {})
         | 
| 5447 5483 | 
             
                end
         | 
| 5448 5484 |  | 
| 5449 5485 | 
             
                def test_fetch_color_with_valid_data
         | 
| @@ -5476,7 +5512,6 @@ module MarkdownExec | |
| 5476 5512 | 
             
              class TestHashDelegatorFormatReferencesSendColor < Minitest::Test
         | 
| 5477 5513 | 
             
                def setup
         | 
| 5478 5514 | 
             
                  @hd = HashDelegator.new
         | 
| 5479 | 
            -
                  @hd.instance_variable_set(:@delegate_object, {})
         | 
| 5480 5515 | 
             
                end
         | 
| 5481 5516 |  | 
| 5482 5517 | 
             
                def test_format_references_send_color_with_valid_data
         | 
| @@ -5581,7 +5616,6 @@ module MarkdownExec | |
| 5581 5616 | 
             
                # )
         | 
| 5582 5617 |  | 
| 5583 5618 | 
             
                # def history_files(
         | 
| 5584 | 
            -
                #   link_state,
         | 
| 5585 5619 | 
             
                #   direction: :reverse,
         | 
| 5586 5620 | 
             
                #   filename: nil,
         | 
| 5587 5621 | 
             
                #   home: Dir.pwd,
         | 
| @@ -5590,9 +5624,10 @@ module MarkdownExec | |
| 5590 5624 | 
             
                # )
         | 
| 5591 5625 |  | 
| 5592 5626 | 
             
                def test_call
         | 
| 5593 | 
            -
                  @hd.expects(:history_files).with( | 
| 5594 | 
            -
                  @hd.execute_block_type_history_ux( | 
| 5595 | 
            -
             | 
| 5627 | 
            +
                  @hd.expects(:history_files).with(filename: '*', path: nil).once
         | 
| 5628 | 
            +
                  @hd.execute_block_type_history_ux(
         | 
| 5629 | 
            +
                    filename: '*', link_state: LinkState.new, selected: FCB.new(body: [])
         | 
| 5630 | 
            +
                  )
         | 
| 5596 5631 | 
             
                end
         | 
| 5597 5632 | 
             
              end
         | 
| 5598 5633 |  | 
| @@ -5677,11 +5712,9 @@ module MarkdownExec | |
| 5677 5712 |  | 
| 5678 5713 | 
             
              class TestHashDelegatorHandleStream < Minitest::Test
         | 
| 5679 5714 | 
             
                def setup
         | 
| 5680 | 
            -
                  @hd = HashDelegator.new
         | 
| 5715 | 
            +
                  @hd = HashDelegator.new(output_stdout: true)
         | 
| 5681 5716 | 
             
                  @hd.instance_variable_set(:@run_state,
         | 
| 5682 5717 | 
             
                                            OpenStruct.new(files: StreamsOut.new))
         | 
| 5683 | 
            -
                  @hd.instance_variable_set(:@delegate_object,
         | 
| 5684 | 
            -
                                            { output_stdout: true })
         | 
| 5685 5718 | 
             
                end
         | 
| 5686 5719 |  | 
| 5687 5720 | 
             
                def test_handle_stream
         | 
| @@ -5713,9 +5746,7 @@ module MarkdownExec | |
| 5713 5746 |  | 
| 5714 5747 | 
             
              class TestHashDelegatorIterBlocksFromNestedFiles < Minitest::Test
         | 
| 5715 5748 | 
             
                def setup
         | 
| 5716 | 
            -
                  @hd = HashDelegator.new
         | 
| 5717 | 
            -
                  @hd.instance_variable_set(:@delegate_object,
         | 
| 5718 | 
            -
                                            { filename: 'test.md' })
         | 
| 5749 | 
            +
                  @hd = HashDelegator.new(filename: 'test.md')
         | 
| 5719 5750 | 
             
                  @hd.stubs(:check_file_existence).with('test.md').returns(true)
         | 
| 5720 5751 | 
             
                  @hd.stubs(:initial_state).returns({})
         | 
| 5721 5752 | 
             
                  @hd.stubs(:cfile).returns(Minitest::Mock.new)
         | 
| @@ -5744,12 +5775,11 @@ module MarkdownExec | |
| 5744 5775 |  | 
| 5745 5776 | 
             
              class TestHashDelegatorMenuChromeColoredOption < Minitest::Test
         | 
| 5746 5777 | 
             
                def setup
         | 
| 5747 | 
            -
                  @hd = HashDelegator.new
         | 
| 5748 | 
            -
             | 
| 5749 | 
            -
             | 
| 5750 | 
            -
             | 
| 5751 | 
            -
             | 
| 5752 | 
            -
                                            })
         | 
| 5778 | 
            +
                  @hd = HashDelegator.new(
         | 
| 5779 | 
            +
                    menu_chrome_color: :red,
         | 
| 5780 | 
            +
                    menu_chrome_format: '-- %s --',
         | 
| 5781 | 
            +
                    menu_option_back_name: 'Back'
         | 
| 5782 | 
            +
                  )
         | 
| 5753 5783 | 
             
                  @hd.stubs(:menu_chrome_formatted_option)
         | 
| 5754 5784 | 
             
                     .with(:menu_option_back_name).returns('-- Back --')
         | 
| 5755 5785 | 
             
                  @hd.stubs(:string_send_color)
         | 
| @@ -5763,8 +5793,9 @@ module MarkdownExec | |
| 5763 5793 | 
             
                end
         | 
| 5764 5794 |  | 
| 5765 5795 | 
             
                def test_menu_chrome_colored_option_without_color
         | 
| 5766 | 
            -
                  @hd. | 
| 5767 | 
            -
             | 
| 5796 | 
            +
                  @hd = HashDelegator.new(menu_option_back_name: 'Back')
         | 
| 5797 | 
            +
                  @hd.stubs(:menu_chrome_formatted_option)
         | 
| 5798 | 
            +
                     .with(:menu_option_back_name).returns('-- Back --')
         | 
| 5768 5799 | 
             
                  assert_equal '-- Back --',
         | 
| 5769 5800 | 
             
                               @hd.menu_chrome_colored_option(:menu_option_back_name)
         | 
| 5770 5801 | 
             
                end
         | 
| @@ -5772,11 +5803,10 @@ module MarkdownExec | |
| 5772 5803 |  | 
| 5773 5804 | 
             
              class TestHashDelegatorMenuChromeOption < Minitest::Test
         | 
| 5774 5805 | 
             
                def setup
         | 
| 5775 | 
            -
                  @hd = HashDelegator.new
         | 
| 5776 | 
            -
             | 
| 5777 | 
            -
             | 
| 5778 | 
            -
             | 
| 5779 | 
            -
                                            })
         | 
| 5806 | 
            +
                  @hd = HashDelegator.new(
         | 
| 5807 | 
            +
                    menu_chrome_format: '-- %s --',
         | 
| 5808 | 
            +
                    menu_option_back_name: "'Back'"
         | 
| 5809 | 
            +
                  )
         | 
| 5780 5810 | 
             
                  HashDelegator.stubs(:safeval).with("'Back'").returns('Back')
         | 
| 5781 5811 | 
             
                end
         | 
| 5782 5812 |  | 
| @@ -5786,8 +5816,7 @@ module MarkdownExec | |
| 5786 5816 | 
             
                end
         | 
| 5787 5817 |  | 
| 5788 5818 | 
             
                def test_menu_chrome_formatted_option_without_format
         | 
| 5789 | 
            -
                  @hd. | 
| 5790 | 
            -
                                            { menu_option_back_name: "'Back'" })
         | 
| 5819 | 
            +
                  @hd = HashDelegator.new(menu_option_back_name: "'Back'")
         | 
| 5791 5820 | 
             
                  assert_equal 'Back',
         | 
| 5792 5821 | 
             
                               @hd.menu_chrome_formatted_option(:menu_option_back_name)
         | 
| 5793 5822 | 
             
                end
         | 
| @@ -5795,10 +5824,12 @@ module MarkdownExec | |
| 5795 5824 |  | 
| 5796 5825 | 
             
              class TestHashDelegatorStartFencedBlock < Minitest::Test
         | 
| 5797 5826 | 
             
                def setup
         | 
| 5798 | 
            -
                  @hd = HashDelegator.new( | 
| 5799 | 
            -
             | 
| 5800 | 
            -
             | 
| 5801 | 
            -
             | 
| 5827 | 
            +
                  @hd = HashDelegator.new(
         | 
| 5828 | 
            +
                    {
         | 
| 5829 | 
            +
                      block_calls_scan: 'CALLS_REGEX',
         | 
| 5830 | 
            +
                      block_name_wrapper_match: 'WRAPPER_REGEX'
         | 
| 5831 | 
            +
                    }
         | 
| 5832 | 
            +
                  )
         | 
| 5802 5833 | 
             
                end
         | 
| 5803 5834 |  | 
| 5804 5835 | 
             
                def test_start_fenced_block
         | 
| @@ -5816,9 +5847,7 @@ module MarkdownExec | |
| 5816 5847 |  | 
| 5817 5848 | 
             
              class TestHashDelegatorStringSendColor < Minitest::Test
         | 
| 5818 5849 | 
             
                def setup
         | 
| 5819 | 
            -
                  @hd = HashDelegator.new
         | 
| 5820 | 
            -
                  @hd.instance_variable_set(:@delegate_object,
         | 
| 5821 | 
            -
                                            { red: 'red', green: 'green' })
         | 
| 5850 | 
            +
                  @hd = HashDelegator.new(red: 'red', green: 'green')
         | 
| 5822 5851 | 
             
                end
         | 
| 5823 5852 |  | 
| 5824 5853 | 
             
                def test_string_send_color
         | 
    
        data/lib/markdown_exec.rb
    CHANGED
    
    | @@ -656,32 +656,6 @@ module MarkdownExec | |
| 656 656 | 
             
                  @options.merge(@options.run_state.to_h)
         | 
| 657 657 | 
             
                end
         | 
| 658 658 |  | 
| 659 | 
            -
                def iter_source_blocks(source, &block)
         | 
| 660 | 
            -
                  case source
         | 
| 661 | 
            -
                  when 1
         | 
| 662 | 
            -
                    HashDelegator.new(@options).blocks_from_nested_files.each(&block)
         | 
| 663 | 
            -
                  when 2
         | 
| 664 | 
            -
                    blocks_in_file, menu_blocks, mdoc =
         | 
| 665 | 
            -
                      HashDelegator.new(@options)
         | 
| 666 | 
            -
                                   .mdoc_menu_and_blocks_from_nested_files(LinkState.new)
         | 
| 667 | 
            -
                    blocks_in_file.each(&block)
         | 
| 668 | 
            -
                  when 3
         | 
| 669 | 
            -
                    blocks_in_file, menu_blocks, mdoc =
         | 
| 670 | 
            -
                      HashDelegator.new(@options)
         | 
| 671 | 
            -
                                   .mdoc_menu_and_blocks_from_nested_files(LinkState.new)
         | 
| 672 | 
            -
                    menu_blocks.each(&block)
         | 
| 673 | 
            -
                  else
         | 
| 674 | 
            -
                    @options.iter_blocks_from_nested_files do |btype, fcb|
         | 
| 675 | 
            -
                      case btype
         | 
| 676 | 
            -
                      when :blocks
         | 
| 677 | 
            -
                        yield fcb
         | 
| 678 | 
            -
                      when :filter
         | 
| 679 | 
            -
                        %i[blocks]
         | 
| 680 | 
            -
                      end
         | 
| 681 | 
            -
                    end
         | 
| 682 | 
            -
                  end
         | 
| 683 | 
            -
                end
         | 
| 684 | 
            -
             | 
| 685 659 | 
             
                ##
         | 
| 686 660 | 
             
                # Returns a lambda expression based on the given procname.
         | 
| 687 661 | 
             
                # @param procname [String] The name of the process to generate a lambda for.
         | 
| @@ -916,7 +890,7 @@ module MarkdownExec | |
| 916 890 | 
             
                    # save value to options hash if option is named
         | 
| 917 891 | 
             
                    #
         | 
| 918 892 | 
             
                    lambda { |value|
         | 
| 919 | 
            -
                      name = item[:long_name]&.present? ?  | 
| 893 | 
            +
                      name = item[:long_name]&.present? ? "--#{item[:long_name]}" : "-#{item[:short_name]}"
         | 
| 920 894 | 
             
                      options_parsed << item.merge(name: name, value: value)
         | 
| 921 895 | 
             
                      (item[:proccode] ? item[:proccode].call(value) : value).tap do |converted|
         | 
| 922 896 | 
             
                        options[item[:opt_name]] = converted if item[:opt_name]
         | 
| @@ -1013,7 +987,16 @@ module MarkdownExec | |
| 1013 987 | 
             
                # Presents a TTY prompt to select an option or exit, returns selected option or nil
         | 
| 1014 988 | 
             
                def select_option_or_exit(prompt_text, strings, opts = {})
         | 
| 1015 989 | 
             
                  @options.select_option_with_metadata(
         | 
| 1016 | 
            -
                    prompt_text, | 
| 990 | 
            +
                    prompt_text,
         | 
| 991 | 
            +
                    strings,
         | 
| 992 | 
            +
                    opts,
         | 
| 993 | 
            +
                    menu_blocks: strings.map do |string|
         | 
| 994 | 
            +
                      FCB.new(
         | 
| 995 | 
            +
                        chrome: true,
         | 
| 996 | 
            +
                        dname: string,
         | 
| 997 | 
            +
                        id: string
         | 
| 998 | 
            +
                      )
         | 
| 999 | 
            +
                    end
         | 
| 1017 1000 | 
             
                  )&.fetch(:selected)
         | 
| 1018 1001 | 
             
                end
         | 
| 1019 1002 |  | 
    
        data/lib/mdoc.rb
    CHANGED
    
    | @@ -355,13 +355,12 @@ module MarkdownExec | |
| 355 355 | 
             
                  else
         | 
| 356 356 | 
             
                    opts[:hide_blocks_by_name] &&
         | 
| 357 357 | 
             
                      ((opts[:block_name_hidden_match]&.present? &&
         | 
| 358 | 
            -
                        block. | 
| 358 | 
            +
                        block.s2title&.match(Regexp.new(opts[:block_name_hidden_match]))) ||
         | 
| 359 359 | 
             
                       (opts[:block_name_include_match]&.present? &&
         | 
| 360 | 
            -
                        block. | 
| 360 | 
            +
                        block.s2title&.match(Regexp.new(opts[:block_name_include_match]))) ||
         | 
| 361 361 | 
             
                       (opts[:block_name_wrapper_match]&.present? &&
         | 
| 362 | 
            -
                        block. | 
| 363 | 
            -
                      (block. | 
| 364 | 
            -
             | 
| 362 | 
            +
                        block.s2title&.match(Regexp.new(opts[:block_name_wrapper_match])))) &&
         | 
| 363 | 
            +
                      (block.s2title&.present? || block[:label]&.present?)
         | 
| 365 364 | 
             
                  end
         | 
| 366 365 | 
             
                end
         | 
| 367 366 |  | 
| @@ -555,7 +554,7 @@ if $PROGRAM_NAME == __FILE__ | |
| 555 554 | 
             
                  def test_hide_menu_block_on_name
         | 
| 556 555 | 
             
                    opts = { hide_blocks_by_name: true,
         | 
| 557 556 | 
             
                             block_name_hidden_match: 'block1' }
         | 
| 558 | 
            -
                    block = FCB.new( | 
| 557 | 
            +
                    block = FCB.new(s2title: 'block1')
         | 
| 559 558 | 
             
                    result = @doc.hide_menu_block_on_name(opts, block)
         | 
| 560 559 | 
             
                    assert result # this should be true based on the given logic
         | 
| 561 560 | 
             
                  end
         | 
    
        data/lib/menu.src.yml
    CHANGED
    
    
    
        data/lib/menu.yml
    CHANGED
    
    | @@ -44,6 +44,7 @@ | |
| 44 44 | 
             
              :procname: val_as_str
         | 
| 45 45 | 
             
            - :opt_name: block_name_match
         | 
| 46 46 | 
             
              :env_var: MDE_BLOCK_NAME_MATCH
         | 
| 47 | 
            +
              :description: Pattern for the block name in the line defining the block
         | 
| 47 48 | 
             
              :default: ":(?<title>\\S+)( |$)"
         | 
| 48 49 | 
             
              :procname: val_as_str
         | 
| 49 50 | 
             
            - :opt_name: block_name_nick_match
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: markdown_exec
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.8. | 
| 4 | 
            +
              version: 2.8.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Fareed Stevenson
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2025-02- | 
| 11 | 
            +
            date: 2025-02-19 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: clipboard
         | 
| @@ -107,9 +107,11 @@ files: | |
| 107 107 | 
             
            - assets/select_a_block.png
         | 
| 108 108 | 
             
            - assets/select_a_file.png
         | 
| 109 109 | 
             
            - bats/bats.bats
         | 
| 110 | 
            +
            - bats/block-hide.bats
         | 
| 110 111 | 
             
            - bats/block-type-opts.bats
         | 
| 111 112 | 
             
            - bats/block-type-ux-auto.bats
         | 
| 112 113 | 
             
            - bats/block-type-ux-exec.bats
         | 
| 114 | 
            +
            - bats/block-type-ux-require.bats
         | 
| 113 115 | 
             
            - bats/block-type-ux-row-format.bats
         | 
| 114 116 | 
             
            - bats/block-type-ux-transform.bats
         | 
| 115 117 | 
             
            - bats/block-type-vars.bats
         | 
| @@ -140,11 +142,13 @@ files: | |
| 140 142 | 
             
            - bin/tab_completion.sh
         | 
| 141 143 | 
             
            - bin/tab_completion.sh.erb
         | 
| 142 144 | 
             
            - docs/dev/bats-document-configuration.md
         | 
| 145 | 
            +
            - docs/dev/block-hide.md
         | 
| 143 146 | 
             
            - docs/dev/block-type-bash.md
         | 
| 144 147 | 
             
            - docs/dev/block-type-opts.md
         | 
| 145 148 | 
             
            - docs/dev/block-type-port.md
         | 
| 146 149 | 
             
            - docs/dev/block-type-ux-auto.md
         | 
| 147 150 | 
             
            - docs/dev/block-type-ux-exec.md
         | 
| 151 | 
            +
            - docs/dev/block-type-ux-require.md
         | 
| 148 152 | 
             
            - docs/dev/block-type-ux-row-format.md
         | 
| 149 153 | 
             
            - docs/dev/block-type-ux-transform.md
         | 
| 150 154 | 
             
            - docs/dev/block-type-vars.md
         |