lib/hash_delegator.rb in markdown_exec-2.6.0 vs lib/hash_delegator.rb in markdown_exec-2.7.0

- old
+ new

@@ -262,14 +262,13 @@ def set_file_permissions(file_path, chmod_value) File.chmod(chmod_value, file_path) end # find tables in multiple lines and format horizontally - def tables_into_columns!(blocks_menu, delegate_object) + def tables_into_columns!(blocks_menu, delegate_object, screen_width_for_table) return unless delegate_object[:tables_into_columns] - screenwidth = delegate_object[:console_width] lines = blocks_menu.map(&:oname) text_tables = TableExtractor.extract_tables( lines, regexp: delegate_object[:table_parse_regexp] ) @@ -299,14 +298,14 @@ indent = blocks_menu[range.first].oname.split('|', 2).first # replace text in each block range.each.with_index do |block_ind, ind| fcb = blocks_menu[block_ind] - fcb.s3formatted_table_row = fcb.padded = table__hs[ind] #### + fcb.s3formatted_table_row = fcb.padded = table__hs[ind] fcb.padded_width = table__hs[ind].padded_width if fcb.center - cw = (screenwidth - table__hs[ind].padded_width) / 2 + cw = (screen_width_for_table - table__hs[ind].padded_width) / 2 if cw.positive? indent = ' ' * cw fcb.s3indent = fcb.indent = indent end else @@ -319,11 +318,11 @@ end # s0indent: indent, # s0printable: line_obj[:text], # s1decorated: decorated, # s2title = fcb.oname - # s3formatted_table_row = fcb.padded = table__hs[ind]#### + # s3formatted_table_row = fcb.padded = table__hs[ind] # Creates a TTY prompt with custom settings. Specifically, # it disables the default 'cross' symbol and # defines a lambda function to handle interrupts. # @return [TTY::Prompt] A new TTY::Prompt instance @@ -640,12 +639,10 @@ position: :initial) append_divider(id: "#{id}.final", menu_blocks: menu_blocks, position: :final) end - public - # Appends a chrome block, which is a menu option for Back or Exit # # @param all_blocks [Array] The current blocks in the menu # @param type [Symbol] The type of chrome block to add (:back or :exit) def append_chrome_block(menu_blocks:, menu_state:, id: '') @@ -774,11 +771,11 @@ end tree.decorate end def assign_key_value_in_bash(key, value) - if value =~ /["$\\`]/ + if value.to_s =~ /["$\\`]/ # requiring ShellWords to write into Bash scripts "#{key}=#{Shellwords.escape(value)}" else "#{key}=\"#{value}\"" end @@ -789,35 +786,56 @@ # Iterates through nested files to collect various types # of blocks, including dividers, tasks, and others. # The method categorizes blocks based on their type and processes them accordingly. # # @return [Array<FCB>] An array of FCB objects representing the blocks. - def blocks_from_nested_files + def blocks_from_nested_files( + link_state: @dml_link_state || LinkState.new + ) register_console_attributes(@delegate_object) @decor_patterns_from_delegate_object_for_block_create = collect_line_decor_patterns(@delegate_object) count = 0 blocks = [] iter_blocks_from_nested_files do |btype, fcb| count += 1 + + # text substitution in menu + # + expand_references = lambda do |fcb| + expand_variable_references!(blocks: [fcb], link_state: link_state, + initial_code_required: false) + expand_variable_references!( + blocks: [fcb], + echo_format: '%s', + initial_code_required: false, + key_format: '$(%s)', + link_state: link_state, + group_name: :command, + pattern: options_command_substitution_regexp + ) + end + case btype when :blocks if @delegate_object[:bash] fcb.for_menu!( block_calls_scan: @delegate_object[:block_calls_scan], block_name_match: @delegate_object[:block_name_match], block_name_nick_match: @delegate_object[:block_name_nick_match], - id: "*#{count}", + id: "*#{count}" ) do |oname, color| apply_block_type_color_option(oname, color) end end + expand_references.call(fcb) blocks << fcb when :filter # types accepted %i[blocks line] when :line unless @delegate_object[:no_chrome] + expand_references.call(fcb) create_and_add_chrome_blocks(blocks, fcb, id: "*#{count}", init_ids: init_ids) end end end @@ -851,14 +869,16 @@ end end # private - def build_replacement_dictionary(commands, link_state) + def build_replacement_dictionary(commands, link_state, + initial_code_required: false, key_format:) evaluate_shell_expressions( - link_state.inherited_lines_block, commands, - key_format: "${%s}" # no need to escape variable name for regexp + (link_state&.inherited_lines_block || ''), commands, + initial_code_required: initial_code_required, + key_format: key_format ) # !!t end def calc_logged_stdout_filename(block_name:) return unless @delegate_object[:saved_stdout_folder] @@ -1020,13 +1040,11 @@ ) ) end def command_execute_in_own_window_format_arguments( - home: Dir.pwd, - erls:, - rest: '' + erls:, home: Dir.pwd, rest: '' ) { batch_index: @run_state.batch_index, batch_random: @run_state.batch_random, block_name: @delegate_object[:block_name], @@ -1143,23 +1161,25 @@ ) HashDelegator.count_matches_in_lines(lines, regex) / 2 end def count_named_group_occurrences( - blocks, pattern, exclude_types: [BlockType::SHELL] + blocks, pattern, exclude_types: [BlockType::SHELL], + group_name: ) # Initialize a counter for named group occurrences occurrence_count = Hash.new(0) + return occurrence_count if pattern == // blocks.each do |block| # Skip processing for shell-type blocks next if exclude_types.include?(block.type) # Scan each block name for matches of the pattern - block.oname.scan(pattern) do |(_, variable_name)| + ([block.oname || ''] + block.body).join("\n").scan(pattern) do |(_, _variable_name)| pattern.match($LAST_MATCH_INFO.to_s) # Reapply match for named groups - occurrence_count[$LAST_MATCH_INFO[:variable]] += 1 + occurrence_count[$LAST_MATCH_INFO[group_name]] += 1 end end occurrence_count end @@ -1173,22 +1193,18 @@ # @param format_option [String] The format string to be used # for the new block. # @param color_method [Symbol] The color method to apply # to the block's display name. # return number of lines added - def create_and_add_chrome_block(blocks:, match_data:, - collapse: nil, - format_option:, color_method:, - case_conversion: nil, - center: nil, - decor_patterns: [], - disabled: true, - id: '', - level: 0, - type: '', - wrap: nil) - line_cap = NamedCaptureExtractor::extract_named_group2(match_data) + def create_and_add_chrome_block( + blocks:, case_conversion: nil, center: nil, + collapse: nil, color_method:, decor_patterns: [], + disabled: true, format_option:, id: '', + level: 0, match_data:, type: '', + wrap: nil + ) + line_cap = NamedCaptureExtractor.extract_named_group2(match_data) # replace tabs in indent line_cap[:indent] ||= '' line_cap[:indent] = line_cap[:indent].dup if line_cap[:indent].frozen? line_cap[:indent].gsub!("\t", ' ') # replace tabs in text @@ -1197,25 +1213,23 @@ line_cap[:text].gsub!("\t", ' ') # missing capture line_cap[:collapse] ||= '' line_cap[:line] ||= '' - accepted_width = @delegate_object[:console_width] - 2 - line_caps = [line_cap] - if wrap && line_cap[:text].length > accepted_width - wrapper = StringWrapper.new(width: accepted_width - line_cap[:indent].length) + if wrap && line_cap[:text].length > screen_width_for_wrapping + wrapper = StringWrapper.new(width: screen_width_for_wrapping - line_cap[:indent].length) line_caps = wrapper.wrap(line_cap[:text]).map do |wrapped_line| line_cap.dup.merge(text: wrapped_line) end end if center line_caps.each do |line_obj| line_obj[:indent] = - if line_obj[:text].length < accepted_width - ' ' * ((accepted_width - line_obj[:text].length) / 2) + if line_obj[:text].length < screen_width_for_wrapping + ' ' * ((screen_width_for_wrapping - line_obj[:text].length) / 2) else '' end end end @@ -1246,12 +1260,10 @@ center: center, chrome: true, collapse: collapse.nil? ? (line_obj[:collapse] == COLLAPSIBLE_TOKEN_COLLAPSE) : collapse, token: line_obj[:collapse], disabled: disabled ? TtyMenu::DISABLE : nil, - #### - # id: "#{@delegate_object[:filename]}:#{index}", id: "#{id}.#{index}", level: level, s0indent: indent, s0printable: line_obj[:text], s1decorated: decorated, @@ -1290,11 +1302,11 @@ when COLLAPSIBLE_TOKEN_COLLAPSE true when COLLAPSIBLE_TOKEN_EXPAND false else - false#### + false end, color_method: criteria[:color] && @delegate_object[criteria[:color]].to_sym, decor_patterns: @@ -1862,10 +1874,11 @@ selected, directory: @delegate_object[:document_configurations_directory], exit_prompt: @delegate_object[:prompt_filespec_back], filename_pattern: @delegate_object[:vars_block_filename_pattern], glob: @delegate_object[:document_configurations_glob], + menu_options: HashDelegator.options_for_tty_menu(@delegate_object), view: @delegate_object[:vars_block_filename_view] ) block_data = HashDelegator.parse_yaml_data_from_body(selected.body) if selected_option = select_option_with_metadata( prompt_title, @@ -1876,26 +1889,28 @@ block_data['glob'] || glob ) ).sort.map do |file| { name: format( block_data['view'] || view, - NamedCaptureExtractor::extract_named_group2( + NamedCaptureExtractor.extract_named_group2( file.match( Regexp.new(block_data['filename_pattern'] || filename_pattern) ) ) ), oname: file } end, - simple_menu_options + menu_options.merge( + cycle: true + ) ) if selected_option.dname != exit_prompt File.readlines(selected_option.oname, chomp: true) end else - warn "No matching files found" ### + warn 'No matching files found' end end # Collects required code lines based on the selected block and # the delegate object's configuration. @@ -1962,11 +1977,11 @@ else @delegate_object[:document_saved_lines_glob] end save_filespec_from_expression(directory_glob).tap do |save_filespec| - if save_filespec && save != exit_prompt + if save_filespec && save_filespec != exit_prompt begin File.write(save_filespec, HashDelegator.join_code_lines(code_lines)) rescue Errno::ENOENT report_error($ERROR_INFO) @@ -2138,39 +2153,47 @@ def expand_blocks_with_replacements( menu_blocks, replacements, exclude_types: [BlockType::SHELL] ) # update blocks # - Regexp.union(replacements.keys).tap do |pattern| + Regexp.union(replacements.keys.map do |word| + Regexp.new(Regexp.escape(word)) + end).tap do |pattern| menu_blocks.each do |block| next if exclude_types.include?(block.type) block.expand_variables_in_attributes!(pattern, replacements) end end end def expand_variable_references!( - # echo_format: 'echo "$%s"', echo_format: 'echo $%s', link_state:, blocks:, - pattern: Regexp.new(@delegate_object[:variable_expression_regexp]) + group_name: :variable, + initial_code_required: false, + key_format: '${%s}', + pattern: nil ) - # Count occurrences of named groups in each block - variable_counts = count_named_group_occurrences(blocks, pattern) + pattern ||= options_variable_expression_regexp + return if pattern.nil? - # Generate echo commands for each variable based on its count + variable_counts = count_named_group_occurrences(blocks, pattern, + group_name: group_name) + return if variable_counts.nil? + echo_commands = generate_echo_commands(variable_counts, echo_format) - # Build a dictionary to replace variables with the corresponding commands - replacements = build_replacement_dictionary(echo_commands, link_state) + replacements = build_replacement_dictionary( + echo_commands, link_state, + initial_code_required: initial_code_required, + key_format: key_format + ) - # Exit early if no replacements are needed return if replacements.nil? - # Expand each block with replacements from the dictionary expand_blocks_with_replacements(blocks, replacements) end # Retrieves a specific data symbol from the delegate object, # converts it to a string, and applies a color style @@ -2282,11 +2305,11 @@ def generate_echo_commands(variable_counts, echo_format) # commands to echo variables # commands = {} - variable_counts.each do |variable, count| + variable_counts.each do |variable, _count| command = format(echo_format, variable) commands[variable] = command end commands end @@ -2378,31 +2401,29 @@ in_fenced_block: false, headings: [] } end - public - # Iterates through blocks in a file, applying the provided block to each line. # The iteration only occurs if the file exists. # @yield [Symbol] :filter Yields to obtain selected messages for processing. def iter_blocks_from_nested_files(&block) return unless check_file_existence(@delegate_object[:filename]) state = initial_state selected_types = yield :filter cfile.readlines( @delegate_object[:filename], - import_paths: @delegate_object[:import_paths]&.split(':') + import_paths: options_import_paths ).each_with_index do |nested_line, index| - if nested_line - update_line_and_block_state( - nested_line, state, selected_types, - id: "#{@delegate_object[:filename]}:#{index}", - &block - ) - end + next unless nested_line + + update_line_and_block_state( + nested_line, state, selected_types, + id: "#{@delegate_object[:filename]}:#{index}", + &block + ) end end def iter_source_blocks(source, &block) case source @@ -2578,19 +2599,19 @@ @vars_most_recent_filename = @delegate_object[:filename] code_from_vars_block_to_set_environment_variables(block) end def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [], - default: nil) + prior_answer: nil) if @delegate_object[:block_name].present? block = all_blocks.find do |item| item.pub_name == @delegate_object[:block_name] end source = OpenStruct.new(block_name_from_ui: false) else block_state = wait_for_user_selected_block(all_blocks, menu_blocks, - default) + prior_answer) return if block_state.nil? block = block_state.block source = OpenStruct.new(block_name_from_ui: true) state = block_state.state @@ -2691,23 +2712,19 @@ # menu_blocks, @compressed_ids = mdoc.fcbs_per_options( @delegate_object.merge!(compressed_ids: @compressed_ids) ) - # text substitution in menu - # - expand_variable_references!(blocks: menu_blocks, link_state: link_state) - # expand_command_substition!(blocks: menu_blocks, link_state: link_state) - # chrome for menu # add_menu_chrome_blocks!(id: id, menu_blocks: menu_blocks, link_state: link_state) ### compress empty lines HashDelegator.delete_consecutive_blank_lines!(menu_blocks) - HashDelegator.tables_into_columns!(menu_blocks, @delegate_object) #### + HashDelegator.tables_into_columns!(menu_blocks, @delegate_object, + screen_width_for_table) [all_blocks, menu_blocks, mdoc] end def menu_add_disabled_option(document_glob) @@ -2803,10 +2820,23 @@ next_keep_code: false, next_load_file: LoadFile::REUSE ) end + def options_command_substitution_regexp + Regexp.new(@delegate_object[:command_substitution_regexp] || '') + end + + def options_import_paths + @delegate_object[:import_paths]&.split(':') || '' + end + + def options_variable_expression_regexp + @delegate_object[:variable_expression_regexp].present? && + Regexp.new(@delegate_object[:variable_expression_regexp]) + end + def output_color_formatted(data_sym, color_sym) formatted_string = string_send_color(@delegate_object[data_sym], color_sym) @fout.fout formatted_string end @@ -2925,13 +2955,28 @@ # # @param all_blocks [Array<Hash>] The list of blocks from the file. # @param opts [Hash] The options hash. # @return [Array<Hash>] The updated blocks menu. def blocks_as_menu_items(menu_blocks) + # prefix first active line, inactive for rest + active = @delegate_object[:prompt_margin_left_text] + inactive = ' ' * active.length + select_blocks(menu_blocks).map do |fcb| - fcb.name = fcb.indented_decorated || (fcb.indent + (fcb.s1decorated || fcb.dname)) - fcb.value = fcb.id || fcb.name + multiline = fcb.indented_decorated || + (fcb.indent + (fcb.s1decorated || fcb.dname)) + + fcb.name = multiline.each_line.with_index.map do |line, index| + if fcb.fetch(:disabled, nil).nil? + index.zero? ? active : inactive + else + inactive + end + line.chomp + end.join("\n") + + fcb.value = fcb.id || fcb.name.split("\n").first + fcb.to_h end end def print_formatted_option(key, value) @@ -2951,11 +2996,11 @@ if in_block if end_pattern.present? && line.match?(end_pattern) in_block = false elsif scan1.present? if format1.present? - caps = NamedCaptureExtractor::extract_named_groups(line, scan1) + caps = NamedCaptureExtractor.extract_named_groups(line, scan1) if caps formatted = format(format1, caps) collected_lines << formatted end else @@ -3076,10 +3121,22 @@ end sel == MenuOptions::YES end + def prompt_margin_left_text + @delegate_object[:prompt_margin_left_text] + end + + def prompt_margin_left_width + prompt_margin_left_text.length + end + + def prompt_margin_right_width + 0 + end + # public def prompt_select_code_filename( filenames, color_sym: :prompt_color_after_script_execution, @@ -3170,12 +3227,15 @@ regexp: @delegate_object[:saved_asset_match] ) history_files( @dml_link_state, filename: - asset.present? ? saved_asset_filename(asset, - @dml_link_state) : filename, + if asset.present? + saved_asset_filename(asset, @dml_link_state) + else + filename + end, path: path )&.map do |file| unless Regexp.new(regexp) =~ file warn "Cannot parse name: #{file}" next @@ -3190,28 +3250,27 @@ end def saved_asset_for_history( file:, form:, match_info: ) - begin - OpenStruct.new( - file: file[(Dir.pwd.length + 1)..-1], - full: file, - row: format( - form, - # default '*' so unknown parameters are given a wildcard - match_info.names.each_with_object(Hash.new('*')) do |name, hash| - hash[name.to_sym] = match_info[name] - end - ) + + OpenStruct.new( + file: file[(Dir.pwd.length + 1)..-1], + full: file, + row: format( + form, + # default '*' so unknown parameters are given a wildcard + match_info.names.each_with_object(Hash.new('*')) do |name, hash| + hash[name.to_sym] = match_info[name] + end ) - rescue KeyError - # pp $!, $@ - warn "Cannot format with: #{@delegate_object[:saved_history_format]}" - error_handler('saved_history_format') - return :break - end + ) + rescue KeyError + # pp $!, $@ + warn "Cannot format with: #{@delegate_object[:saved_history_format]}" + error_handler('saved_history_format') + :break end # Processes YAML data from the selected menu item, updating delegate # objects and optionally printing formatted output. # @param selected [Hash] Selected item from the menu containing a YAML body. @@ -3280,10 +3339,12 @@ # opts = { console_width: nil, console_height: nil, select_page_height: nil } # register_console_attributes(opts) # # opts will be updated with the current console dimensions # # and pagination settings. def register_console_attributes(opts) + return unless IO.console + if (resized = @delegate_object[:menu_resize_terminal]) resize_terminal end if resized || !opts[:console_width] @@ -3303,13 +3364,13 @@ # private def replace_keys_in_lines(replacement_dictionary, lines) # Create a regex pattern that matches any key in the replacement dictionary - pattern = Regexp.union(replacement_dictionary.keys.map { |key| + pattern = Regexp.union(replacement_dictionary.keys.map do |key| "%<#{key}>" - }) + end) # Iterate over each line and apply gsub with the replacement hash lines.map do |line| line.gsub(pattern) { |match| replacement_dictionary[match] } end @@ -3427,12 +3488,28 @@ shell: shell ) ).generate_name end + def screen_width + if @delegate_object[:screen_width] && @delegate_object[:screen_width].positive? + @delegate_object[:screen_width] + else + @delegate_object[:console_width] + end + end + + def screen_width_for_table + screen_width - prompt_margin_left_width - prompt_margin_right_width - 2 # prompt is symbol + space (width: 2) + end + + def screen_width_for_wrapping + screen_width_for_table + end + def select_document_if_multiple(options, files, prompt:) - return files if files.class == String ### + return files if files.class == String return files[0] if (count = files.count) == 1 return unless count >= 2 opts = options.dup @@ -3461,13 +3538,24 @@ begin props = { active_color: active_color_pastel.detach, # activate dynamic list searching on letter/number key presses + cycle: true, filter: true, + per_page: @delegate_object[:select_page_height] }.freeze + if menu_items.all? do |item| + !item.is_a?(String) && item[:disabled] + end + menu_items.each do |prompt_item| + puts prompt_item[:dname] + end + return + end + # crashes if all menu options are disabled # crashes if default is not an existing item # selection = @prompt.select(prompt_text, menu_items, @@ -3482,11 +3570,10 @@ return end selected = menu_items.find do |item| if item.instance_of?(Hash) - # (item[:id] || item[:name] || item[:dname]) == selection [item[:id], item[:name], item[:dname]].include?(selection) elsif item.instance_of?(MarkdownExec::FCB) item.dname == selection || item.id == selection else item == selection @@ -3553,26 +3640,21 @@ menu_with_back: @delegate_object[:menu_with_back] ) menu_with_back && @link_history.prior_state_exist? end - def simple_menu_options( - per_page: @delegate_object[:select_page_height] - ) - { cycle: true, - per_page: per_page } - end + def simple_menu_options; end # Initializes a new fenced code block (FCB) object based # on the provided line and heading information. # @param line [String] The line initiating the fenced block. # @param headings [Array<String>] Current headings hierarchy. # @param fenced_start_extended_regex [Regexp] # Regular expression to identify fenced block start. # @return [MarkdownExec::FCB] A new FCB instance with the parsed attributes. def start_fenced_block(line, headings, fenced_start_extended_regex) - fcb_title_groups = NamedCaptureExtractor::extract_named_groups( + fcb_title_groups = NamedCaptureExtractor.extract_named_groups( line, fenced_start_extended_regex ) rest = fcb_title_groups.fetch(:rest, '') reqs, wraps = @@ -3625,14 +3707,14 @@ oname: oname, reqs: reqs, shell: fcb_title_groups.fetch(:shell, ''), start_line: line, stdin: if (tn = rest.match(/<(?<type>\$)?(?<name>[A-Za-z_-]\S+)/)) - NamedCaptureExtractor::extract_named_group2(tn) + NamedCaptureExtractor.extract_named_group2(tn) end, stdout: if (tn = rest.match(/>(?<type>\$)?(?<name>[\w.\-]+)/)) - NamedCaptureExtractor::extract_named_group2(tn) + NamedCaptureExtractor.extract_named_group2(tn) end, title: title, type: fcb_title_groups.fetch(:type, ''), wraps: wraps ) @@ -3734,11 +3816,11 @@ def vux_await_user_selection @dml_block_state = load_cli_or_user_selected_block( all_blocks: @dml_blocks_in_file, menu_blocks: @dml_menu_blocks, - default: @dml_menu_default_dname + prior_answer: @dml_menu_default_dname ) if !@dml_block_state # HashDelegator.error_handler('block_state missing', { abort: true }) # document has no enabled items :break @@ -4002,11 +4084,11 @@ ).run do |msg, data| case msg when :parse_document # once for each menu vux_parse_document(id: 'vux_parse_document') vux_menu_append_history_files(formatted_choice_ostructs, - id: "vux_menu_append_history_files",) + id: 'vux_menu_append_history_files') vux_publish_document_file_name_for_external_automation when :display_menu # does not display vux_clear_menu_state @@ -4154,11 +4236,10 @@ @dml_link_state.block_name end # update @delegate_object and @menu_base_options in auto_load # - # @dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc, @dml_link_state = @dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc = mdoc_menu_and_blocks_from_nested_files(@dml_link_state, id: id) dump_delobj(@dml_blocks_in_file, @dml_menu_blocks, @dml_link_state) end @@ -4218,17 +4299,18 @@ end rescue Interrupt # user interrupts process end - def wait_for_user_selected_block(all_blocks, menu_blocks, default) - block_state = wait_for_user_selection(all_blocks, menu_blocks, default) + def wait_for_user_selected_block(all_blocks, menu_blocks, prior_answer) + block_state = wait_for_user_selection(all_blocks, menu_blocks, + prior_answer) handle_back_or_continue(block_state) block_state end - def wait_for_user_selection(_all_blocks, menu_blocks, default) + def wait_for_user_selection(_all_blocks, menu_blocks, prior_answer) if @delegate_object[:clear_screen_for_select_block] printf("\e[1;1H\e[2J") end prompt_title = string_send_color( @@ -4240,14 +4322,24 @@ if menu_items.empty? return SelectedBlockMenuState.new(nil, OpenStruct.new, MenuState::EXIT) end - # default value may not match if color is different from + selected_answer = case prior_answer + when nil + nil + when String + menu_blocks.find { |block| + block.dname.include?(prior_answer) + }&.name + when Struct + prior_answer.index || prior_answer.name + end + # prior_answer value may not match if color is different from # originating menu (opts changed while processing) - selection_opts = if default && menu_blocks.map(&:dname).include?(default) - @delegate_object.merge(default: default) + selection_opts = if selected_answer + @delegate_object.merge(default: selected_answer) else @delegate_object end selection_opts.merge!( @@ -4372,10 +4464,14 @@ end def self.next_link_state(*args, **kwargs, &block) super end + + def self.options_for_tty_menu(options) + options.slice(:menu_active_color_pastel_messages, :select_page_height) + end end end return if $PROGRAM_NAME != __FILE__ @@ -5133,10 +5229,10 @@ @hd.stubs(:update_line_and_block_state) end def test_iter_blocks_from_nested_files @hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'], - import_paths: nil) + import_paths: '') selected_types = ['filtered message'] result = @hd.iter_blocks_from_nested_files { selected_types } assert_equal ['line 1', 'line 2'], result