markdown_exec 1.8.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +20 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +2 -8
- data/bin/tab_completion.sh +11 -3
- data/examples/colors.md +41 -19
- data/examples/document_options.md +8 -0
- data/examples/duplicate_block.md +5 -8
- data/examples/import0.md +3 -5
- data/examples/import1.md +1 -1
- data/examples/include.md +16 -10
- data/examples/indent.md +2 -0
- data/examples/index.md +68 -0
- data/examples/linked.md +100 -39
- data/examples/llm.md +54 -0
- data/lib/constants.rb +6 -1
- data/lib/find_files.rb +1 -2
- data/lib/hash_delegator.rb +529 -211
- data/lib/input_sequencer.rb +229 -0
- data/lib/link_history.rb +11 -5
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +4 -6
- data/lib/mdoc.rb +7 -7
- data/lib/menu.src.yml +60 -25
- data/lib/menu.yml +53 -20
- metadata +6 -3
- data/examples/infile_config.md +0 -10
data/lib/hash_delegator.rb
CHANGED
|
@@ -11,6 +11,7 @@ require 'optparse'
|
|
|
11
11
|
require 'set'
|
|
12
12
|
require 'shellwords'
|
|
13
13
|
require 'tmpdir'
|
|
14
|
+
# require 'tty-file'
|
|
14
15
|
require 'tty-prompt'
|
|
15
16
|
require 'yaml'
|
|
16
17
|
|
|
@@ -40,10 +41,6 @@ class String
|
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
module HashDelegatorSelf
|
|
43
|
-
# def add_back_option(menu_blocks)
|
|
44
|
-
# append_chrome_block(menu_blocks, MenuState::BACK)
|
|
45
|
-
# end
|
|
46
|
-
|
|
47
44
|
# Applies an ANSI color method to a string using a specified color key.
|
|
48
45
|
# The method retrieves the color method from the provided hash. If the color key
|
|
49
46
|
# is not present in the hash, it uses a default color method.
|
|
@@ -185,16 +182,20 @@ module HashDelegatorSelf
|
|
|
185
182
|
fcb.oname = fcb.dname = fcb.title || ''
|
|
186
183
|
end
|
|
187
184
|
|
|
185
|
+
def join_code_lines(lines)
|
|
186
|
+
((lines || []) + ['']).join("\n")
|
|
187
|
+
end
|
|
188
|
+
|
|
188
189
|
def merge_lists(*args)
|
|
189
190
|
# Filters out nil values, flattens the arrays, and ensures an empty list is returned if no valid lists are provided
|
|
190
191
|
merged = args.compact.flatten
|
|
191
192
|
merged.empty? ? [] : merged
|
|
192
193
|
end
|
|
193
194
|
|
|
194
|
-
def next_link_state(block_name_from_cli
|
|
195
|
+
def next_link_state(block_name_from_cli:, was_using_cli:, block_state:, block_name: nil)
|
|
195
196
|
# &bsp 'next_link_state', block_name_from_cli, was_using_cli, block_state
|
|
196
197
|
# Set block_name based on block_name_from_cli
|
|
197
|
-
block_name =
|
|
198
|
+
block_name = @cli_block_name if block_name_from_cli
|
|
198
199
|
# &bsp 'block_name:', block_name
|
|
199
200
|
|
|
200
201
|
# Determine the state of breaker based on was_using_cli and the block type
|
|
@@ -210,6 +211,8 @@ module HashDelegatorSelf
|
|
|
210
211
|
|
|
211
212
|
def parse_yaml_data_from_body(body)
|
|
212
213
|
body.any? ? YAML.load(body.join("\n")) : {}
|
|
214
|
+
rescue StandardError
|
|
215
|
+
error_handler('parse_yaml_data_from_body', { abort: true })
|
|
213
216
|
end
|
|
214
217
|
|
|
215
218
|
# Reads required code blocks from a temporary file specified by an environment variable.
|
|
@@ -264,21 +267,15 @@ module HashDelegatorSelf
|
|
|
264
267
|
# @param fcb [Object] The fcb object whose attributes are to be updated.
|
|
265
268
|
# @param selected_messages [Array<Symbol>] A list of message types to determine if yielding is applicable.
|
|
266
269
|
# @param block [Block] An optional block to yield to if conditions are met.
|
|
267
|
-
def update_menu_attrib_yield_selected(fcb
|
|
270
|
+
def update_menu_attrib_yield_selected(fcb:, messages:, configuration: {}, &block)
|
|
268
271
|
initialize_fcb_names(fcb)
|
|
269
272
|
return unless fcb.body
|
|
270
273
|
|
|
271
274
|
default_block_title_from_body(fcb)
|
|
272
|
-
MarkdownExec::Filter.yield_to_block_if_applicable(fcb,
|
|
275
|
+
MarkdownExec::Filter.yield_to_block_if_applicable(fcb, messages, configuration,
|
|
273
276
|
&block)
|
|
274
277
|
end
|
|
275
278
|
|
|
276
|
-
# Writes the provided code blocks to a file.
|
|
277
|
-
# @param code_blocks [String] Code blocks to write into the file.
|
|
278
|
-
def write_code_to_file(content, path)
|
|
279
|
-
File.write(path, content)
|
|
280
|
-
end
|
|
281
|
-
|
|
282
279
|
def write_execution_output_to_file(files, filespec)
|
|
283
280
|
FileUtils.mkdir_p File.dirname(filespec)
|
|
284
281
|
|
|
@@ -304,7 +301,6 @@ module HashDelegatorSelf
|
|
|
304
301
|
block.call(:line, MarkdownExec::FCB.new(body: [line]))
|
|
305
302
|
end
|
|
306
303
|
end
|
|
307
|
-
### require_relative 'hash_delegator_self'
|
|
308
304
|
|
|
309
305
|
# This module provides methods for compacting and converting data structures.
|
|
310
306
|
module CompactionHelpers
|
|
@@ -408,40 +404,37 @@ module MarkdownExec
|
|
|
408
404
|
# along with initial and final dividers, based on the delegate object's configuration.
|
|
409
405
|
#
|
|
410
406
|
# @param menu_blocks [Array] The array of menu block elements to be modified.
|
|
411
|
-
def add_menu_chrome_blocks!(menu_blocks
|
|
407
|
+
def add_menu_chrome_blocks!(menu_blocks:, link_state:)
|
|
412
408
|
return unless @delegate_object[:menu_link_format].present?
|
|
413
409
|
|
|
414
|
-
if @delegate_object[:menu_with_inherited_lines]
|
|
415
|
-
add_inherited_lines(menu_blocks,
|
|
416
|
-
link_state)
|
|
417
|
-
end
|
|
410
|
+
add_inherited_lines(menu_blocks: menu_blocks, link_state: link_state) if @delegate_object[:menu_with_inherited_lines]
|
|
418
411
|
|
|
419
412
|
# back before exit
|
|
420
|
-
add_back_option(menu_blocks) if should_add_back_option?
|
|
413
|
+
add_back_option(menu_blocks: menu_blocks) if should_add_back_option?
|
|
421
414
|
|
|
422
415
|
# exit after other options
|
|
423
|
-
add_exit_option(menu_blocks) if @delegate_object[:menu_with_exit]
|
|
416
|
+
add_exit_option(menu_blocks: menu_blocks) if @delegate_object[:menu_with_exit]
|
|
424
417
|
|
|
425
|
-
add_dividers(menu_blocks)
|
|
418
|
+
add_dividers(menu_blocks: menu_blocks)
|
|
426
419
|
end
|
|
427
420
|
|
|
428
421
|
private
|
|
429
422
|
|
|
430
|
-
def add_back_option(menu_blocks)
|
|
431
|
-
append_chrome_block(menu_blocks, MenuState::BACK)
|
|
423
|
+
def add_back_option(menu_blocks:)
|
|
424
|
+
append_chrome_block(menu_blocks: menu_blocks, menu_state: MenuState::BACK)
|
|
432
425
|
end
|
|
433
426
|
|
|
434
|
-
def add_dividers(menu_blocks)
|
|
435
|
-
append_divider(menu_blocks, :initial)
|
|
436
|
-
append_divider(menu_blocks, :final)
|
|
427
|
+
def add_dividers(menu_blocks:)
|
|
428
|
+
append_divider(menu_blocks: menu_blocks, position: :initial)
|
|
429
|
+
append_divider(menu_blocks: menu_blocks, position: :final)
|
|
437
430
|
end
|
|
438
431
|
|
|
439
|
-
def add_exit_option(menu_blocks)
|
|
440
|
-
append_chrome_block(menu_blocks, MenuState::EXIT)
|
|
432
|
+
def add_exit_option(menu_blocks:)
|
|
433
|
+
append_chrome_block(menu_blocks: menu_blocks, menu_state: MenuState::EXIT)
|
|
441
434
|
end
|
|
442
435
|
|
|
443
|
-
def add_inherited_lines(menu_blocks
|
|
444
|
-
append_inherited_lines(menu_blocks, link_state)
|
|
436
|
+
def add_inherited_lines(menu_blocks:, link_state:)
|
|
437
|
+
append_inherited_lines(menu_blocks: menu_blocks, link_state: link_state)
|
|
445
438
|
end
|
|
446
439
|
|
|
447
440
|
public
|
|
@@ -450,8 +443,8 @@ module MarkdownExec
|
|
|
450
443
|
#
|
|
451
444
|
# @param all_blocks [Array] The current blocks in the menu
|
|
452
445
|
# @param type [Symbol] The type of chrome block to add (:back or :exit)
|
|
453
|
-
def append_chrome_block(menu_blocks
|
|
454
|
-
case
|
|
446
|
+
def append_chrome_block(menu_blocks:, menu_state:)
|
|
447
|
+
case menu_state
|
|
455
448
|
when MenuState::BACK
|
|
456
449
|
history_state_partition
|
|
457
450
|
option_name = @delegate_object[:menu_option_back_name]
|
|
@@ -483,7 +476,7 @@ module MarkdownExec
|
|
|
483
476
|
#
|
|
484
477
|
# @param menu_blocks [Array] The array of menu block elements.
|
|
485
478
|
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
|
486
|
-
def append_inherited_lines(menu_blocks
|
|
479
|
+
def append_inherited_lines(menu_blocks:, link_state:, position: top)
|
|
487
480
|
return unless link_state.inherited_lines.present?
|
|
488
481
|
|
|
489
482
|
insert_at_top = @delegate_object[:menu_inherited_lines_at_top]
|
|
@@ -516,7 +509,7 @@ module MarkdownExec
|
|
|
516
509
|
#
|
|
517
510
|
# @param menu_blocks [Array] The array of menu block elements.
|
|
518
511
|
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
|
519
|
-
def append_divider(menu_blocks
|
|
512
|
+
def append_divider(menu_blocks:, position:)
|
|
520
513
|
return unless divider_formatting_present?(position)
|
|
521
514
|
|
|
522
515
|
divider = create_divider(position)
|
|
@@ -538,6 +531,15 @@ module MarkdownExec
|
|
|
538
531
|
end
|
|
539
532
|
end
|
|
540
533
|
|
|
534
|
+
def assign_key_value_in_bash(key, value)
|
|
535
|
+
if value =~ /["$\\`]/
|
|
536
|
+
# requiring ShellWords to write into Bash scripts
|
|
537
|
+
"#{key}=#{Shellwords.escape(value)}"
|
|
538
|
+
else
|
|
539
|
+
"#{key}=\"#{value}\""
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
541
543
|
# private
|
|
542
544
|
|
|
543
545
|
# Iterates through nested files to collect various types of blocks, including dividers, tasks, and others.
|
|
@@ -599,11 +601,9 @@ module MarkdownExec
|
|
|
599
601
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
|
600
602
|
# @param selected [Hash] The selected block.
|
|
601
603
|
# @return [Array<String>] Required code blocks as an array of lines.
|
|
602
|
-
def collect_required_code_lines(mdoc
|
|
603
|
-
set_environment_variables_for_block(selected) if selected[:shell] == BlockType::VARS
|
|
604
|
-
|
|
604
|
+
def collect_required_code_lines(mdoc:, selected:, block_source:, link_state: LinkState.new)
|
|
605
605
|
required = mdoc.collect_recursively_required_code(
|
|
606
|
-
selected[:nickname] || selected[:oname],
|
|
606
|
+
anyname: selected[:nickname] || selected[:oname],
|
|
607
607
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
|
608
608
|
label_format_below: @delegate_object[:shell_code_label_format_below],
|
|
609
609
|
block_source: block_source
|
|
@@ -619,12 +619,14 @@ module MarkdownExec
|
|
|
619
619
|
runtime_exception(:runtime_exception_error_level,
|
|
620
620
|
'unmet_dependencies, flag: runtime_exception_error_level',
|
|
621
621
|
required[:unmet_dependencies])
|
|
622
|
-
|
|
622
|
+
else
|
|
623
623
|
warn format_and_highlight_dependencies(dependencies,
|
|
624
624
|
highlight: [@delegate_object[:block_name]])
|
|
625
625
|
end
|
|
626
626
|
|
|
627
|
-
|
|
627
|
+
code_lines = selected[:shell] == BlockType::VARS ? set_environment_variables_for_block(selected) : []
|
|
628
|
+
|
|
629
|
+
HashDelegator.code_merge(link_state&.inherited_lines, required[:code] + code_lines)
|
|
628
630
|
end
|
|
629
631
|
|
|
630
632
|
def command_execute(command, args: [])
|
|
@@ -663,14 +665,14 @@ module MarkdownExec
|
|
|
663
665
|
'-c', command,
|
|
664
666
|
@delegate_object[:filename],
|
|
665
667
|
*args) do |stdin, stdout, stderr, exec_thr|
|
|
666
|
-
handle_stream(stdout, ExecutionStreams::StdOut) do |line|
|
|
668
|
+
handle_stream(stream: stdout, file_type: ExecutionStreams::StdOut) do |line|
|
|
667
669
|
yield nil, line, nil, exec_thr if block_given?
|
|
668
670
|
end
|
|
669
|
-
handle_stream(stderr, ExecutionStreams::StdErr) do |line|
|
|
671
|
+
handle_stream(stream: stderr, file_type: ExecutionStreams::StdErr) do |line|
|
|
670
672
|
yield nil, nil, line, exec_thr if block_given?
|
|
671
673
|
end
|
|
672
674
|
|
|
673
|
-
in_thr = handle_stream($stdin, ExecutionStreams::StdIn) do |line|
|
|
675
|
+
in_thr = handle_stream(stream: $stdin, file_type: ExecutionStreams::StdIn) do |line|
|
|
674
676
|
stdin.puts(line)
|
|
675
677
|
yield line, nil, nil, exec_thr if block_given?
|
|
676
678
|
end
|
|
@@ -699,7 +701,7 @@ module MarkdownExec
|
|
|
699
701
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
|
700
702
|
end
|
|
701
703
|
|
|
702
|
-
def load_cli_or_user_selected_block(all_blocks, menu_blocks, default)
|
|
704
|
+
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [], default: nil)
|
|
703
705
|
if @delegate_object[:block_name].present?
|
|
704
706
|
block = all_blocks.find do |item|
|
|
705
707
|
item[:oname] == @delegate_object[:block_name]
|
|
@@ -723,18 +725,18 @@ module MarkdownExec
|
|
|
723
725
|
# @param mdoc [Object] The markdown document object containing code blocks.
|
|
724
726
|
# @param selected [Hash] The selected item from the menu to be executed.
|
|
725
727
|
# @return [LoadFileLinkState] An object indicating whether to load the next block or reuse the current one.
|
|
726
|
-
def compile_execute_and_trigger_reuse(mdoc
|
|
727
|
-
required_lines = collect_required_code_lines(mdoc, selected, link_state,
|
|
728
|
+
def compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:, link_state: nil)
|
|
729
|
+
required_lines = collect_required_code_lines(mdoc: mdoc, selected: selected, link_state: link_state,
|
|
728
730
|
block_source: block_source)
|
|
729
731
|
output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
|
|
730
|
-
display_required_code(required_lines) if output_or_approval
|
|
732
|
+
display_required_code(required_lines: required_lines) if output_or_approval
|
|
731
733
|
allow_execution = if @delegate_object[:user_must_approve]
|
|
732
|
-
prompt_for_user_approval(required_lines, selected)
|
|
734
|
+
prompt_for_user_approval(required_lines: required_lines, selected: selected)
|
|
733
735
|
else
|
|
734
736
|
true
|
|
735
737
|
end
|
|
736
738
|
|
|
737
|
-
execute_required_lines(required_lines, selected) if allow_execution
|
|
739
|
+
execute_required_lines(required_lines: required_lines, selected: selected) if allow_execution
|
|
738
740
|
|
|
739
741
|
link_state.block_name = nil
|
|
740
742
|
LoadFileLinkState.new(LoadFile::Reuse, link_state)
|
|
@@ -766,8 +768,8 @@ module MarkdownExec
|
|
|
766
768
|
# @param match_data [MatchData] The match data containing named captures for formatting.
|
|
767
769
|
# @param format_option [String] The format string to be used for the new block.
|
|
768
770
|
# @param color_method [Symbol] The color method to apply to the block's display name.
|
|
769
|
-
def create_and_add_chrome_block(blocks
|
|
770
|
-
color_method)
|
|
771
|
+
def create_and_add_chrome_block(blocks:, match_data:, format_option:,
|
|
772
|
+
color_method:)
|
|
771
773
|
oname = format(format_option,
|
|
772
774
|
match_data.named_captures.transform_keys(&:to_sym))
|
|
773
775
|
blocks.push FCB.new(
|
|
@@ -800,8 +802,12 @@ module MarkdownExec
|
|
|
800
802
|
next
|
|
801
803
|
end
|
|
802
804
|
|
|
803
|
-
create_and_add_chrome_block(
|
|
804
|
-
|
|
805
|
+
create_and_add_chrome_block(
|
|
806
|
+
blocks: blocks,
|
|
807
|
+
match_data: mbody,
|
|
808
|
+
format_option: @delegate_object[criteria[:format]],
|
|
809
|
+
color_method: @delegate_object[criteria[:color]].to_sym
|
|
810
|
+
)
|
|
805
811
|
break
|
|
806
812
|
end
|
|
807
813
|
end
|
|
@@ -829,9 +835,7 @@ module MarkdownExec
|
|
|
829
835
|
return true if @run_state.block_name_from_cli
|
|
830
836
|
|
|
831
837
|
# return false if @prior_execution_block == @delegate_object[:block_name]
|
|
832
|
-
if @prior_execution_block == @delegate_object[:block_name]
|
|
833
|
-
return @allowed_execution_block == @prior_execution_block || prompt_approve_repeat
|
|
834
|
-
end
|
|
838
|
+
return @allowed_execution_block == @prior_execution_block || prompt_approve_repeat if @prior_execution_block == @delegate_object[:block_name]
|
|
835
839
|
|
|
836
840
|
@prior_execution_block = @delegate_object[:block_name]
|
|
837
841
|
@allowed_execution_block = nil
|
|
@@ -865,7 +869,7 @@ module MarkdownExec
|
|
|
865
869
|
# It wraps the code lines between a formatted header and tail.
|
|
866
870
|
#
|
|
867
871
|
# @param required_lines [Array<String>] The lines of code to be displayed.
|
|
868
|
-
def display_required_code(required_lines)
|
|
872
|
+
def display_required_code(required_lines:)
|
|
869
873
|
output_color_formatted(:script_preview_head,
|
|
870
874
|
:script_preview_frame_color)
|
|
871
875
|
required_lines.each { |cb| @fout.fout cb }
|
|
@@ -892,10 +896,10 @@ module MarkdownExec
|
|
|
892
896
|
#
|
|
893
897
|
# @param required_lines [Array<String>] The lines of code to be executed.
|
|
894
898
|
# @param selected [FCB] The selected functional code block object.
|
|
895
|
-
def execute_required_lines(required_lines
|
|
896
|
-
write_command_file(required_lines, selected) if @delegate_object[:save_executed_script]
|
|
899
|
+
def execute_required_lines(required_lines: [], selected: FCB.new)
|
|
900
|
+
write_command_file(required_lines: required_lines, selected: selected) if @delegate_object[:save_executed_script]
|
|
897
901
|
calc_logged_stdout_filename
|
|
898
|
-
format_and_execute_command(required_lines)
|
|
902
|
+
format_and_execute_command(code_lines: required_lines)
|
|
899
903
|
post_execution_process
|
|
900
904
|
end
|
|
901
905
|
|
|
@@ -908,12 +912,14 @@ module MarkdownExec
|
|
|
908
912
|
# @param opts [Hash] Options hash containing configuration settings.
|
|
909
913
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
|
910
914
|
#
|
|
911
|
-
def execute_shell_type(selected
|
|
912
|
-
block_source:)
|
|
915
|
+
def execute_shell_type(selected:, mdoc:, block_source:, link_state: LinkState.new)
|
|
913
916
|
if selected.fetch(:shell, '') == BlockType::LINK
|
|
914
917
|
debounce_reset
|
|
915
|
-
push_link_history_and_trigger_load(selected.fetch(:body, ''),
|
|
916
|
-
|
|
918
|
+
push_link_history_and_trigger_load(link_block_body: selected.fetch(:body, ''),
|
|
919
|
+
mdoc: mdoc,
|
|
920
|
+
selected: selected,
|
|
921
|
+
link_state: link_state,
|
|
922
|
+
block_source: block_source)
|
|
917
923
|
|
|
918
924
|
elsif @menu_user_clicked_back_link
|
|
919
925
|
debounce_reset
|
|
@@ -921,13 +927,50 @@ module MarkdownExec
|
|
|
921
927
|
|
|
922
928
|
elsif selected[:shell] == BlockType::OPTS
|
|
923
929
|
debounce_reset
|
|
924
|
-
|
|
930
|
+
block_names = []
|
|
931
|
+
code_lines = []
|
|
932
|
+
dependencies = {}
|
|
933
|
+
options_state = read_show_options_and_trigger_reuse(selected: selected, link_state: link_state)
|
|
934
|
+
|
|
935
|
+
## apply options to current state
|
|
936
|
+
#
|
|
925
937
|
@menu_base_options.merge!(options_state.options)
|
|
926
938
|
@delegate_object.merge!(options_state.options)
|
|
927
|
-
|
|
939
|
+
|
|
940
|
+
### options_state.load_file_link_state
|
|
941
|
+
link_state = LinkState.new
|
|
942
|
+
link_history_push_and_next(
|
|
943
|
+
curr_block_name: selected[:oname],
|
|
944
|
+
curr_document_filename: @delegate_object[:filename],
|
|
945
|
+
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
|
946
|
+
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
|
947
|
+
inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
|
948
|
+
next_block_name: '',
|
|
949
|
+
next_document_filename: @delegate_object[:filename],
|
|
950
|
+
next_load_file: LoadFile::Reuse
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
elsif selected[:shell] == BlockType::VARS
|
|
955
|
+
debounce_reset
|
|
956
|
+
block_names = []
|
|
957
|
+
code_lines = set_environment_variables_for_block(selected)
|
|
958
|
+
dependencies = {}
|
|
959
|
+
link_history_push_and_next(
|
|
960
|
+
curr_block_name: selected[:oname],
|
|
961
|
+
curr_document_filename: @delegate_object[:filename],
|
|
962
|
+
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
|
963
|
+
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
|
964
|
+
inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
|
965
|
+
next_block_name: '',
|
|
966
|
+
next_document_filename: @delegate_object[:filename],
|
|
967
|
+
next_load_file: LoadFile::Reuse
|
|
968
|
+
)
|
|
928
969
|
|
|
929
970
|
elsif debounce_allows
|
|
930
|
-
compile_execute_and_trigger_reuse(mdoc
|
|
971
|
+
compile_execute_and_trigger_reuse(mdoc: mdoc,
|
|
972
|
+
selected: selected,
|
|
973
|
+
link_state: link_state,
|
|
931
974
|
block_source: block_source)
|
|
932
975
|
else
|
|
933
976
|
LoadFileLinkState.new(LoadFile::Reuse, link_state)
|
|
@@ -948,8 +991,8 @@ module MarkdownExec
|
|
|
948
991
|
string_send_color(data_string, color_sym)
|
|
949
992
|
end
|
|
950
993
|
|
|
951
|
-
def format_and_execute_command(
|
|
952
|
-
formatted_command =
|
|
994
|
+
def format_and_execute_command(code_lines:)
|
|
995
|
+
formatted_command = code_lines.flatten.join("\n")
|
|
953
996
|
@fout.fout fetch_color(data_sym: :script_execution_head,
|
|
954
997
|
color_sym: :script_execution_frame_color)
|
|
955
998
|
command_execute(formatted_command, args: @pass_args)
|
|
@@ -1032,7 +1075,7 @@ module MarkdownExec
|
|
|
1032
1075
|
@menu_user_clicked_back_link = block_state.state == MenuState::BACK
|
|
1033
1076
|
end
|
|
1034
1077
|
|
|
1035
|
-
def handle_stream(stream
|
|
1078
|
+
def handle_stream(stream:, file_type:, swap: false)
|
|
1036
1079
|
@process_mutex.synchronize do
|
|
1037
1080
|
Thread.new do
|
|
1038
1081
|
stream.each_line do |line|
|
|
@@ -1086,10 +1129,10 @@ module MarkdownExec
|
|
|
1086
1129
|
end
|
|
1087
1130
|
end
|
|
1088
1131
|
|
|
1089
|
-
def link_block_data_eval(link_state, code_lines, selected, link_block_data)
|
|
1132
|
+
def link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source:)
|
|
1090
1133
|
all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines)
|
|
1091
1134
|
|
|
1092
|
-
if link_block_data.fetch(
|
|
1135
|
+
if link_block_data.fetch(LinkKeys::Exec, false)
|
|
1093
1136
|
@run_state.files = Hash.new([])
|
|
1094
1137
|
output_lines = []
|
|
1095
1138
|
|
|
@@ -1097,14 +1140,14 @@ module MarkdownExec
|
|
|
1097
1140
|
@delegate_object[:shell],
|
|
1098
1141
|
'-c', all_code.join("\n")
|
|
1099
1142
|
) do |stdin, stdout, stderr, _exec_thr|
|
|
1100
|
-
handle_stream(stdout, ExecutionStreams::StdOut) do |line|
|
|
1143
|
+
handle_stream(stream: stdout, file_type: ExecutionStreams::StdOut) do |line|
|
|
1101
1144
|
output_lines.push(line)
|
|
1102
1145
|
end
|
|
1103
|
-
handle_stream(stderr, ExecutionStreams::StdErr) do |line|
|
|
1146
|
+
handle_stream(stream: stderr, file_type: ExecutionStreams::StdErr) do |line|
|
|
1104
1147
|
output_lines.push(line)
|
|
1105
1148
|
end
|
|
1106
1149
|
|
|
1107
|
-
in_thr = handle_stream($stdin, ExecutionStreams::StdIn) do |line|
|
|
1150
|
+
in_thr = handle_stream(stream: $stdin, file_type: ExecutionStreams::StdIn) do |line|
|
|
1108
1151
|
stdin.puts(line)
|
|
1109
1152
|
end
|
|
1110
1153
|
|
|
@@ -1127,13 +1170,10 @@ module MarkdownExec
|
|
|
1127
1170
|
output_lines = `#{all_code.join("\n")}`.split("\n")
|
|
1128
1171
|
end
|
|
1129
1172
|
|
|
1130
|
-
unless output_lines
|
|
1131
|
-
HashDelegator.error_handler('all_code eval output_lines is nil', { abort: true })
|
|
1132
|
-
end
|
|
1173
|
+
HashDelegator.error_handler('all_code eval output_lines is nil', { abort: true }) unless output_lines
|
|
1133
1174
|
|
|
1134
1175
|
label_format_above = @delegate_object[:shell_code_label_format_above]
|
|
1135
1176
|
label_format_below = @delegate_object[:shell_code_label_format_below]
|
|
1136
|
-
block_source = { document_filename: link_state&.document_filename }
|
|
1137
1177
|
|
|
1138
1178
|
[label_format_above && format(label_format_above,
|
|
1139
1179
|
block_source.merge({ block_name: selected[:oname] }))] +
|
|
@@ -1172,20 +1212,126 @@ module MarkdownExec
|
|
|
1172
1212
|
)
|
|
1173
1213
|
end
|
|
1174
1214
|
|
|
1215
|
+
# format + glob + select for file in load block
|
|
1216
|
+
# name has references to ENV vars and doc and batch vars incl. timestamp
|
|
1217
|
+
def load_filespec_from_expression(expression)
|
|
1218
|
+
# Process expression with embedded formatting
|
|
1219
|
+
expanded_expression = formatted_expression(expression)
|
|
1220
|
+
|
|
1221
|
+
# Handle wildcards or direct file specification
|
|
1222
|
+
if contains_wildcards?(expanded_expression)
|
|
1223
|
+
load_filespec_wildcard_expansion(expanded_expression)
|
|
1224
|
+
else
|
|
1225
|
+
expanded_expression
|
|
1226
|
+
end
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
def save_filespec_from_expression(expression)
|
|
1230
|
+
# Process expression with embedded formatting
|
|
1231
|
+
formatted = formatted_expression(expression)
|
|
1232
|
+
|
|
1233
|
+
# Handle wildcards or direct file specification
|
|
1234
|
+
if contains_wildcards?(formatted)
|
|
1235
|
+
save_filespec_wildcard_expansion(formatted)
|
|
1236
|
+
else
|
|
1237
|
+
formatted
|
|
1238
|
+
end
|
|
1239
|
+
end
|
|
1240
|
+
|
|
1241
|
+
# private
|
|
1242
|
+
|
|
1243
|
+
# Expand expression if it contains format specifiers
|
|
1244
|
+
def formatted_expression(expr)
|
|
1245
|
+
expr.include?('%{') ? format_expression(expr) : expr
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
# Format expression using environment variables and run state
|
|
1249
|
+
def format_expression(expr)
|
|
1250
|
+
data = link_load_format_data
|
|
1251
|
+
ENV.each { |key, value| data[key] = value }
|
|
1252
|
+
format(expr, data)
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
# Check if the expression contains wildcard characters
|
|
1256
|
+
def contains_wildcards?(expr)
|
|
1257
|
+
expr.match(%r{\*|\?|\[})
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
# Handle expression with wildcard characters
|
|
1261
|
+
def load_filespec_wildcard_expansion(expr)
|
|
1262
|
+
files = find_files(expr)
|
|
1263
|
+
case files.count
|
|
1264
|
+
when 0
|
|
1265
|
+
HashDelegator.error_handler("no files found with '#{expr}' ", { abort: true })
|
|
1266
|
+
when 1
|
|
1267
|
+
files.first
|
|
1268
|
+
else
|
|
1269
|
+
prompt_select_code_filename(files)
|
|
1270
|
+
end
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
# Handle expression with wildcard characters
|
|
1274
|
+
# allow user to select or enter
|
|
1275
|
+
def puts_gets_oprompt_(filespec)
|
|
1276
|
+
puts format(@delegate_object[:prompt_show_expr_format],
|
|
1277
|
+
{ expr: filespec })
|
|
1278
|
+
puts @delegate_object[:prompt_enter_filespec]
|
|
1279
|
+
gets.chomp
|
|
1280
|
+
end
|
|
1281
|
+
|
|
1282
|
+
# prompt user to enter a path (i.e. containing a path separator)
|
|
1283
|
+
# or name to substitute into the wildcard expression
|
|
1284
|
+
def prompt_for_filespec_with_wildcard(filespec)
|
|
1285
|
+
puts format(@delegate_object[:prompt_show_expr_format],
|
|
1286
|
+
{ expr: filespec })
|
|
1287
|
+
puts @delegate_object[:prompt_enter_filespec]
|
|
1288
|
+
resolve_path_or_substitute(gets.chomp, filespec)
|
|
1289
|
+
end
|
|
1290
|
+
|
|
1291
|
+
# Handle expression with wildcard characters
|
|
1292
|
+
# allow user to select or enter
|
|
1293
|
+
def save_filespec_wildcard_expansion(filespec)
|
|
1294
|
+
files = find_files(filespec)
|
|
1295
|
+
case files.count
|
|
1296
|
+
when 0
|
|
1297
|
+
prompt_for_filespec_with_wildcard(filespec)
|
|
1298
|
+
else
|
|
1299
|
+
## user selects from existing files or other
|
|
1300
|
+
# input into path with wildcard for easy entry
|
|
1301
|
+
#
|
|
1302
|
+
name = prompt_select_code_filename([@delegate_object[:prompt_filespec_other]] + files)
|
|
1303
|
+
if name == @delegate_object[:prompt_filespec_other]
|
|
1304
|
+
prompt_for_filespec_with_wildcard(filespec)
|
|
1305
|
+
else
|
|
1306
|
+
name
|
|
1307
|
+
end
|
|
1308
|
+
end
|
|
1309
|
+
end
|
|
1310
|
+
|
|
1311
|
+
def link_load_format_data
|
|
1312
|
+
{
|
|
1313
|
+
batch_index: @run_state.batch_index,
|
|
1314
|
+
batch_random: @run_state.batch_random,
|
|
1315
|
+
block_name: @delegate_object[:block_name],
|
|
1316
|
+
document_filename: File.basename(@delegate_object[:filename]),
|
|
1317
|
+
document_filespec: @delegate_object[:filename],
|
|
1318
|
+
home: Dir.pwd,
|
|
1319
|
+
started_at: Time.now.utc.strftime(@delegate_object[:execute_command_title_time_format])
|
|
1320
|
+
}
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1175
1323
|
# Loads auto blocks based on delegate object settings and updates if new filename is detected.
|
|
1176
1324
|
# Executes a specified block once per filename.
|
|
1177
1325
|
# @param all_blocks [Array] Array of all block elements.
|
|
1178
1326
|
# @return [Boolean, nil] True if values were modified, nil otherwise.
|
|
1179
1327
|
def load_auto_blocks(all_blocks)
|
|
1180
1328
|
block_name = @delegate_object[:document_load_opts_block_name]
|
|
1181
|
-
unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
|
1182
|
-
return
|
|
1183
|
-
end
|
|
1329
|
+
return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
|
1184
1330
|
|
|
1185
1331
|
block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
|
1186
1332
|
return unless block
|
|
1187
1333
|
|
|
1188
|
-
options_state = read_show_options_and_trigger_reuse(block)
|
|
1334
|
+
options_state = read_show_options_and_trigger_reuse(selected: block)
|
|
1189
1335
|
@menu_base_options.merge!(options_state.options)
|
|
1190
1336
|
@delegate_object.merge!(options_state.options)
|
|
1191
1337
|
|
|
@@ -1211,7 +1357,7 @@ module MarkdownExec
|
|
|
1211
1357
|
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_blocks(all_blocks)
|
|
1212
1358
|
|
|
1213
1359
|
menu_blocks = mdoc.fcbs_per_options(@delegate_object)
|
|
1214
|
-
add_menu_chrome_blocks!(menu_blocks, link_state)
|
|
1360
|
+
add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
|
|
1215
1361
|
### compress empty lines
|
|
1216
1362
|
HashDelegator.delete_consecutive_blank_lines!(menu_blocks) if true
|
|
1217
1363
|
[all_blocks, menu_blocks, mdoc]
|
|
@@ -1253,13 +1399,6 @@ module MarkdownExec
|
|
|
1253
1399
|
end
|
|
1254
1400
|
end
|
|
1255
1401
|
|
|
1256
|
-
def shift_cli_argument
|
|
1257
|
-
return true unless @menu_base_options[:input_cli_rest].present?
|
|
1258
|
-
|
|
1259
|
-
@cli_block_name = @menu_base_options[:input_cli_rest].shift
|
|
1260
|
-
false
|
|
1261
|
-
end
|
|
1262
|
-
|
|
1263
1402
|
def output_color_formatted(data_sym, color_sym)
|
|
1264
1403
|
formatted_string = string_send_color(@delegate_object[data_sym],
|
|
1265
1404
|
color_sym)
|
|
@@ -1338,7 +1477,7 @@ module MarkdownExec
|
|
|
1338
1477
|
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
|
1339
1478
|
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
|
1340
1479
|
inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
|
1341
|
-
next_block_name: '', # not link_block_data[
|
|
1480
|
+
next_block_name: '', # not link_block_data[LinkKeys::Block] || ''
|
|
1342
1481
|
next_document_filename: @delegate_object[:filename], # not next_document_filename
|
|
1343
1482
|
next_load_file: LoadFile::Reuse # not next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
|
|
1344
1483
|
)
|
|
@@ -1482,7 +1621,7 @@ module MarkdownExec
|
|
|
1482
1621
|
#
|
|
1483
1622
|
# @return [Boolean] Returns true if the user approves (selects 'Yes'), false otherwise.
|
|
1484
1623
|
##
|
|
1485
|
-
def prompt_for_user_approval(required_lines
|
|
1624
|
+
def prompt_for_user_approval(required_lines:, selected:)
|
|
1486
1625
|
# Present a selection menu for user approval.
|
|
1487
1626
|
sel = @prompt.select(
|
|
1488
1627
|
string_send_color(@delegate_object[:prompt_approve_block],
|
|
@@ -1502,7 +1641,7 @@ module MarkdownExec
|
|
|
1502
1641
|
if sel == MenuOptions::SCRIPT_TO_CLIPBOARD
|
|
1503
1642
|
copy_to_clipboard(required_lines)
|
|
1504
1643
|
elsif sel == MenuOptions::SAVE_SCRIPT
|
|
1505
|
-
save_to_file(required_lines, selected)
|
|
1644
|
+
save_to_file(required_lines: required_lines, selected: selected)
|
|
1506
1645
|
end
|
|
1507
1646
|
|
|
1508
1647
|
sel == MenuOptions::YES
|
|
@@ -1527,6 +1666,21 @@ module MarkdownExec
|
|
|
1527
1666
|
|
|
1528
1667
|
# public
|
|
1529
1668
|
|
|
1669
|
+
def prompt_select_code_filename(filenames)
|
|
1670
|
+
@prompt.select(
|
|
1671
|
+
string_send_color(@delegate_object[:prompt_select_code_file],
|
|
1672
|
+
:prompt_color_after_script_execution),
|
|
1673
|
+
filter: true,
|
|
1674
|
+
quiet: true
|
|
1675
|
+
) do |menu|
|
|
1676
|
+
filenames.each do |filename|
|
|
1677
|
+
menu.choice filename
|
|
1678
|
+
end
|
|
1679
|
+
end
|
|
1680
|
+
rescue TTY::Reader::InputInterrupt
|
|
1681
|
+
exit 1
|
|
1682
|
+
end
|
|
1683
|
+
|
|
1530
1684
|
# Handles the processing of a link block in Markdown Execution.
|
|
1531
1685
|
# It loads YAML data from the link_block_body content, pushes the state to history,
|
|
1532
1686
|
# sets environment variables, and decides on the next block to load.
|
|
@@ -1535,25 +1689,18 @@ module MarkdownExec
|
|
|
1535
1689
|
# @param mdoc [Object] Markdown document object.
|
|
1536
1690
|
# @param selected [FCB] Selected code block.
|
|
1537
1691
|
# @return [LoadFileLinkState] Object indicating the next action for file loading.
|
|
1538
|
-
def push_link_history_and_trigger_load(link_block_body, mdoc, selected,
|
|
1539
|
-
link_state
|
|
1692
|
+
def push_link_history_and_trigger_load(link_block_body: [], mdoc: nil, selected: FCB.new,
|
|
1693
|
+
link_state: LinkState.new, block_source: {})
|
|
1540
1694
|
link_block_data = HashDelegator.parse_yaml_data_from_body(link_block_body)
|
|
1541
1695
|
|
|
1542
|
-
# load key and values from link block into current environment
|
|
1543
|
-
#
|
|
1544
|
-
(link_block_data['vars'] || []).each do |(key, value)|
|
|
1545
|
-
ENV[key] = value.to_s
|
|
1546
|
-
### add to inherited_lines
|
|
1547
|
-
end
|
|
1548
|
-
|
|
1549
1696
|
## collect blocks specified by block
|
|
1550
1697
|
#
|
|
1551
1698
|
if mdoc
|
|
1552
1699
|
code_info = mdoc.collect_recursively_required_code(
|
|
1553
|
-
selected[:oname],
|
|
1700
|
+
anyname: selected[:oname],
|
|
1554
1701
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
|
1555
1702
|
label_format_below: @delegate_object[:shell_code_label_format_below],
|
|
1556
|
-
block_source:
|
|
1703
|
+
block_source: block_source
|
|
1557
1704
|
)
|
|
1558
1705
|
code_lines = code_info[:code]
|
|
1559
1706
|
block_names = code_info[:block_names]
|
|
@@ -1563,22 +1710,34 @@ module MarkdownExec
|
|
|
1563
1710
|
code_lines = []
|
|
1564
1711
|
dependencies = {}
|
|
1565
1712
|
end
|
|
1566
|
-
next_document_filename = link_block_data['file'] || @delegate_object[:filename]
|
|
1567
1713
|
|
|
1568
|
-
|
|
1714
|
+
# load key and values from link block into current environment
|
|
1715
|
+
#
|
|
1716
|
+
if link_block_data[LinkKeys::Vars]
|
|
1717
|
+
code_lines.push "# #{selected[:oname]}"
|
|
1718
|
+
(link_block_data[LinkKeys::Vars] || []).each do |(key, value)|
|
|
1719
|
+
ENV[key] = value.to_s
|
|
1720
|
+
code_lines.push(assign_key_value_in_bash(key, value))
|
|
1721
|
+
end
|
|
1722
|
+
end
|
|
1723
|
+
|
|
1724
|
+
## append blocks loaded, apply LinkKeys::Eval
|
|
1569
1725
|
#
|
|
1570
|
-
if (
|
|
1571
|
-
|
|
1726
|
+
if (load_expr = link_block_data.fetch(LinkKeys::Load, '')).present?
|
|
1727
|
+
load_filespec = load_filespec_from_expression(load_expr)
|
|
1728
|
+
code_lines += File.readlines(load_filespec, chomp: true) if load_filespec
|
|
1572
1729
|
end
|
|
1573
1730
|
|
|
1574
1731
|
# if an eval link block, evaluate code_lines and return its standard output
|
|
1575
1732
|
#
|
|
1576
|
-
if link_block_data.fetch(
|
|
1577
|
-
false) || link_block_data.fetch(
|
|
1578
|
-
code_lines = link_block_data_eval(link_state, code_lines, selected, link_block_data)
|
|
1733
|
+
if link_block_data.fetch(LinkKeys::Eval,
|
|
1734
|
+
false) || link_block_data.fetch(LinkKeys::Exec, false)
|
|
1735
|
+
code_lines = link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source: block_source)
|
|
1579
1736
|
end
|
|
1580
1737
|
|
|
1581
|
-
|
|
1738
|
+
next_document_filename = write_inherited_lines_to_file(link_state, link_block_data)
|
|
1739
|
+
|
|
1740
|
+
if link_block_data[LinkKeys::Return]
|
|
1582
1741
|
pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
|
|
1583
1742
|
dependencies, selected)
|
|
1584
1743
|
|
|
@@ -1589,13 +1748,26 @@ module MarkdownExec
|
|
|
1589
1748
|
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
|
1590
1749
|
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
|
1591
1750
|
inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
|
1592
|
-
next_block_name: link_block_data
|
|
1751
|
+
next_block_name: link_block_data.fetch(LinkKeys::NextBlock,
|
|
1752
|
+
nil) || link_block_data[LinkKeys::Block] || '',
|
|
1593
1753
|
next_document_filename: next_document_filename,
|
|
1594
1754
|
next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
|
|
1595
1755
|
)
|
|
1596
1756
|
end
|
|
1597
1757
|
end
|
|
1598
1758
|
|
|
1759
|
+
# Determines if a given path is absolute or substitutes a placeholder in an expression with the path.
|
|
1760
|
+
# @param path [String] The input path to check or fill in.
|
|
1761
|
+
# @param expression [String] The expression where a wildcard '*' is replaced by the path if it's not absolute.
|
|
1762
|
+
# @return [String] The absolute path or the expression with the wildcard replaced by the path.
|
|
1763
|
+
def resolve_path_or_substitute(path, expression)
|
|
1764
|
+
if path.include?('/')
|
|
1765
|
+
path
|
|
1766
|
+
else
|
|
1767
|
+
expression.gsub('*', path)
|
|
1768
|
+
end
|
|
1769
|
+
end
|
|
1770
|
+
|
|
1599
1771
|
def runtime_exception(exception_sym, name, items)
|
|
1600
1772
|
if @delegate_object[exception_sym] != 0
|
|
1601
1773
|
data = { name: name, detail: items.join(', ') }
|
|
@@ -1615,11 +1787,23 @@ module MarkdownExec
|
|
|
1615
1787
|
exit @delegate_object[exception_sym]
|
|
1616
1788
|
end
|
|
1617
1789
|
|
|
1618
|
-
def save_to_file(required_lines
|
|
1619
|
-
write_command_file(required_lines, selected)
|
|
1790
|
+
def save_to_file(required_lines:, selected:)
|
|
1791
|
+
write_command_file(required_lines: required_lines, selected: selected)
|
|
1620
1792
|
@fout.fout "File saved: #{@run_state.saved_filespec}"
|
|
1621
1793
|
end
|
|
1622
1794
|
|
|
1795
|
+
def block_state_for_name_from_cli(block_name)
|
|
1796
|
+
SelectedBlockMenuState.new(
|
|
1797
|
+
@dml_blocks_in_file.find do |item|
|
|
1798
|
+
item[:oname] == block_name
|
|
1799
|
+
end&.merge(
|
|
1800
|
+
block_name_from_cli: true,
|
|
1801
|
+
block_name_from_ui: false
|
|
1802
|
+
),
|
|
1803
|
+
MenuState::CONTINUE
|
|
1804
|
+
)
|
|
1805
|
+
end
|
|
1806
|
+
|
|
1623
1807
|
# Select and execute a code block from a Markdown document.
|
|
1624
1808
|
#
|
|
1625
1809
|
# This method allows the user to interactively select a code block from a
|
|
@@ -1628,52 +1812,109 @@ module MarkdownExec
|
|
|
1628
1812
|
# @return [Nil] Returns nil if no code block is selected or an error occurs.
|
|
1629
1813
|
def document_menu_loop
|
|
1630
1814
|
@menu_base_options = @delegate_object
|
|
1631
|
-
|
|
1815
|
+
@dml_link_state = LinkState.new(
|
|
1632
1816
|
block_name: @delegate_object[:block_name],
|
|
1633
1817
|
document_filename: @delegate_object[:filename]
|
|
1634
1818
|
)
|
|
1635
|
-
@run_state.block_name_from_cli =
|
|
1636
|
-
@cli_block_name =
|
|
1637
|
-
|
|
1638
|
-
|
|
1819
|
+
@run_state.block_name_from_cli = @dml_link_state.block_name.present?
|
|
1820
|
+
@cli_block_name = @dml_link_state.block_name
|
|
1821
|
+
@dml_now_using_cli = @run_state.block_name_from_cli
|
|
1822
|
+
@dml_menu_default_dname = nil
|
|
1823
|
+
@dml_block_state = SelectedBlockMenuState.new
|
|
1639
1824
|
|
|
1640
1825
|
@run_state.batch_random = Random.new.rand
|
|
1641
1826
|
@run_state.batch_index = 0
|
|
1642
1827
|
|
|
1643
|
-
|
|
1644
|
-
@
|
|
1645
|
-
@
|
|
1828
|
+
InputSequencer.new(
|
|
1829
|
+
@delegate_object[:filename],
|
|
1830
|
+
@delegate_object[:input_cli_rest]
|
|
1831
|
+
).run do |msg, data|
|
|
1832
|
+
case msg
|
|
1833
|
+
when :parse_document # once for each menu
|
|
1834
|
+
# puts "@ - parse document #{data}"
|
|
1835
|
+
ii_parse_document(data)
|
|
1836
|
+
|
|
1837
|
+
when :display_menu
|
|
1838
|
+
# warn "@ - display menu:"
|
|
1839
|
+
# ii_display_menu
|
|
1840
|
+
@dml_block_state = SelectedBlockMenuState.new
|
|
1841
|
+
@delegate_object[:block_name] = nil
|
|
1842
|
+
|
|
1843
|
+
when :user_choice
|
|
1844
|
+
# puts "? - Select a block to execute (or type #{$texit} to exit):"
|
|
1845
|
+
break if ii_user_choice == :break # into @dml_block_state
|
|
1846
|
+
break if @dml_block_state.block.nil? # no block matched
|
|
1847
|
+
|
|
1848
|
+
# puts "! - Executing block: #{data}"
|
|
1849
|
+
@dml_block_state.block[:oname]
|
|
1850
|
+
|
|
1851
|
+
when :execute_block
|
|
1852
|
+
block_name = data
|
|
1853
|
+
if block_name == '* Back' ####
|
|
1854
|
+
debounce_reset
|
|
1855
|
+
@menu_user_clicked_back_link = true
|
|
1856
|
+
load_file_link_state = pop_link_history_and_trigger_load
|
|
1857
|
+
@dml_link_state = load_file_link_state.link_state
|
|
1858
|
+
|
|
1859
|
+
InputSequencer.merge_link_state(
|
|
1860
|
+
@dml_link_state,
|
|
1861
|
+
InputSequencer.next_link_state(
|
|
1862
|
+
block_name: @dml_link_state.block_name,
|
|
1863
|
+
document_filename: @dml_link_state.document_filename,
|
|
1864
|
+
prior_block_was_link: true
|
|
1865
|
+
)
|
|
1866
|
+
)
|
|
1646
1867
|
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1868
|
+
else
|
|
1869
|
+
@dml_block_state = block_state_for_name_from_cli(block_name)
|
|
1870
|
+
if @dml_block_state.block[:shell] == BlockType::OPTS
|
|
1871
|
+
debounce_reset
|
|
1872
|
+
link_state = LinkState.new
|
|
1873
|
+
options_state = read_show_options_and_trigger_reuse(
|
|
1874
|
+
selected: @dml_block_state.block,
|
|
1875
|
+
link_state: link_state
|
|
1876
|
+
)
|
|
1877
|
+
|
|
1878
|
+
@menu_base_options.merge!(options_state.options)
|
|
1879
|
+
@delegate_object.merge!(options_state.options)
|
|
1880
|
+
options_state.load_file_link_state.link_state
|
|
1881
|
+
else
|
|
1882
|
+
ii_execute_block(block_name)
|
|
1650
1883
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
# &bsp '@run_state.block_name_from_cli:',@run_state.block_name_from_cli
|
|
1656
|
-
if !block_state
|
|
1657
|
-
HashDelegator.error_handler('block_state missing', { abort: true })
|
|
1658
|
-
elsif block_state.state == MenuState::EXIT
|
|
1659
|
-
# &bsp 'load_cli_or_user_selected_block -> break'
|
|
1660
|
-
break
|
|
1661
|
-
end
|
|
1884
|
+
if prompt_user_exit(block_name_from_cli: @run_state.block_name_from_cli,
|
|
1885
|
+
selected: @dml_block_state.block)
|
|
1886
|
+
return :break
|
|
1887
|
+
end
|
|
1662
1888
|
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1889
|
+
## order of block name processing: link block, cli, from user
|
|
1890
|
+
#
|
|
1891
|
+
@cli_block_name = block_name
|
|
1892
|
+
@dml_link_state.block_name, @run_state.block_name_from_cli, cli_break = \
|
|
1893
|
+
HashDelegator.next_link_state(
|
|
1894
|
+
block_name_from_cli: !@dml_link_state.block_name,
|
|
1895
|
+
was_using_cli: @dml_now_using_cli,
|
|
1896
|
+
block_state: @dml_block_state,
|
|
1897
|
+
block_name: @dml_link_state.block_name
|
|
1898
|
+
)
|
|
1899
|
+
|
|
1900
|
+
if !@dml_block_state.block[:block_name_from_ui] && cli_break
|
|
1901
|
+
# &bsp '!block_name_from_ui + cli_break -> break'
|
|
1902
|
+
return :break
|
|
1903
|
+
end
|
|
1670
1904
|
|
|
1671
|
-
|
|
1672
|
-
|
|
1905
|
+
InputSequencer.next_link_state(
|
|
1906
|
+
block_name: @dml_link_state.block_name,
|
|
1907
|
+
prior_block_was_link: @dml_block_state.block[:shell] != BlockType::BASH
|
|
1908
|
+
)
|
|
1909
|
+
end
|
|
1910
|
+
end
|
|
1673
1911
|
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1912
|
+
when :exit?
|
|
1913
|
+
data == $texit
|
|
1914
|
+
when :stay?
|
|
1915
|
+
data == $stay
|
|
1916
|
+
else
|
|
1917
|
+
raise "Invalid message: #{msg}"
|
|
1677
1918
|
end
|
|
1678
1919
|
end
|
|
1679
1920
|
rescue StandardError
|
|
@@ -1681,23 +1922,66 @@ module MarkdownExec
|
|
|
1681
1922
|
{ abort: true })
|
|
1682
1923
|
end
|
|
1683
1924
|
|
|
1684
|
-
def
|
|
1925
|
+
def ii_parse_document(_document_filename)
|
|
1926
|
+
@run_state.batch_index += 1
|
|
1927
|
+
@run_state.in_own_window = false
|
|
1928
|
+
|
|
1929
|
+
# &bsp 'loop', block_name_from_cli, @cli_block_name
|
|
1930
|
+
@run_state.block_name_from_cli, @dml_now_using_cli, @dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc = \
|
|
1931
|
+
set_delobj_menu_loop_vars(block_name_from_cli: @run_state.block_name_from_cli,
|
|
1932
|
+
now_using_cli: @dml_now_using_cli,
|
|
1933
|
+
link_state: @dml_link_state)
|
|
1934
|
+
end
|
|
1935
|
+
|
|
1936
|
+
def ii_user_choice
|
|
1937
|
+
@dml_block_state = load_cli_or_user_selected_block(all_blocks: @dml_blocks_in_file,
|
|
1938
|
+
menu_blocks: @dml_menu_blocks,
|
|
1939
|
+
default: @dml_menu_default_dname)
|
|
1940
|
+
# &bsp '@run_state.block_name_from_cli:',@run_state.block_name_from_cli
|
|
1941
|
+
if !@dml_block_state
|
|
1942
|
+
HashDelegator.error_handler('block_state missing', { abort: true })
|
|
1943
|
+
elsif @dml_block_state.state == MenuState::EXIT
|
|
1944
|
+
# &bsp 'load_cli_or_user_selected_block -> break'
|
|
1945
|
+
:break
|
|
1946
|
+
end
|
|
1947
|
+
end
|
|
1948
|
+
|
|
1949
|
+
def ii_execute_block(block_name)
|
|
1950
|
+
@dml_block_state = block_state_for_name_from_cli(block_name)
|
|
1951
|
+
|
|
1952
|
+
dump_and_warn_block_state(selected: @dml_block_state.block)
|
|
1953
|
+
@dml_link_state, @dml_menu_default_dname = \
|
|
1954
|
+
exec_bash_next_state(
|
|
1955
|
+
selected: @dml_block_state.block,
|
|
1956
|
+
mdoc: @dml_mdoc,
|
|
1957
|
+
link_state: @dml_link_state,
|
|
1958
|
+
block_source: {
|
|
1959
|
+
document_filename: @delegate_object[:filename],
|
|
1960
|
+
time_now_date: Time.now.utc.strftime(@delegate_object[:shell_code_label_time_format])
|
|
1961
|
+
}
|
|
1962
|
+
)
|
|
1963
|
+
end
|
|
1964
|
+
|
|
1965
|
+
def exec_bash_next_state(selected:, mdoc:, link_state:, block_source: {})
|
|
1685
1966
|
lfls = execute_shell_type(
|
|
1686
|
-
|
|
1687
|
-
mdoc,
|
|
1688
|
-
link_state,
|
|
1689
|
-
block_source:
|
|
1967
|
+
selected: selected,
|
|
1968
|
+
mdoc: mdoc,
|
|
1969
|
+
link_state: link_state,
|
|
1970
|
+
block_source: block_source
|
|
1690
1971
|
)
|
|
1691
1972
|
|
|
1692
1973
|
# if the same menu is being displayed, collect the display name of the selected menu item for use as the default item
|
|
1693
1974
|
[lfls.link_state,
|
|
1694
|
-
lfls.load_file == LoadFile::Load ? nil :
|
|
1975
|
+
lfls.load_file == LoadFile::Load ? nil : selected[:dname]]
|
|
1695
1976
|
end
|
|
1696
1977
|
|
|
1697
|
-
def set_delobj_menu_loop_vars(block_name_from_cli
|
|
1978
|
+
def set_delobj_menu_loop_vars(block_name_from_cli:, now_using_cli:, link_state:)
|
|
1698
1979
|
block_name_from_cli, now_using_cli = \
|
|
1699
|
-
manage_cli_selection_state(block_name_from_cli
|
|
1700
|
-
|
|
1980
|
+
manage_cli_selection_state(block_name_from_cli: block_name_from_cli,
|
|
1981
|
+
now_using_cli: now_using_cli,
|
|
1982
|
+
link_state: link_state)
|
|
1983
|
+
set_delob_filename_block_name(link_state: link_state,
|
|
1984
|
+
block_name_from_cli: block_name_from_cli)
|
|
1701
1985
|
|
|
1702
1986
|
# update @delegate_object and @menu_base_options in auto_load
|
|
1703
1987
|
#
|
|
@@ -1709,14 +1993,14 @@ module MarkdownExec
|
|
|
1709
1993
|
|
|
1710
1994
|
# user prompt to exit if the menu will be displayed again
|
|
1711
1995
|
#
|
|
1712
|
-
def prompt_user_exit(block_name_from_cli
|
|
1996
|
+
def prompt_user_exit(block_name_from_cli:, selected:)
|
|
1713
1997
|
!block_name_from_cli &&
|
|
1714
|
-
|
|
1998
|
+
selected[:shell] == BlockType::BASH &&
|
|
1715
1999
|
@delegate_object[:pause_after_script_execution] &&
|
|
1716
2000
|
prompt_select_continue == MenuState::EXIT
|
|
1717
2001
|
end
|
|
1718
2002
|
|
|
1719
|
-
def manage_cli_selection_state(block_name_from_cli
|
|
2003
|
+
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:, link_state:)
|
|
1720
2004
|
if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name]
|
|
1721
2005
|
# &bsp 'pause cli control, allow user to select block'
|
|
1722
2006
|
block_name_from_cli = false
|
|
@@ -1739,7 +2023,7 @@ module MarkdownExec
|
|
|
1739
2023
|
#
|
|
1740
2024
|
# @param link_state [LinkState] The current link state object.
|
|
1741
2025
|
# @param block_name_from_cli [Boolean] Indicates if the block name is from CLI.
|
|
1742
|
-
def set_delob_filename_block_name(link_state
|
|
2026
|
+
def set_delob_filename_block_name(link_state:, block_name_from_cli:)
|
|
1743
2027
|
@delegate_object[:filename] = link_state.document_filename
|
|
1744
2028
|
link_state.block_name = @delegate_object[:block_name] =
|
|
1745
2029
|
block_name_from_cli ? @cli_block_name : link_state.block_name
|
|
@@ -1752,9 +2036,7 @@ module MarkdownExec
|
|
|
1752
2036
|
# @param menu_blocks [Hash] Hash of menu blocks.
|
|
1753
2037
|
# @param link_state [LinkState] Current state of the link.
|
|
1754
2038
|
def dump_delobj(blocks_in_file, menu_blocks, link_state)
|
|
1755
|
-
if @delegate_object[:dump_delegate_object]
|
|
1756
|
-
warn format_and_highlight_hash(@delegate_object, label: '@delegate_object')
|
|
1757
|
-
end
|
|
2039
|
+
warn format_and_highlight_hash(@delegate_object, label: '@delegate_object') if @delegate_object[:dump_delegate_object]
|
|
1758
2040
|
|
|
1759
2041
|
if @delegate_object[:dump_blocks_in_file]
|
|
1760
2042
|
warn format_and_highlight_dependencies(compact_and_index_hash(blocks_in_file),
|
|
@@ -1766,20 +2048,22 @@ module MarkdownExec
|
|
|
1766
2048
|
label: 'menu_blocks')
|
|
1767
2049
|
end
|
|
1768
2050
|
|
|
2051
|
+
warn format_and_highlight_lines(link_state.inherited_block_names, label: 'inherited_block_names') if @delegate_object[:dump_inherited_block_names]
|
|
2052
|
+
warn format_and_highlight_lines(link_state.inherited_dependencies, label: 'inherited_dependencies') if @delegate_object[:dump_inherited_dependencies]
|
|
1769
2053
|
return unless @delegate_object[:dump_inherited_lines]
|
|
1770
2054
|
|
|
1771
2055
|
warn format_and_highlight_lines(link_state.inherited_lines, label: 'inherited_lines')
|
|
1772
2056
|
end
|
|
1773
2057
|
|
|
1774
|
-
def dump_and_warn_block_state(
|
|
1775
|
-
if
|
|
2058
|
+
def dump_and_warn_block_state(selected:)
|
|
2059
|
+
if selected.nil?
|
|
1776
2060
|
Exceptions.warn_format("Block not found -- name: #{@delegate_object[:block_name]}",
|
|
1777
2061
|
{ abort: true })
|
|
1778
2062
|
end
|
|
1779
2063
|
|
|
1780
2064
|
return unless @delegate_object[:dump_selected_block]
|
|
1781
2065
|
|
|
1782
|
-
warn
|
|
2066
|
+
warn selected.to_yaml.sub(/^(?:---\n)?/, "Block:\n")
|
|
1783
2067
|
end
|
|
1784
2068
|
|
|
1785
2069
|
# Presents a TTY prompt to select an option or exit, returns metadata including option and selected
|
|
@@ -1814,14 +2098,20 @@ module MarkdownExec
|
|
|
1814
2098
|
end
|
|
1815
2099
|
|
|
1816
2100
|
def set_environment_variables_for_block(selected)
|
|
2101
|
+
code_lines = []
|
|
1817
2102
|
YAML.load(selected[:body].join("\n"))&.each do |key, value|
|
|
1818
2103
|
ENV[key] = value.to_s
|
|
2104
|
+
|
|
2105
|
+
require 'shellwords'
|
|
2106
|
+
code_lines.push "#{key}=\"#{Shellwords.escape(value)}\""
|
|
2107
|
+
|
|
1819
2108
|
next unless @delegate_object[:menu_vars_set_format].present?
|
|
1820
2109
|
|
|
1821
2110
|
formatted_string = format(@delegate_object[:menu_vars_set_format],
|
|
1822
2111
|
{ key: key, value: value })
|
|
1823
2112
|
print string_send_color(formatted_string, :menu_vars_set_color)
|
|
1824
2113
|
end
|
|
2114
|
+
code_lines
|
|
1825
2115
|
end
|
|
1826
2116
|
|
|
1827
2117
|
def should_add_back_option?
|
|
@@ -1908,8 +2198,12 @@ module MarkdownExec
|
|
|
1908
2198
|
if state[:in_fenced_block]
|
|
1909
2199
|
## end of code block
|
|
1910
2200
|
#
|
|
1911
|
-
HashDelegator.update_menu_attrib_yield_selected(
|
|
1912
|
-
|
|
2201
|
+
HashDelegator.update_menu_attrib_yield_selected(
|
|
2202
|
+
fcb: state[:fcb],
|
|
2203
|
+
messages: selected_messages,
|
|
2204
|
+
configuration: @delegate_object,
|
|
2205
|
+
&block
|
|
2206
|
+
)
|
|
1913
2207
|
state[:in_fenced_block] = false
|
|
1914
2208
|
else
|
|
1915
2209
|
## start of code block
|
|
@@ -1942,7 +2236,7 @@ module MarkdownExec
|
|
|
1942
2236
|
# @param selected [Hash] Selected item from the menu containing a YAML body.
|
|
1943
2237
|
# @param tgt2 [Hash, nil] An optional target hash to update with YAML data.
|
|
1944
2238
|
# @return [LoadFileLinkState] An instance indicating the next action for loading files.
|
|
1945
|
-
def read_show_options_and_trigger_reuse(selected
|
|
2239
|
+
def read_show_options_and_trigger_reuse(selected:, link_state: LinkState.new)
|
|
1946
2240
|
obj = {}
|
|
1947
2241
|
data = YAML.load(selected[:body].join("\n"))
|
|
1948
2242
|
(data || []).each do |key, value|
|
|
@@ -1996,7 +2290,7 @@ module MarkdownExec
|
|
|
1996
2290
|
end
|
|
1997
2291
|
|
|
1998
2292
|
# Handles the core logic for generating the command file's metadata and content.
|
|
1999
|
-
def write_command_file(required_lines
|
|
2293
|
+
def write_command_file(required_lines:, selected:)
|
|
2000
2294
|
return unless @delegate_object[:save_executed_script]
|
|
2001
2295
|
|
|
2002
2296
|
time_now = Time.now.utc
|
|
@@ -2032,25 +2326,16 @@ module MarkdownExec
|
|
|
2032
2326
|
HashDelegator.error_handler('write_command_file')
|
|
2033
2327
|
end
|
|
2034
2328
|
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
)[:code]
|
|
2046
|
-
else
|
|
2047
|
-
[]
|
|
2048
|
-
end
|
|
2049
|
-
|
|
2050
|
-
code_blocks = (HashDelegator.read_required_blocks_from_temp_file(import_filename) +
|
|
2051
|
-
c1).join("\n")
|
|
2052
|
-
|
|
2053
|
-
HashDelegator.write_code_to_file(code_blocks, temp_file_path)
|
|
2329
|
+
def write_inherited_lines_to_file(link_state, link_block_data)
|
|
2330
|
+
save_expr = link_block_data.fetch(LinkKeys::Save, '')
|
|
2331
|
+
if save_expr.present?
|
|
2332
|
+
save_filespec = save_filespec_from_expression(save_expr)
|
|
2333
|
+
File.write(save_filespec, HashDelegator.join_code_lines(link_state&.inherited_lines))
|
|
2334
|
+
# TTY::File.create_file save_filespec, HahDelegator.join_code_lines(link_state&.inherited_lines), force: true
|
|
2335
|
+
@delegate_object[:filename]
|
|
2336
|
+
else
|
|
2337
|
+
link_block_data[LinkKeys::File] || @delegate_object[:filename]
|
|
2338
|
+
end
|
|
2054
2339
|
end
|
|
2055
2340
|
end
|
|
2056
2341
|
end
|
|
@@ -2063,6 +2348,11 @@ Bundler.require(:default)
|
|
|
2063
2348
|
require 'minitest/autorun'
|
|
2064
2349
|
require 'mocha/minitest'
|
|
2065
2350
|
|
|
2351
|
+
####
|
|
2352
|
+
require_relative 'dev/instance_method_wrapper'
|
|
2353
|
+
# MarkdownExec::HashDelegator.prepend(InstanceMethodWrapper)
|
|
2354
|
+
# MarkdownExec::HashDelegator.singleton_class.prepend(ClassMethodWrapper)
|
|
2355
|
+
|
|
2066
2356
|
module MarkdownExec
|
|
2067
2357
|
class TestHashDelegator < Minitest::Test
|
|
2068
2358
|
def setup
|
|
@@ -2094,14 +2384,14 @@ module MarkdownExec
|
|
|
2094
2384
|
# Test case for empty body
|
|
2095
2385
|
def test_push_link_history_and_trigger_load_with_empty_body
|
|
2096
2386
|
assert_equal LoadFile::Reuse,
|
|
2097
|
-
@hd.push_link_history_and_trigger_load
|
|
2387
|
+
@hd.push_link_history_and_trigger_load.load_file
|
|
2098
2388
|
end
|
|
2099
2389
|
|
|
2100
2390
|
# Test case for non-empty body without 'file' key
|
|
2101
2391
|
def test_push_link_history_and_trigger_load_without_file_key
|
|
2102
2392
|
body = ["vars:\n KEY: VALUE"]
|
|
2103
2393
|
assert_equal LoadFile::Reuse,
|
|
2104
|
-
@hd.push_link_history_and_trigger_load(body
|
|
2394
|
+
@hd.push_link_history_and_trigger_load(link_block_body: body).load_file
|
|
2105
2395
|
end
|
|
2106
2396
|
|
|
2107
2397
|
# Test case for non-empty body with 'file' key
|
|
@@ -2111,10 +2401,12 @@ module MarkdownExec
|
|
|
2111
2401
|
LinkState.new(block_name: 'sample_block',
|
|
2112
2402
|
document_filename: 'sample_file',
|
|
2113
2403
|
inherited_dependencies: {},
|
|
2114
|
-
inherited_lines: []))
|
|
2404
|
+
inherited_lines: ['# ', 'KEY="VALUE"']))
|
|
2115
2405
|
assert_equal expected_result,
|
|
2116
|
-
@hd.push_link_history_and_trigger_load(
|
|
2117
|
-
|
|
2406
|
+
@hd.push_link_history_and_trigger_load(
|
|
2407
|
+
link_block_body: body,
|
|
2408
|
+
selected: FCB.new(block_name: 'sample_block', filename: 'sample_file')
|
|
2409
|
+
)
|
|
2118
2410
|
end
|
|
2119
2411
|
|
|
2120
2412
|
def test_indent_all_lines_with_indent
|
|
@@ -2192,7 +2484,7 @@ module MarkdownExec
|
|
|
2192
2484
|
|
|
2193
2485
|
def test_append_divider_initial
|
|
2194
2486
|
menu_blocks = []
|
|
2195
|
-
@hd.append_divider(menu_blocks, :initial)
|
|
2487
|
+
@hd.append_divider(menu_blocks: menu_blocks, position: :initial)
|
|
2196
2488
|
|
|
2197
2489
|
assert_equal 1, menu_blocks.size
|
|
2198
2490
|
assert_equal 'Formatted Divider', menu_blocks.first.dname
|
|
@@ -2200,7 +2492,7 @@ module MarkdownExec
|
|
|
2200
2492
|
|
|
2201
2493
|
def test_append_divider_final
|
|
2202
2494
|
menu_blocks = []
|
|
2203
|
-
@hd.append_divider(menu_blocks, :final)
|
|
2495
|
+
@hd.append_divider(menu_blocks: menu_blocks, position: :final)
|
|
2204
2496
|
|
|
2205
2497
|
assert_equal 1, menu_blocks.size
|
|
2206
2498
|
assert_equal 'Formatted Divider', menu_blocks.last.dname
|
|
@@ -2209,7 +2501,7 @@ module MarkdownExec
|
|
|
2209
2501
|
def test_append_divider_without_format
|
|
2210
2502
|
@hd.instance_variable_set(:@delegate_object, {})
|
|
2211
2503
|
menu_blocks = []
|
|
2212
|
-
@hd.append_divider(menu_blocks, :initial)
|
|
2504
|
+
@hd.append_divider(menu_blocks: menu_blocks, position: :initial)
|
|
2213
2505
|
|
|
2214
2506
|
assert_empty menu_blocks
|
|
2215
2507
|
end
|
|
@@ -2280,9 +2572,9 @@ module MarkdownExec
|
|
|
2280
2572
|
def test_collect_required_code_lines_with_vars
|
|
2281
2573
|
YAML.stubs(:load).returns({ 'key' => 'value' })
|
|
2282
2574
|
@mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
|
|
2283
|
-
result = @hd.collect_required_code_lines(@mdoc, @selected, block_source: {})
|
|
2575
|
+
result = @hd.collect_required_code_lines(mdoc: @mdoc, selected: @selected, block_source: {})
|
|
2284
2576
|
|
|
2285
|
-
assert_equal ['code line'], result
|
|
2577
|
+
assert_equal ['code line', 'key="value"'], result
|
|
2286
2578
|
end
|
|
2287
2579
|
end
|
|
2288
2580
|
|
|
@@ -2299,7 +2591,7 @@ module MarkdownExec
|
|
|
2299
2591
|
@hd.instance_variable_set(:@delegate_object,
|
|
2300
2592
|
{ block_name: 'block1' })
|
|
2301
2593
|
|
|
2302
|
-
result = @hd.load_cli_or_user_selected_block(all_blocks
|
|
2594
|
+
result = @hd.load_cli_or_user_selected_block(all_blocks: all_blocks)
|
|
2303
2595
|
|
|
2304
2596
|
assert_equal all_blocks.first.merge(block_name_from_ui: false), result.block
|
|
2305
2597
|
assert_nil result.state
|
|
@@ -2310,7 +2602,7 @@ module MarkdownExec
|
|
|
2310
2602
|
:some_state)
|
|
2311
2603
|
@hd.stubs(:wait_for_user_selected_block).returns(block_state)
|
|
2312
2604
|
|
|
2313
|
-
result = @hd.load_cli_or_user_selected_block
|
|
2605
|
+
result = @hd.load_cli_or_user_selected_block
|
|
2314
2606
|
|
|
2315
2607
|
assert_equal block_state.block.merge(block_name_from_ui: true), result.block
|
|
2316
2608
|
assert_equal :some_state, result.state
|
|
@@ -2437,7 +2729,7 @@ module MarkdownExec
|
|
|
2437
2729
|
@hd.instance_variable_get(:@delegate_object).stubs(:[]).with(:script_preview_tail).returns('Footer')
|
|
2438
2730
|
@hd.instance_variable_get(:@fout).expects(:fout).times(4)
|
|
2439
2731
|
|
|
2440
|
-
@hd.display_required_code(required_lines)
|
|
2732
|
+
@hd.display_required_code(required_lines: required_lines)
|
|
2441
2733
|
|
|
2442
2734
|
# Verifying that fout is called for each line and for header & footer
|
|
2443
2735
|
assert true # Placeholder for actual test assertions
|
|
@@ -2647,7 +2939,7 @@ module MarkdownExec
|
|
|
2647
2939
|
stream = StringIO.new("line 1\nline 2\n")
|
|
2648
2940
|
file_type = :stdout
|
|
2649
2941
|
|
|
2650
|
-
Thread.new { @hd.handle_stream(stream, file_type) }
|
|
2942
|
+
Thread.new { @hd.handle_stream(stream: stream, file_type: file_type) }
|
|
2651
2943
|
|
|
2652
2944
|
@hd.wait_for_stream_processing
|
|
2653
2945
|
|
|
@@ -2660,7 +2952,7 @@ module MarkdownExec
|
|
|
2660
2952
|
file_type = :stdout
|
|
2661
2953
|
stream.stubs(:each_line).raises(IOError)
|
|
2662
2954
|
|
|
2663
|
-
Thread.new { @hd.handle_stream(stream, file_type) }
|
|
2955
|
+
Thread.new { @hd.handle_stream(stream: stream, file_type: file_type) }
|
|
2664
2956
|
|
|
2665
2957
|
@hd.wait_for_stream_processing
|
|
2666
2958
|
|
|
@@ -2824,13 +3116,13 @@ module MarkdownExec
|
|
|
2824
3116
|
HashDelegator.expects(:default_block_title_from_body).with(@fcb)
|
|
2825
3117
|
Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message], {})
|
|
2826
3118
|
|
|
2827
|
-
HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
|
|
3119
|
+
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb, messages: [:some_message])
|
|
2828
3120
|
end
|
|
2829
3121
|
|
|
2830
3122
|
def test_update_menu_attrib_yield_selected_without_body
|
|
2831
3123
|
@fcb.stubs(:body).returns(nil)
|
|
2832
3124
|
HashDelegator.expects(:initialize_fcb_names).with(@fcb)
|
|
2833
|
-
HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
|
|
3125
|
+
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb, messages: [:some_message])
|
|
2834
3126
|
end
|
|
2835
3127
|
end
|
|
2836
3128
|
|
|
@@ -2901,4 +3193,30 @@ module MarkdownExec
|
|
|
2901
3193
|
refute block_called
|
|
2902
3194
|
end
|
|
2903
3195
|
end
|
|
3196
|
+
|
|
3197
|
+
def test_resolves_absolute_path
|
|
3198
|
+
absolute_path = '/usr/local/bin'
|
|
3199
|
+
assert_equal '/usr/local/bin', resolve_path_or_substitute(absolute_path, 'prefix/*/suffix')
|
|
3200
|
+
end
|
|
3201
|
+
|
|
3202
|
+
def test_substitutes_wildcard_with_path
|
|
3203
|
+
path = 'bin'
|
|
3204
|
+
expression = 'prefix/*/suffix'
|
|
3205
|
+
expected_result = 'prefix/bin/suffix'
|
|
3206
|
+
assert_equal expected_result, resolve_path_or_substitute(path, expression)
|
|
3207
|
+
end
|
|
3208
|
+
|
|
3209
|
+
def test_handles_path_with_no_separator_as_is
|
|
3210
|
+
path = 'bin'
|
|
3211
|
+
expression = 'prefix*suffix'
|
|
3212
|
+
expected_result = 'prefixbinsuffix'
|
|
3213
|
+
assert_equal expected_result, resolve_path_or_substitute(path, expression)
|
|
3214
|
+
end
|
|
3215
|
+
|
|
3216
|
+
def test_returns_expression_unchanged_for_empty_path
|
|
3217
|
+
path = ''
|
|
3218
|
+
expression = 'prefix/*/suffix'
|
|
3219
|
+
expected_result = 'prefix/*/suffix'
|
|
3220
|
+
assert_equal expected_result, resolve_path_or_substitute(path, expression)
|
|
3221
|
+
end
|
|
2904
3222
|
end # module MarkdownExec
|