markdown_exec 2.1.0 → 2.2.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 +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
|