Class: MarkdownExec::HashDelegatorParent
- Extended by:
- HashDelegatorSelf
- Includes:
- CompactionHelpers, TextAnalyzer
- Defined in:
- lib/hash_delegator.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#most_recent_loaded_filename ⇒ Object
Returns the value of attribute most_recent_loaded_filename.
-
#p_all_arguments ⇒ Object
Returns the value of attribute p_all_arguments.
-
#p_options_parsed ⇒ Object
Returns the value of attribute p_options_parsed.
-
#p_params ⇒ Object
Returns the value of attribute p_params.
-
#p_rest ⇒ Object
Returns the value of attribute p_rest.
-
#pass_args ⇒ Object
Returns the value of attribute pass_args.
-
#run_state ⇒ Object
Returns the value of attribute run_state.
Instance Method Summary collapse
-
#absolute_path(file_path) ⇒ String
Returns the absolute path of the given file path.
-
#add_menu_chrome_blocks!(menu_blocks:, link_state:) ⇒ Object
Modifies the provided menu blocks array by adding ‘Back’ and ‘Exit’ options, along with initial and final dividers, based on the delegate object’s configuration.
-
#append_chrome_block(menu_blocks:, menu_state:) ⇒ Object
Appends a chrome block, which is a menu option for Back or Exit.
-
#append_divider(menu_blocks:, position:) ⇒ Object
Appends a formatted divider to the specified position in a menu block array.
-
#append_inherited_lines(menu_blocks:, link_state:, position: top) ⇒ Object
Appends a formatted divider to the specified position in a menu block array.
-
#apply_block_type_color_option(name, block_type_color_option) ⇒ String
Applies shell color options to the given string if applicable.
- #apply_tree_decorations(text, color_method, decor_patterns) ⇒ Object
- #assign_key_value_in_bash(key, value) ⇒ Object
-
#block_state_for_name_from_cli(block_name) ⇒ Object
find a block by its original (undecorated) name or nickname (not visible in menu) if matched, the block returned has properties that it is from cli and not ui.
- #blocks_find_by_block_name(blocks, block_name) ⇒ Object
-
#blocks_from_nested_files ⇒ Array<FCB>
Iterates through nested files to collect various types of blocks, including dividers, tasks, and others.
-
#calc_logged_stdout_filename(block_name:) ⇒ Object
private.
- #cfile ⇒ Object
-
#check_file_existence(filename) ⇒ Object
Check whether the document exists and is readable.
- #code_from_vars_block_to_set_environment_variables(selected) ⇒ Object
- #collect_line_decor_patterns(delegate_object) ⇒ Object
- #command_execute(command, shell:, args: []) ⇒ Object
- #command_execute_in_own_window(args:, script:) ⇒ Object
- #command_execute_in_own_window_format_arguments(home: Dir.pwd, rest: '') ⇒ Object
- #command_execute_in_process(args:, command:, filename:, shell:) ⇒ Object
-
#compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:, link_state:) ⇒ LoadFileLinkState
This method is responsible for handling the execution of generic blocks in a markdown document.
-
#contains_wildcards?(expr) ⇒ Boolean
Check if the expression contains wildcard characters.
- #copy_to_clipboard(required_lines) ⇒ Object
-
#count_blocks_in_filename ⇒ Integer
Counts the number of fenced code blocks in a file.
-
#create_and_add_chrome_block(blocks:, match_data:, format_option:, color_method:, case_conversion: nil, center: nil, decor_patterns: [], wrap: nil) ⇒ Object
Creates and adds a formatted block to the blocks array based on the provided match and format options.
-
#create_and_add_chrome_blocks(blocks, fcb) ⇒ Object
Processes lines within the file and converts them into blocks if they match certain criteria.
- #create_divider(position) ⇒ Object
-
#debounce_allows ⇒ Boolean
Prompts user if named block is the same as the prior execution.
- #debounce_reset ⇒ Object
-
#determine_block_state(selected_option) ⇒ SelectedBlockMenuState
Determines the state of a selected block in the menu based on the selected option.
-
#display_required_code(required_lines:) ⇒ Object
Displays the required lines of code with color formatting for the preview section.
- #divider_formatting_present?(position) ⇒ Boolean
- #dml_menu_append_chrome_item(name, count, type, menu_state: MenuState::LOAD, always_create: true, always_enable: true) ⇒ Object
- #do_save_execution_output ⇒ Object
-
#document_name_in_glob_as_file_name(document_filename: @dml_link_state.document_filename, format_glob: , remove_regexp: %r{^\./}, subst_regexp: /[\/:\.\* ]/, subst_string: '_') ⇒ Object
remove leading “./” replace characters: / : .
- #dump_and_warn_block_state(name:, selected:) ⇒ Object
-
#dump_delobj(blocks_in_file, menu_blocks, link_state) ⇒ Object
Outputs warnings based on the delegate object’s configuration.
-
#edit_text(initial_text, temp_name: 'edit_text') ⇒ String?
Opens text in an editor for user modification and returns the modified text.
-
#execute_block_by_type_for_lfls(selected:, mdoc:, block_source:, link_state: LinkState.new) ⇒ Object
Execute a code block after approval and provide user interaction options.
- #execute_block_for_state_and_name(selected:, mdoc:, link_state:, block_source: {}) ⇒ Object
- #execute_block_in_state(block_name) ⇒ Object
- #execute_block_type_history_ux(directory: , filename: '*', form: '%{line}', link_state:, regexp: "^(?<line>.*)$", selected:) ⇒ Object
-
#execute_block_type_link_with_state(link_block_body: [], mdoc: nil, selected: FCB.new, link_state: LinkState.new, block_source: {}) ⇒ LoadFileLinkState
Handles the processing of a link block in Markdown Execution.
- #execute_block_type_load_code_lines(selected, directory: , filename_pattern: , glob: , view: ) ⇒ Object
-
#execute_block_type_port_code_lines(mdoc:, selected:, block_source:, link_state: LinkState.new) ⇒ Array<String>
Collects required code lines based on the selected block and the delegate object’s configuration.
- #execute_block_type_save(code_lines:, selected:) ⇒ Object
-
#execute_command_with_streams(command) {|stdin, stdout, stderr, thread| ... } ⇒ Integer
Executes a given command and processes its input, output, and error streams.
- #execute_history_select(files_table_rows, exit_prompt: , pause_refresh: false, stream:) ⇒ Object
- #execute_inherited_save(code_lines: @dml_link_state.inherited_lines) ⇒ Object
- #execute_navigate_back ⇒ Object
-
#execute_required_lines(required_lines: [], selected: FCB.new, shell:) ⇒ Object
Executes a block of code that has been approved for execution.
-
#fetch_color(default: '', data_sym: :execution_report_preview_head, color_sym: :execution_report_preview_frame_color) ⇒ String
Retrieves a specific data symbol from the delegate object, converts it to a string, and applies a color style based on the specified color symbol.
-
#file_info(file_path) ⇒ Object
size of a file in bytes and the number of lines.
- #format_and_execute_command(code_lines:, shell:) ⇒ Object
-
#format_expression(expr) ⇒ Object
Format expression using environment variables and run state.
-
#format_references_send_color(color_sym: :execution_report_preview_frame_color, context: {}, default: '', format_sym: :output_execution_label_format) ⇒ String
Formats a string based on a given context and applies color styling to it.
-
#formatted_expression(expr) ⇒ Object
Expand expression if it contains format specifiers.
- #fout_execution_report ⇒ Object
- #generate_temp_filename(ext = '.sh') ⇒ Object
-
#handle_back_or_continue(block_state) ⇒ Object
Updates the delegate object’s state based on the provided block state.
- #handle_stream(stream:, file_type:, swap: false) ⇒ Object
- #history_files(link_state, direction: :reverse, filename: nil, home: Dir.pwd, order: :chronological, path: '') ⇒ Object
-
#initial_state ⇒ Object
Initializes variables for regex and other states.
-
#initialize(delegate_object = {}) ⇒ HashDelegatorParent
constructor
A new instance of HashDelegatorParent.
-
#iter_blocks_from_nested_files {|Symbol| ... } ⇒ Object
Iterates through blocks in a file, applying the provided block to each line.
- #iter_source_blocks(source, &block) ⇒ Object
- #link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source:, shell:) ⇒ Object
- #link_history_push_and_next(curr_block_name:, curr_document_filename:, inherited_block_names:, inherited_dependencies:, inherited_lines:, keep_code:, next_block_name:, next_document_filename:, next_keep_code:, next_load_file:) ⇒ Object
- #link_load_format_data ⇒ Object
- #list_blocks ⇒ Object
-
#load_auto_opts_block(all_blocks, mdoc:) ⇒ Boolean?
Loads auto blocks based on delegate object settings and updates if new filename is detected.
- #load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [], default: nil) ⇒ Object
-
#load_filespec_from_expression(expression) ⇒ Object
format + glob + select for file in load block name has references to ENV vars and doc and batch vars incl.
-
#load_filespec_wildcard_expansion(expr, auto_load_single: false) ⇒ Object
Handle expression with wildcard characters.
- #manage_cli_selection_state(block_name_from_cli:, now_using_cli:, link_state:) ⇒ Object
- #mdoc_and_blocks_from_nested_files ⇒ Object
-
#mdoc_menu_and_blocks_from_nested_files(link_state) ⇒ Object
Handles the file loading and returns the blocks in the file and MDoc instance.
- #menu_add_disabled_option(document_glob) ⇒ Object
-
#menu_chrome_colored_option(option_symbol = :menu_option_back_name) ⇒ String
Formats and optionally colors a menu option based on delegate object’s configuration.
-
#menu_chrome_formatted_option(option_symbol = :menu_option_back_name) ⇒ String
Formats a menu option based on the delegate object’s configuration.
-
#method_missing(method_name, *args, &block) ⇒ Object
If a method is missing, treat it as a key for the @delegate_object.
- #next_state_append_code(selected, link_state, code_lines) ⇒ Object
- #next_state_set_code(selected, link_state, code_lines) ⇒ Object
- #output_color_formatted(data_sym, color_sym) ⇒ Object
- #output_execution_summary ⇒ Object
- #output_labeled_value(label, value, level) ⇒ Object
- #pause_user_exit ⇒ Object
- #pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines, dependencies, selected, next_block_name: nil) ⇒ Object
-
#pop_link_history_new_state ⇒ LinkState
This method handles the back-link operation in the Markdown execution context.
- #post_execution_process ⇒ Object
-
#prepare_blocks_menu(menu_blocks) ⇒ Array<Hash>
Prepare the blocks menu by adding labels and other necessary details.
- #print_formatted_option(key, value) ⇒ Object
-
#process_string_array(arr, begin_pattern: nil, end_pattern: nil, scan1: nil, format1: nil) ⇒ Object
private.
- #prompt_approve_repeat ⇒ Object
- #prompt_for_command(prompt) ⇒ Object
-
#prompt_for_filespec_with_wildcard(filespec) ⇒ String?
Prompts the user to enter a path or name to substitute into the wildcard expression.
-
#prompt_for_user_approval(required_lines:, selected:) ⇒ Boolean
Presents a menu to the user for approving an action and performs additional tasks based on the selection.
-
#prompt_select_code_filename(filenames, color_sym: :prompt_color_after_script_execution, cycle: true, enum: false, quiet: true, string: ) ⇒ Object
public.
- #prompt_select_continue(filter: true, quiet: true) ⇒ Object
-
#prompt_user_exit(block_name_from_cli:, selected:) ⇒ Object
user prompt to exit if the menu will be displayed again.
- #publish_for_external_automation(message:) ⇒ Object
-
#puts_gets_oprompt_(filespec) ⇒ Object
Handle expression with wildcard characters allow user to select or enter.
- #read_saved_assets_for_history_table(asset: nil, filename: nil, form: , path: , regexp: ) ⇒ Object
-
#read_show_options_and_trigger_reuse(selected:, mdoc:, link_state: LinkState.new) ⇒ LoadFileLinkState
Processes YAML data from the selected menu item, updating delegate objects and optionally printing formatted output.
-
#register_console_attributes(opts) ⇒ Object
Registers console attributes by modifying the options hash.
- #report_error(err) ⇒ Object
-
#respond_to?(method_name, include_private = false) ⇒ Boolean
Check if the delegate object responds to a given method.
- #runtime_exception(exception_sym, name, items) ⇒ Object
-
#save_filespec_from_expression(expression) ⇒ Object
allow user to select or enter.
-
#save_filespec_wildcard_expansion(filespec) ⇒ Object
Handle expression with wildcard characters allow user to select or enter.
- #save_to_file(required_lines:, selected:, shell:) ⇒ Object
- #saved_asset_filename(filename, link_state = LinkState.new) ⇒ Object
- #saved_asset_for_history(file:, form:, match_info:) ⇒ Object
- #select_document_if_multiple(options, files, prompt:) ⇒ Object
-
#select_option_with_metadata(prompt_text, menu_items, opts = {}) ⇒ Object
Presents a TTY prompt to select an option or exit, returns metadata including option and selected.
- #shell ⇒ Object
- #shell=(value) ⇒ Object
- #shell_escape_asset_format(code_lines:, enable: , raw: , shell:) ⇒ Object
- #should_add_back_option?(menu_with_back: ) ⇒ Boolean
- #simple_menu_options(per_page: ) ⇒ Object
-
#start_fenced_block(line, headings, fenced_start_extended_regex) ⇒ MarkdownExec::FCB
Initializes a new fenced code block (FCB) object based on the provided line and heading information.
-
#string_send_color(string, color_sym) ⇒ String
Applies a color method to a string based on the provided color symbol.
-
#update_line_and_block_state(nested_line, state, selected_types, &block) ⇒ Void
Processes an individual line within a loop, updating headings and handling fenced code blocks.
-
#update_menu_base(options) ⇒ Object
apply options to current state.
- #variable_expansions!(echo_command_form: 'echo "$%s"', link_state:, menu_blocks:, regexp: Regexp.new(@delegate_object[:variable_expression_regexp])) ⇒ Object
- #vux_await_user_selection ⇒ Object
- #vux_clear_menu_state ⇒ Object
- #vux_edit_inherited ⇒ Object
- #vux_execute_and_prompt(block_name) ⇒ Object
- #vux_execute_block_per_type(block_name, formatted_choice_ostructs) ⇒ Object
- #vux_formatted_names_for_state_chrome_blocks(names: %w[back edit history load save shell view]) ⇒ Object
- #vux_history_files_table_rows ⇒ Object
- #vux_init ⇒ Object
- #vux_input_and_execute_shell_commands(stream:, shell:) ⇒ Object
-
#vux_load_code_files_into_state ⇒ Object
load file with code lines per options.
- #vux_load_inherited ⇒ Object
-
#vux_main_loop ⇒ Nil
Select and execute a code block from a Markdown document.
- #vux_menu_append_history_files(formatted_choice_ostructs) ⇒ Object
- #vux_navigate_back_for_ls ⇒ Object
- #vux_parse_document ⇒ Object
- #vux_publish_block_name_for_external_automation(block_name) ⇒ Object
- #vux_publish_document_file_name_for_external_automation ⇒ Object
-
#vux_user_selected_block_name ⇒ Object
return :break to break from loop.
- #vux_view_inherited(stream:) ⇒ Object
- #wait_for_stream_processing ⇒ Object
- #wait_for_user_selected_block(all_blocks, menu_blocks, default) ⇒ Object
- #wait_for_user_selection(_all_blocks, menu_blocks, default) ⇒ Object
-
#write_command_file(required_lines:, selected:, shell: nil) ⇒ Object
Handles the core logic for generating the command file’s metadata and content.
-
#write_file_with_directory_creation(content:, filespec:) ⇒ Object
Ensure the directory exists before writing the file.
-
#write_inherited_lines_to_file(link_state, link_block_data) ⇒ Object
return next document file name.
Methods included from HashDelegatorSelf
apply_color_from_hash, block_find, code_merge, count_matches_in_lines, create_directory_for_file, create_file_and_write_string_with_permissions, default_block_title_from_body, delete_consecutive_blank_lines!, error_handler, indent_all_lines, initialize_fcb_names, join_code_lines, merge_lists, next_link_state, parse_yaml_data_from_body, read_required_blocks_from_temp_file, remove_file_without_standard_errors, safeval, set_file_permissions, tables_into_columns!, tty_prompt_without_disabled_symbol, update_menu_attrib_yield_selected, yield_line_if_selected
Methods included from TextAnalyzer
analyze_hierarchy, highlight_segments, yield_matches_and_non_matches
Methods included from CompactionHelpers
#compact_and_convert_array_to_hash, #compact_and_index_hash, #compact_hash
Constructor Details
#initialize(delegate_object = {}) ⇒ HashDelegatorParent
Returns a new instance of HashDelegatorParent.
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
# File 'lib/hash_delegator.rb', line 542 def initialize(delegate_object = {}) @delegate_object = delegate_object @prompt = HashDelegator.tty_prompt_without_disabled_symbol @most_recent_loaded_filename = nil @pass_args = [] @run_state = OpenStruct.new( link_history: [], source: OpenStruct.new ) @link_history = LinkHistory.new @fout = FOut.new(@delegate_object) ### slice only relevant keys @process_mutex = Mutex.new @process_cv = ConditionVariable.new @p_all_arguments = [] @p_options_parsed = [] @p_params = {} @p_rest = [] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, &block) ⇒ Object
If a method is missing, treat it as a key for the @delegate_object.
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 |
# File 'lib/hash_delegator.rb', line 2610 def method_missing(method_name, *args, &block) if @delegate_object.respond_to?(method_name) @delegate_object.send(method_name, *args, &block) elsif method_name.to_s.end_with?('=') && args.size == 1 @delegate_object[method_name.to_s.chop.to_sym] = args.first else @delegate_object[method_name] # super end end |
Instance Attribute Details
#most_recent_loaded_filename ⇒ Object
Returns the value of attribute most_recent_loaded_filename.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def most_recent_loaded_filename @most_recent_loaded_filename end |
#p_all_arguments ⇒ Object
Returns the value of attribute p_all_arguments.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def p_all_arguments @p_all_arguments end |
#p_options_parsed ⇒ Object
Returns the value of attribute p_options_parsed.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def @p_options_parsed end |
#p_params ⇒ Object
Returns the value of attribute p_params.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def p_params @p_params end |
#p_rest ⇒ Object
Returns the value of attribute p_rest.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def p_rest @p_rest end |
#pass_args ⇒ Object
Returns the value of attribute pass_args.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def pass_args @pass_args end |
#run_state ⇒ Object
Returns the value of attribute run_state.
535 536 537 |
# File 'lib/hash_delegator.rb', line 535 def run_state @run_state end |
Instance Method Details
#absolute_path(file_path) ⇒ String
Returns the absolute path of the given file path. If the provided path is already absolute, it returns it as is. Otherwise, it prefixes the path with the current working directory.
Example usage:
absolute_path('/absolute/path/to/file.txt') # => '/absolute/path/to/file.txt'
absolute_path('relative/path/to/file.txt') # => '/current/working/directory/relative/path/to/file.txt'
586 587 588 589 590 591 592 |
# File 'lib/hash_delegator.rb', line 586 def absolute_path(file_path) if File.absolute_path?(file_path) file_path else File.join(Dir.getwd, file_path) end end |
#add_menu_chrome_blocks!(menu_blocks:, link_state:) ⇒ Object
Modifies the provided menu blocks array by adding ‘Back’ and ‘Exit’ options, along with initial and final dividers, based on the delegate object’s configuration.
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
# File 'lib/hash_delegator.rb', line 598 def (menu_blocks:, link_state:) return unless @delegate_object[:menu_link_format].present? if @delegate_object[:menu_with_inherited_lines] add_inherited_lines(menu_blocks: , link_state: link_state) end # back before exit add_back_option(menu_blocks: ) if should_add_back_option? # exit after other options if @delegate_object[:menu_with_exit] add_exit_option(menu_blocks: ) end append_divider(menu_blocks: , position: :initial) append_divider(menu_blocks: , position: :final) end |
#append_chrome_block(menu_blocks:, menu_state:) ⇒ Object
Appends a chrome block, which is a menu option for Back or Exit
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
# File 'lib/hash_delegator.rb', line 698 def append_chrome_block(menu_blocks:, menu_state:) case when MenuState::BACK history_state_partition option_name = @delegate_object[:menu_option_back_name] insert_at_top = @delegate_object[:menu_back_at_top] when MenuState::EDIT option_name = @delegate_object[:menu_option_edit_name] insert_at_top = @delegate_object[:menu_load_at_top] when MenuState::EXIT option_name = @delegate_object[:menu_option_exit_name] insert_at_top = @delegate_object[:menu_exit_at_top] when MenuState::HISTORY option_name = @delegate_object[:menu_option_history_name] insert_at_top = @delegate_object[:menu_load_at_top] when MenuState::LOAD option_name = @delegate_object[:menu_option_load_name] insert_at_top = @delegate_object[:menu_load_at_top] when MenuState::SAVE option_name = @delegate_object[:menu_option_save_name] insert_at_top = @delegate_object[:menu_load_at_top] when MenuState::SHELL option_name = @delegate_object[:menu_option_shell_name] insert_at_top = @delegate_object[:menu_load_at_top] when MenuState::VIEW option_name = @delegate_object[:menu_option_view_name] insert_at_top = @delegate_object[:menu_load_at_top] else raise "Missing MenuState: #{}" end formatted_name = format(@delegate_object[:menu_link_format], HashDelegator.safeval(option_name)) chrome_block = FCB.new( chrome: true, dname: HashDelegator.new(@delegate_object).string_send_color( formatted_name, :menu_chrome_color ), nickname: formatted_name, oname: formatted_name ) if insert_at_top .unshift(chrome_block) else .push(chrome_block) end chrome_block end |
#append_divider(menu_blocks:, position:) ⇒ Object
Appends a formatted divider to the specified position in a menu block array. The method checks for the presence of formatting options before appending.
754 755 756 757 758 759 |
# File 'lib/hash_delegator.rb', line 754 def append_divider(menu_blocks:, position:) return unless divider_formatting_present?(position) divider = create_divider(position) position == :initial ? .unshift(divider) : .push(divider) end |
#append_inherited_lines(menu_blocks:, link_state:, position: top) ⇒ Object
Appends a formatted divider to the specified position in a menu block array. The method checks for the presence of formatting options before appending.
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
# File 'lib/hash_delegator.rb', line 766 def append_inherited_lines(menu_blocks:, link_state:, position: top) return unless link_state.inherited_lines_present? insert_at_top = @delegate_object[:menu_inherited_lines_at_top] chrome_blocks = link_state.inherited_lines_map do |line| formatted = format(@delegate_object[:menu_inherited_lines_format], { line: line }) FCB.new( chrome: true, disabled: '', dname: HashDelegator.new(@delegate_object).string_send_color( formatted, :menu_inherited_lines_color ), oname: formatted ) end if insert_at_top # Prepend an array of elements to the beginning .unshift(*chrome_blocks) else # Append an array of elements to the end .concat(chrome_blocks) end rescue StandardError HashDelegator.error_handler('append_inherited_lines') end |
#apply_block_type_color_option(name, block_type_color_option) ⇒ String
Applies shell color options to the given string if applicable.
801 802 803 804 805 806 807 |
# File 'lib/hash_delegator.rb', line 801 def apply_block_type_color_option(name, block_type_color_option) if block_type_color_option && @delegate_object[block_type_color_option].present? string_send_color(name, block_type_color_option) else name end end |
#apply_tree_decorations(text, color_method, decor_patterns) ⇒ Object
809 810 811 812 813 814 815 816 817 818 819 820 821 |
# File 'lib/hash_delegator.rb', line 809 def apply_tree_decorations(text, color_method, decor_patterns) tree = HierarchyString.new([{ text: text, color: color_method }]) if color_method decor_patterns.each do |pc| analyzed_hierarchy = TextAnalyzer.analyze_hierarchy( tree.substrings, pc[:pattern], color_method, pc[:color_method] ) tree = HierarchyString.new(analyzed_hierarchy) end end tree.decorate end |
#assign_key_value_in_bash(key, value) ⇒ Object
823 824 825 826 827 828 829 830 |
# File 'lib/hash_delegator.rb', line 823 def assign_key_value_in_bash(key, value) if value =~ /["$\\`]/ # requiring ShellWords to write into Bash scripts "#{key}=#{Shellwords.escape(value)}" else "#{key}=\"#{value}\"" end end |
#block_state_for_name_from_cli(block_name) ⇒ Object
find a block by its original (undecorated) name or nickname (not visible in menu) if matched, the block returned has properties that it is from cli and not ui
873 874 875 876 877 878 879 880 881 882 |
# File 'lib/hash_delegator.rb', line 873 def block_state_for_name_from_cli(block_name) SelectedBlockMenuState.new( blocks_find_by_block_name(@dml_blocks_in_file, block_name), OpenStruct.new( block_name_from_cli: true, block_name_from_ui: false ), MenuState::CONTINUE ) end |
#blocks_find_by_block_name(blocks, block_name) ⇒ Object
884 885 886 887 888 889 890 891 892 893 |
# File 'lib/hash_delegator.rb', line 884 def blocks_find_by_block_name(blocks, block_name) @dml_blocks_in_file.find do |item| # 2024-08-04 match oname for long block names # 2024-08-04 match nickname for long block names block_name == item.pub_name || block_name == item.nickname || block_name == item.oname end || @dml_menu_blocks.find do |item| # 2024-08-22 search in menu blocks to allow matching of automatic chrome with nickname block_name == item.pub_name || block_name == item.nickname || block_name == item.oname end end |
#blocks_from_nested_files ⇒ Array<FCB>
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.
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
# File 'lib/hash_delegator.rb', line 839 def blocks_from_nested_files register_console_attributes(@delegate_object) @decor_patterns_from_delegate_object_for_block_create = collect_line_decor_patterns(@delegate_object) blocks = [] iter_blocks_from_nested_files do |btype, fcb| case btype when :blocks if @delegate_object[:bash] fcb.( 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], ) do |oname, color| apply_block_type_color_option(oname, color) end end blocks << fcb when :filter # types accepted %i[blocks line] when :line unless @delegate_object[:no_chrome] create_and_add_chrome_blocks(blocks, fcb) end end end # !!t blocks.count blocks rescue StandardError HashDelegator.error_handler('blocks_from_nested_files') end |
#calc_logged_stdout_filename(block_name:) ⇒ Object
private
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
# File 'lib/hash_delegator.rb', line 897 def calc_logged_stdout_filename(block_name:) return unless @delegate_object[:saved_stdout_folder] @delegate_object[:logged_stdout_filename] = SavedAsset.new( blockname: block_name, filename: @delegate_object[:filename], prefix: @delegate_object[:logged_stdout_filename_prefix], time: Time.now.utc, exts: '.out.txt', saved_asset_format: shell_escape_asset_format( code_lines: @dml_link_state.inherited_lines, shell: ShellType::BASH ) ).generate_name @logged_stdout_filespec = @delegate_object[:logged_stdout_filespec] = File.join @delegate_object[:saved_stdout_folder], @delegate_object[:logged_stdout_filename] end |
#cfile ⇒ Object
920 921 922 923 924 |
# File 'lib/hash_delegator.rb', line 920 def cfile @cfile ||= CachedNestedFileReader.new( import_pattern: @delegate_object.fetch(:import_pattern) #, "^ *@import +(?<name>.+?) *$") ) end |
#check_file_existence(filename) ⇒ Object
Check whether the document exists and is readable
927 928 929 930 931 932 933 934 935 936 937 938 |
# File 'lib/hash_delegator.rb', line 927 def check_file_existence(filename) unless filename&.present? @fout.fout 'No blocks found.' return false end unless File.exist? filename @fout.fout 'Document is missing.' return false end true end |
#code_from_vars_block_to_set_environment_variables(selected) ⇒ Object
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 |
# File 'lib/hash_delegator.rb', line 940 def code_from_vars_block_to_set_environment_variables(selected) code_lines = [] YAML.load(selected.body.join("\n"))&.each do |key, value| ENV[key] = value.to_s require 'shellwords' code_lines.push "#{key}=\"#{Shellwords.escape(value)}\"" next unless @delegate_object[:menu_vars_set_format].present? formatted_string = format(@delegate_object[:menu_vars_set_format], { key: key, value: value }) print string_send_color(formatted_string, :menu_vars_set_color) end code_lines end |
#collect_line_decor_patterns(delegate_object) ⇒ Object
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 |
# File 'lib/hash_delegator.rb', line 957 def collect_line_decor_patterns(delegate_object) extract_patterns = lambda do |key| return [] unless delegate_object[key].present? HashDelegator.safeval(delegate_object[key]).map do |pc| { color_method: pc[:color_method].to_sym, pattern: Regexp.new(pc[:pattern]) } end end %i[line_decor_pre line_decor_main line_decor_post].flat_map do |key| extract_patterns.call(key) end end |
#command_execute(command, shell:, args: []) ⇒ Object
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 |
# File 'lib/hash_delegator.rb', line 974 def command_execute(command, shell:, args: []) @run_state.files = StreamsOut.new @run_state. = @delegate_object @run_state.started_at = Time.now.utc if @delegate_object[:execute_in_own_window] && @delegate_object[:execute_command_format].present? && @run_state.saved_filespec.present? @run_state.in_own_window = true command_execute_in_own_window( args: args, script: @delegate_object[:execute_command_format] ) else @run_state.in_own_window = false command_execute_in_process( args: args, command: command, filename: @delegate_object[:filename], shell: shell ) end @run_state.completed_at = Time.now.utc rescue Errno::ENOENT report_error($ERROR_INFO) rescue SignalException => err # Handle SignalException @run_state.aborted_at = Time.now.utc @run_state. = 'SIGTERM' @run_state.error = err @run_state.files.append_stream_line(ExecutionStreams::STD_ERR, @run_state.) @fout.fout "Error ENOENT: #{err.inspect}" end |
#command_execute_in_own_window(args:, script:) ⇒ Object
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 |
# File 'lib/hash_delegator.rb', line 1010 def command_execute_in_own_window(args:, script:) system( format( script, command_execute_in_own_window_format_arguments( rest: args ? args.join(' ') : '' ) ) ) end |
#command_execute_in_own_window_format_arguments(home: Dir.pwd, rest: '') ⇒ Object
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
# File 'lib/hash_delegator.rb', line 1021 def command_execute_in_own_window_format_arguments(home: Dir.pwd, rest: '') { batch_index: @run_state.batch_index, batch_random: @run_state.batch_random, block_name: @delegate_object[:block_name], document_filename: File.basename(@delegate_object[:filename]), document_filespec: @delegate_object[:filename], home: home, output_filename: File.basename( @delegate_object[:logged_stdout_filespec] ), output_filespec: @delegate_object[:logged_stdout_filespec], rest: rest, script_filename: @run_state.saved_filespec, script_filespec: File.join(home, @run_state.saved_filespec), started_at: @run_state.started_at.strftime( @delegate_object[:execute_command_title_time_format] ) } end |
#command_execute_in_process(args:, command:, filename:, shell:) ⇒ Object
1042 1043 1044 1045 1046 1047 |
# File 'lib/hash_delegator.rb', line 1042 def command_execute_in_process(args:, command:, filename:, shell:) execute_command_with_streams( [shell, '-c', command, @delegate_object[:filename], *args] ) end |
#compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:, link_state:) ⇒ LoadFileLinkState
This method is responsible for handling the execution of
generic blocks in a markdown document.
It collects the required code lines from the document and,
depending on the configuration, may display the code for
user approval before execution. It then executes the approved block.
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 |
# File 'lib/hash_delegator.rb', line 1061 def compile_execute_and_trigger_reuse( mdoc:, selected:, block_source:, link_state: ) required_lines = execute_block_type_port_code_lines( mdoc: mdoc, selected: selected, link_state: link_state, block_source: block_source ) output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve] if output_or_approval display_required_code(required_lines: required_lines) end allow_execution = if @delegate_object[:user_must_approve] prompt_for_user_approval( required_lines: required_lines, selected: selected ) else true end if allow_execution execute_required_lines(required_lines: required_lines, selected: selected, shell: selected.shell) end link_state.block_name = nil end |
#contains_wildcards?(expr) ⇒ Boolean
Check if the expression contains wildcard characters
1092 1093 1094 |
# File 'lib/hash_delegator.rb', line 1092 def contains_wildcards?(expr) expr.match(%r{\*|\?|\[}) end |
#copy_to_clipboard(required_lines) ⇒ Object
1096 1097 1098 1099 1100 1101 1102 |
# File 'lib/hash_delegator.rb', line 1096 def copy_to_clipboard(required_lines) text = required_lines.flatten.join($INPUT_RECORD_SEPARATOR) Clipboard.copy(text) @fout.fout "Clipboard updated: #{required_lines.count} blocks," \ " #{required_lines.flatten.count} lines," \ " #{text.length} characters" end |
#count_blocks_in_filename ⇒ Integer
Counts the number of fenced code blocks in a file. It reads lines from a file and counts occurrences of lines
matching the fenced block regex.
Assumes that every fenced block starts and ends with a
distinct line (hence divided by 2).
1111 1112 1113 1114 1115 1116 1117 1118 |
# File 'lib/hash_delegator.rb', line 1111 def count_blocks_in_filename regex = Regexp.new(@delegate_object[:fenced_start_and_end_regex]) lines = cfile.readlines( @delegate_object[:filename], import_paths: @delegate_object[:import_paths]&.split(':') ) HashDelegator.count_matches_in_lines(lines, regex) / 2 end |
#create_and_add_chrome_block(blocks:, match_data:, format_option:, color_method:, case_conversion: nil, center: nil, decor_patterns: [], wrap: nil) ⇒ Object
Creates and adds a formatted block to the blocks array
based on the provided match and format options.
return number of lines added
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 |
# File 'lib/hash_delegator.rb', line 1131 def create_and_add_chrome_block(blocks:, match_data:, format_option:, color_method:, case_conversion: nil, center: nil, decor_patterns: [], 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 line_cap[:text] ||= '' line_cap[:text] = line_cap[:text].dup if line_cap[:text].frozen? line_cap[:text].gsub!("\t", ' ') # missing capture line_cap[:line] ||= '' accepted_width = @delegate_object[:console_width] - 2 line_caps = if wrap if line_cap[:text].length > accepted_width wrapper = StringWrapper.new( width: accepted_width - line_cap[:indent].length ) wrapper.wrap(line_cap[:text]).map do |line| line_cap.dup.merge(text: line) end else [line_cap] end else [line_cap] 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) else '' end end end line_caps.each do |line_obj| next if line_obj[:text].nil? case case_conversion when :upcase line_obj[:text].upcase! when :downcase line_obj[:text].downcase! end # format expects :line to be text only line_obj[:line] = line_obj[:text] oname = if format_option format(format_option, line_obj) else line_obj[:line] end decorated = apply_tree_decorations( oname, color_method, decor_patterns ) line_obj[:line] = line_obj[:indent] + line_obj[:text] blocks.push FCB.new( chrome: true, disabled: '', dname: line_obj[:indent] + decorated, oname: line_obj[:text] ) end line_caps.count end |
#create_and_add_chrome_blocks(blocks, fcb) ⇒ Object
Processes lines within the file and converts them into
blocks if they match certain criteria.
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 |
# File 'lib/hash_delegator.rb', line 1216 def create_and_add_chrome_blocks(blocks, fcb) # rubocop:disable Layout/LineLength match_criteria = [ { format: :menu_note_format, match: :menu_table_rows_match }, { color: :menu_heading1_color, format: :menu_heading1_format, match: :heading1_match, wrap: true, center: :heading1_center, case_conversion: :upcase }, { color: :menu_heading2_color, format: :menu_heading2_format, match: :heading2_match, wrap: true, center: :heading2_center }, { color: :menu_heading3_color, format: :menu_heading3_format, match: :heading3_match, wrap: true, center: :heading3_center, case_conversion: :downcase }, { color: :menu_divider_color, format: :menu_divider_format, match: :menu_divider_match }, { color: :menu_note_color, format: :menu_note_format, match: :menu_note_match, wrap: true }, { color: :menu_task_color, format: :menu_task_format, match: :menu_task_match, wrap: true } ] # rubocop:enable Layout/LineLength # rubocop:enable Style/UnlessElse match_criteria.each do |criteria| unless @delegate_object[criteria[:match]].present? && (mbody = fcb.body[0].match @delegate_object[criteria[:match]]) next end create_and_add_chrome_block( blocks: blocks, case_conversion: criteria[:case_conversion], center: criteria[:center] && @delegate_object[criteria[:center]], color_method: criteria[:color] && @delegate_object[criteria[:color]].to_sym, decor_patterns: @decor_patterns_from_delegate_object_for_block_create, format_option: criteria[:format] && @delegate_object[criteria[:format]], match_data: mbody, wrap: criteria[:wrap] ) break end end |
#create_divider(position) ⇒ Object
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 |
# File 'lib/hash_delegator.rb', line 1253 def create_divider(position) divider_key = if position == :initial :menu_initial_divider else :menu_final_divider end oname = format(@delegate_object[:menu_divider_format], HashDelegator.safeval(@delegate_object[divider_key])) FCB.new( chrome: true, disabled: '', dname: string_send_color(oname, :menu_divider_color), oname: oname ) end |
#debounce_allows ⇒ Boolean
Prompts user if named block is the same as the prior execution.
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 |
# File 'lib/hash_delegator.rb', line 1273 def debounce_allows return true unless @delegate_object[:debounce_execution] # filter block if selected in menu return true if @run_state.source.block_name_from_cli # return false if @prior_execution_block == @delegate_object[:block_name] if @prior_execution_block == @delegate_object[:block_name] return @allowed_execution_block == @prior_execution_block || prompt_approve_repeat end @prior_execution_block = @delegate_object[:block_name] @allowed_execution_block = nil true end |
#debounce_reset ⇒ Object
1290 1291 1292 |
# File 'lib/hash_delegator.rb', line 1290 def debounce_reset @prior_execution_block = nil end |
#determine_block_state(selected_option) ⇒ SelectedBlockMenuState
Determines the state of a selected block in the menu based
on the selected option.
It categorizes the selected option into either EXIT, BACK,
or CONTINUE state.
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 |
# File 'lib/hash_delegator.rb', line 1302 def determine_block_state(selected_option) return if selected_option.nil? option_name = selected_option[:oname] if option_name == (:menu_option_exit_name) return SelectedBlockMenuState.new(nil, OpenStruct.new, MenuState::EXIT) end if option_name == (:menu_option_back_name) return SelectedBlockMenuState.new(selected_option, OpenStruct.new, MenuState::BACK) end SelectedBlockMenuState.new(selected_option, OpenStruct.new, MenuState::CONTINUE) end |
#display_required_code(required_lines:) ⇒ Object
Displays the required lines of code with color formatting
for the preview section.
It wraps the code lines between a formatted header and
tail.
1328 1329 1330 1331 1332 1333 1334 |
# File 'lib/hash_delegator.rb', line 1328 def display_required_code(required_lines:) output_color_formatted(:script_preview_head, :script_preview_frame_color) required_lines.each { |cb| @fout.fout cb } output_color_formatted(:script_preview_tail, :script_preview_frame_color) end |
#divider_formatting_present?(position) ⇒ Boolean
1336 1337 1338 1339 1340 1341 1342 1343 1344 |
# File 'lib/hash_delegator.rb', line 1336 def divider_formatting_present?(position) divider_key = if position == :initial :menu_initial_divider else :menu_final_divider end @delegate_object[:menu_divider_format].present? && @delegate_object[divider_key].present? end |
#dml_menu_append_chrome_item(name, count, type, menu_state: MenuState::LOAD, always_create: true, always_enable: true) ⇒ Object
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 |
# File 'lib/hash_delegator.rb', line 1346 def ( name, count, type, menu_state: MenuState::LOAD, always_create: true, always_enable: true ) raise unless name.present? raise if @dml_menu_blocks.nil? item = @dml_menu_blocks.find { |block| block.oname == name } # create menu item when it is needed (count > 0) # if item.nil? && (always_create || count.positive?) item = append_chrome_block(menu_blocks: @dml_menu_blocks, menu_state: ) end # update item if it exists # return unless item item.dname = type.present? ? "#{name} (#{count} #{type})" : name if always_enable || count.positive? item.delete(:disabled) else item[:disabled] = '' end end |
#do_save_execution_output ⇒ Object
1374 1375 1376 1377 1378 1379 1380 1381 |
# File 'lib/hash_delegator.rb', line 1374 def do_save_execution_output return unless @delegate_object[:save_execution_output] return if @run_state.in_own_window @run_state.files.write_execution_output_to_file( @delegate_object[:logged_stdout_filespec] ) end |
#document_name_in_glob_as_file_name(document_filename: @dml_link_state.document_filename, format_glob: , remove_regexp: %r{^\./}, subst_regexp: /[\/:\.\* ]/, subst_string: '_') ⇒ Object
remove leading “./” replace characters: / : . * (space) with: (underscore)
1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 |
# File 'lib/hash_delegator.rb', line 1385 def document_name_in_glob_as_file_name( document_filename: @dml_link_state.document_filename, format_glob: @delegate_object[:document_saved_lines_glob], remove_regexp: %r{^\./}, subst_regexp: /[\/:\.\* ]/, subst_string: '_' ) if document_filename.nil? || document_filename.empty? return document_filename end format( format_glob, { document_filename: document_filename.gsub(remove_regexp, '') .gsub(subst_regexp, subst_string) } ) end |
#dump_and_warn_block_state(name:, selected:) ⇒ Object
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 |
# File 'lib/hash_delegator.rb', line 1404 def dump_and_warn_block_state(name:, selected:) if selected.nil? Exceptions.warn_format("Block not found -- name: #{name}", { abort: true }) end return unless @delegate_object[:dump_selected_block] warn selected.to_yaml.sub(/^(?:---\n)?/, "Block:\n") end |
#dump_delobj(blocks_in_file, menu_blocks, link_state) ⇒ Object
Outputs warnings based on the delegate object’s configuration
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 |
# File 'lib/hash_delegator.rb', line 1423 def dump_delobj(blocks_in_file, , link_state) if @delegate_object[:dump_delegate_object] warn format_and_highlight_hash(@delegate_object, label: '@delegate_object') end if @delegate_object[:dump_blocks_in_file] warn format_and_highlight_dependencies( compact_and_index_hash(blocks_in_file), label: 'blocks_in_file' ) end if @delegate_object[:dump_menu_blocks] warn format_and_highlight_dependencies( compact_and_index_hash(), label: 'menu_blocks' ) end if @delegate_object[:dump_inherited_block_names] warn format_and_highlight_lines(link_state.inherited_block_names, label: 'inherited_block_names') end if @delegate_object[:dump_inherited_dependencies] warn format_and_highlight_lines(link_state.inherited_dependencies, label: 'inherited_dependencies') end return unless @delegate_object[:dump_inherited_lines] warn format_and_highlight_lines(link_state.inherited_lines, label: 'inherited_lines') end |
#edit_text(initial_text, temp_name: 'edit_text') ⇒ String?
Opens text in an editor for user modification and
returns the modified text.
This method reads the provided text, opens it in the default editor, and allows the user to modify it. If the user makes changes, the modified text is returned. If the user exits the editor without making changes or the editor is closed abruptly, appropriate messages are displayed.
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 |
# File 'lib/hash_delegator.rb', line 1471 def edit_text(initial_text, temp_name: 'edit_text') # Create a temporary file to store the initial text temp_file = Tempfile.new(temp_name) temp_file.write(initial_text) temp_file.rewind # Capture the modification time of the temporary file before editing before_mtime = temp_file.mtime # Open the temporary file in the default editor system("#{ENV['EDITOR'] || 'vi'} #{temp_file.path}") # Capture the exit status of the editor editor_exit_status = $?.exitstatus # Reopen the file to ensure the updated modification time is read temp_file.open after_mtime = temp_file.mtime # Check if the editor was exited normally or was interrupted if editor_exit_status != 0 warn 'The editor was closed abruptly. No changes were made.' temp_file.close temp_file.unlink return end result_text = nil # Read the file if it was modified if before_mtime != after_mtime temp_file.rewind result_text = temp_file.read end # Remove the temporary file temp_file.close temp_file.unlink result_text end |
#execute_block_by_type_for_lfls(selected:, mdoc:, block_source:, link_state: LinkState.new) ⇒ Object
Execute a code block after approval and provide user interaction options.
This method displays required code blocks, asks for user approval, and executes the code block if approved. It also allows users to copy the code to the clipboard or save it to a file.
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 |
# File 'lib/hash_delegator.rb', line 1521 def execute_block_by_type_for_lfls( selected:, mdoc:, block_source:, link_state: LinkState.new ) # !!v selected # order should not be important other than else clause if selected.type == BlockType::EDIT debounce_reset # !!v link_state.inherited_lines_block vux_edit_inherited return :break if pause_user_exit next_state_append_code(selected, link_state, []) elsif selected.type == BlockType::HISTORY # !!b debounce_reset return :break if execute_block_type_history_ux( selected: selected, link_state: link_state ) == :no_history LoadFileLinkState.new(LoadFile::REUSE, link_state) elsif selected.type == BlockType::LINK debounce_reset execute_block_type_link_with_state(link_block_body: selected.body, mdoc: mdoc, selected: selected, link_state: link_state, block_source: block_source) elsif selected.type == BlockType::LOAD debounce_reset code_lines = execute_block_type_load_code_lines(selected) next_state_append_code(selected, link_state, code_lines) elsif selected.type == BlockType::SAVE debounce_reset execute_block_type_save( code_lines: link_state&.inherited_lines, selected: selected ) LoadFileLinkState.new(LoadFile::REUSE, link_state) elsif selected.type == BlockType::VIEW debounce_reset vux_view_inherited(stream: $stderr) return :break if pause_user_exit LoadFileLinkState.new(LoadFile::REUSE, link_state) # from CLI elsif selected.nickname == @delegate_object[:menu_option_exit_name][:line] debounce_reset LoadFileLinkState.new(LoadFile::EXIT, link_state) elsif @menu_user_clicked_back_link debounce_reset LoadFileLinkState.new( LoadFile::LOAD, pop_link_history_new_state ) elsif selected.type == BlockType::OPTS debounce_reset code_lines = [] = ( link_state: link_state, mdoc: @dml_mdoc, selected: selected ) (.) link_state = LinkState.new next_state_append_code(selected, link_state, code_lines) elsif selected.type == BlockType::PORT debounce_reset required_lines = execute_block_type_port_code_lines( mdoc: @dml_mdoc, selected: selected, link_state: link_state, block_source: block_source ) next_state_set_code(selected, link_state, required_lines) elsif selected.type == BlockType::VARS debounce_reset next_state_append_code(selected, link_state, code_from_vars_block_to_set_environment_variables(selected)) elsif debounce_allows compile_execute_and_trigger_reuse(mdoc: mdoc, selected: selected, link_state: link_state, block_source: block_source) LoadFileLinkState.new(LoadFile::REUSE, link_state) else LoadFileLinkState.new(LoadFile::REUSE, link_state) end end |
#execute_block_for_state_and_name(selected:, mdoc:, link_state:, block_source: {}) ⇒ Object
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 |
# File 'lib/hash_delegator.rb', line 1626 def execute_block_for_state_and_name( selected:, mdoc:, link_state:, block_source: {} ) lfls = execute_block_by_type_for_lfls( selected: selected, mdoc: mdoc, link_state: link_state, block_source: block_source ) # if the same menu is being displayed, collect the display name # of the selected menu item for use as the default item [lfls.link_state, lfls.load_file == LoadFile::LOAD ? nil : selected.dname, # 2024-08-22 true to quit lfls.load_file == LoadFile::EXIT] end |
#execute_block_in_state(block_name) ⇒ Object
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 |
# File 'lib/hash_delegator.rb', line 1644 def execute_block_in_state(block_name) @dml_block_state = block_state_for_name_from_cli(block_name) dump_and_warn_block_state(name: block_name, selected: @dml_block_state.block) @dml_link_state, @dml_menu_default_dname, quit = execute_block_for_state_and_name( selected: @dml_block_state.block, mdoc: @dml_mdoc, link_state: @dml_link_state, block_source: { document_filename: @delegate_object[:filename], time_now_date: Time.now.utc.strftime( @delegate_object[:shell_code_label_time_format] ) } ) :break if quit end |
#execute_block_type_history_ux(directory: , filename: '*', form: '%{line}', link_state:, regexp: "^(?<line>.*)$", selected:) ⇒ Object
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 |
# File 'lib/hash_delegator.rb', line 1663 def execute_block_type_history_ux( directory: @delegate_object[:document_configurations_directory], filename: '*', form: '%{line}', link_state:, regexp: "^(?<line>.*)$", selected: ) block_data = HashDelegator.parse_yaml_data_from_body(selected.body) files_table_rows = read_saved_assets_for_history_table( filename: filename, form: form, path: block_data['directory'] || directory, regexp: regexp ) return :no_history unless files_table_rows execute_history_select(files_table_rows, stream: $stderr) end |
#execute_block_type_link_with_state(link_block_body: [], mdoc: nil, selected: FCB.new, link_state: LinkState.new, block_source: {}) ⇒ LoadFileLinkState
Handles the processing of a link block in Markdown Execution. It loads YAML data from the link_block_body content,
pushes the state to history, sets environment variables,
and decides on the next block to load.
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 |
# File 'lib/hash_delegator.rb', line 1694 def execute_block_type_link_with_state( link_block_body: [], mdoc: nil, selected: FCB.new, link_state: LinkState.new, block_source: {} ) # !!p link_block_body selected link_block_data = HashDelegator.parse_yaml_data_from_body(link_block_body) # !!v link_block_data ## collect blocks specified by block # if mdoc code_info = mdoc.collect_recursively_required_code( anyname: selected.pub_name, label_format_above: @delegate_object[:shell_code_label_format_above], label_format_below: @delegate_object[:shell_code_label_format_below], block_source: block_source ) code_lines = code_info[:code] block_names = code_info[:block_names] dependencies = code_info[:dependencies] else block_names = [] code_lines = [] dependencies = {} end # load key and values from link block into current environment # if link_block_data[LinkKeys::VARS] code_lines.push BashCommentFormatter.format_comment(selected.pub_name) (link_block_data[LinkKeys::VARS] || []).each do |(key, value)| ENV[key] = value.to_s code_lines.push(assign_key_value_in_bash(key, value)) end end ## append blocks loaded # if (load_expr = link_block_data.fetch(LinkKeys::LOAD, '')).present? load_filespec = load_filespec_from_expression(load_expr) if load_filespec begin code_lines += File.readlines(load_filespec, chomp: true) rescue Errno::ENOENT report_error($ERROR_INFO) end end end # if an eval link block, evaluate code_lines and return its standard output # if link_block_data.fetch(LinkKeys::EVAL, false) || link_block_data.fetch(LinkKeys::EXEC, false) code_lines = link_block_data_eval( link_state, code_lines, selected, link_block_data, block_source: block_source, shell: @delegate_object[:block_type_default] ) end # config next state # next_document_filename = write_inherited_lines_to_file(link_state, link_block_data) next_block_name = link_block_data.fetch( LinkKeys::NEXT_BLOCK, nil ) || link_block_data.fetch(LinkKeys::BLOCK, nil) || '' if link_block_data[LinkKeys::RETURN] pop_add_current_code_to_head_and_trigger_load( link_state, block_names, code_lines, dependencies, selected, next_block_name: next_block_name ) else next_keep_code = link_state&.keep_code || link_block_data.fetch('keep', false) #/*LinkKeys::KEEP*/ link_history_push_and_next( curr_block_name: selected.pub_name, curr_document_filename: @delegate_object[:filename], inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq, inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data inherited_lines: HashDelegator.code_merge( link_state&.inherited_lines, code_lines ), keep_code: link_state&.keep_code, next_block_name: next_block_name, next_document_filename: next_document_filename, next_keep_code: next_keep_code, next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD ) end end |
#execute_block_type_load_code_lines(selected, directory: , filename_pattern: , glob: , view: ) ⇒ Object
1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 |
# File 'lib/hash_delegator.rb', line 1791 def execute_block_type_load_code_lines( selected, directory: @delegate_object[:document_configurations_directory], filename_pattern: @delegate_object[:vars_block_filename_pattern], glob: @delegate_object[:document_configurations_glob], view: @delegate_object[:vars_block_filename_view] ) # !!p selected block_data = HashDelegator.parse_yaml_data_from_body(selected.body) # !!v block_data if selected_option = ( prompt_title, Dir.glob( File.join( Dir.pwd, block_data['directory'] || directory, block_data['glob'] || glob ) ).sort.map do |file| { name: format( block_data['view'] || view, NamedCaptureExtractor::extract_named_group2( file.match( Regexp.new(block_data['filename_pattern'] || filename_pattern) ) ) ), oname: file } end, ) File.readlines(selected_option.oname, chomp: true) else warn "No matching files found" ### end end |
#execute_block_type_port_code_lines(mdoc:, selected:, block_source:, link_state: LinkState.new) ⇒ Array<String>
Collects required code lines based on the selected block and
the delegate object's configuration.
If the block type is VARS, it also sets environment variables
based on the block's content.
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 |
# File 'lib/hash_delegator.rb', line 1837 def execute_block_type_port_code_lines(mdoc:, selected:, block_source:, link_state: LinkState.new) required = mdoc.collect_recursively_required_code( anyname: selected.pub_name, label_format_above: @delegate_object[:shell_code_label_format_above], label_format_below: @delegate_object[:shell_code_label_format_below], block_source: block_source ) # !!t 'required' dependencies = ( link_state&.inherited_dependencies || {} ).merge(required[:dependencies] || {}) required[:unmet_dependencies] = ( required[:unmet_dependencies] || [] ) - (link_state&.inherited_block_names || []) if required[:unmet_dependencies].present? ### filter against link_state.inherited_block_names warn format_and_highlight_dependencies( dependencies, highlight: required[:unmet_dependencies] ) runtime_exception( :runtime_exception_error_level, 'unmet_dependencies, flag: runtime_exception_error_level', required[:unmet_dependencies] ) elsif @delegate_object[:dump_dependencies] warn format_and_highlight_dependencies( dependencies, highlight: [@delegate_object[:block_name]] ) end if selected[:type] == BlockType::OPTS # body of blocks is returned as a list of lines to be read an YAML HashDelegator.code_merge(required[:blocks].map(&:body).flatten(1)) else code_lines = if selected.type == BlockType::VARS code_from_vars_block_to_set_environment_variables(selected) else [] end HashDelegator.code_merge(link_state&.inherited_lines, required[:code] + code_lines) end end |
#execute_block_type_save(code_lines:, selected:) ⇒ Object
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 |
# File 'lib/hash_delegator.rb', line 1883 def execute_block_type_save(code_lines:, selected:) # !!p code_lines, selected block_data = HashDelegator.parse_yaml_data_from_body(selected.body) # !!v block_data directory_glob = if block_data['directory'] # !!b File.join( block_data['directory'], block_data['glob'] || @delegate_object[:document_saved_lines_glob].split('/').last ) else # !!b @delegate_object[:document_saved_lines_glob] end # !!v directory_glob save_filespec_from_expression(directory_glob).tap do |save_filespec| if save_filespec begin File.write(save_filespec, HashDelegator.join_code_lines(code_lines)) rescue Errno::ENOENT report_error($ERROR_INFO) end end end end |
#execute_command_with_streams(command) {|stdin, stdout, stderr, thread| ... } ⇒ Integer
Executes a given command and processes its
input, output, and error streams.
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 |
# File 'lib/hash_delegator.rb', line 1928 def execute_command_with_streams(command) exit_status = nil Open3.popen3(*command) do |stdin, stdout, stderr, exec_thread| # Handle stdout stream handle_stream(stream: stdout, file_type: ExecutionStreams::STD_OUT) do |line| yield nil, line, nil, exec_thread if block_given? end # Handle stderr stream handle_stream(stream: stderr, file_type: ExecutionStreams::STD_ERR) do |line| yield nil, nil, line, exec_thread if block_given? end # Handle stdin stream input_thread = handle_stream(stream: $stdin, file_type: ExecutionStreams::STD_IN) do |line| stdin.puts(line) yield line, nil, nil, exec_thread if block_given? end # Wait for all streams to be processed wait_for_stream_processing exec_thread.join # Ensure the input thread is killed if it's still alive sleep 0.1 input_thread.kill if input_thread&.alive? # Retrieve the exit status exit_status = exec_thread.value.exitstatus end exit_status end |
#execute_history_select(files_table_rows, exit_prompt: , pause_refresh: false, stream:) ⇒ Object
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 |
# File 'lib/hash_delegator.rb', line 1966 def execute_history_select( files_table_rows, exit_prompt: @delegate_object[:prompt_filespec_back], pause_refresh: false, stream: ) # repeat select+display until user exits pause_now = false row_attrib = :row loop do if pause_now && (prompt_select_continue == MenuState::EXIT) break end # menu with Back and Facet options at top case (name = prompt_select_code_filename( [exit_prompt, @delegate_object[:prompt_filespec_facet]] + files_table_rows.map(&row_attrib), string: @delegate_object[:prompt_select_history_file], color_sym: :prompt_color_after_script_execution )) when exit_prompt break when @delegate_object[:prompt_filespec_facet] row_attrib = row_attrib == :row ? :file : :row pause_now = false else file = files_table_rows.select { |ftr| ftr.row == name }&.first info = file_info(file.file) stream.puts "#{file.file} - #{info[:lines]} lines / " \ "#{info[:size]} bytes" stream.puts( File.readlines(file.file, chomp: false).map.with_index do |line, ind| format(' %s. %s', AnsiString.new(format('% 4d', ind + 1)).send(:violet), line) end ) pause_now = pause_refresh end end end |
#execute_inherited_save(code_lines: @dml_link_state.inherited_lines) ⇒ Object
2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 |
# File 'lib/hash_delegator.rb', line 2012 def execute_inherited_save( code_lines: @dml_link_state.inherited_lines ) return unless save_filespec = save_filespec_from_expression( document_name_in_glob_as_file_name ) unless write_file_with_directory_creation( content: HashDelegator.join_code_lines(code_lines), filespec: save_filespec ) :break end end |
#execute_navigate_back ⇒ Object
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 |
# File 'lib/hash_delegator.rb', line 2027 def execute_navigate_back @menu_user_clicked_back_link = true keep_code = @dml_link_state.keep_code inherited_lines = keep_code ? @dml_link_state.inherited_lines_block : nil @dml_link_state = pop_link_history_new_state { block_name: @dml_link_state.block_name, document_filename: @dml_link_state.document_filename, inherited_lines: inherited_lines, keep_code: keep_code } end |
#execute_required_lines(required_lines: [], selected: FCB.new, shell:) ⇒ Object
Executes a block of code that has been approved for execution. It sets the script block name, writes command files if
required,
and handles the execution
including output formatting and summarization.
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 |
# File 'lib/hash_delegator.rb', line 2051 def execute_required_lines( required_lines: [], selected: FCB.new, shell: ) if @delegate_object[:save_executed_script] write_command_file(required_lines: required_lines, selected: selected, shell: shell) end if @dml_block_state calc_logged_stdout_filename(block_name: @dml_block_state.block.oname) end format_and_execute_command(code_lines: required_lines, shell: shell) post_execution_process end |
#fetch_color(default: '', data_sym: :execution_report_preview_head, color_sym: :execution_report_preview_frame_color) ⇒ String
Retrieves a specific data symbol from the delegate object, converts it to a string, and applies a color style based on the specified color symbol.
2077 2078 2079 2080 2081 2082 |
# File 'lib/hash_delegator.rb', line 2077 def fetch_color(default: '', data_sym: :execution_report_preview_head, color_sym: :execution_report_preview_frame_color) data_string = @delegate_object.fetch(data_sym, default).to_s string_send_color(data_string, color_sym) end |
#file_info(file_path) ⇒ Object
size of a file in bytes and the number of lines
2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 |
# File 'lib/hash_delegator.rb', line 2085 def file_info(file_path) file_size = 0 line_count = 0 File.open(file_path, 'r') do |file| file.each_line do |_line| line_count += 1 end file_size = file.size end { size: file_size, lines: line_count } end |
#format_and_execute_command(code_lines:, shell:) ⇒ Object
2099 2100 2101 2102 2103 2104 2105 2106 |
# File 'lib/hash_delegator.rb', line 2099 def format_and_execute_command(code_lines:, shell:) formatted_command = code_lines.flatten.join("\n") @fout.fout fetch_color(data_sym: :script_execution_head, color_sym: :script_execution_frame_color) command_execute(formatted_command, args: @pass_args, shell: shell) @fout.fout fetch_color(data_sym: :script_execution_tail, color_sym: :script_execution_frame_color) end |
#format_expression(expr) ⇒ Object
Format expression using environment variables and run state
2109 2110 2111 2112 2113 |
# File 'lib/hash_delegator.rb', line 2109 def format_expression(expr) data = link_load_format_data ENV.each { |key, value| data[key.to_sym] = value } format(expr, data) end |
#format_references_send_color(color_sym: :execution_report_preview_frame_color, context: {}, default: '', format_sym: :output_execution_label_format) ⇒ String
Formats a string based on a given context and
applies color styling to it.
It retrieves format and color information from
the delegate object and processes accordingly.
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 |
# File 'lib/hash_delegator.rb', line 2128 def format_references_send_color( color_sym: :execution_report_preview_frame_color, context: {}, default: '', format_sym: :output_execution_label_format ) formatted_string = format(@delegate_object.fetch(format_sym, ''), context).to_s string_send_color(formatted_string, color_sym) end |
#formatted_expression(expr) ⇒ Object
Expand expression if it contains format specifiers
2140 2141 2142 |
# File 'lib/hash_delegator.rb', line 2140 def formatted_expression(expr) expr.include?('%{') ? format_expression(expr) : expr end |
#fout_execution_report ⇒ Object
2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 |
# File 'lib/hash_delegator.rb', line 2144 def fout_execution_report @fout.fout fetch_color(data_sym: :execution_report_preview_head, color_sym: :execution_report_preview_frame_color) [ ['Block', @run_state.script_block_name], ['Command', ([MarkdownExec::BIN_NAME, @delegate_object[:filename]] + (@run_state.link_history.map { |item| item[:block_name] }) + [@run_state.script_block_name]).join(' ')], ['Script', @run_state.saved_filespec], ['StdOut', @delegate_object[:logged_stdout_filespec]] ].each do |label, value| next unless value output_labeled_value(label, value, DISPLAY_LEVEL_ADMIN) end @fout.fout fetch_color(data_sym: :execution_report_preview_tail, color_sym: :execution_report_preview_frame_color) end |
#generate_temp_filename(ext = '.sh') ⇒ Object
2165 2166 2167 2168 2169 2170 2171 2172 2173 |
# File 'lib/hash_delegator.rb', line 2165 def generate_temp_filename(ext = '.sh') filename = begin Dir::Tmpname.make_tmpname(['x', ext], nil) rescue NoMethodError require 'securerandom' "#{SecureRandom.urlsafe_base64}#{ext}" end File.join(Dir.tmpdir, filename) end |
#handle_back_or_continue(block_state) ⇒ Object
Updates the delegate object’s state based on the provided block state. It sets the block name and determines
if the user clicked the back link in the menu.
2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 |
# File 'lib/hash_delegator.rb', line 2181 def handle_back_or_continue(block_state) return if block_state.nil? unless [MenuState::BACK, MenuState::CONTINUE].include?(block_state.state) return end @delegate_object[:block_name] = block_state.block.pub_name @menu_user_clicked_back_link = block_state.state == MenuState::BACK end |
#handle_stream(stream:, file_type:, swap: false) ⇒ Object
2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 |
# File 'lib/hash_delegator.rb', line 2192 def handle_stream(stream:, file_type:, swap: false) @process_mutex.synchronize do Thread.new do stream.each_line do |line| line.strip! if @run_state.files.streams @run_state.files.append_stream_line(file_type, line) end puts line if @delegate_object[:output_stdout] yield line if block_given? end rescue IOError # Handle IOError ensure @process_cv.signal end end end |
#history_files(link_state, direction: :reverse, filename: nil, home: Dir.pwd, order: :chronological, path: '') ⇒ Object
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 |
# File 'lib/hash_delegator.rb', line 2214 def history_files( link_state, direction: :reverse, filename: nil, home: Dir.pwd, order: :chronological, path: '' ) # !!v filename, 'path', path # !!v File.join(home, path, filename) files = Dir.glob( File.join(home, path, filename) ) # !!v files sorted_files = case order when :alphabetical files.sort when :chronological files.sort_by { |file| File.mtime(file) } else raise ArgumentError, "Invalid order: #{order}" end direction == :reverse ? sorted_files.reverse : sorted_files end |
#initial_state ⇒ Object
Initializes variables for regex and other states
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 |
# File 'lib/hash_delegator.rb', line 2241 def initial_state { fenced_start_and_end_regex: Regexp.new(@delegate_object.fetch( :fenced_start_and_end_regex, '^(?<indent> *)`{3,}' )), fenced_start_extended_regex: Regexp.new(@delegate_object.fetch( :fenced_start_and_end_regex, '^(?<indent> *)`{3,}' )), fcb: MarkdownExec::FCB.new, in_fenced_block: false, headings: [] } end |
#iter_blocks_from_nested_files {|Symbol| ... } ⇒ Object
Iterates through blocks in a file, applying the provided block to each line. The iteration only occurs if the file exists.
2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 |
# File 'lib/hash_delegator.rb', line 2262 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(':') ).each do |nested_line| if nested_line update_line_and_block_state(nested_line, state, selected_types, &block) end end end |
#iter_source_blocks(source, &block) ⇒ Object
2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 |
# File 'lib/hash_delegator.rb', line 2278 def iter_source_blocks(source, &block) # !!v source case source when 1 blocks_from_nested_files.each(&block) when 2 @dml_blocks_in_file.each(&block) when 3 @dml_menu_blocks.each(&block) else iter_blocks_from_nested_files do |btype, fcb| case btype when :blocks yield fcb when :filter %i[blocks] end end end end |
#link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source:, shell:) ⇒ Object
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 |
# File 'lib/hash_delegator.rb', line 2299 def link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source:, shell:) all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines) output_lines = [] Tempfile.open do |file| cmd = "#{shell} #{file.path}" file.write(all_code.join("\n")) file.rewind if link_block_data.fetch(LinkKeys::EXEC, false) @run_state.files = StreamsOut.new execute_command_with_streams([cmd]) do |_stdin, stdout, stderr, _thread| line = stdout || stderr output_lines.push(line) if line end ## select output_lines that look like assignment or match other specs # output_lines = process_string_array( output_lines, begin_pattern: @delegate_object.fetch(:output_assignment_begin, nil), end_pattern: @delegate_object.fetch(:output_assignment_end, nil), scan1: @delegate_object.fetch(:output_assignment_match, nil), format1: @delegate_object.fetch(:output_assignment_format, nil) ) else output_lines = `#{cmd}`.split("\n") end end unless output_lines HashDelegator.error_handler('all_code eval output_lines is nil', { abort: true }) end label_format_above = @delegate_object[:shell_code_label_format_above] label_format_below = @delegate_object[:shell_code_label_format_below] [label_format_above.present? && format(label_format_above, block_source.merge({ block_name: selected.pub_name }))] + output_lines.map do |line| re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)')) next unless re =~ line re.gsub_format(line, link_block_data.fetch('format', '%{line}')) end.compact + [label_format_below.present? && format(label_format_below, block_source.merge({ block_name: selected.pub_name }))] end |
#link_history_push_and_next(curr_block_name:, curr_document_filename:, inherited_block_names:, inherited_dependencies:, inherited_lines:, keep_code:, next_block_name:, next_document_filename:, next_keep_code:, next_load_file:) ⇒ Object
2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 |
# File 'lib/hash_delegator.rb', line 2357 def link_history_push_and_next( curr_block_name:, curr_document_filename:, inherited_block_names:, inherited_dependencies:, inherited_lines:, keep_code:, next_block_name:, next_document_filename:, next_keep_code:, next_load_file: ) @link_history.push( LinkState.new( block_name: curr_block_name, document_filename: curr_document_filename, inherited_block_names: inherited_block_names, inherited_dependencies: inherited_dependencies, inherited_lines: inherited_lines, keep_code: keep_code ) ) LoadFileLinkState.new( next_load_file, LinkState.new( block_name: next_block_name, document_filename: next_document_filename, inherited_block_names: inherited_block_names, inherited_dependencies: inherited_dependencies, inherited_lines: inherited_lines, keep_code: next_keep_code ) ) end |
#link_load_format_data ⇒ Object
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 |
# File 'lib/hash_delegator.rb', line 2388 def link_load_format_data { batch_index: @run_state.batch_index, batch_random: @run_state.batch_random, block_name: @delegate_object[:block_name], document_filename: File.basename(@delegate_object[:filename]), document_filespec: @delegate_object[:filename], home: Dir.pwd, started_at: Time.now.utc.strftime( @delegate_object[:execute_command_title_time_format] ) } end |
#list_blocks ⇒ Object
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 |
# File 'lib/hash_delegator.rb', line 2402 def list_blocks # !!b = @delegate_object[:list_blocks_message] block_eval = @delegate_object[:list_blocks_eval] # !!v message block_eval list = [] iter_source_blocks(@delegate_object[:list_blocks_type]) do |block| # !!v block list << (block_eval.present? ? eval(block_eval) : block.send()) end list.compact! # !!v list @fout.fout_list(list) end |
#load_auto_opts_block(all_blocks, mdoc:) ⇒ Boolean?
Loads auto blocks based on delegate object settings and updates
if new filename is detected.
Executes a specified block once per filename.
2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 |
# File 'lib/hash_delegator.rb', line 2424 def load_auto_opts_block(all_blocks, mdoc:) block_name = @delegate_object[:document_load_opts_block_name] unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename] return end block = HashDelegator.block_find(all_blocks, :oname, block_name) return unless block = ( mdoc: mdoc, selected: block ) (.) @most_recent_loaded_filename = @delegate_object[:filename] true end |
#load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [], default: nil) ⇒ Object
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 |
# File 'lib/hash_delegator.rb', line 2444 def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [], default: nil) # !!b 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, , default) return if block_state.nil? block = block_state.block source = OpenStruct.new(block_name_from_ui: true) state = block_state.state end SelectedBlockMenuState.new(block, source, state) end |
#load_filespec_from_expression(expression) ⇒ Object
format + glob + select for file in load block name has references to ENV vars and doc and batch vars
incl.
2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 |
# File 'lib/hash_delegator.rb', line 2468 def load_filespec_from_expression(expression) # Process expression with embedded formatting = formatted_expression(expression) # Handle wildcards or direct file specification if contains_wildcards?() load_filespec_wildcard_expansion() else end end |
#load_filespec_wildcard_expansion(expr, auto_load_single: false) ⇒ Object
Handle expression with wildcard characters
2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 |
# File 'lib/hash_delegator.rb', line 2481 def load_filespec_wildcard_expansion(expr, auto_load_single: false) files = find_files(expr) if files.count.zero? HashDelegator.error_handler("no files found with '#{expr}' ", { abort: true }) elsif auto_load_single && files.count == 1 files.first else ## user selects from existing files or other # case (name = prompt_select_code_filename( [@delegate_object[:prompt_filespec_back]] + files, string: @delegate_object[:prompt_select_code_file], color_sym: :prompt_color_after_script_execution )) when @delegate_object[:prompt_filespec_back] # do nothing else name end end end |
#manage_cli_selection_state(block_name_from_cli:, now_using_cli:, link_state:) ⇒ Object
2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 |
# File 'lib/hash_delegator.rb', line 2504 def manage_cli_selection_state(block_name_from_cli:, now_using_cli:, link_state:) if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name] # !!b 'pause cli control, allow user to select block' block_name_from_cli = false now_using_cli = false @menu_base_options[:block_name] = @delegate_object[:block_name] = \ link_state.block_name = @cli_block_name = nil end @delegate_object = @menu_base_options.dup @menu_user_clicked_back_link = false [block_name_from_cli, now_using_cli] end |
#mdoc_and_blocks_from_nested_files ⇒ Object
2522 2523 2524 2525 2526 2527 2528 |
# File 'lib/hash_delegator.rb', line 2522 def mdoc_and_blocks_from_nested_files = blocks_from_nested_files mdoc = MDoc.new() do |nopts| @delegate_object.merge!(nopts) end [, mdoc] end |
#mdoc_menu_and_blocks_from_nested_files(link_state) ⇒ Object
Handles the file loading and returns the blocks
in the file and MDoc instance
2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 |
# File 'lib/hash_delegator.rb', line 2533 def (link_state) all_blocks, mdoc = mdoc_and_blocks_from_nested_files # recreate menu with new options # if load_auto_opts_block(all_blocks, mdoc: mdoc) all_blocks, mdoc = mdoc_and_blocks_from_nested_files end = mdoc.(@delegate_object) variable_expansions!(menu_blocks: , link_state: link_state) (menu_blocks: , link_state: link_state) ### compress empty lines HashDelegator.delete_consecutive_blank_lines!() HashDelegator.tables_into_columns!(, @delegate_object) [all_blocks, , mdoc] # !!r end |
#menu_add_disabled_option(document_glob) ⇒ Object
2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 |
# File 'lib/hash_delegator.rb', line 2553 def (document_glob) raise unless document_glob.present? raise if @dml_menu_blocks.nil? block = @dml_menu_blocks.find { |item| item.oname == document_glob } # create menu item when it is needed (count > 0) # return unless block.nil? chrome_block = FCB.new( chrome: true, disabled: '', dname: HashDelegator.new(@delegate_object).string_send_color( document_glob, :menu_inherited_lines_color ), oname: formatted_name ) if insert_at_top @dml_menu_blocks.unshift(chrome_block) else @dml_menu_blocks.push(chrome_block) end end |
#menu_chrome_colored_option(option_symbol = :menu_option_back_name) ⇒ String
Formats and optionally colors a menu option based on delegate
object's configuration.
2585 2586 2587 2588 2589 2590 |
# File 'lib/hash_delegator.rb', line 2585 def (option_symbol = :menu_option_back_name) formatted_option = (option_symbol) return formatted_option unless @delegate_object[:menu_chrome_color] string_send_color(formatted_option, :menu_chrome_color) end |
#menu_chrome_formatted_option(option_symbol = :menu_option_back_name) ⇒ String
Formats a menu option based on the delegate object’s configuration. It safely evaluates the value of the option and optionally formats it.
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 |
# File 'lib/hash_delegator.rb', line 2597 def (option_symbol = :menu_option_back_name) option_value = HashDelegator.safeval(@delegate_object.fetch( option_symbol, '' )) if @delegate_object[:menu_chrome_format] format(@delegate_object[:menu_chrome_format], option_value) else option_value end end |
#next_state_append_code(selected, link_state, code_lines) ⇒ Object
2621 2622 2623 2624 2625 2626 2627 |
# File 'lib/hash_delegator.rb', line 2621 def next_state_append_code(selected, link_state, code_lines) next_state_set_code( selected, link_state, HashDelegator.code_merge(link_state&.inherited_lines, code_lines) ) end |
#next_state_set_code(selected, link_state, code_lines) ⇒ Object
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 |
# File 'lib/hash_delegator.rb', line 2629 def next_state_set_code(selected, link_state, code_lines) block_names = [] dependencies = {} link_history_push_and_next( curr_block_name: selected.pub_name, curr_document_filename: @delegate_object[:filename], inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq, inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data inherited_lines: HashDelegator.code_merge(code_lines), keep_code: link_state&.keep_code, next_block_name: '', next_document_filename: @delegate_object[:filename], next_keep_code: false, next_load_file: LoadFile::REUSE ) end |
#output_color_formatted(data_sym, color_sym) ⇒ Object
2648 2649 2650 2651 2652 |
# File 'lib/hash_delegator.rb', line 2648 def output_color_formatted(data_sym, color_sym) formatted_string = string_send_color(@delegate_object[data_sym], color_sym) @fout.fout formatted_string end |
#output_execution_summary ⇒ Object
2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 |
# File 'lib/hash_delegator.rb', line 2654 def output_execution_summary return unless @delegate_object[:output_execution_summary] @fout.fout_section 'summary', { execute_aborted_at: @run_state.aborted_at, execute_completed_at: @run_state.completed_at, execute_error: @run_state.error, execute_error_message: @run_state., execute_options: @run_state., execute_started_at: @run_state.started_at, saved_filespec: @run_state.saved_filespec, script_block_name: @run_state.script_block_name, streamed_lines: @run_state.files.streams } end |
#output_labeled_value(label, value, level) ⇒ Object
2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 |
# File 'lib/hash_delegator.rb', line 2670 def output_labeled_value(label, value, level) @fout.lout format_references_send_color( context: { name: string_send_color(label, :output_execution_label_name_color), value: string_send_color(value.to_s, :output_execution_label_value_color) }, format_sym: :output_execution_label_format ), level: level end |
#pause_user_exit ⇒ Object
2681 2682 2683 2684 |
# File 'lib/hash_delegator.rb', line 2681 def pause_user_exit @delegate_object[:pause_after_script_execution] && prompt_select_continue == MenuState::EXIT end |
#pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines, dependencies, selected, next_block_name: nil) ⇒ Object
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 |
# File 'lib/hash_delegator.rb', line 2686 def pop_add_current_code_to_head_and_trigger_load( link_state, block_names, code_lines, dependencies, selected, next_block_name: nil ) pop = @link_history.pop # updatable if pop.document_filename next_state = LinkState.new( block_name: pop.block_name, document_filename: pop.document_filename, inherited_block_names: (pop.inherited_block_names + block_names).sort.uniq, inherited_dependencies: dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data inherited_lines: HashDelegator.code_merge(pop.inherited_lines, code_lines) ) @link_history.push(next_state) next_state.block_name = nil LoadFileLinkState.new(LoadFile::LOAD, next_state) else # no history exists; must have been called independently # => retain script link_history_push_and_next( curr_block_name: selected.pub_name, curr_document_filename: @delegate_object[:filename], inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq, inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines), keep_code: link_state&.keep_code, next_block_name: next_block_name, next_document_filename: @delegate_object[:filename], # not next_document_filename next_keep_code: false, next_load_file: LoadFile::REUSE # not next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD ) # LoadFileLinkState.new(LoadFile::REUSE, link_state) end end |
#pop_link_history_new_state ⇒ LinkState
This method handles the back-link operation in the Markdown execution context. It updates the history state for the next block.
2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 |
# File 'lib/hash_delegator.rb', line 2733 def pop_link_history_new_state pop = @link_history.pop peek = @link_history.peek LinkState.new( document_filename: pop.document_filename, inherited_block_names: peek.inherited_block_names, inherited_dependencies: peek.inherited_dependencies, inherited_lines: peek.inherited_lines ) end |
#post_execution_process ⇒ Object
2744 2745 2746 2747 2748 |
# File 'lib/hash_delegator.rb', line 2744 def post_execution_process do_save_execution_output output_execution_summary fout_execution_report if @delegate_object[:output_execution_report] end |
#prepare_blocks_menu(menu_blocks) ⇒ Array<Hash>
Prepare the blocks menu by adding labels and other necessary details. Remove filtered blocks.
2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 |
# File 'lib/hash_delegator.rb', line 2756 def () .map do |fcb| next if Filter.( @delegate_object, fcb, %i[block_name_include_match block_name_wrapper_match] ) fcb.name = fcb.dname # fcb.label = BlockLabel.make( # body: fcb.body, # filename: @delegate_object[:filename], # headings: fcb.headings, # menu_blocks_with_docname: @delegate_object[:menu_blocks_with_docname], # menu_blocks_with_headings: @delegate_object[:menu_blocks_with_headings], # text: fcb.text, # title: fcb.title # ) fcb.to_h end.compact end |
#print_formatted_option(key, value) ⇒ Object
2778 2779 2780 2781 2782 |
# File 'lib/hash_delegator.rb', line 2778 def print_formatted_option(key, value) formatted_str = format(@delegate_object[:menu_opts_set_format], { key: key, value: value }) print string_send_color(formatted_str, :menu_opts_set_color) end |
#process_string_array(arr, begin_pattern: nil, end_pattern: nil, scan1: nil, format1: nil) ⇒ Object
private
2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 |
# File 'lib/hash_delegator.rb', line 2786 def process_string_array(arr, begin_pattern: nil, end_pattern: nil, scan1: nil, format1: nil) in_block = !begin_pattern.present? collected_lines = [] arr.each do |line| 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) if caps formatted = format(format1, caps) collected_lines << formatted end else caps = line.match(scan1) if caps formatted = caps[0] collected_lines << formatted end end else collected_lines << line end elsif begin_pattern.present? && line.match?(begin_pattern) in_block = true end end collected_lines end |
#prompt_approve_repeat ⇒ Object
2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 |
# File 'lib/hash_delegator.rb', line 2820 def prompt_approve_repeat sel = @prompt.select( string_send_color(@delegate_object[:prompt_debounce], :prompt_color_after_script_execution), default: @delegate_object[:prompt_no], filter: true, quiet: true ) do || .choice @delegate_object[:prompt_yes] .choice @delegate_object[:prompt_no] .choice @delegate_object[:prompt_uninterrupted] end return false if sel == @delegate_object[:prompt_no] return true if sel == @delegate_object[:prompt_yes] @allowed_execution_block = @prior_execution_block true end |
#prompt_for_command(prompt) ⇒ Object
2839 2840 2841 2842 2843 2844 2845 |
# File 'lib/hash_delegator.rb', line 2839 def prompt_for_command(prompt) print prompt gets.chomp rescue Interrupt nil end |
#prompt_for_filespec_with_wildcard(filespec) ⇒ String?
Prompts the user to enter a path or name to substitute
into the wildcard expression.
If interrupted by the user (e.g., pressing Ctrl-C), it
returns nil.
2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 |
# File 'lib/hash_delegator.rb', line 2856 def prompt_for_filespec_with_wildcard(filespec) puts format(@delegate_object[:prompt_show_expr_format], { expr: filespec }) puts @delegate_object[:prompt_enter_filespec] begin input = $stdin.gets.chomp PathUtils.resolve_path_or_substitute(input, filespec) rescue Interrupt puts "\nOperation interrupted. Returning nil." nil end end |
#prompt_for_user_approval(required_lines:, selected:) ⇒ Boolean
Presents a menu to the user for approving an action
and performs additional tasks based on the selection.
The function provides options for approval, rejection,
copying data to clipboard, or saving data to a file.
2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 |
# File 'lib/hash_delegator.rb', line 2894 def prompt_for_user_approval(required_lines:, selected:) # Present a selection menu for user approval. sel = @prompt.select( string_send_color(@delegate_object[:prompt_approve_block], :prompt_color_after_script_execution), filter: true ) do || .default MenuOptions::YES .choice @delegate_object[:prompt_yes], MenuOptions::YES .choice @delegate_object[:prompt_no], MenuOptions::NO .choice @delegate_object[:prompt_script_to_clipboard], MenuOptions::SCRIPT_TO_CLIPBOARD .choice @delegate_object[:prompt_save_script], MenuOptions::SAVE_SCRIPT end if sel == MenuOptions::SCRIPT_TO_CLIPBOARD copy_to_clipboard(required_lines) elsif sel == MenuOptions::SAVE_SCRIPT save_to_file( required_lines: required_lines, selected: selected, shell: selected.shell ) end sel == MenuOptions::YES end |
#prompt_select_code_filename(filenames, color_sym: :prompt_color_after_script_execution, cycle: true, enum: false, quiet: true, string: ) ⇒ Object
public
2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 |
# File 'lib/hash_delegator.rb', line 2924 def prompt_select_code_filename( filenames, color_sym: :prompt_color_after_script_execution, cycle: true, enum: false, quiet: true, string: @delegate_object[:prompt_select_code_file] ) @prompt.select( string_send_color(string, color_sym), cycle: cycle, filter: !enum, per_page: @delegate_object[:select_page_height], quiet: quiet ) do || .enum '.' if enum filenames.each.with_index do |filename, ind| if enum .choice filename, ind + 1 else .choice filename end end end end |
#prompt_select_continue(filter: true, quiet: true) ⇒ Object
2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 |
# File 'lib/hash_delegator.rb', line 2950 def prompt_select_continue(filter: true, quiet: true) sel = @prompt.select( string_send_color(@delegate_object[:prompt_after_script_execution], :prompt_color_after_script_execution), filter: filter, quiet: quiet ) do || .choice @delegate_object[:prompt_yes] .choice @delegate_object[:prompt_exit] end sel == @delegate_object[:prompt_exit] ? MenuState::EXIT : MenuState::CONTINUE end |
#prompt_user_exit(block_name_from_cli:, selected:) ⇒ Object
user prompt to exit if the menu will be displayed again
2965 2966 2967 2968 2969 |
# File 'lib/hash_delegator.rb', line 2965 def prompt_user_exit(block_name_from_cli:, selected:) selected.type == BlockType::SHELL && @delegate_object[:pause_after_script_execution] && prompt_select_continue == MenuState::EXIT end |
#publish_for_external_automation(message:) ⇒ Object
2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 |
# File 'lib/hash_delegator.rb', line 2971 def publish_for_external_automation(message:) return if @delegate_object[:publish_document_file_name].empty? pipe_path = absolute_path(@delegate_object[:publish_document_file_name]) case @delegate_object[:publish_document_file_mode] when 'append' File.write(pipe_path, + "\n", mode: 'a') when 'fifo' unless @vux_pipe_open unless File.exist?(pipe_path) FileUtils.mkfifo(pipe_path) @vux_pipe_created = pipe_path end @vux_pipe_open = File.open(pipe_path, 'w') end @vux_pipe_open.puts( + "\n") @vux_pipe_open.flush when 'write' File.write(pipe_path, ) else raise 'Invalid publish_document_file_mode:' \ " #{@delegate_object[:publish_document_file_mode]}" end end |
#puts_gets_oprompt_(filespec) ⇒ Object
Handle expression with wildcard characters allow user to select or enter
2999 3000 3001 3002 3003 3004 |
# File 'lib/hash_delegator.rb', line 2999 def puts_gets_oprompt_(filespec) puts format(@delegate_object[:prompt_show_expr_format], { expr: filespec }) puts @delegate_object[:prompt_enter_filespec] gets.chomp end |
#read_saved_assets_for_history_table(asset: nil, filename: nil, form: , path: , regexp: ) ⇒ Object
3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 |
# File 'lib/hash_delegator.rb', line 3006 def read_saved_assets_for_history_table( asset: nil, filename: nil, form: @delegate_object[:saved_history_format], path: @delegate_object[:saved_script_folder], regexp: @delegate_object[:saved_asset_match] ) history_files( @dml_link_state, filename: asset.present? ? saved_asset_filename(asset, @dml_link_state) : filename, path: path )&.map do |file| unless Regexp.new(regexp) =~ file warn "Cannot parse name: #{file}" next end saved_asset = saved_asset_for_history( file: file, form: form, match_info: $LAST_MATCH_INFO ) saved_asset == :break ? nil : saved_asset end&.compact end |
#read_show_options_and_trigger_reuse(selected:, mdoc:, link_state: LinkState.new) ⇒ LoadFileLinkState
Processes YAML data from the selected menu item, updating delegate
objects and optionally printing formatted output.
3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 |
# File 'lib/hash_delegator.rb', line 3062 def (selected:, mdoc:, link_state: LinkState.new) obj = {} # concatenated body of all required blocks loaded a YAML data = (YAML.load( execute_block_type_port_code_lines( mdoc: mdoc, selected: selected, link_state: link_state, block_source: {} ).join("\n") ) || {}).transform_keys(&:to_sym) if selected.type == BlockType::OPTS obj = data else (data || []).each do |key, value| sym_key = key.to_sym obj[sym_key] = value if @delegate_object[:menu_opts_set_format].present? print_formatted_option(key, value) end end end link_state.block_name = nil OpenStruct.new(options: obj, load_file_link_state: LoadFileLinkState.new( LoadFile::REUSE, link_state )) end |
#register_console_attributes(opts) ⇒ Object
Registers console attributes by modifying the options hash. This method handles terminal resizing and adjusts the console dimensions and pagination settings based on the current terminal size.
3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 |
# File 'lib/hash_delegator.rb', line 3125 def register_console_attributes(opts) if (resized = @delegate_object[:menu_resize_terminal]) resize_terminal end if resized || !opts[:console_width] opts[:console_height], opts[:console_width] = opts[:console_winsize] = IO.console.winsize end unless opts[:select_page_height]&.positive? opts[:per_page] = opts[:select_page_height] = [opts[:console_height] - 3, 4].max end rescue StandardError HashDelegator.error_handler('register_console_attributes', { abort: true }) end |
#report_error(err) ⇒ Object
3145 3146 3147 3148 3149 3150 3151 3152 3153 |
# File 'lib/hash_delegator.rb', line 3145 def report_error(err) # Handle ENOENT error @run_state.aborted_at = Time.now.utc @run_state. = err. @run_state.error = err @run_state.files.append_stream_line(ExecutionStreams::STD_ERR, @run_state.) @fout.fout err.inspect end |
#respond_to?(method_name, include_private = false) ⇒ Boolean
Check if the delegate object responds to a given method.
3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 |
# File 'lib/hash_delegator.rb', line 3161 def respond_to?(method_name, include_private = false) if super true elsif @delegate_object.respond_to?(method_name, include_private) true elsif method_name.to_s.end_with?('=') && @delegate_object.respond_to?(:[]=, include_private) true else @delegate_object.respond_to?(method_name, include_private) end end |
#runtime_exception(exception_sym, name, items) ⇒ Object
3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 |
# File 'lib/hash_delegator.rb', line 3174 def runtime_exception(exception_sym, name, items) if @delegate_object[exception_sym] != 0 data = { name: name, detail: items.join(', ') } warn( AnsiString.new( format( @delegate_object.fetch(:exception_format_name, "\n%{name}"), data ) ).send(@delegate_object.fetch(:exception_color_name, :red)) + AnsiString.new( format( @delegate_object.fetch(:exception_format_detail, " - %{detail}\n"), data ) ).send(@delegate_object.fetch(:exception_color_detail, :yellow)) ) end return unless (@delegate_object[exception_sym]).positive? exit @delegate_object[exception_sym] end |
#save_filespec_from_expression(expression) ⇒ Object
allow user to select or enter
3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 |
# File 'lib/hash_delegator.rb', line 3199 def save_filespec_from_expression(expression) # Process expression with embedded formatting formatted = formatted_expression(expression) # Handle wildcards or direct file specification if contains_wildcards?(formatted) save_filespec_wildcard_expansion(formatted) else formatted end end |
#save_filespec_wildcard_expansion(filespec) ⇒ Object
Handle expression with wildcard characters allow user to select or enter
3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 |
# File 'lib/hash_delegator.rb', line 3213 def save_filespec_wildcard_expansion(filespec) files = find_files(filespec) case files.count when 0 prompt_for_filespec_with_wildcard(filespec) else ## user selects from existing files or other # input into path with wildcard for easy entry # case (name = prompt_select_code_filename( [@delegate_object[:prompt_filespec_back], @delegate_object[:prompt_filespec_other]] + files, string: @delegate_object[:prompt_select_code_file], color_sym: :prompt_color_after_script_execution )) when @delegate_object[:prompt_filespec_back] # do nothing when @delegate_object[:prompt_filespec_other] prompt_for_filespec_with_wildcard(filespec) else name end end end |
#save_to_file(required_lines:, selected:, shell:) ⇒ Object
3238 3239 3240 3241 3242 3243 |
# File 'lib/hash_delegator.rb', line 3238 def save_to_file(required_lines:, selected:, shell:) write_command_file( required_lines: required_lines, selected: selected, shell: shell ) @fout.fout "File saved: #{@run_state.saved_filespec}" end |
#saved_asset_filename(filename, link_state = LinkState.new) ⇒ Object
3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 |
# File 'lib/hash_delegator.rb', line 3245 def saved_asset_filename(filename, link_state = LinkState.new) SavedAsset.new( filename: filename, saved_asset_format: shell_escape_asset_format( code_lines: link_state&.inherited_lines, shell: shell ) ).generate_name end |
#saved_asset_for_history(file:, form:, match_info:) ⇒ Object
3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 |
# File 'lib/hash_delegator.rb', line 3033 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 ) ) rescue KeyError # pp $!, $@ warn "Cannot format with: #{@delegate_object[:saved_history_format]}" error_handler('saved_history_format') return :break end end |
#select_document_if_multiple(options, files, prompt:) ⇒ Object
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 |
# File 'lib/hash_delegator.rb', line 3256 def select_document_if_multiple(, files, prompt:) # binding.irb return files if files.class == String ### return files[0] if (count = files.count) == 1 return unless count >= 2 opts = .dup select_option_or_exit( string_send_color( prompt, :prompt_color_after_script_execution ), files, opts.merge(per_page: opts[:select_page_height]) ) end |
#select_option_with_metadata(prompt_text, menu_items, opts = {}) ⇒ Object
Presents a TTY prompt to select an option or exit,
returns including option and selected
3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 |
# File 'lib/hash_delegator.rb', line 3276 def (prompt_text, , opts = {}) # !!v prompt_text menu_items ## configure to environment # register_console_attributes(opts) # crashes if all menu options are disabled begin selection = @prompt.select(prompt_text, , opts.merge(filter: true)) # !!v selection rescue NoMethodError # no enabled options in page return end selected = .find do |item| if item.instance_of?(Hash) (item[:name] || item[:dname]) == selection elsif item.instance_of?(MarkdownExec::FCB) item.dname == selection else item == selection end end if selected.instance_of?(String) selected = FCB.new(dname: selected) elsif selected.instance_of?(Hash) selected = FCB.new(selected) end unless selected HashDelegator.error_handler('select_option_with_metadata', error: 'menu item not found') exit 1 end if selection == (:menu_option_back_name) selected.option = selection selected.type = BlockType::LINK elsif selection == (:menu_option_exit_name) selected.option = selection else selected.selected = selection end selected end |
#shell ⇒ Object
3325 3326 3327 |
# File 'lib/hash_delegator.rb', line 3325 def shell @delegate_object[:shell] end |
#shell=(value) ⇒ Object
3329 3330 3331 |
# File 'lib/hash_delegator.rb', line 3329 def shell=(value) @delegate_object[:shell] = value end |
#shell_escape_asset_format(code_lines:, enable: , raw: , shell:) ⇒ Object
3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 |
# File 'lib/hash_delegator.rb', line 3333 def shell_escape_asset_format( code_lines:, enable: @delegate_object[:shell_parameter_expansion], raw: @delegate_object[:saved_asset_format], shell: ) return raw unless enable # unchanged if no parameter expansion takes place return raw unless /$/ =~ raw filespec = generate_temp_filename cmd = [shell, '-c', filespec].join(' ') marker = Random.new.rand.to_s code = (code_lines || []) + ["echo -n \"#{marker}#{raw}\""] # !!t code File.write filespec, HashDelegator.join_code_lines(code) File.chmod 0o755, filespec out = `#{cmd}`.sub(/.*?#{marker}/m, '') File.delete filespec out # !!r end |
#should_add_back_option?(menu_with_back: ) ⇒ Boolean
3359 3360 3361 3362 3363 |
# File 'lib/hash_delegator.rb', line 3359 def should_add_back_option?( menu_with_back: @delegate_object[:menu_with_back] ) && @link_history.prior_state_exist? end |
#simple_menu_options(per_page: ) ⇒ Object
3365 3366 3367 3368 3369 3370 |
# File 'lib/hash_delegator.rb', line 3365 def ( per_page: @delegate_object[:select_page_height] ) { cycle: true, per_page: per_page } end |
#start_fenced_block(line, headings, fenced_start_extended_regex) ⇒ MarkdownExec::FCB
Initializes a new fenced code block (FCB) object based
on the provided line and heading information.
3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 |
# File 'lib/hash_delegator.rb', line 3379 def start_fenced_block(line, headings, fenced_start_extended_regex) fcb_title_groups = NamedCaptureExtractor::extract_named_groups( line, fenced_start_extended_regex ) rest = fcb_title_groups.fetch(:rest, '') reqs, wraps = ArrayUtil.partition_by_predicate(rest.scan(/\+[^\s]+/).map do |req| req[1..-1] end) do |name| !name.match(Regexp.new(@delegate_object[:block_name_wrapper_match])) end # adjust captured type if fcb_title_groups[:type].present? case fcb_title_groups[:type] when *ShellType::ALL # convert type to shell fcb_title_groups[:shell] = fcb_title_groups[:type] fcb_title_groups[:type] = BlockType::SHELL end else # treat as the default shell fcb_title_groups[:shell] = @delegate_object[:block_type_default] fcb_title_groups[:type] = BlockType::SHELL end dname = oname = title = '' nickname = nil if @delegate_object[:block_name_nick_match].present? && oname =~ Regexp.new(@delegate_object[:block_name_nick_match]) nickname = $~[0] else dname = oname = title = fcb_title_groups.fetch(:name, '') end # disable fcb for data blocks disabled = if fcb_title_groups.fetch(:type, '') == BlockType::YAML TtyMenu::DISABLE else nil end MarkdownExec::FCB.new( body: [], call: rest.match( Regexp.new(@delegate_object[:block_calls_scan]) )&.to_a&.first, disabled: disabled, dname: dname, headings: headings, indent: fcb_title_groups.fetch(:indent, ''), nickname: nickname, 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) end, stdout: if (tn = rest.match(/>(?<type>\$)?(?<name>[\w.\-]+)/)) NamedCaptureExtractor::extract_named_group2(tn) end, title: title, type: fcb_title_groups.fetch(:type, ''), wraps: wraps ) end |
#string_send_color(string, color_sym) ⇒ String
Applies a color method to a string based on the provided color symbol. The color method is fetched from @delegate_object and applied to the string.
3455 3456 3457 |
# File 'lib/hash_delegator.rb', line 3455 def string_send_color(string, color_sym) HashDelegator.apply_color_from_hash(string, @delegate_object, color_sym) end |
#update_line_and_block_state(nested_line, state, selected_types, &block) ⇒ Void
Processes an individual line within a loop, updating headings
and handling fenced code blocks.
This function is designed to be called within a loop that iterates
through each line of a document.
the current fenced code block being processed.
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 |
# File 'lib/hash_delegator.rb', line 3490 def update_line_and_block_state(nested_line, state, selected_types, &block) line = nested_line.to_s if line.match(@delegate_object[:fenced_start_and_end_regex]) if state[:in_fenced_block] ## end of code block # HashDelegator.( fcb: state[:fcb], messages: selected_types, configuration: @delegate_object, &block ) state[:in_fenced_block] = false else ## start of code block # state[:fcb] = start_fenced_block( line, state[:headings], @delegate_object[:fenced_start_extended_regex] ) state[:fcb][:depth] = nested_line[:depth] state[:fcb][:indention] = nested_line[:indention] state[:in_fenced_block] = true end elsif state[:in_fenced_block] && state[:fcb].body ## add line to fenced code block # remove fcb indent if possible # state[:fcb].body += [ line.chomp.sub(/^#{state[:fcb].indent}/, '') ] elsif nested_line[:depth].zero? || @delegate_object[:menu_include_imported_notes] # add line if it is depth 0 or option allows it # HashDelegator.yield_line_if_selected(line, selected_types, &block) else # !!b 'line is not recognized for block state' end end |
#update_menu_base(options) ⇒ Object
apply options to current state
3536 3537 3538 3539 3540 |
# File 'lib/hash_delegator.rb', line 3536 def () # under simple uses, @menu_base_options may be nil @menu_base_options&.merge!() @delegate_object.merge!() end |
#variable_expansions!(echo_command_form: 'echo "$%s"', link_state:, menu_blocks:, regexp: Regexp.new(@delegate_object[:variable_expression_regexp])) ⇒ Object
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
# File 'lib/hash_delegator.rb', line 618 def variable_expansions!( echo_command_form: 'echo "$%s"', link_state:, menu_blocks:, regexp: Regexp.new(@delegate_object[:variable_expression_regexp]) ) # !!v link_state.inherited_lines_block # collect variables in menu_blocks # variables_count = Hash.new(0) .each do |fcb| next if fcb.type == BlockType::SHELL fcb.oname.scan(regexp) do |(expression, variable)| expression.match(regexp) variables_count[$LAST_MATCH_INFO[:variable]] += 1 end end # !!v variables_count # commands to echo variables # commands = {} variables_count.each do |variable, count| command = format(echo_command_form, variable) commands[variable] = command end # !!v commands # replacement dictionary from evaluated commands # replacement_dictionary = evaluate_shell_expressions( link_state.inherited_lines_block, commands, key_format: "${%s}" # no need to escape variable name for regexp ) # !!t return if replacement_dictionary.nil? # update blocks # Regexp.union(replacement_dictionary.keys).tap do |pattern| .each do |fcb| next if fcb.type == BlockType::SHELL fcb.variable_expansion!(pattern, replacement_dictionary) end end end |
#vux_await_user_selection ⇒ Object
3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 |
# File 'lib/hash_delegator.rb', line 3542 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 ) # !!b '@run_state.source.block_name_from_cli:',@run_state.source.block_name_from_cli if !@dml_block_state # HashDelegator.error_handler('block_state missing', { abort: true }) # document has no enabled items :break elsif @dml_block_state.state == MenuState::EXIT # !!b 'load_cli_or_user_selected_block -> break' :break end end |
#vux_clear_menu_state ⇒ Object
3559 3560 3561 3562 |
# File 'lib/hash_delegator.rb', line 3559 def @dml_block_state = SelectedBlockMenuState.new @delegate_object[:block_name] = nil end |
#vux_edit_inherited ⇒ Object
3564 3565 3566 3567 |
# File 'lib/hash_delegator.rb', line 3564 def vux_edit_inherited edited = edit_text(@dml_link_state.inherited_lines_block) @dml_link_state.inherited_lines = edited.split("\n") if edited end |
#vux_execute_and_prompt(block_name) ⇒ Object
3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 |
# File 'lib/hash_delegator.rb', line 3569 def vux_execute_and_prompt(block_name) @dml_block_state = block_state_for_name_from_cli(block_name) if @dml_block_state.block && @dml_block_state.block.type == BlockType::OPTS debounce_reset link_state = LinkState.new = ( link_state: link_state, mdoc: @dml_mdoc, selected: @dml_block_state.block ) (.) .load_file_link_state.link_state return end return :break if execute_block_in_state(block_name) == :break if prompt_user_exit( block_name_from_cli: @run_state.source.block_name_from_cli, selected: @dml_block_state.block ) return :break end ## order of block name processing: link block, cli, from # user # @dml_link_state.block_name, @run_state.source.block_name_from_cli, cli_break = HashDelegator.next_link_state( block_name: @dml_link_state.block_name, block_name_from_cli: @dml_now_using_cli, block_state: @dml_block_state, was_using_cli: @dml_now_using_cli ) # !!b '!block_name_from_ui + cli_break -> break' !@dml_block_state.source.block_name_from_ui && cli_break && :break end |
#vux_execute_block_per_type(block_name, formatted_choice_ostructs) ⇒ Object
3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 |
# File 'lib/hash_delegator.rb', line 3611 def vux_execute_block_per_type(block_name, formatted_choice_ostructs) case block_name when formatted_choice_ostructs[:back].pub_name debounce_reset vux_navigate_back_for_ls when formatted_choice_ostructs[:edit].pub_name debounce_reset vux_edit_inherited return :break if pause_user_exit InputSequencer.next_link_state(prior_block_was_link: true) when formatted_choice_ostructs[:history].pub_name debounce_reset return :break unless files_table_rows = vux_history_files_table_rows execute_history_select(files_table_rows, stream: $stderr) return :break if pause_user_exit InputSequencer.next_link_state(prior_block_was_link: true) when formatted_choice_ostructs[:load].pub_name debounce_reset vux_load_inherited return :break if pause_user_exit InputSequencer.next_link_state(prior_block_was_link: true) when formatted_choice_ostructs[:save].pub_name debounce_reset return :break if execute_inherited_save == :break InputSequencer.next_link_state(prior_block_was_link: true) when formatted_choice_ostructs[:shell].pub_name debounce_reset vux_input_and_execute_shell_commands(stream: $stderr, shell: shell) return :break if pause_user_exit InputSequencer.next_link_state(prior_block_was_link: true) when formatted_choice_ostructs[:view].pub_name debounce_reset vux_view_inherited(stream: $stderr) return :break if pause_user_exit InputSequencer.next_link_state(prior_block_was_link: true) else return :break if vux_execute_and_prompt(block_name) == :break InputSequencer.next_link_state( block_name: @dml_link_state.block_name, prior_block_was_link: @dml_block_state.block.type != BlockType::SHELL ) end end |
#vux_formatted_names_for_state_chrome_blocks(names: %w[back edit history load save shell view]) ⇒ Object
3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 |
# File 'lib/hash_delegator.rb', line 3670 def vux_formatted_names_for_state_chrome_blocks( names: %w[back edit history load save shell view] ) names.each_with_object({}) do |name, result| do_key = :"menu_option_#{name}_name" oname = HashDelegator.safeval(@delegate_object[do_key]) dname = format(@delegate_object[:menu_link_format], oname) result[name.to_sym] = OpenStruct.new( dname: dname, name: dname, oname: dname, pub_name: dname.pub_name ) end end |
#vux_history_files_table_rows ⇒ Object
3686 3687 3688 3689 3690 3691 |
# File 'lib/hash_delegator.rb', line 3686 def vux_history_files_table_rows read_saved_assets_for_history_table( asset: @delegate_object[:filename], form: @delegate_object[:saved_history_format] ) end |
#vux_init ⇒ Object
3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 |
# File 'lib/hash_delegator.rb', line 3693 def vux_init @menu_base_options = @delegate_object @dml_link_state = LinkState.new( block_name: @delegate_object[:block_name], document_filename: @delegate_object[:filename] ) @run_state.source.block_name_from_cli = @dml_link_state.block_name.present? @cli_block_name = @dml_link_state.block_name @dml_now_using_cli = @run_state.source.block_name_from_cli @dml_menu_default_dname = nil @dml_block_state = SelectedBlockMenuState.new @doc_saved_lines_files = [] @run_state.batch_random = Random.new.rand @run_state.batch_index = 0 @run_state.files = StreamsOut.new end |
#vux_input_and_execute_shell_commands(stream:, shell:) ⇒ Object
3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 |
# File 'lib/hash_delegator.rb', line 3713 def vux_input_and_execute_shell_commands(stream:, shell:) loop do command = prompt_for_command( AnsiString.new(":MDE #{Time.now.strftime('%FT%TZ')}> ").send(:bgreen) ) break if !command.present? || command == 'exit' exit_status = execute_command_with_streams( [shell, '-c', command] ) case exit_status when 0 stream.puts "#{AnsiString.new('OK').green} #{exit_status}" else stream.puts "#{AnsiString.new('ERR').bred} #{exit_status}" end end end |
#vux_load_code_files_into_state ⇒ Object
load file with code lines per options
3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 |
# File 'lib/hash_delegator.rb', line 3734 def vux_load_code_files_into_state return unless @menu_base_options[:load_code].present? @dml_link_state.inherited_lines = @menu_base_options[:load_code].split(':').map do |path| File.readlines(path, chomp: true) end.flatten(1) inherited_block_names = [] inherited_dependencies = {} selected = FCB.new(oname: 'load_code') pop_add_current_code_to_head_and_trigger_load( @dml_link_state, inherited_block_names, code_lines, inherited_dependencies, selected ) end |
#vux_load_inherited ⇒ Object
3751 3752 3753 3754 3755 3756 3757 3758 3759 |
# File 'lib/hash_delegator.rb', line 3751 def vux_load_inherited return unless filespec = load_filespec_from_expression( document_name_in_glob_as_file_name ) @dml_link_state.inherited_lines_append( File.readlines(filespec, chomp: true) ) end |
#vux_main_loop ⇒ Nil
Select and execute a code block from a Markdown document.
This method allows the user to interactively select a code block from a Markdown document, obtain approval, and execute the chosen block of code.
3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 |
# File 'lib/hash_delegator.rb', line 3768 def vux_main_loop vux_init vux_load_code_files_into_state formatted_choice_ostructs = vux_formatted_names_for_state_chrome_blocks block_list = [@delegate_object[:block_name]].select(&:present?).compact + @delegate_object[:input_cli_rest] @delegate_object[:block_name] = nil process_commands( arguments: @p_all_arguments, named_procs: yield(:command_names, @delegate_object), options_parsed: @p_options_parsed, rest: @p_rest, enable_search: @delegate_object[:default_find_select_open] ) do |type, data| case type when ArgPro::ActSetBlockName @delegate_object[:block_name] = data @delegate_object[:input_cli_rest] = '' when ArgPro::ConvertValue # call for side effects, output, or exit data[0].call(data[1]) when ArgPro::ActFileIsMissing raise FileMissingError, data, caller when ArgPro::ActFind find_value(data, execute_chosen_found: true) when ArgPro::ActSetFileName @delegate_object[:filename] = data when ArgPro::ActSetPath @delegate_object[:path] = data when ArgPro::CallProcess yield :call_proc, [@delegate_object, data] when ArgPro::ActSetOption @delegate_object[data[0]] = data[1] else raise end end InputSequencer.new( @delegate_object[:filename], block_list ).run do |msg, data| # !!v msg data # !!t msg case msg when :parse_document # once for each menu vux_parse_document (formatted_choice_ostructs) vux_publish_document_file_name_for_external_automation when :display_menu when :end_of_cli # !!b # yield :end_of_cli, @delegate_object if @delegate_object[:list_blocks] # !!b list_blocks :exit end when :user_choice vux_user_selected_block_name when :execute_block ret = vux_execute_block_per_type(data, formatted_choice_ostructs) vux_publish_block_name_for_external_automation(data) ret when :close_ux if @vux_pipe_open.present? && File.exist?(@vux_pipe_open) @vux_pipe_open.close @vux_pipe_open = nil end if @vux_pipe_created.present? && File.exist?(@vux_pipe_created) File.delete(@vux_pipe_created) @vux_pipe_created = nil end when :exit? data == $texit when :stay? data == $stay else raise "Invalid message: #{msg}" end end end |
#vux_menu_append_history_files(formatted_choice_ostructs) ⇒ Object
3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 |
# File 'lib/hash_delegator.rb', line 3865 def (formatted_choice_ostructs) if @delegate_object[:menu_for_history] history_files( @dml_link_state, filename: saved_asset_filename(@delegate_object[:filename], @dml_link_state), path: @delegate_object[:saved_script_folder] ).tap do |files| if files.count.positive? ( formatted_choice_ostructs[:history].oname, files.count, 'files', menu_state: MenuState::HISTORY ) end end end return unless @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present? document_glob = document_name_in_glob_as_file_name files = document_glob ? Dir.glob(document_glob) : [] @doc_saved_lines_files = files.count.positive? ? files : [] lines_count = @dml_link_state.inherited_lines_count # add menu items (glob, load, save) and enable selectively if files.count.positive? || lines_count.positive? (document_glob) end if files.count.positive? ( formatted_choice_ostructs[:load].dname, files.count, 'files', menu_state: MenuState::LOAD ) end if @delegate_object[:menu_inherited_lines_edit_always] || lines_count.positive? ( formatted_choice_ostructs[:edit].dname, lines_count, 'lines', menu_state: MenuState::EDIT ) end if lines_count.positive? ( formatted_choice_ostructs[:save].dname, 1, '', menu_state: MenuState::SAVE ) end if lines_count.positive? ( formatted_choice_ostructs[:view].dname, 1, '', menu_state: MenuState::VIEW ) end # rubocop:disable Style/GuardClause if @delegate_object[:menu_with_shell] ( formatted_choice_ostructs[:shell].dname, 1, '', menu_state: MenuState::SHELL ) end # rubocop:enable Style/GuardClause # # reflect new menu items # @dml_mdoc = MDoc.new(@dml_menu_blocks) end |
#vux_navigate_back_for_ls ⇒ Object
3933 3934 3935 3936 3937 3938 3939 3940 |
# File 'lib/hash_delegator.rb', line 3933 def vux_navigate_back_for_ls InputSequencer.merge_link_state( @dml_link_state, InputSequencer.next_link_state( **execute_navigate_back.merge(prior_block_was_link: true) ) ) end |
#vux_parse_document ⇒ Object
3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 |
# File 'lib/hash_delegator.rb', line 3942 def vux_parse_document @run_state.batch_index += 1 @run_state.in_own_window = false @run_state.source.block_name_from_cli, @dml_now_using_cli = manage_cli_selection_state( block_name_from_cli: @run_state.source.block_name_from_cli, now_using_cli: @dml_now_using_cli, link_state: @dml_link_state ) @delegate_object[:filename] = @dml_link_state.document_filename @dml_link_state.block_name = @delegate_object[:block_name] = if @run_state.source.block_name_from_cli @cli_block_name else @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) dump_delobj(@dml_blocks_in_file, @dml_menu_blocks, @dml_link_state) # !!b 'loop', @run_state.source.block_name_from_cli, @cli_block_name end |
#vux_publish_block_name_for_external_automation(block_name) ⇒ Object
3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 |
# File 'lib/hash_delegator.rb', line 3969 def vux_publish_block_name_for_external_automation(block_name) publish_for_external_automation( message: format( @delegate_object[:publish_block_name_format], { block: block_name, document: @delegate_object[:filename], time: Time.now.utc.strftime( @delegate_object[:publish_time_format] ) } ) ) end |
#vux_publish_document_file_name_for_external_automation ⇒ Object
3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 |
# File 'lib/hash_delegator.rb', line 3982 def vux_publish_document_file_name_for_external_automation return unless @delegate_object[:publish_document_file_name].present? publish_for_external_automation( message: format( @delegate_object[:publish_document_name_format], { document: @delegate_object[:filename], time: Time.now.utc.strftime( @delegate_object[:publish_time_format] ) } ) ) end |
#vux_user_selected_block_name ⇒ Object
return :break to break from loop
3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 |
# File 'lib/hash_delegator.rb', line 3997 def vux_user_selected_block_name # !!b if @dml_link_state.block_name.present? # @prior_block_was_link = true @dml_block_state.block = blocks_find_by_block_name( @dml_blocks_in_file, @dml_link_state.block_name ) @dml_link_state.block_name = nil else # puts "? - Select a block to execute (or type #{$texit} # to exit):" return :break if vux_await_user_selection == :break return :break if @dml_block_state.block.nil? # no block matched end # puts "! - Executing block: #{data}" @dml_block_state.block&.pub_name end |
#vux_view_inherited(stream:) ⇒ Object
4016 4017 4018 |
# File 'lib/hash_delegator.rb', line 4016 def vux_view_inherited(stream:) stream.puts @dml_link_state.inherited_lines_block end |
#wait_for_stream_processing ⇒ Object
4020 4021 4022 4023 4024 4025 4026 |
# File 'lib/hash_delegator.rb', line 4020 def wait_for_stream_processing @process_mutex.synchronize do @process_cv.wait(@process_mutex) end rescue Interrupt # user interrupts process end |
#wait_for_user_selected_block(all_blocks, menu_blocks, default) ⇒ Object
4028 4029 4030 4031 4032 4033 |
# File 'lib/hash_delegator.rb', line 4028 def wait_for_user_selected_block(all_blocks, , default) # !!b block_state = wait_for_user_selection(all_blocks, , default) handle_back_or_continue(block_state) block_state end |
#wait_for_user_selection(_all_blocks, menu_blocks, default) ⇒ Object
4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 |
# File 'lib/hash_delegator.rb', line 4035 def wait_for_user_selection(_all_blocks, , default) # !!b if @delegate_object[:clear_screen_for_select_block] printf("\e[1;1H\e[2J") end # !!b prompt_title = string_send_color( @delegate_object[:prompt_select_block].to_s, :prompt_color_after_script_execution ) # !!b = () if .empty? return SelectedBlockMenuState.new(nil, OpenStruct.new, MenuState::EXIT) end # !!b # default value may not match if color is different from # originating menu (opts changed while processing) selection_opts = if default && .map(&:dname).include?(default) @delegate_object.merge(default: default) else @delegate_object end # !!b selection_opts.merge!( { cycle: @delegate_object[:select_page_cycle], per_page: @delegate_object[:select_page_height] } ) selected_option = (prompt_title, , selection_opts) # !!b determine_block_state(selected_option) end |
#write_command_file(required_lines:, selected:, shell: nil) ⇒ Object
Handles the core logic for generating the command file’s metadata and content.
4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 |
# File 'lib/hash_delegator.rb', line 4076 def write_command_file(required_lines:, selected:, shell: nil) return unless @delegate_object[:save_executed_script] time_now = Time.now.utc @run_state.saved_script_filename = SavedAsset.new( blockname: selected.pub_name, exts: '.sh', filename: @delegate_object[:filename], prefix: @delegate_object[:saved_script_filename_prefix], saved_asset_format: shell_escape_asset_format( code_lines: @dml_link_state.inherited_lines, shell: shell ), time: time_now ).generate_name @run_state.saved_filespec = File.join(@delegate_object[:saved_script_folder], @run_state.saved_script_filename) shebang = if @delegate_object[:shebang]&.present? "#{@delegate_object[:shebang]} #{shell}\n" else '' end content = shebang + "# file_name: #{@delegate_object[:filename]}\n" \ "# block_name: #{@delegate_object[:block_name]}\n" \ "# time: #{time_now}\n" \ "#{required_lines.flatten.join("\n")}\n" HashDelegator.( @run_state.saved_filespec, content, @delegate_object[:saved_script_chmod] ) rescue StandardError HashDelegator.error_handler('write_command_file') end |
#write_file_with_directory_creation(content:, filespec:) ⇒ Object
Ensure the directory exists before writing the file
4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 |
# File 'lib/hash_delegator.rb', line 4119 def write_file_with_directory_creation(content:, filespec:) directory = File.dirname(filespec) begin FileUtils.mkdir_p(directory) File.write(filespec, content) rescue Errno::EACCES warn "Permission denied: Unable to write to file '#{filespec}'" nil rescue Errno::EROFS warn 'Read-only file system: Unable to write to file ' \ "'#{filespec}'" nil rescue StandardError => err warn 'An error occurred while writing to file ' \ "'#{filespec}': #{err.}" nil end end |
#write_inherited_lines_to_file(link_state, link_block_data) ⇒ Object
return next document file name
4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 |
# File 'lib/hash_delegator.rb', line 4140 def write_inherited_lines_to_file(link_state, link_block_data) save_expr = link_block_data.fetch(LinkKeys::SAVE, '') if save_expr.present? save_filespec = save_filespec_from_expression(save_expr) File.write(save_filespec, HashDelegator.join_code_lines(link_state&.inherited_lines)) @delegate_object[:filename] else link_block_data[LinkKeys::FILE] || @delegate_object[:filename] end end |