markdown_exec 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -2
- data/CHANGELOG.md +14 -1
- data/Gemfile +3 -3
- data/Gemfile.lock +134 -92
- data/README.md +13 -13
- data/bin/tab_completion.sh +14 -3
- data/bin/tab_completion.sh.erb +0 -1
- data/examples/bash-blocks.md +58 -0
- data/examples/block-names.md +27 -0
- data/examples/indent.md +43 -2
- data/examples/link-blocks-block.md +5 -0
- data/examples/link-blocks-load-save.md +59 -0
- data/examples/link-blocks-vars.md +56 -0
- data/examples/linked.md +6 -101
- data/examples/opts-blocks-require.md +28 -0
- data/examples/{port.md → port-blocks.md} +18 -9
- data/examples/save.md +76 -4
- data/examples/vars-blocks.md +38 -0
- data/lib/constants.rb +1 -1
- data/lib/fcb.rb +202 -16
- data/lib/filter.rb +12 -12
- data/lib/hash_delegator.rb +647 -321
- data/lib/link_history.rb +34 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +56 -75
- data/lib/mdoc.rb +112 -57
- data/lib/menu.src.yml +34 -21
- data/lib/menu.yml +30 -19
- data/lib/namer.rb +50 -0
- data/lib/poly.rb +152 -0
- data/lib/saved_assets.rb +4 -11
- data/lib/string_util.rb +0 -1
- metadata +14 -6
- data/examples/vars.md +0 -20
- /data/examples/{opts.md → opts-blocks.md} +0 -0
- /data/examples/{pass-through.md → pass-through-arguments.md} +0 -0
data/lib/hash_delegator.rb
CHANGED
@@ -31,12 +31,15 @@ require_relative 'fout'
|
|
31
31
|
require_relative 'hash'
|
32
32
|
require_relative 'link_history'
|
33
33
|
require_relative 'mdoc'
|
34
|
+
require_relative 'namer'
|
34
35
|
require_relative 'regexp'
|
35
36
|
require_relative 'resize_terminal'
|
36
37
|
require_relative 'std_out_err_logger'
|
37
38
|
require_relative 'streams_out'
|
38
39
|
require_relative 'string_util'
|
39
40
|
|
41
|
+
$pd = false unless defined?($pd)
|
42
|
+
|
40
43
|
class String
|
41
44
|
# Checks if the string is not empty.
|
42
45
|
# @return [Boolean] Returns true if the string is not empty, false otherwise.
|
@@ -54,7 +57,8 @@ module HashDelegatorSelf
|
|
54
57
|
# @param color_key [String, Symbol] The key representing the desired color method in the color_methods hash.
|
55
58
|
# @param default_method [String] (optional) Default color method to use if color_key is not found in color_methods. Defaults to 'plain'.
|
56
59
|
# @return [String] The colored string.
|
57
|
-
def apply_color_from_hash(string, color_methods, color_key,
|
60
|
+
def apply_color_from_hash(string, color_methods, color_key,
|
61
|
+
default_method: 'plain')
|
58
62
|
color_method = color_methods.fetch(color_key, default_method).to_sym
|
59
63
|
string.to_s.send(color_method)
|
60
64
|
end
|
@@ -78,17 +82,17 @@ module HashDelegatorSelf
|
|
78
82
|
# colored_string = apply_color_from_hash(string, color_transformations, :red)
|
79
83
|
# puts colored_string # This will print the string in red
|
80
84
|
|
81
|
-
# Searches for the first element in a collection where the specified
|
85
|
+
# Searches for the first element in a collection where the specified message sent to an element matches a given value.
|
82
86
|
# This method is particularly useful for finding a specific hash-like object within an enumerable collection.
|
83
87
|
# If no match is found, it returns a specified default value.
|
84
88
|
#
|
85
89
|
# @param blocks [Enumerable] The collection of hash-like objects to search.
|
86
|
-
# @param
|
87
|
-
# @param value [Object] The value to match against
|
90
|
+
# @param msg [Symbol, String] The message to send to each element of the collection.
|
91
|
+
# @param value [Object] The value to match against the result of the message sent to each element.
|
88
92
|
# @param default [Object, nil] The default value to return if no match is found (optional).
|
89
93
|
# @return [Object, nil] The first matching element or the default value if no match is found.
|
90
|
-
def block_find(blocks,
|
91
|
-
blocks.find { |item| item
|
94
|
+
def block_find(blocks, msg, value, default = nil)
|
95
|
+
blocks.find { |item| item.send(msg) == value } || default
|
92
96
|
end
|
93
97
|
|
94
98
|
def code_merge(*bodies)
|
@@ -132,8 +136,10 @@ module HashDelegatorSelf
|
|
132
136
|
# delete the current line if it is empty and the previous is also empty
|
133
137
|
def delete_consecutive_blank_lines!(blocks_menu)
|
134
138
|
blocks_menu.process_and_conditionally_delete! do |prev_item, current_item, _next_item|
|
135
|
-
prev_item&.fetch(:chrome, nil) &&
|
136
|
-
|
139
|
+
prev_item&.fetch(:chrome, nil) &&
|
140
|
+
!(prev_item && prev_item.oname.present?) &&
|
141
|
+
current_item&.fetch(:chrome, nil) &&
|
142
|
+
!(current_item && current_item.oname.present?)
|
137
143
|
end
|
138
144
|
end
|
139
145
|
|
@@ -188,13 +194,14 @@ module HashDelegatorSelf
|
|
188
194
|
merged.empty? ? [] : merged
|
189
195
|
end
|
190
196
|
|
191
|
-
def next_link_state(block_name_from_cli:, was_using_cli:, block_state:,
|
197
|
+
def next_link_state(block_name_from_cli:, was_using_cli:, block_state:,
|
198
|
+
block_name: nil)
|
192
199
|
# Set block_name based on block_name_from_cli
|
193
200
|
block_name = @cli_block_name if block_name_from_cli
|
194
201
|
|
195
202
|
# Determine the state of breaker based on was_using_cli and the block type
|
196
|
-
# true only when block_name is nil, block_name_from_cli is false, was_using_cli is true, and the block_state.block
|
197
|
-
breaker = !block_name && !block_name_from_cli && was_using_cli && block_state.block.
|
203
|
+
# true only when block_name is nil, block_name_from_cli is false, was_using_cli is true, and the block_state.block.shell equals BlockType::BASH. In all other scenarios, breaker is false.
|
204
|
+
breaker = !block_name && !block_name_from_cli && was_using_cli && block_state.block.shell == BlockType::BASH
|
198
205
|
|
199
206
|
# Reset block_name_from_cli if the conditions are not met
|
200
207
|
block_name_from_cli ||= false
|
@@ -282,7 +289,8 @@ module HashDelegatorSelf
|
|
282
289
|
# @param fcb [Object] The fcb object whose attributes are to be updated.
|
283
290
|
# @param selected_messages [Array<Symbol>] A list of message types to determine if yielding is applicable.
|
284
291
|
# @param block [Block] An optional block to yield to if conditions are met.
|
285
|
-
def update_menu_attrib_yield_selected(fcb:, messages:, configuration: {},
|
292
|
+
def update_menu_attrib_yield_selected(fcb:, messages:, configuration: {},
|
293
|
+
&block)
|
286
294
|
initialize_fcb_names(fcb)
|
287
295
|
return unless fcb.body
|
288
296
|
|
@@ -429,7 +437,9 @@ class StringWrapper
|
|
429
437
|
words.each.with_index do |word, index|
|
430
438
|
trial_length = word.length
|
431
439
|
trial_length += @first_indent.length if index.zero?
|
432
|
-
|
440
|
+
if index != 0
|
441
|
+
trial_length += current_line.length + 1 + @rest_indent.length
|
442
|
+
end
|
433
443
|
if trial_length > max_line_length && (words.count != 0)
|
434
444
|
lines << current_line
|
435
445
|
current_line = word
|
@@ -480,7 +490,8 @@ module MarkdownExec
|
|
480
490
|
@most_recent_loaded_filename = nil
|
481
491
|
@pass_args = []
|
482
492
|
@run_state = OpenStruct.new(
|
483
|
-
link_history: []
|
493
|
+
link_history: [],
|
494
|
+
source: OpenStruct.new
|
484
495
|
)
|
485
496
|
@link_history = LinkHistory.new
|
486
497
|
@fout = FOut.new(@delegate_object) ### slice only relevant keys
|
@@ -506,13 +517,18 @@ module MarkdownExec
|
|
506
517
|
def add_menu_chrome_blocks!(menu_blocks:, link_state:)
|
507
518
|
return unless @delegate_object[:menu_link_format].present?
|
508
519
|
|
509
|
-
|
520
|
+
if @delegate_object[:menu_with_inherited_lines]
|
521
|
+
add_inherited_lines(menu_blocks: menu_blocks,
|
522
|
+
link_state: link_state)
|
523
|
+
end
|
510
524
|
|
511
525
|
# back before exit
|
512
526
|
add_back_option(menu_blocks: menu_blocks) if should_add_back_option?
|
513
527
|
|
514
528
|
# exit after other options
|
515
|
-
|
529
|
+
if @delegate_object[:menu_with_exit]
|
530
|
+
add_exit_option(menu_blocks: menu_blocks)
|
531
|
+
end
|
516
532
|
|
517
533
|
add_dividers(menu_blocks: menu_blocks)
|
518
534
|
end
|
@@ -588,6 +604,20 @@ module MarkdownExec
|
|
588
604
|
else
|
589
605
|
menu_blocks.push(chrome_block)
|
590
606
|
end
|
607
|
+
|
608
|
+
chrome_block
|
609
|
+
end
|
610
|
+
|
611
|
+
# Appends a formatted divider to the specified position in a menu block array.
|
612
|
+
# The method checks for the presence of formatting options before appending.
|
613
|
+
#
|
614
|
+
# @param menu_blocks [Array] The array of menu block elements.
|
615
|
+
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
616
|
+
def append_divider(menu_blocks:, position:)
|
617
|
+
return unless divider_formatting_present?(position)
|
618
|
+
|
619
|
+
divider = create_divider(position)
|
620
|
+
position == :initial ? menu_blocks.unshift(divider) : menu_blocks.push(divider)
|
591
621
|
end
|
592
622
|
|
593
623
|
# Appends a formatted divider to the specified position in a menu block array.
|
@@ -596,10 +626,10 @@ module MarkdownExec
|
|
596
626
|
# @param menu_blocks [Array] The array of menu block elements.
|
597
627
|
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
598
628
|
def append_inherited_lines(menu_blocks:, link_state:, position: top)
|
599
|
-
return unless link_state.
|
629
|
+
return unless link_state.inherited_lines_present?
|
600
630
|
|
601
631
|
insert_at_top = @delegate_object[:menu_inherited_lines_at_top]
|
602
|
-
chrome_blocks = link_state.
|
632
|
+
chrome_blocks = link_state.inherited_lines_map do |line|
|
603
633
|
formatted = format(@delegate_object[:menu_inherited_lines_format],
|
604
634
|
{ line: line })
|
605
635
|
FCB.new(
|
@@ -623,18 +653,6 @@ module MarkdownExec
|
|
623
653
|
HashDelegator.error_handler('append_inherited_lines')
|
624
654
|
end
|
625
655
|
|
626
|
-
# Appends a formatted divider to the specified position in a menu block array.
|
627
|
-
# The method checks for the presence of formatting options before appending.
|
628
|
-
#
|
629
|
-
# @param menu_blocks [Array] The array of menu block elements.
|
630
|
-
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
631
|
-
def append_divider(menu_blocks:, position:)
|
632
|
-
return unless divider_formatting_present?(position)
|
633
|
-
|
634
|
-
divider = create_divider(position)
|
635
|
-
position == :initial ? menu_blocks.unshift(divider) : menu_blocks.push(divider)
|
636
|
-
end
|
637
|
-
|
638
656
|
# private
|
639
657
|
|
640
658
|
# Applies shell color options to the given string if applicable.
|
@@ -672,7 +690,7 @@ module MarkdownExec
|
|
672
690
|
iter_blocks_from_nested_files do |btype, fcb|
|
673
691
|
process_block_based_on_type(blocks, btype, fcb)
|
674
692
|
end
|
675
|
-
# &
|
693
|
+
# &bt blocks.count
|
676
694
|
blocks
|
677
695
|
rescue StandardError
|
678
696
|
HashDelegator.error_handler('blocks_from_nested_files')
|
@@ -684,7 +702,8 @@ module MarkdownExec
|
|
684
702
|
SelectedBlockMenuState.new(
|
685
703
|
@dml_blocks_in_file.find do |item|
|
686
704
|
block_name == item.pub_name
|
687
|
-
end
|
705
|
+
end,
|
706
|
+
OpenStruct.new(
|
688
707
|
block_name_from_cli: true,
|
689
708
|
block_name_from_ui: false
|
690
709
|
),
|
@@ -698,12 +717,14 @@ module MarkdownExec
|
|
698
717
|
return unless @delegate_object[:saved_stdout_folder]
|
699
718
|
|
700
719
|
@delegate_object[:logged_stdout_filename] =
|
701
|
-
SavedAsset.new(
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
720
|
+
SavedAsset.new(
|
721
|
+
blockname: block_name,
|
722
|
+
filename: @delegate_object[:filename],
|
723
|
+
prefix: @delegate_object[:logged_stdout_filename_prefix],
|
724
|
+
time: Time.now.utc,
|
725
|
+
exts: '.out.txt',
|
726
|
+
saved_asset_format: shell_escape_asset_format(@dml_link_state)
|
727
|
+
).generate_name
|
707
728
|
|
708
729
|
@logged_stdout_filespec =
|
709
730
|
@delegate_object[:logged_stdout_filespec] =
|
@@ -737,13 +758,14 @@ module MarkdownExec
|
|
737
758
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
738
759
|
# @param selected [Hash] The selected block.
|
739
760
|
# @return [Array<String>] Required code blocks as an array of lines.
|
740
|
-
def collect_required_code_lines(mdoc:, selected:, block_source:,
|
761
|
+
def collect_required_code_lines(mdoc:, selected:, block_source:,
|
762
|
+
link_state: LinkState.new)
|
741
763
|
required = mdoc.collect_recursively_required_code(
|
742
764
|
anyname: selected.pub_name,
|
743
765
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
744
766
|
label_format_below: @delegate_object[:shell_code_label_format_below],
|
745
767
|
block_source: block_source
|
746
|
-
)
|
768
|
+
) # &bt 'required'
|
747
769
|
dependencies = (link_state&.inherited_dependencies || {}).merge(required[:dependencies] || {})
|
748
770
|
required[:unmet_dependencies] =
|
749
771
|
(required[:unmet_dependencies] || []) - (link_state&.inherited_block_names || [])
|
@@ -755,14 +777,19 @@ module MarkdownExec
|
|
755
777
|
runtime_exception(:runtime_exception_error_level,
|
756
778
|
'unmet_dependencies, flag: runtime_exception_error_level',
|
757
779
|
required[:unmet_dependencies])
|
758
|
-
|
780
|
+
elsif false ### use option 2024-08-02
|
759
781
|
warn format_and_highlight_dependencies(dependencies,
|
760
782
|
highlight: [@delegate_object[:block_name]])
|
761
783
|
end
|
762
784
|
|
763
|
-
|
764
|
-
|
765
|
-
|
785
|
+
if selected[:shell] == BlockType::OPTS
|
786
|
+
# body of blocks is returned as a list of lines to be read an YAML
|
787
|
+
HashDelegator.code_merge(required[:blocks].map(&:body).flatten(1))
|
788
|
+
else
|
789
|
+
code_lines = selected.shell == BlockType::VARS ? set_environment_variables_for_block(selected) : []
|
790
|
+
HashDelegator.code_merge(link_state&.inherited_lines,
|
791
|
+
required[:code] + code_lines)
|
792
|
+
end
|
766
793
|
end
|
767
794
|
|
768
795
|
def command_execute(command, args: [])
|
@@ -783,7 +810,8 @@ module MarkdownExec
|
|
783
810
|
else
|
784
811
|
@run_state.in_own_window = false
|
785
812
|
execute_command_with_streams(
|
786
|
-
[@delegate_object[:shell], '-c', command,
|
813
|
+
[@delegate_object[:shell], '-c', command,
|
814
|
+
@delegate_object[:filename], *args]
|
787
815
|
)
|
788
816
|
end
|
789
817
|
|
@@ -793,14 +821,16 @@ module MarkdownExec
|
|
793
821
|
@run_state.aborted_at = Time.now.utc
|
794
822
|
@run_state.error_message = err.message
|
795
823
|
@run_state.error = err
|
796
|
-
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
824
|
+
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
825
|
+
@run_state.error_message)
|
797
826
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
798
827
|
rescue SignalException => err
|
799
828
|
# Handle SignalException
|
800
829
|
@run_state.aborted_at = Time.now.utc
|
801
830
|
@run_state.error_message = 'SIGTERM'
|
802
831
|
@run_state.error = err
|
803
|
-
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
832
|
+
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
833
|
+
@run_state.error_message)
|
804
834
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
805
835
|
end
|
806
836
|
|
@@ -830,18 +860,25 @@ module MarkdownExec
|
|
830
860
|
# @param mdoc [Object] The markdown document object containing code blocks.
|
831
861
|
# @param selected [Hash] The selected item from the menu to be executed.
|
832
862
|
# @return [LoadFileLinkState] An object indicating whether to load the next block or reuse the current one.
|
833
|
-
def compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:,
|
863
|
+
def compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:,
|
864
|
+
link_state: nil)
|
834
865
|
required_lines = collect_required_code_lines(mdoc: mdoc, selected: selected, link_state: link_state,
|
835
866
|
block_source: block_source)
|
836
867
|
output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
|
837
|
-
|
868
|
+
if output_or_approval
|
869
|
+
display_required_code(required_lines: required_lines)
|
870
|
+
end
|
838
871
|
allow_execution = if @delegate_object[:user_must_approve]
|
839
|
-
prompt_for_user_approval(required_lines: required_lines,
|
872
|
+
prompt_for_user_approval(required_lines: required_lines,
|
873
|
+
selected: selected)
|
840
874
|
else
|
841
875
|
true
|
842
876
|
end
|
843
877
|
|
844
|
-
|
878
|
+
if allow_execution
|
879
|
+
execute_required_lines(required_lines: required_lines,
|
880
|
+
selected: selected)
|
881
|
+
end
|
845
882
|
|
846
883
|
link_state.block_name = nil
|
847
884
|
LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
@@ -999,10 +1036,12 @@ module MarkdownExec
|
|
999
1036
|
return true unless @delegate_object[:debounce_execution]
|
1000
1037
|
|
1001
1038
|
# filter block if selected in menu
|
1002
|
-
return true if @run_state.block_name_from_cli
|
1039
|
+
return true if @run_state.source.block_name_from_cli
|
1003
1040
|
|
1004
1041
|
# return false if @prior_execution_block == @delegate_object[:block_name]
|
1005
|
-
|
1042
|
+
if @prior_execution_block == @delegate_object[:block_name]
|
1043
|
+
return @allowed_execution_block == @prior_execution_block || prompt_approve_repeat
|
1044
|
+
end
|
1006
1045
|
|
1007
1046
|
@prior_execution_block = @delegate_object[:block_name]
|
1008
1047
|
@allowed_execution_block = nil
|
@@ -1019,17 +1058,21 @@ module MarkdownExec
|
|
1019
1058
|
# @param selected_option [Hash] The selected menu option.
|
1020
1059
|
# @return [SelectedBlockMenuState] An object representing the state of the selected block.
|
1021
1060
|
def determine_block_state(selected_option)
|
1022
|
-
option_name = selected_option
|
1061
|
+
option_name = selected_option[:oname]
|
1023
1062
|
if option_name == menu_chrome_formatted_option(:menu_option_exit_name)
|
1024
1063
|
return SelectedBlockMenuState.new(nil,
|
1064
|
+
OpenStruct.new,
|
1025
1065
|
MenuState::EXIT)
|
1026
1066
|
end
|
1027
1067
|
if option_name == menu_chrome_formatted_option(:menu_option_back_name)
|
1028
1068
|
return SelectedBlockMenuState.new(selected_option,
|
1069
|
+
OpenStruct.new,
|
1029
1070
|
MenuState::BACK)
|
1030
1071
|
end
|
1031
1072
|
|
1032
|
-
SelectedBlockMenuState.new(selected_option,
|
1073
|
+
SelectedBlockMenuState.new(selected_option,
|
1074
|
+
OpenStruct.new,
|
1075
|
+
MenuState::CONTINUE)
|
1033
1076
|
end
|
1034
1077
|
|
1035
1078
|
# Displays the required lines of code with color formatting for the preview section.
|
@@ -1068,9 +1111,9 @@ module MarkdownExec
|
|
1068
1111
|
block_name: @delegate_object[:block_name],
|
1069
1112
|
document_filename: @delegate_object[:filename]
|
1070
1113
|
)
|
1071
|
-
@run_state.block_name_from_cli = @dml_link_state.block_name.present?
|
1114
|
+
@run_state.source.block_name_from_cli = @dml_link_state.block_name.present?
|
1072
1115
|
@cli_block_name = @dml_link_state.block_name
|
1073
|
-
@dml_now_using_cli = @run_state.block_name_from_cli
|
1116
|
+
@dml_now_using_cli = @run_state.source.block_name_from_cli
|
1074
1117
|
@dml_menu_default_dname = nil
|
1075
1118
|
@dml_block_state = SelectedBlockMenuState.new
|
1076
1119
|
@doc_saved_lines_files = []
|
@@ -1078,18 +1121,28 @@ module MarkdownExec
|
|
1078
1121
|
## load file with code lines per options
|
1079
1122
|
#
|
1080
1123
|
if @menu_base_options[:load_code].present?
|
1081
|
-
@dml_link_state.inherited_lines =
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1124
|
+
@dml_link_state.inherited_lines =
|
1125
|
+
@menu_base_options[:load_code].split(':').map do |path|
|
1126
|
+
File.readlines(path, chomp: true)
|
1127
|
+
end.flatten(1)
|
1085
1128
|
|
1086
1129
|
inherited_block_names = []
|
1087
1130
|
inherited_dependencies = {}
|
1088
|
-
selected =
|
1089
|
-
pop_add_current_code_to_head_and_trigger_load(@dml_link_state, inherited_block_names,
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1131
|
+
selected = FCB.new(oname: 'load_code')
|
1132
|
+
pop_add_current_code_to_head_and_trigger_load(@dml_link_state, inherited_block_names,
|
1133
|
+
code_lines, inherited_dependencies, selected)
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
fdo = ->(option) {
|
1137
|
+
name = format(@delegate_object[:menu_link_format],
|
1138
|
+
HashDelegator.safeval(@delegate_object[option]))
|
1139
|
+
OpenStruct.new(
|
1140
|
+
dname: name,
|
1141
|
+
oname: name,
|
1142
|
+
name: name,
|
1143
|
+
pub_name: name.pub_name
|
1144
|
+
)
|
1145
|
+
}
|
1093
1146
|
item_back = fdo.call(:menu_option_back_name)
|
1094
1147
|
item_edit = fdo.call(:menu_option_edit_name)
|
1095
1148
|
item_history = fdo.call(:menu_option_history_name)
|
@@ -1101,36 +1154,65 @@ module MarkdownExec
|
|
1101
1154
|
@run_state.batch_random = Random.new.rand
|
1102
1155
|
@run_state.batch_index = 0
|
1103
1156
|
|
1157
|
+
@run_state.files = StreamsOut.new
|
1158
|
+
|
1104
1159
|
InputSequencer.new(
|
1105
1160
|
@delegate_object[:filename],
|
1106
1161
|
@delegate_object[:input_cli_rest]
|
1107
1162
|
).run do |msg, data|
|
1163
|
+
# &bt msg
|
1108
1164
|
case msg
|
1109
1165
|
when :parse_document # once for each menu
|
1110
1166
|
# puts "@ - parse document #{data}"
|
1111
1167
|
inpseq_parse_document(data)
|
1112
1168
|
|
1113
1169
|
if @delegate_object[:menu_for_history]
|
1114
|
-
history_files.tap do |files|
|
1115
|
-
|
1170
|
+
history_files(@dml_link_state).tap do |files|
|
1171
|
+
if files.count.positive?
|
1172
|
+
menu_enable_option(item_history.oname, files.count, 'files',
|
1173
|
+
menu_state: MenuState::HISTORY)
|
1174
|
+
end
|
1116
1175
|
end
|
1117
1176
|
end
|
1118
1177
|
|
1119
1178
|
if @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present?
|
1120
1179
|
|
1121
|
-
sf = document_name_in_glob_as_file_name(
|
1180
|
+
sf = document_name_in_glob_as_file_name(
|
1181
|
+
@dml_link_state.document_filename,
|
1182
|
+
@delegate_object[:document_saved_lines_glob]
|
1183
|
+
)
|
1122
1184
|
files = sf ? Dir.glob(sf) : []
|
1123
1185
|
@doc_saved_lines_files = files.count.positive? ? files : []
|
1124
1186
|
|
1125
|
-
lines_count = @dml_link_state.
|
1187
|
+
lines_count = @dml_link_state.inherited_lines_count
|
1126
1188
|
|
1127
1189
|
# add menu items (glob, load, save) and enable selectively
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1190
|
+
if files.count.positive? || lines_count.positive?
|
1191
|
+
menu_add_disabled_option(sf)
|
1192
|
+
end
|
1193
|
+
if files.count.positive?
|
1194
|
+
menu_enable_option(item_load.dname, files.count, 'files',
|
1195
|
+
menu_state: MenuState::LOAD)
|
1196
|
+
end
|
1197
|
+
if lines_count.positive?
|
1198
|
+
menu_enable_option(item_edit.dname, lines_count, 'lines',
|
1199
|
+
menu_state: MenuState::EDIT)
|
1200
|
+
end
|
1201
|
+
if lines_count.positive?
|
1202
|
+
menu_enable_option(item_save.dname, 1, '',
|
1203
|
+
menu_state: MenuState::SAVE)
|
1204
|
+
end
|
1205
|
+
if lines_count.positive?
|
1206
|
+
menu_enable_option(item_view.dname, 1, '',
|
1207
|
+
menu_state: MenuState::VIEW)
|
1208
|
+
end
|
1209
|
+
if @delegate_object[:menu_with_shell]
|
1210
|
+
menu_enable_option(item_shell.dname, 1, '',
|
1211
|
+
menu_state: MenuState::SHELL)
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
# # reflect new menu items
|
1215
|
+
# @dml_mdoc = MDoc.new(@dml_menu_blocks)
|
1134
1216
|
end
|
1135
1217
|
|
1136
1218
|
when :display_menu
|
@@ -1143,7 +1225,7 @@ module MarkdownExec
|
|
1143
1225
|
if @dml_link_state.block_name.present?
|
1144
1226
|
# @prior_block_was_link = true
|
1145
1227
|
@dml_block_state.block = @dml_blocks_in_file.find do |item|
|
1146
|
-
item.pub_name == @dml_link_state.block_name
|
1228
|
+
item.pub_name == @dml_link_state.block_name || item.oname == @dml_link_state.block_name
|
1147
1229
|
end
|
1148
1230
|
@dml_link_state.block_name = nil
|
1149
1231
|
else
|
@@ -1156,7 +1238,7 @@ module MarkdownExec
|
|
1156
1238
|
|
1157
1239
|
when :execute_block
|
1158
1240
|
case (block_name = data)
|
1159
|
-
when item_back
|
1241
|
+
when item_back.pub_name
|
1160
1242
|
debounce_reset
|
1161
1243
|
@menu_user_clicked_back_link = true
|
1162
1244
|
load_file_link_state = pop_link_history_and_trigger_load
|
@@ -1171,64 +1253,94 @@ module MarkdownExec
|
|
1171
1253
|
)
|
1172
1254
|
)
|
1173
1255
|
|
1174
|
-
when item_edit
|
1256
|
+
when item_edit.pub_name
|
1175
1257
|
debounce_reset
|
1176
|
-
edited = edit_text(@dml_link_state.
|
1258
|
+
edited = edit_text(@dml_link_state.inherited_lines_block)
|
1177
1259
|
@dml_link_state.inherited_lines = edited.split("\n") if edited
|
1178
1260
|
|
1179
1261
|
return :break if pause_user_exit
|
1180
1262
|
|
1181
1263
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1182
1264
|
|
1183
|
-
when item_history
|
1265
|
+
when item_history.pub_name
|
1184
1266
|
debounce_reset
|
1185
|
-
files = history_files
|
1267
|
+
files = history_files(@dml_link_state)
|
1186
1268
|
files_table_rows = files.map do |file|
|
1187
1269
|
if Regexp.new(@delegate_object[:saved_asset_match]) =~ file
|
1188
|
-
|
1270
|
+
begin
|
1271
|
+
OpenStruct.new(
|
1272
|
+
file: file,
|
1273
|
+
row: format(
|
1274
|
+
@delegate_object[:saved_history_format],
|
1275
|
+
# create with default '*' so unknown parameters are given a wildcard
|
1276
|
+
$~.names.each_with_object(Hash.new('*')) do |name, hash|
|
1277
|
+
hash[name.to_sym] = $~[name]
|
1278
|
+
end
|
1279
|
+
)
|
1280
|
+
)
|
1281
|
+
rescue KeyError
|
1282
|
+
# pp $!, $@
|
1283
|
+
warn "Cannot format with: #{@delegate_object[:saved_history_format]}"
|
1284
|
+
error_handler('saved_history_format')
|
1285
|
+
break
|
1286
|
+
end
|
1189
1287
|
else
|
1190
1288
|
warn "Cannot parse name: #{file}"
|
1191
1289
|
next
|
1192
1290
|
end
|
1193
|
-
end
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1291
|
+
end&.compact
|
1292
|
+
|
1293
|
+
return :break unless files_table_rows
|
1294
|
+
|
1295
|
+
# repeat select+display until user exits
|
1296
|
+
row_attrib = :row
|
1297
|
+
loop do
|
1298
|
+
# menu with Back and Facet options at top
|
1299
|
+
case (name = prompt_select_code_filename(
|
1300
|
+
[@delegate_object[:prompt_filespec_back],
|
1301
|
+
@delegate_object[:prompt_filespec_facet]] +
|
1302
|
+
files_table_rows.map(&row_attrib),
|
1303
|
+
string: @delegate_object[:prompt_select_history_file],
|
1304
|
+
color_sym: :prompt_color_after_script_execution
|
1305
|
+
))
|
1306
|
+
when @delegate_object[:prompt_filespec_back]
|
1307
|
+
break
|
1308
|
+
when @delegate_object[:prompt_filespec_facet]
|
1309
|
+
row_attrib = row_attrib == :row ? :file : :row
|
1310
|
+
else
|
1311
|
+
file = files_table_rows.select { |ftr| ftr.row == name }&.first
|
1312
|
+
info = file_info(file.file)
|
1313
|
+
warn "#{file.file} - #{info[:lines]} lines / #{info[:size]} bytes"
|
1314
|
+
warn(File.readlines(file.file,
|
1315
|
+
chomp: false).map.with_index do |line, ind|
|
1316
|
+
format(' %s. %s', format('% 4d', ind + 1).violet, line)
|
1317
|
+
end)
|
1318
|
+
end
|
1210
1319
|
end
|
1211
1320
|
|
1212
1321
|
return :break if pause_user_exit
|
1213
1322
|
|
1214
1323
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1215
1324
|
|
1216
|
-
when item_load
|
1325
|
+
when item_load.pub_name
|
1217
1326
|
debounce_reset
|
1218
|
-
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1327
|
+
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1328
|
+
@delegate_object[:document_saved_lines_glob])
|
1219
1329
|
load_filespec = load_filespec_from_expression(sf)
|
1220
1330
|
if load_filespec
|
1221
|
-
@dml_link_state.
|
1222
|
-
|
1331
|
+
@dml_link_state.inherited_lines_append(
|
1332
|
+
File.readlines(load_filespec, chomp: true)
|
1333
|
+
)
|
1223
1334
|
end
|
1224
1335
|
|
1225
1336
|
return :break if pause_user_exit
|
1226
1337
|
|
1227
1338
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1228
1339
|
|
1229
|
-
when item_save
|
1340
|
+
when item_save.pub_name
|
1230
1341
|
debounce_reset
|
1231
|
-
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1342
|
+
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1343
|
+
@delegate_object[:document_saved_lines_glob])
|
1232
1344
|
save_filespec = save_filespec_from_expression(sf)
|
1233
1345
|
if save_filespec && !write_file_with_directory_creation(
|
1234
1346
|
save_filespec,
|
@@ -1240,7 +1352,7 @@ module MarkdownExec
|
|
1240
1352
|
|
1241
1353
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1242
1354
|
|
1243
|
-
when item_shell
|
1355
|
+
when item_shell.pub_name
|
1244
1356
|
debounce_reset
|
1245
1357
|
loop do
|
1246
1358
|
command = prompt_for_command(":MDE #{Time.now.strftime('%FT%TZ')}> ".bgreen)
|
@@ -1261,9 +1373,9 @@ module MarkdownExec
|
|
1261
1373
|
|
1262
1374
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1263
1375
|
|
1264
|
-
when item_view
|
1376
|
+
when item_view.pub_name
|
1265
1377
|
debounce_reset
|
1266
|
-
warn @dml_link_state.
|
1378
|
+
warn @dml_link_state.inherited_lines_block
|
1267
1379
|
|
1268
1380
|
return :break if pause_user_exit
|
1269
1381
|
|
@@ -1271,28 +1383,28 @@ module MarkdownExec
|
|
1271
1383
|
|
1272
1384
|
else
|
1273
1385
|
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1274
|
-
if @dml_block_state.block && @dml_block_state.block.
|
1386
|
+
if @dml_block_state.block && @dml_block_state.block.shell == BlockType::OPTS
|
1275
1387
|
debounce_reset
|
1276
1388
|
link_state = LinkState.new
|
1277
1389
|
options_state = read_show_options_and_trigger_reuse(
|
1278
|
-
|
1279
|
-
|
1390
|
+
link_state: link_state,
|
1391
|
+
mdoc: @dml_mdoc,
|
1392
|
+
selected: @dml_block_state.block
|
1280
1393
|
)
|
1281
1394
|
|
1282
|
-
|
1283
|
-
@delegate_object.merge!(options_state.options)
|
1395
|
+
update_menu_base(options_state.options)
|
1284
1396
|
options_state.load_file_link_state.link_state
|
1285
1397
|
else
|
1286
1398
|
inpseq_execute_block(block_name)
|
1287
1399
|
|
1288
|
-
if prompt_user_exit(block_name_from_cli: @run_state.block_name_from_cli,
|
1400
|
+
if prompt_user_exit(block_name_from_cli: @run_state.source.block_name_from_cli,
|
1289
1401
|
selected: @dml_block_state.block)
|
1290
1402
|
return :break
|
1291
1403
|
end
|
1292
1404
|
|
1293
1405
|
## order of block name processing: link block, cli, from user
|
1294
1406
|
#
|
1295
|
-
@dml_link_state.block_name, @run_state.block_name_from_cli, cli_break =
|
1407
|
+
@dml_link_state.block_name, @run_state.source.block_name_from_cli, cli_break =
|
1296
1408
|
HashDelegator.next_link_state(
|
1297
1409
|
block_name: @dml_link_state.block_name,
|
1298
1410
|
block_name_from_cli: @dml_now_using_cli,
|
@@ -1300,14 +1412,14 @@ module MarkdownExec
|
|
1300
1412
|
was_using_cli: @dml_now_using_cli
|
1301
1413
|
)
|
1302
1414
|
|
1303
|
-
if !@dml_block_state.
|
1415
|
+
if !@dml_block_state.source.block_name_from_ui && cli_break
|
1304
1416
|
# &bsp '!block_name_from_ui + cli_break -> break'
|
1305
1417
|
return :break
|
1306
1418
|
end
|
1307
1419
|
|
1308
1420
|
InputSequencer.next_link_state(
|
1309
1421
|
block_name: @dml_link_state.block_name,
|
1310
|
-
prior_block_was_link: @dml_block_state.block.
|
1422
|
+
prior_block_was_link: @dml_block_state.block.shell != BlockType::BASH
|
1311
1423
|
)
|
1312
1424
|
end
|
1313
1425
|
end
|
@@ -1328,9 +1440,13 @@ module MarkdownExec
|
|
1328
1440
|
# remove leading "./"
|
1329
1441
|
# replace characters: / : . * (space) with: (underscore)
|
1330
1442
|
def document_name_in_glob_as_file_name(document_filename, glob)
|
1331
|
-
|
1443
|
+
if document_filename.nil? || document_filename.empty?
|
1444
|
+
return document_filename
|
1445
|
+
end
|
1332
1446
|
|
1333
|
-
format(glob,
|
1447
|
+
format(glob,
|
1448
|
+
{ document_filename: document_filename.gsub(%r{^\./}, '').gsub(/[\/:\.\* ]/,
|
1449
|
+
'_') })
|
1334
1450
|
end
|
1335
1451
|
|
1336
1452
|
def dump_and_warn_block_state(selected:)
|
@@ -1351,7 +1467,10 @@ module MarkdownExec
|
|
1351
1467
|
# @param menu_blocks [Hash] Hash of menu blocks.
|
1352
1468
|
# @param link_state [LinkState] Current state of the link.
|
1353
1469
|
def dump_delobj(blocks_in_file, menu_blocks, link_state)
|
1354
|
-
|
1470
|
+
if @delegate_object[:dump_delegate_object]
|
1471
|
+
warn format_and_highlight_hash(@delegate_object,
|
1472
|
+
label: '@delegate_object')
|
1473
|
+
end
|
1355
1474
|
|
1356
1475
|
if @delegate_object[:dump_blocks_in_file]
|
1357
1476
|
warn format_and_highlight_dependencies(compact_and_index_hash(blocks_in_file),
|
@@ -1363,11 +1482,18 @@ module MarkdownExec
|
|
1363
1482
|
label: 'menu_blocks')
|
1364
1483
|
end
|
1365
1484
|
|
1366
|
-
|
1367
|
-
|
1485
|
+
if @delegate_object[:dump_inherited_block_names]
|
1486
|
+
warn format_and_highlight_lines(link_state.inherited_block_names,
|
1487
|
+
label: 'inherited_block_names')
|
1488
|
+
end
|
1489
|
+
if @delegate_object[:dump_inherited_dependencies]
|
1490
|
+
warn format_and_highlight_lines(link_state.inherited_dependencies,
|
1491
|
+
label: 'inherited_dependencies')
|
1492
|
+
end
|
1368
1493
|
return unless @delegate_object[:dump_inherited_lines]
|
1369
1494
|
|
1370
|
-
warn format_and_highlight_lines(link_state.inherited_lines,
|
1495
|
+
warn format_and_highlight_lines(link_state.inherited_lines,
|
1496
|
+
label: 'inherited_lines')
|
1371
1497
|
end
|
1372
1498
|
|
1373
1499
|
# Opens text in an editor for user modification and returns the modified text.
|
@@ -1432,7 +1558,7 @@ module MarkdownExec
|
|
1432
1558
|
|
1433
1559
|
# if the same menu is being displayed, collect the display name of the selected menu item for use as the default item
|
1434
1560
|
[lfls.link_state,
|
1435
|
-
lfls.load_file == LoadFile::LOAD ? nil : selected
|
1561
|
+
lfls.load_file == LoadFile::LOAD ? nil : selected.dname]
|
1436
1562
|
#.tap { |ret| pp [__FILE__,__LINE__,'exec_bash_next_state()',ret] }
|
1437
1563
|
end
|
1438
1564
|
|
@@ -1453,17 +1579,20 @@ module MarkdownExec
|
|
1453
1579
|
|
1454
1580
|
Open3.popen3(*command) do |stdin, stdout, stderr, exec_thread|
|
1455
1581
|
# Handle stdout stream
|
1456
|
-
handle_stream(stream: stdout,
|
1582
|
+
handle_stream(stream: stdout,
|
1583
|
+
file_type: ExecutionStreams::STD_OUT) do |line|
|
1457
1584
|
yield nil, line, nil, exec_thread if block_given?
|
1458
1585
|
end
|
1459
1586
|
|
1460
1587
|
# Handle stderr stream
|
1461
|
-
handle_stream(stream: stderr,
|
1588
|
+
handle_stream(stream: stderr,
|
1589
|
+
file_type: ExecutionStreams::STD_ERR) do |line|
|
1462
1590
|
yield nil, nil, line, exec_thread if block_given?
|
1463
1591
|
end
|
1464
1592
|
|
1465
1593
|
# Handle stdin stream
|
1466
|
-
input_thread = handle_stream(stream: $stdin,
|
1594
|
+
input_thread = handle_stream(stream: $stdin,
|
1595
|
+
file_type: ExecutionStreams::STD_IN) do |line|
|
1467
1596
|
stdin.puts(line)
|
1468
1597
|
yield line, nil, nil, exec_thread if block_given?
|
1469
1598
|
end
|
@@ -1490,8 +1619,13 @@ module MarkdownExec
|
|
1490
1619
|
# @param required_lines [Array<String>] The lines of code to be executed.
|
1491
1620
|
# @param selected [FCB] The selected functional code block object.
|
1492
1621
|
def execute_required_lines(required_lines: [], selected: FCB.new)
|
1493
|
-
|
1494
|
-
|
1622
|
+
if @delegate_object[:save_executed_script]
|
1623
|
+
write_command_file(required_lines: required_lines,
|
1624
|
+
selected: selected)
|
1625
|
+
end
|
1626
|
+
if @dml_block_state
|
1627
|
+
calc_logged_stdout_filename(block_name: @dml_block_state.block.oname)
|
1628
|
+
end
|
1495
1629
|
format_and_execute_command(code_lines: required_lines)
|
1496
1630
|
post_execution_process
|
1497
1631
|
end
|
@@ -1505,10 +1639,11 @@ module MarkdownExec
|
|
1505
1639
|
# @param opts [Hash] Options hash containing configuration settings.
|
1506
1640
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
1507
1641
|
#
|
1508
|
-
def execute_shell_type(selected:, mdoc:, block_source:,
|
1509
|
-
|
1642
|
+
def execute_shell_type(selected:, mdoc:, block_source:,
|
1643
|
+
link_state: LinkState.new)
|
1644
|
+
if selected.shell == BlockType::LINK
|
1510
1645
|
debounce_reset
|
1511
|
-
push_link_history_and_trigger_load(link_block_body: selected.
|
1646
|
+
push_link_history_and_trigger_load(link_block_body: selected.body,
|
1512
1647
|
mdoc: mdoc,
|
1513
1648
|
selected: selected,
|
1514
1649
|
link_state: link_state,
|
@@ -1518,46 +1653,34 @@ module MarkdownExec
|
|
1518
1653
|
debounce_reset
|
1519
1654
|
pop_link_history_and_trigger_load
|
1520
1655
|
|
1521
|
-
elsif selected
|
1656
|
+
elsif selected.shell == BlockType::OPTS
|
1522
1657
|
debounce_reset
|
1523
|
-
block_names = []
|
1524
1658
|
code_lines = []
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
@delegate_object.merge!(options_state.options)
|
1659
|
+
options_state = read_show_options_and_trigger_reuse(
|
1660
|
+
link_state: link_state,
|
1661
|
+
mdoc: @dml_mdoc,
|
1662
|
+
selected: selected
|
1663
|
+
)
|
1664
|
+
update_menu_base(options_state.options)
|
1532
1665
|
|
1533
1666
|
### options_state.load_file_link_state
|
1534
1667
|
link_state = LinkState.new
|
1535
|
-
|
1536
|
-
curr_block_name: selected.pub_name,
|
1537
|
-
curr_document_filename: @delegate_object[:filename],
|
1538
|
-
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
1539
|
-
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
1540
|
-
inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
1541
|
-
next_block_name: '',
|
1542
|
-
next_document_filename: @delegate_object[:filename],
|
1543
|
-
next_load_file: LoadFile::REUSE
|
1544
|
-
)
|
1668
|
+
next_state_append_code(selected, link_state, code_lines)
|
1545
1669
|
|
1546
|
-
elsif selected
|
1670
|
+
elsif selected.shell == BlockType::PORT
|
1547
1671
|
debounce_reset
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
curr_document_filename: @delegate_object[:filename],
|
1554
|
-
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
1555
|
-
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
1556
|
-
inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
1557
|
-
next_block_name: '',
|
1558
|
-
next_document_filename: @delegate_object[:filename],
|
1559
|
-
next_load_file: LoadFile::REUSE
|
1672
|
+
required_lines = collect_required_code_lines(
|
1673
|
+
mdoc: @dml_mdoc,
|
1674
|
+
selected: selected,
|
1675
|
+
link_state: link_state,
|
1676
|
+
block_source: block_source
|
1560
1677
|
)
|
1678
|
+
next_state_set_code(selected, link_state, required_lines)
|
1679
|
+
|
1680
|
+
elsif selected.shell == BlockType::VARS
|
1681
|
+
debounce_reset
|
1682
|
+
next_state_append_code(selected, link_state,
|
1683
|
+
set_environment_variables_for_block(selected))
|
1561
1684
|
|
1562
1685
|
elsif debounce_allows
|
1563
1686
|
compile_execute_and_trigger_reuse(mdoc: mdoc,
|
@@ -1646,6 +1769,16 @@ module MarkdownExec
|
|
1646
1769
|
expr.include?('%{') ? format_expression(expr) : expr
|
1647
1770
|
end
|
1648
1771
|
|
1772
|
+
def generate_temp_filename(ext = '.sh')
|
1773
|
+
filename = begin
|
1774
|
+
Dir::Tmpname.make_tmpname(['x', ext], nil)
|
1775
|
+
rescue NoMethodError
|
1776
|
+
require 'securerandom'
|
1777
|
+
"#{SecureRandom.urlsafe_base64}#{ext}"
|
1778
|
+
end
|
1779
|
+
File.join(Dir.tmpdir, filename)
|
1780
|
+
end
|
1781
|
+
|
1649
1782
|
# Processes a block to generate its summary, modifying its attributes based on various matching criteria.
|
1650
1783
|
# It handles special formatting for bash blocks, extracting and setting properties like call, stdin, stdout, and dname.
|
1651
1784
|
#
|
@@ -1659,7 +1792,7 @@ module MarkdownExec
|
|
1659
1792
|
bm = extract_named_captures_from_option(titlexcall,
|
1660
1793
|
@delegate_object[:block_name_match])
|
1661
1794
|
|
1662
|
-
shell_color_option = SHELL_COLOR_OPTIONS[fcb
|
1795
|
+
shell_color_option = SHELL_COLOR_OPTIONS[fcb.shell]
|
1663
1796
|
|
1664
1797
|
if @delegate_object[:block_name_nick_match].present? && fcb.oname =~ Regexp.new(@delegate_object[:block_name_nick_match])
|
1665
1798
|
fcb.nickname = $~[0]
|
@@ -1670,9 +1803,10 @@ module MarkdownExec
|
|
1670
1803
|
|
1671
1804
|
fcb.dname = HashDelegator.indent_all_lines(
|
1672
1805
|
apply_shell_color_option(fcb.oname, shell_color_option),
|
1673
|
-
fcb.
|
1806
|
+
fcb.indent
|
1674
1807
|
)
|
1675
|
-
|
1808
|
+
|
1809
|
+
fcb # &br
|
1676
1810
|
end
|
1677
1811
|
|
1678
1812
|
# Updates the delegate object's state based on the provided block state.
|
@@ -1695,13 +1829,13 @@ module MarkdownExec
|
|
1695
1829
|
Thread.new do
|
1696
1830
|
stream.each_line do |line|
|
1697
1831
|
line.strip!
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
# print line
|
1702
|
-
puts line
|
1832
|
+
if @run_state.files.streams
|
1833
|
+
@run_state.files.append_stream_line(file_type,
|
1834
|
+
line)
|
1703
1835
|
end
|
1704
1836
|
|
1837
|
+
puts line if @delegate_object[:output_stdout]
|
1838
|
+
|
1705
1839
|
yield line if block_given?
|
1706
1840
|
end
|
1707
1841
|
rescue IOError
|
@@ -1712,25 +1846,40 @@ module MarkdownExec
|
|
1712
1846
|
end
|
1713
1847
|
end
|
1714
1848
|
|
1715
|
-
def history_files
|
1716
|
-
Dir.glob(
|
1849
|
+
def history_files(link_state, order: :chronological, direction: :reverse)
|
1850
|
+
files = Dir.glob(
|
1717
1851
|
File.join(
|
1718
1852
|
@delegate_object[:saved_script_folder],
|
1719
|
-
SavedAsset.new(
|
1720
|
-
|
1853
|
+
SavedAsset.new(
|
1854
|
+
filename: @delegate_object[:filename],
|
1855
|
+
saved_asset_format: shell_escape_asset_format(link_state)
|
1856
|
+
).generate_name
|
1721
1857
|
)
|
1722
1858
|
)
|
1859
|
+
|
1860
|
+
sorted_files = case order
|
1861
|
+
when :alphabetical
|
1862
|
+
files.sort
|
1863
|
+
when :chronological
|
1864
|
+
files.sort_by { |file| File.mtime(file) }
|
1865
|
+
else
|
1866
|
+
raise ArgumentError, "Invalid order: #{order}"
|
1867
|
+
end
|
1868
|
+
|
1869
|
+
direction == :reverse ? sorted_files.reverse : sorted_files
|
1723
1870
|
end
|
1724
1871
|
|
1725
1872
|
# Initializes variables for regex and other states
|
1726
1873
|
def initial_state
|
1727
1874
|
{
|
1728
|
-
fenced_start_and_end_regex:
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1875
|
+
fenced_start_and_end_regex:
|
1876
|
+
Regexp.new(@delegate_object.fetch(
|
1877
|
+
:fenced_start_and_end_regex, '^(?<indent> *)`{3,}'
|
1878
|
+
)),
|
1879
|
+
fenced_start_extended_regex:
|
1880
|
+
Regexp.new(@delegate_object.fetch(
|
1881
|
+
:fenced_start_and_end_regex, '^(?<indent> *)`{3,}'
|
1882
|
+
)),
|
1734
1883
|
fcb: MarkdownExec::FCB.new,
|
1735
1884
|
in_fenced_block: false,
|
1736
1885
|
headings: []
|
@@ -1740,7 +1889,7 @@ module MarkdownExec
|
|
1740
1889
|
def inpseq_execute_block(block_name)
|
1741
1890
|
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1742
1891
|
dump_and_warn_block_state(selected: @dml_block_state.block)
|
1743
|
-
@dml_link_state, @dml_menu_default_dname =
|
1892
|
+
@dml_link_state, @dml_menu_default_dname =
|
1744
1893
|
exec_bash_next_state(
|
1745
1894
|
selected: @dml_block_state.block,
|
1746
1895
|
mdoc: @dml_mdoc,
|
@@ -1757,8 +1906,8 @@ module MarkdownExec
|
|
1757
1906
|
@run_state.in_own_window = false
|
1758
1907
|
|
1759
1908
|
# &bsp 'loop', block_name_from_cli, @cli_block_name
|
1760
|
-
@run_state.block_name_from_cli, @dml_now_using_cli, @dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc =
|
1761
|
-
set_delobj_menu_loop_vars(block_name_from_cli: @run_state.block_name_from_cli,
|
1909
|
+
@run_state.source.block_name_from_cli, @dml_now_using_cli, @dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc =
|
1910
|
+
set_delobj_menu_loop_vars(block_name_from_cli: @run_state.source.block_name_from_cli,
|
1762
1911
|
now_using_cli: @dml_now_using_cli,
|
1763
1912
|
link_state: @dml_link_state)
|
1764
1913
|
end
|
@@ -1767,7 +1916,7 @@ module MarkdownExec
|
|
1767
1916
|
@dml_block_state = load_cli_or_user_selected_block(all_blocks: @dml_blocks_in_file,
|
1768
1917
|
menu_blocks: @dml_menu_blocks,
|
1769
1918
|
default: @dml_menu_default_dname)
|
1770
|
-
# &bsp '@run_state.block_name_from_cli:',@run_state.block_name_from_cli
|
1919
|
+
# &bsp '@run_state.source.block_name_from_cli:',@run_state.source.block_name_from_cli
|
1771
1920
|
if !@dml_block_state
|
1772
1921
|
HashDelegator.error_handler('block_state missing', { abort: true })
|
1773
1922
|
elsif @dml_block_state.state == MenuState::EXIT
|
@@ -1793,8 +1942,10 @@ module MarkdownExec
|
|
1793
1942
|
end
|
1794
1943
|
end
|
1795
1944
|
|
1796
|
-
def link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
1797
|
-
|
1945
|
+
def link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
1946
|
+
block_source:)
|
1947
|
+
all_code = HashDelegator.code_merge(link_state&.inherited_lines,
|
1948
|
+
code_lines)
|
1798
1949
|
output_lines = []
|
1799
1950
|
|
1800
1951
|
Tempfile.open do |file|
|
@@ -1813,7 +1964,8 @@ module MarkdownExec
|
|
1813
1964
|
#
|
1814
1965
|
output_lines = process_string_array(
|
1815
1966
|
output_lines,
|
1816
|
-
begin_pattern: @delegate_object.fetch(:output_assignment_begin,
|
1967
|
+
begin_pattern: @delegate_object.fetch(:output_assignment_begin,
|
1968
|
+
nil),
|
1817
1969
|
end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
|
1818
1970
|
scan1: @delegate_object.fetch(:output_assignment_match, nil),
|
1819
1971
|
format1: @delegate_object.fetch(:output_assignment_format, nil)
|
@@ -1824,7 +1976,10 @@ module MarkdownExec
|
|
1824
1976
|
end
|
1825
1977
|
end
|
1826
1978
|
|
1827
|
-
|
1979
|
+
unless output_lines
|
1980
|
+
HashDelegator.error_handler('all_code eval output_lines is nil',
|
1981
|
+
{ abort: true })
|
1982
|
+
end
|
1828
1983
|
|
1829
1984
|
label_format_above = @delegate_object[:shell_code_label_format_above]
|
1830
1985
|
label_format_below = @delegate_object[:shell_code_label_format_below]
|
@@ -1833,7 +1988,11 @@ module MarkdownExec
|
|
1833
1988
|
block_source.merge({ block_name: selected.pub_name }))] +
|
1834
1989
|
output_lines.map do |line|
|
1835
1990
|
re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
|
1836
|
-
|
1991
|
+
next unless re =~ line
|
1992
|
+
|
1993
|
+
re.gsub_format(line,
|
1994
|
+
link_block_data.fetch('format',
|
1995
|
+
'%{line}'))
|
1837
1996
|
end.compact +
|
1838
1997
|
[label_format_below && format(label_format_below,
|
1839
1998
|
block_source.merge({ block_name: selected.pub_name }))]
|
@@ -1882,34 +2041,41 @@ module MarkdownExec
|
|
1882
2041
|
# Executes a specified block once per filename.
|
1883
2042
|
# @param all_blocks [Array] Array of all block elements.
|
1884
2043
|
# @return [Boolean, nil] True if values were modified, nil otherwise.
|
1885
|
-
def load_auto_opts_block(all_blocks)
|
2044
|
+
def load_auto_opts_block(all_blocks, mdoc:)
|
1886
2045
|
block_name = @delegate_object[:document_load_opts_block_name]
|
1887
|
-
|
2046
|
+
unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
2047
|
+
return
|
2048
|
+
end
|
1888
2049
|
|
1889
2050
|
block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1890
2051
|
return unless block
|
1891
2052
|
|
1892
|
-
options_state = read_show_options_and_trigger_reuse(
|
1893
|
-
|
1894
|
-
|
2053
|
+
options_state = read_show_options_and_trigger_reuse(
|
2054
|
+
mdoc: mdoc,
|
2055
|
+
selected: block
|
2056
|
+
)
|
2057
|
+
update_menu_base(options_state.options)
|
1895
2058
|
|
1896
2059
|
@most_recent_loaded_filename = @delegate_object[:filename]
|
1897
2060
|
true
|
1898
2061
|
end
|
1899
2062
|
|
1900
|
-
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [],
|
2063
|
+
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [],
|
2064
|
+
default: nil)
|
1901
2065
|
if @delegate_object[:block_name].present?
|
1902
2066
|
block = all_blocks.find do |item|
|
1903
2067
|
item.pub_name == @delegate_object[:block_name]
|
1904
|
-
end
|
2068
|
+
end
|
2069
|
+
source = OpenStruct.new(block_name_from_ui: false)
|
1905
2070
|
else
|
1906
2071
|
block_state = wait_for_user_selected_block(all_blocks, menu_blocks,
|
1907
2072
|
default)
|
1908
|
-
block = block_state.block
|
2073
|
+
block = block_state.block
|
2074
|
+
source = OpenStruct.new(block_name_from_ui: true)
|
1909
2075
|
state = block_state.state
|
1910
2076
|
end
|
1911
2077
|
|
1912
|
-
SelectedBlockMenuState.new(block, state)
|
2078
|
+
SelectedBlockMenuState.new(block, source, state)
|
1913
2079
|
rescue StandardError
|
1914
2080
|
HashDelegator.error_handler('load_cli_or_user_selected_block')
|
1915
2081
|
end
|
@@ -1932,7 +2098,8 @@ module MarkdownExec
|
|
1932
2098
|
def load_filespec_wildcard_expansion(expr, auto_load_single: false)
|
1933
2099
|
files = find_files(expr)
|
1934
2100
|
if files.count.zero?
|
1935
|
-
HashDelegator.error_handler("no files found with '#{expr}' ",
|
2101
|
+
HashDelegator.error_handler("no files found with '#{expr}' ",
|
2102
|
+
{ abort: true })
|
1936
2103
|
elsif auto_load_single && files.count == 1
|
1937
2104
|
files.first
|
1938
2105
|
else
|
@@ -1966,20 +2133,22 @@ module MarkdownExec
|
|
1966
2133
|
|
1967
2134
|
# recreate menu with new options
|
1968
2135
|
#
|
1969
|
-
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(
|
2136
|
+
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(
|
2137
|
+
all_blocks, mdoc: mdoc
|
2138
|
+
)
|
1970
2139
|
|
1971
2140
|
menu_blocks = mdoc.fcbs_per_options(@delegate_object)
|
1972
2141
|
add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
|
1973
2142
|
### compress empty lines
|
1974
2143
|
HashDelegator.delete_consecutive_blank_lines!(menu_blocks)
|
1975
|
-
[all_blocks, menu_blocks, mdoc]
|
2144
|
+
[all_blocks, menu_blocks, mdoc] # &br
|
1976
2145
|
end
|
1977
2146
|
|
1978
2147
|
def menu_add_disabled_option(name)
|
1979
2148
|
raise unless name.present?
|
1980
2149
|
raise if @dml_menu_blocks.nil?
|
1981
2150
|
|
1982
|
-
block = @dml_menu_blocks.find { |item| item
|
2151
|
+
block = @dml_menu_blocks.find { |item| item.oname == name }
|
1983
2152
|
|
1984
2153
|
# create menu item when it is needed (count > 0)
|
1985
2154
|
#
|
@@ -2017,7 +2186,9 @@ module MarkdownExec
|
|
2017
2186
|
# @param option_symbol [Symbol] The symbol key for the menu option in the delegate object.
|
2018
2187
|
# @return [String] The formatted or original value of the menu option.
|
2019
2188
|
def menu_chrome_formatted_option(option_symbol = :menu_option_back_name)
|
2020
|
-
option_value = HashDelegator.safeval(@delegate_object.fetch(
|
2189
|
+
option_value = HashDelegator.safeval(@delegate_object.fetch(
|
2190
|
+
option_symbol, ''
|
2191
|
+
))
|
2021
2192
|
|
2022
2193
|
if @delegate_object[:menu_chrome_format]
|
2023
2194
|
format(@delegate_object[:menu_chrome_format], option_value)
|
@@ -2030,20 +2201,20 @@ module MarkdownExec
|
|
2030
2201
|
raise unless name.present?
|
2031
2202
|
raise if @dml_menu_blocks.nil?
|
2032
2203
|
|
2033
|
-
item = @dml_menu_blocks.find { |block| block
|
2204
|
+
item = @dml_menu_blocks.find { |block| block.oname == name }
|
2034
2205
|
|
2035
2206
|
# create menu item when it is needed (count > 0)
|
2036
2207
|
#
|
2037
2208
|
if item.nil? && count.positive?
|
2038
|
-
append_chrome_block(menu_blocks: @dml_menu_blocks,
|
2039
|
-
|
2209
|
+
item = append_chrome_block(menu_blocks: @dml_menu_blocks,
|
2210
|
+
menu_state: menu_state)
|
2040
2211
|
end
|
2041
2212
|
|
2042
2213
|
# update item if it exists
|
2043
2214
|
#
|
2044
2215
|
return unless item
|
2045
2216
|
|
2046
|
-
item
|
2217
|
+
item.dname = type.present? ? "#{name} (#{count} #{type})" : name
|
2047
2218
|
if count.positive?
|
2048
2219
|
item.delete(:disabled)
|
2049
2220
|
else
|
@@ -2051,14 +2222,15 @@ module MarkdownExec
|
|
2051
2222
|
end
|
2052
2223
|
end
|
2053
2224
|
|
2054
|
-
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:,
|
2225
|
+
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:,
|
2226
|
+
link_state:)
|
2055
2227
|
if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name]
|
2056
2228
|
# &bsp 'pause cli control, allow user to select block'
|
2057
2229
|
block_name_from_cli = false
|
2058
2230
|
now_using_cli = false
|
2059
|
-
@menu_base_options[:block_name] =
|
2231
|
+
@menu_base_options[:block_name] =
|
2060
2232
|
@delegate_object[:block_name] = \
|
2061
|
-
link_state.block_name =
|
2233
|
+
link_state.block_name =
|
2062
2234
|
@cli_block_name = nil
|
2063
2235
|
end
|
2064
2236
|
|
@@ -2079,6 +2251,27 @@ module MarkdownExec
|
|
2079
2251
|
end
|
2080
2252
|
end
|
2081
2253
|
|
2254
|
+
def next_state_append_code(selected, link_state, code_lines)
|
2255
|
+
next_state_set_code(selected, link_state, HashDelegator.code_merge(
|
2256
|
+
link_state&.inherited_lines, code_lines
|
2257
|
+
))
|
2258
|
+
end
|
2259
|
+
|
2260
|
+
def next_state_set_code(selected, link_state, code_lines)
|
2261
|
+
block_names = []
|
2262
|
+
dependencies = {}
|
2263
|
+
link_history_push_and_next(
|
2264
|
+
curr_block_name: selected.pub_name,
|
2265
|
+
curr_document_filename: @delegate_object[:filename],
|
2266
|
+
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2267
|
+
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2268
|
+
inherited_lines: HashDelegator.code_merge(code_lines),
|
2269
|
+
next_block_name: '',
|
2270
|
+
next_document_filename: @delegate_object[:filename],
|
2271
|
+
next_load_file: LoadFile::REUSE
|
2272
|
+
)
|
2273
|
+
end
|
2274
|
+
|
2082
2275
|
def output_color_formatted(data_sym, color_sym)
|
2083
2276
|
formatted_string = string_send_color(@delegate_object[data_sym],
|
2084
2277
|
color_sym)
|
@@ -2159,9 +2352,12 @@ module MarkdownExec
|
|
2159
2352
|
link_history_push_and_next(
|
2160
2353
|
curr_block_name: selected.pub_name,
|
2161
2354
|
curr_document_filename: @delegate_object[:filename],
|
2162
|
-
inherited_block_names:
|
2163
|
-
|
2164
|
-
|
2355
|
+
inherited_block_names:
|
2356
|
+
((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2357
|
+
inherited_dependencies:
|
2358
|
+
(link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2359
|
+
inherited_lines:
|
2360
|
+
HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
2165
2361
|
next_block_name: next_block_name,
|
2166
2362
|
next_document_filename: @delegate_object[:filename], # not next_document_filename
|
2167
2363
|
next_load_file: LoadFile::REUSE # not next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD
|
@@ -2177,12 +2373,15 @@ module MarkdownExec
|
|
2177
2373
|
def pop_link_history_and_trigger_load
|
2178
2374
|
pop = @link_history.pop
|
2179
2375
|
peek = @link_history.peek
|
2180
|
-
LoadFileLinkState.new(
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2376
|
+
LoadFileLinkState.new(
|
2377
|
+
LoadFile::LOAD,
|
2378
|
+
LinkState.new(
|
2379
|
+
document_filename: pop.document_filename,
|
2380
|
+
inherited_block_names: peek.inherited_block_names,
|
2381
|
+
inherited_dependencies: peek.inherited_dependencies,
|
2382
|
+
inherited_lines: peek.inherited_lines
|
2383
|
+
)
|
2384
|
+
)
|
2186
2385
|
end
|
2187
2386
|
|
2188
2387
|
def post_execution_process
|
@@ -2198,20 +2397,21 @@ module MarkdownExec
|
|
2198
2397
|
# @return [Array<Hash>] The updated blocks menu.
|
2199
2398
|
def prepare_blocks_menu(menu_blocks)
|
2200
2399
|
menu_blocks.map do |fcb|
|
2201
|
-
next if Filter.prepared_not_in_menu?(
|
2202
|
-
|
2400
|
+
next if Filter.prepared_not_in_menu?(
|
2401
|
+
@delegate_object,
|
2402
|
+
fcb,
|
2403
|
+
%i[block_name_include_match block_name_wrapper_match]
|
2404
|
+
)
|
2203
2405
|
|
2204
|
-
fcb.
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
title: fcb[:title]
|
2214
|
-
)
|
2406
|
+
fcb.name = fcb.dname
|
2407
|
+
fcb.label = BlockLabel.make(
|
2408
|
+
body: fcb.body,
|
2409
|
+
filename: @delegate_object[:filename],
|
2410
|
+
headings: fcb.headings,
|
2411
|
+
menu_blocks_with_docname: @delegate_object[:menu_blocks_with_docname],
|
2412
|
+
menu_blocks_with_headings: @delegate_object[:menu_blocks_with_headings],
|
2413
|
+
text: fcb.text,
|
2414
|
+
title: fcb.title
|
2215
2415
|
)
|
2216
2416
|
fcb.to_h
|
2217
2417
|
end.compact
|
@@ -2232,7 +2432,10 @@ module MarkdownExec
|
|
2232
2432
|
when :filter
|
2233
2433
|
%i[blocks line]
|
2234
2434
|
when :line
|
2235
|
-
|
2435
|
+
unless @delegate_object[:no_chrome]
|
2436
|
+
create_and_add_chrome_blocks(blocks,
|
2437
|
+
fcb)
|
2438
|
+
end
|
2236
2439
|
end
|
2237
2440
|
end
|
2238
2441
|
|
@@ -2305,7 +2508,8 @@ module MarkdownExec
|
|
2305
2508
|
# @param filespec [String] the wildcard expression to be substituted
|
2306
2509
|
# @return [String, nil] the resolved path or substituted expression, or nil if interrupted
|
2307
2510
|
def prompt_for_filespec_with_wildcard(filespec)
|
2308
|
-
puts format(@delegate_object[:prompt_show_expr_format],
|
2511
|
+
puts format(@delegate_object[:prompt_show_expr_format],
|
2512
|
+
{ expr: filespec })
|
2309
2513
|
puts @delegate_object[:prompt_enter_filespec]
|
2310
2514
|
|
2311
2515
|
begin
|
@@ -2362,26 +2566,40 @@ module MarkdownExec
|
|
2362
2566
|
|
2363
2567
|
# public
|
2364
2568
|
|
2365
|
-
def prompt_select_code_filename(
|
2569
|
+
def prompt_select_code_filename(
|
2570
|
+
filenames,
|
2571
|
+
color_sym: :prompt_color_after_script_execution,
|
2572
|
+
cycle: true,
|
2573
|
+
enum: false,
|
2574
|
+
quiet: true,
|
2575
|
+
string: @delegate_object[:prompt_select_code_file]
|
2576
|
+
)
|
2366
2577
|
@prompt.select(
|
2367
2578
|
string_send_color(string, color_sym),
|
2368
|
-
|
2369
|
-
|
2579
|
+
cycle: cycle,
|
2580
|
+
filter: !enum,
|
2581
|
+
per_page: @delegate_object[:select_page_height],
|
2582
|
+
quiet: quiet
|
2370
2583
|
) do |menu|
|
2371
|
-
|
2372
|
-
|
2584
|
+
menu.enum '.' if enum
|
2585
|
+
filenames.each.with_index do |filename, ind|
|
2586
|
+
if enum
|
2587
|
+
menu.choice filename, ind + 1
|
2588
|
+
else
|
2589
|
+
menu.choice filename
|
2590
|
+
end
|
2373
2591
|
end
|
2374
2592
|
end
|
2375
2593
|
rescue TTY::Reader::InputInterrupt
|
2376
2594
|
exit 1
|
2377
2595
|
end
|
2378
2596
|
|
2379
|
-
def prompt_select_continue
|
2597
|
+
def prompt_select_continue(filter: true, quiet: true)
|
2380
2598
|
sel = @prompt.select(
|
2381
2599
|
string_send_color(@delegate_object[:prompt_after_script_execution],
|
2382
2600
|
:prompt_color_after_script_execution),
|
2383
|
-
filter:
|
2384
|
-
quiet:
|
2601
|
+
filter: filter,
|
2602
|
+
quiet: quiet
|
2385
2603
|
) do |menu|
|
2386
2604
|
menu.choice @delegate_object[:prompt_yes]
|
2387
2605
|
menu.choice @delegate_object[:prompt_exit]
|
@@ -2394,7 +2612,7 @@ module MarkdownExec
|
|
2394
2612
|
# user prompt to exit if the menu will be displayed again
|
2395
2613
|
#
|
2396
2614
|
def prompt_user_exit(block_name_from_cli:, selected:)
|
2397
|
-
selected
|
2615
|
+
selected.shell == BlockType::BASH &&
|
2398
2616
|
@delegate_object[:pause_after_script_execution] &&
|
2399
2617
|
prompt_select_continue == MenuState::EXIT
|
2400
2618
|
end
|
@@ -2443,18 +2661,26 @@ module MarkdownExec
|
|
2443
2661
|
#
|
2444
2662
|
if (load_expr = link_block_data.fetch(LinkKeys::LOAD, '')).present?
|
2445
2663
|
load_filespec = load_filespec_from_expression(load_expr)
|
2446
|
-
|
2664
|
+
if load_filespec
|
2665
|
+
code_lines += File.readlines(load_filespec,
|
2666
|
+
chomp: true)
|
2667
|
+
end
|
2447
2668
|
end
|
2448
2669
|
|
2449
2670
|
# if an eval link block, evaluate code_lines and return its standard output
|
2450
2671
|
#
|
2451
2672
|
if link_block_data.fetch(LinkKeys::EVAL,
|
2452
|
-
false) || link_block_data.fetch(LinkKeys::EXEC,
|
2453
|
-
|
2673
|
+
false) || link_block_data.fetch(LinkKeys::EXEC,
|
2674
|
+
false)
|
2675
|
+
code_lines = link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
2676
|
+
block_source: block_source)
|
2454
2677
|
end
|
2455
2678
|
|
2456
|
-
next_document_filename = write_inherited_lines_to_file(link_state,
|
2457
|
-
|
2679
|
+
next_document_filename = write_inherited_lines_to_file(link_state,
|
2680
|
+
link_block_data)
|
2681
|
+
next_block_name = link_block_data.fetch(LinkKeys::NEXT_BLOCK,
|
2682
|
+
nil) || link_block_data.fetch(LinkKeys::BLOCK,
|
2683
|
+
nil) || ''
|
2458
2684
|
|
2459
2685
|
if link_block_data[LinkKeys::RETURN]
|
2460
2686
|
pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
|
@@ -2466,7 +2692,9 @@ module MarkdownExec
|
|
2466
2692
|
curr_document_filename: @delegate_object[:filename],
|
2467
2693
|
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2468
2694
|
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2469
|
-
inherited_lines: HashDelegator.code_merge(
|
2695
|
+
inherited_lines: HashDelegator.code_merge(
|
2696
|
+
link_state&.inherited_lines, code_lines
|
2697
|
+
),
|
2470
2698
|
next_block_name: next_block_name,
|
2471
2699
|
next_document_filename: next_document_filename,
|
2472
2700
|
next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD
|
@@ -2487,14 +2715,29 @@ module MarkdownExec
|
|
2487
2715
|
# @param selected [Hash] Selected item from the menu containing a YAML body.
|
2488
2716
|
# @param tgt2 [Hash, nil] An optional target hash to update with YAML data.
|
2489
2717
|
# @return [LoadFileLinkState] An instance indicating the next action for loading files.
|
2490
|
-
def read_show_options_and_trigger_reuse(selected:,
|
2718
|
+
def read_show_options_and_trigger_reuse(selected:,
|
2719
|
+
mdoc:, link_state: LinkState.new)
|
2491
2720
|
obj = {}
|
2492
|
-
data = YAML.load(selected[:body].join("\n"))
|
2493
|
-
(data || []).each do |key, value|
|
2494
|
-
sym_key = key.to_sym
|
2495
|
-
obj[sym_key] = value
|
2496
2721
|
|
2497
|
-
|
2722
|
+
# concatenated body of all required blocks loaded a YAML
|
2723
|
+
data = YAML.load(
|
2724
|
+
collect_required_code_lines(
|
2725
|
+
mdoc: mdoc, selected: selected,
|
2726
|
+
link_state: link_state, block_source: {}
|
2727
|
+
).join("\n")
|
2728
|
+
).transform_keys(&:to_sym)
|
2729
|
+
|
2730
|
+
if selected.shell == BlockType::OPTS
|
2731
|
+
obj = data
|
2732
|
+
else
|
2733
|
+
(data || []).each do |key, value|
|
2734
|
+
sym_key = key.to_sym
|
2735
|
+
obj[sym_key] = value
|
2736
|
+
|
2737
|
+
if @delegate_object[:menu_opts_set_format].present?
|
2738
|
+
print_formatted_option(key, value)
|
2739
|
+
end
|
2740
|
+
end
|
2498
2741
|
end
|
2499
2742
|
|
2500
2743
|
link_state.block_name = nil
|
@@ -2526,11 +2769,19 @@ module MarkdownExec
|
|
2526
2769
|
resize_terminal
|
2527
2770
|
end
|
2528
2771
|
|
2529
|
-
|
2772
|
+
if resized || !opts[:console_width]
|
2773
|
+
opts[:console_height], opts[:console_width] = opts[:console_winsize] =
|
2774
|
+
IO.console.winsize
|
2775
|
+
end
|
2530
2776
|
|
2531
|
-
|
2777
|
+
unless opts[:select_page_height]&.positive?
|
2778
|
+
opts[:per_page] =
|
2779
|
+
opts[:select_page_height] =
|
2780
|
+
[opts[:console_height] - 3, 4].max
|
2781
|
+
end
|
2532
2782
|
rescue StandardError
|
2533
|
-
HashDelegator.error_handler('register_console_attributes',
|
2783
|
+
HashDelegator.error_handler('register_console_attributes',
|
2784
|
+
{ abort: true })
|
2534
2785
|
end
|
2535
2786
|
|
2536
2787
|
# Check if the delegate object responds to a given method.
|
@@ -2542,7 +2793,8 @@ module MarkdownExec
|
|
2542
2793
|
true
|
2543
2794
|
elsif @delegate_object.respond_to?(method_name, include_private)
|
2544
2795
|
true
|
2545
|
-
elsif method_name.to_s.end_with?('=') && @delegate_object.respond_to?(:[]=,
|
2796
|
+
elsif method_name.to_s.end_with?('=') && @delegate_object.respond_to?(:[]=,
|
2797
|
+
include_private)
|
2546
2798
|
true
|
2547
2799
|
else
|
2548
2800
|
@delegate_object.respond_to?(method_name, include_private)
|
@@ -2593,7 +2845,8 @@ module MarkdownExec
|
|
2593
2845
|
# input into path with wildcard for easy entry
|
2594
2846
|
#
|
2595
2847
|
case (name = prompt_select_code_filename(
|
2596
|
-
[@delegate_object[:prompt_filespec_back],
|
2848
|
+
[@delegate_object[:prompt_filespec_back],
|
2849
|
+
@delegate_object[:prompt_filespec_other]] + files,
|
2597
2850
|
string: @delegate_object[:prompt_select_code_file],
|
2598
2851
|
color_sym: :prompt_color_after_script_execution
|
2599
2852
|
))
|
@@ -2613,37 +2866,46 @@ module MarkdownExec
|
|
2613
2866
|
end
|
2614
2867
|
|
2615
2868
|
# Presents a TTY prompt to select an option or exit, returns metadata including option and selected
|
2616
|
-
def select_option_with_metadata(prompt_text,
|
2869
|
+
def select_option_with_metadata(prompt_text, menu_items, opts = {})
|
2617
2870
|
## configure to environment
|
2618
2871
|
#
|
2619
2872
|
register_console_attributes(opts)
|
2620
2873
|
|
2621
2874
|
# crashes if all menu options are disabled
|
2622
2875
|
selection = @prompt.select(prompt_text,
|
2623
|
-
|
2876
|
+
menu_items,
|
2624
2877
|
opts.merge(filter: true))
|
2625
|
-
|
2878
|
+
|
2879
|
+
selected = menu_items.find do |item|
|
2626
2880
|
if item.instance_of?(Hash)
|
2627
|
-
item[:dname] == selection
|
2881
|
+
(item[:name] || item[:dname]) == selection
|
2882
|
+
elsif item.instance_of?(MarkdownExec::FCB)
|
2883
|
+
item.dname == selection
|
2628
2884
|
else
|
2629
2885
|
item == selection
|
2630
2886
|
end
|
2631
2887
|
end
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2888
|
+
if selected.instance_of?(String)
|
2889
|
+
selected = FCB.new(dname: selected)
|
2890
|
+
elsif selected.instance_of?(Hash)
|
2891
|
+
selected = FCB.new(selected)
|
2892
|
+
end
|
2893
|
+
unless selected
|
2894
|
+
HashDelegator.error_handler('select_option_with_metadata',
|
2895
|
+
error: 'menu item not found')
|
2635
2896
|
exit 1
|
2636
2897
|
end
|
2637
2898
|
|
2638
|
-
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
2899
|
+
if selection == menu_chrome_colored_option(:menu_option_back_name)
|
2900
|
+
selected.option = selection
|
2901
|
+
selected.shell = BlockType::LINK
|
2902
|
+
elsif selection == menu_chrome_colored_option(:menu_option_exit_name)
|
2903
|
+
selected.option = selection
|
2904
|
+
else
|
2905
|
+
selected.selected = selection
|
2906
|
+
end
|
2907
|
+
|
2908
|
+
selected
|
2647
2909
|
rescue TTY::Reader::InputInterrupt
|
2648
2910
|
exit 1
|
2649
2911
|
rescue StandardError
|
@@ -2663,8 +2925,9 @@ module MarkdownExec
|
|
2663
2925
|
block_name_from_cli ? @cli_block_name : link_state.block_name
|
2664
2926
|
end
|
2665
2927
|
|
2666
|
-
def set_delobj_menu_loop_vars(block_name_from_cli:, now_using_cli:,
|
2667
|
-
|
2928
|
+
def set_delobj_menu_loop_vars(block_name_from_cli:, now_using_cli:,
|
2929
|
+
link_state:)
|
2930
|
+
block_name_from_cli, now_using_cli =
|
2668
2931
|
manage_cli_selection_state(block_name_from_cli: block_name_from_cli,
|
2669
2932
|
now_using_cli: now_using_cli,
|
2670
2933
|
link_state: link_state)
|
@@ -2681,7 +2944,7 @@ module MarkdownExec
|
|
2681
2944
|
|
2682
2945
|
def set_environment_variables_for_block(selected)
|
2683
2946
|
code_lines = []
|
2684
|
-
YAML.load(selected
|
2947
|
+
YAML.load(selected.body.join("\n"))&.each do |key, value|
|
2685
2948
|
ENV[key] = value.to_s
|
2686
2949
|
|
2687
2950
|
require 'shellwords'
|
@@ -2696,6 +2959,29 @@ module MarkdownExec
|
|
2696
2959
|
code_lines
|
2697
2960
|
end
|
2698
2961
|
|
2962
|
+
def shell_escape_asset_format(link_state)
|
2963
|
+
raw = @delegate_object[:saved_asset_format]
|
2964
|
+
|
2965
|
+
return raw unless @delegate_object[:shell_parameter_expansion]
|
2966
|
+
|
2967
|
+
# unchanged if no parameter expansion takes place
|
2968
|
+
return raw unless /$/ =~ raw
|
2969
|
+
|
2970
|
+
filespec = generate_temp_filename
|
2971
|
+
cmd = [@delegate_object[:shell], '-c', filespec].join(' ')
|
2972
|
+
|
2973
|
+
marker = Random.new.rand.to_s
|
2974
|
+
|
2975
|
+
code = (link_state&.inherited_lines || []) + ["echo -n \"#{marker}#{raw}\""]
|
2976
|
+
# &bt code
|
2977
|
+
File.write filespec, HashDelegator.join_code_lines(code)
|
2978
|
+
File.chmod 0o755, filespec
|
2979
|
+
|
2980
|
+
out = `#{cmd}`.sub(/.*?#{marker}/m, '')
|
2981
|
+
File.delete filespec
|
2982
|
+
out # &br
|
2983
|
+
end
|
2984
|
+
|
2699
2985
|
def should_add_back_option?
|
2700
2986
|
@delegate_object[:menu_with_back] && @link_history.prior_state_exist?
|
2701
2987
|
end
|
@@ -2818,6 +3104,13 @@ module MarkdownExec
|
|
2818
3104
|
end
|
2819
3105
|
end
|
2820
3106
|
|
3107
|
+
## apply options to current state
|
3108
|
+
#
|
3109
|
+
def update_menu_base(options)
|
3110
|
+
@menu_base_options.merge!(options)
|
3111
|
+
@delegate_object.merge!(options)
|
3112
|
+
end
|
3113
|
+
|
2821
3114
|
def wait_for_stream_processing
|
2822
3115
|
@process_mutex.synchronize do
|
2823
3116
|
@process_cv.wait(@process_mutex)
|
@@ -2839,8 +3132,11 @@ module MarkdownExec
|
|
2839
3132
|
@delegate_object[:prompt_select_block].to_s, :prompt_color_after_script_execution
|
2840
3133
|
)
|
2841
3134
|
|
2842
|
-
|
2843
|
-
|
3135
|
+
menu_items = prepare_blocks_menu(menu_blocks)
|
3136
|
+
if menu_items.empty?
|
3137
|
+
return SelectedBlockMenuState.new(nil, OpenStruct.new,
|
3138
|
+
MenuState::EXIT)
|
3139
|
+
end
|
2844
3140
|
|
2845
3141
|
# default value may not match if color is different from originating menu (opts changed while processing)
|
2846
3142
|
selection_opts = if default && menu_blocks.map(&:dname).include?(default)
|
@@ -2852,7 +3148,7 @@ module MarkdownExec
|
|
2852
3148
|
sph = @delegate_object[:select_page_height]
|
2853
3149
|
selection_opts.merge!(per_page: sph)
|
2854
3150
|
|
2855
|
-
selected_option = select_option_with_metadata(prompt_title,
|
3151
|
+
selected_option = select_option_with_metadata(prompt_title, menu_items,
|
2856
3152
|
selection_opts)
|
2857
3153
|
determine_block_state(selected_option)
|
2858
3154
|
end
|
@@ -2867,7 +3163,7 @@ module MarkdownExec
|
|
2867
3163
|
exts: '.sh',
|
2868
3164
|
filename: @delegate_object[:filename],
|
2869
3165
|
prefix: @delegate_object[:saved_script_filename_prefix],
|
2870
|
-
saved_asset_format: @
|
3166
|
+
saved_asset_format: shell_escape_asset_format(@dml_link_state),
|
2871
3167
|
time: time_now).generate_name
|
2872
3168
|
@run_state.saved_filespec =
|
2873
3169
|
File.join(@delegate_object[:saved_script_folder],
|
@@ -2918,7 +3214,8 @@ module MarkdownExec
|
|
2918
3214
|
save_expr = link_block_data.fetch(LinkKeys::SAVE, '')
|
2919
3215
|
if save_expr.present?
|
2920
3216
|
save_filespec = save_filespec_from_expression(save_expr)
|
2921
|
-
File.write(save_filespec,
|
3217
|
+
File.write(save_filespec,
|
3218
|
+
HashDelegator.join_code_lines(link_state&.inherited_lines))
|
2922
3219
|
@delegate_object[:filename]
|
2923
3220
|
else
|
2924
3221
|
link_block_data[LinkKeys::FILE] || @delegate_object[:filename]
|
@@ -2950,7 +3247,11 @@ module MarkdownExec
|
|
2950
3247
|
obj[key] = cleaned_value if value.is_a?(Hash) || value.is_a?(Struct)
|
2951
3248
|
end
|
2952
3249
|
|
2953
|
-
|
3250
|
+
if obj.is_a?(Hash)
|
3251
|
+
obj.reject! do |_key, value|
|
3252
|
+
[nil, '', [], {}, nil].include?(value)
|
3253
|
+
end
|
3254
|
+
end
|
2954
3255
|
|
2955
3256
|
obj
|
2956
3257
|
end
|
@@ -3014,7 +3315,8 @@ module MarkdownExec
|
|
3014
3315
|
|
3015
3316
|
# Test case for empty body
|
3016
3317
|
def test_next_link_state
|
3017
|
-
@hd.next_link_state(block_name_from_cli: nil, was_using_cli: nil, block_state: nil,
|
3318
|
+
@hd.next_link_state(block_name_from_cli: nil, was_using_cli: nil, block_state: nil,
|
3319
|
+
block_name: nil)
|
3018
3320
|
end
|
3019
3321
|
end
|
3020
3322
|
|
@@ -3061,15 +3363,18 @@ module MarkdownExec
|
|
3061
3363
|
# Test case for non-empty body with 'file' key
|
3062
3364
|
def test_push_link_history_and_trigger_load_with_file_key
|
3063
3365
|
body = ["file: sample_file\nblock: sample_block\nvars:\n KEY: VALUE"]
|
3064
|
-
expected_result = LoadFileLinkState.new(
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3366
|
+
expected_result = LoadFileLinkState.new(
|
3367
|
+
LoadFile::LOAD,
|
3368
|
+
LinkState.new(block_name: 'sample_block',
|
3369
|
+
document_filename: 'sample_file',
|
3370
|
+
inherited_dependencies: {},
|
3371
|
+
inherited_lines: ['# ', 'KEY="VALUE"'])
|
3372
|
+
)
|
3069
3373
|
assert_equal expected_result,
|
3070
3374
|
@hd.push_link_history_and_trigger_load(
|
3071
3375
|
link_block_body: body,
|
3072
|
-
selected: FCB.new(block_name: 'sample_block',
|
3376
|
+
selected: FCB.new(block_name: 'sample_block',
|
3377
|
+
filename: 'sample_file')
|
3073
3378
|
)
|
3074
3379
|
end
|
3075
3380
|
|
@@ -3178,20 +3483,20 @@ module MarkdownExec
|
|
3178
3483
|
end
|
3179
3484
|
|
3180
3485
|
def test_block_find_with_match
|
3181
|
-
blocks = [
|
3182
|
-
result = HashDelegator.block_find(blocks, :
|
3183
|
-
assert_equal(
|
3486
|
+
blocks = [FCB.new(text: 'value1'), FCB.new(text: 'value2')]
|
3487
|
+
result = HashDelegator.block_find(blocks, :text, 'value1')
|
3488
|
+
assert_equal('value1', result.text)
|
3184
3489
|
end
|
3185
3490
|
|
3186
3491
|
def test_block_find_without_match
|
3187
|
-
blocks = [
|
3188
|
-
result = HashDelegator.block_find(blocks, :
|
3492
|
+
blocks = [FCB.new(text: 'value1'), FCB.new(text: 'value2')]
|
3493
|
+
result = HashDelegator.block_find(blocks, :text, 'missing_value')
|
3189
3494
|
assert_nil result
|
3190
3495
|
end
|
3191
3496
|
|
3192
3497
|
def test_block_find_with_default
|
3193
|
-
blocks = [
|
3194
|
-
result = HashDelegator.block_find(blocks, :
|
3498
|
+
blocks = [FCB.new(text: 'value1'), FCB.new(text: 'value2')]
|
3499
|
+
result = HashDelegator.block_find(blocks, :text, 'missing_value', 'default')
|
3195
3500
|
assert_equal 'default', result
|
3196
3501
|
end
|
3197
3502
|
end
|
@@ -3227,7 +3532,7 @@ module MarkdownExec
|
|
3227
3532
|
@hd = HashDelegator.new
|
3228
3533
|
@hd.instance_variable_set(:@delegate_object, {})
|
3229
3534
|
@mdoc = mock('YourMDocClass')
|
3230
|
-
@selected =
|
3535
|
+
@selected = FCB.new(shell: BlockType::VARS, body: ['key: value'])
|
3231
3536
|
HashDelegator.stubs(:read_required_blocks_from_temp_file).returns([])
|
3232
3537
|
@hd.stubs(:string_send_color)
|
3233
3538
|
@hd.stubs(:print)
|
@@ -3236,7 +3541,8 @@ module MarkdownExec
|
|
3236
3541
|
def test_collect_required_code_lines_with_vars
|
3237
3542
|
YAML.stubs(:load).returns({ 'key' => 'value' })
|
3238
3543
|
@mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
|
3239
|
-
result = @hd.collect_required_code_lines(mdoc: @mdoc, selected: @selected,
|
3544
|
+
result = @hd.collect_required_code_lines(mdoc: @mdoc, selected: @selected,
|
3545
|
+
block_source: {})
|
3240
3546
|
|
3241
3547
|
assert_equal ['code line', 'key="value"'], result
|
3242
3548
|
end
|
@@ -3257,18 +3563,24 @@ module MarkdownExec
|
|
3257
3563
|
|
3258
3564
|
result = @hd.load_cli_or_user_selected_block(all_blocks: all_blocks)
|
3259
3565
|
|
3260
|
-
assert_equal all_blocks.first
|
3566
|
+
assert_equal all_blocks.first,
|
3567
|
+
result.block
|
3568
|
+
assert_equal OpenStruct.new(block_name_from_ui: false),
|
3569
|
+
result.source
|
3261
3570
|
assert_nil result.state
|
3262
3571
|
end
|
3263
3572
|
|
3264
3573
|
def test_user_selected_block
|
3265
|
-
block_state = SelectedBlockMenuState.new({ oname: 'block2' },
|
3574
|
+
block_state = SelectedBlockMenuState.new({ oname: 'block2' }, OpenStruct.new,
|
3266
3575
|
:some_state)
|
3267
3576
|
@hd.stubs(:wait_for_user_selected_block).returns(block_state)
|
3268
3577
|
|
3269
3578
|
result = @hd.load_cli_or_user_selected_block
|
3270
3579
|
|
3271
|
-
assert_equal block_state.block
|
3580
|
+
assert_equal block_state.block,
|
3581
|
+
result.block
|
3582
|
+
assert_equal OpenStruct.new(block_name_from_ui: true),
|
3583
|
+
result.source
|
3272
3584
|
assert_equal :some_state, result.state
|
3273
3585
|
end
|
3274
3586
|
end
|
@@ -3351,7 +3663,7 @@ module MarkdownExec
|
|
3351
3663
|
end
|
3352
3664
|
|
3353
3665
|
def test_determine_block_state_exit
|
3354
|
-
selected_option =
|
3666
|
+
selected_option = FCB.new(oname: 'Formatted Option')
|
3355
3667
|
@hd.stubs(:menu_chrome_formatted_option).with(:menu_option_exit_name).returns('Formatted Option')
|
3356
3668
|
|
3357
3669
|
result = @hd.determine_block_state(selected_option)
|
@@ -3361,7 +3673,7 @@ module MarkdownExec
|
|
3361
3673
|
end
|
3362
3674
|
|
3363
3675
|
def test_determine_block_state_back
|
3364
|
-
selected_option =
|
3676
|
+
selected_option = FCB.new(oname: 'Formatted Back Option')
|
3365
3677
|
@hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('Formatted Back Option')
|
3366
3678
|
result = @hd.determine_block_state(selected_option)
|
3367
3679
|
|
@@ -3370,7 +3682,7 @@ module MarkdownExec
|
|
3370
3682
|
end
|
3371
3683
|
|
3372
3684
|
def test_determine_block_state_continue
|
3373
|
-
selected_option =
|
3685
|
+
selected_option = FCB.new(oname: 'Other Option')
|
3374
3686
|
|
3375
3687
|
result = @hd.determine_block_state(selected_option)
|
3376
3688
|
|
@@ -3480,7 +3792,8 @@ module MarkdownExec
|
|
3480
3792
|
def test_format_execution_stream_with_empty_key
|
3481
3793
|
@hd.instance_variable_get(:@run_state).stubs(:files).returns({})
|
3482
3794
|
|
3483
|
-
result = HashDelegator.format_execution_stream(nil,
|
3795
|
+
result = HashDelegator.format_execution_stream(nil,
|
3796
|
+
ExecutionStreams::STD_ERR)
|
3484
3797
|
|
3485
3798
|
assert_equal '', result
|
3486
3799
|
end
|
@@ -3639,7 +3952,8 @@ module MarkdownExec
|
|
3639
3952
|
end
|
3640
3953
|
|
3641
3954
|
def test_iter_blocks_from_nested_files
|
3642
|
-
@hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'],
|
3955
|
+
@hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'],
|
3956
|
+
import_paths: nil)
|
3643
3957
|
selected_messages = ['filtered message']
|
3644
3958
|
|
3645
3959
|
result = @hd.iter_blocks_from_nested_files { selected_messages }
|
@@ -3745,7 +4059,8 @@ module MarkdownExec
|
|
3745
4059
|
|
3746
4060
|
def test_yield_line_if_selected_with_line
|
3747
4061
|
block_called = false
|
3748
|
-
HashDelegator.yield_line_if_selected('Test line',
|
4062
|
+
HashDelegator.yield_line_if_selected('Test line',
|
4063
|
+
[:line]) do |type, content|
|
3749
4064
|
block_called = true
|
3750
4065
|
assert_equal :line, type
|
3751
4066
|
assert_equal 'Test line', content.body[0]
|
@@ -3780,15 +4095,18 @@ module MarkdownExec
|
|
3780
4095
|
def test_update_menu_attrib_yield_selected_with_body
|
3781
4096
|
HashDelegator.expects(:initialize_fcb_names).with(@fcb)
|
3782
4097
|
HashDelegator.expects(:default_block_title_from_body).with(@fcb)
|
3783
|
-
Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message],
|
4098
|
+
Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message],
|
4099
|
+
{})
|
3784
4100
|
|
3785
|
-
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4101
|
+
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4102
|
+
messages: [:some_message])
|
3786
4103
|
end
|
3787
4104
|
|
3788
4105
|
def test_update_menu_attrib_yield_selected_without_body
|
3789
4106
|
@fcb.stubs(:body).returns(nil)
|
3790
4107
|
HashDelegator.expects(:initialize_fcb_names).with(@fcb)
|
3791
|
-
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4108
|
+
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4109
|
+
messages: [:some_message])
|
3792
4110
|
end
|
3793
4111
|
end
|
3794
4112
|
|
@@ -3864,28 +4182,35 @@ module MarkdownExec
|
|
3864
4182
|
def test_absolute_path_returns_unchanged
|
3865
4183
|
absolute_path = '/usr/local/bin'
|
3866
4184
|
expression = 'path/to/*/directory'
|
3867
|
-
assert_equal absolute_path,
|
4185
|
+
assert_equal absolute_path,
|
4186
|
+
PathUtils.resolve_path_or_substitute(absolute_path,
|
4187
|
+
expression)
|
3868
4188
|
end
|
3869
4189
|
|
3870
4190
|
def test_relative_path_gets_substituted
|
3871
4191
|
relative_path = 'my_folder'
|
3872
4192
|
expression = 'path/to/*/directory'
|
3873
4193
|
expected_output = 'path/to/my_folder/directory'
|
3874
|
-
assert_equal expected_output,
|
4194
|
+
assert_equal expected_output,
|
4195
|
+
PathUtils.resolve_path_or_substitute(relative_path,
|
4196
|
+
expression)
|
3875
4197
|
end
|
3876
4198
|
|
3877
4199
|
def test_path_with_no_slash_substitutes_correctly
|
3878
4200
|
relative_path = 'data'
|
3879
4201
|
expression = 'path/to/*/directory'
|
3880
4202
|
expected_output = 'path/to/data/directory'
|
3881
|
-
assert_equal expected_output,
|
4203
|
+
assert_equal expected_output,
|
4204
|
+
PathUtils.resolve_path_or_substitute(relative_path,
|
4205
|
+
expression)
|
3882
4206
|
end
|
3883
4207
|
|
3884
4208
|
def test_empty_path_substitution
|
3885
4209
|
empty_path = ''
|
3886
4210
|
expression = 'path/to/*/directory'
|
3887
4211
|
expected_output = 'path/to//directory'
|
3888
|
-
assert_equal expected_output,
|
4212
|
+
assert_equal expected_output,
|
4213
|
+
PathUtils.resolve_path_or_substitute(empty_path, expression)
|
3889
4214
|
end
|
3890
4215
|
|
3891
4216
|
# Test formatting a string containing UTF-8 characters
|
@@ -3934,7 +4259,8 @@ module MarkdownExec
|
|
3934
4259
|
private
|
3935
4260
|
|
3936
4261
|
def prompt_for_filespec_with_wildcard(filespec)
|
3937
|
-
puts format(@delegate_object[:prompt_show_expr_format],
|
4262
|
+
puts format(@delegate_object[:prompt_show_expr_format],
|
4263
|
+
{ expr: filespec })
|
3938
4264
|
puts @delegate_object[:prompt_enter_filespec]
|
3939
4265
|
|
3940
4266
|
begin
|