markdown_exec 2.1.0 → 2.3.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 +5 -1
- data/CHANGELOG.md +23 -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 +62 -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/colorize.rb +13 -0
- data/lib/constants.rb +1 -1
- data/lib/fcb.rb +202 -16
- data/lib/filter.rb +12 -12
- data/lib/hash_delegator.rb +695 -326
- data/lib/hierarchy_string.rb +133 -0
- data/lib/input_sequencer.rb +4 -2
- data/lib/link_history.rb +34 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +67 -79
- data/lib/mdoc.rb +122 -60
- data/lib/menu.src.yml +71 -21
- data/lib/menu.yml +59 -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
- data/lib/text_analyzer.rb +100 -0
- metadata +16 -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
@@ -29,13 +29,18 @@ require_relative 'fcb'
|
|
29
29
|
require_relative 'filter'
|
30
30
|
require_relative 'fout'
|
31
31
|
require_relative 'hash'
|
32
|
+
require_relative 'hierarchy_string'
|
32
33
|
require_relative 'link_history'
|
33
34
|
require_relative 'mdoc'
|
35
|
+
require_relative 'namer'
|
34
36
|
require_relative 'regexp'
|
35
37
|
require_relative 'resize_terminal'
|
36
38
|
require_relative 'std_out_err_logger'
|
37
39
|
require_relative 'streams_out'
|
38
40
|
require_relative 'string_util'
|
41
|
+
require_relative 'text_analyzer'
|
42
|
+
|
43
|
+
$pd = false unless defined?($pd)
|
39
44
|
|
40
45
|
class String
|
41
46
|
# Checks if the string is not empty.
|
@@ -54,7 +59,8 @@ module HashDelegatorSelf
|
|
54
59
|
# @param color_key [String, Symbol] The key representing the desired color method in the color_methods hash.
|
55
60
|
# @param default_method [String] (optional) Default color method to use if color_key is not found in color_methods. Defaults to 'plain'.
|
56
61
|
# @return [String] The colored string.
|
57
|
-
def apply_color_from_hash(string, color_methods, color_key,
|
62
|
+
def apply_color_from_hash(string, color_methods, color_key,
|
63
|
+
default_method: 'plain')
|
58
64
|
color_method = color_methods.fetch(color_key, default_method).to_sym
|
59
65
|
string.to_s.send(color_method)
|
60
66
|
end
|
@@ -78,17 +84,17 @@ module HashDelegatorSelf
|
|
78
84
|
# colored_string = apply_color_from_hash(string, color_transformations, :red)
|
79
85
|
# puts colored_string # This will print the string in red
|
80
86
|
|
81
|
-
# Searches for the first element in a collection where the specified
|
87
|
+
# Searches for the first element in a collection where the specified message sent to an element matches a given value.
|
82
88
|
# This method is particularly useful for finding a specific hash-like object within an enumerable collection.
|
83
89
|
# If no match is found, it returns a specified default value.
|
84
90
|
#
|
85
91
|
# @param blocks [Enumerable] The collection of hash-like objects to search.
|
86
|
-
# @param
|
87
|
-
# @param value [Object] The value to match against
|
92
|
+
# @param msg [Symbol, String] The message to send to each element of the collection.
|
93
|
+
# @param value [Object] The value to match against the result of the message sent to each element.
|
88
94
|
# @param default [Object, nil] The default value to return if no match is found (optional).
|
89
95
|
# @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
|
96
|
+
def block_find(blocks, msg, value, default = nil)
|
97
|
+
blocks.find { |item| item.send(msg) == value } || default
|
92
98
|
end
|
93
99
|
|
94
100
|
def code_merge(*bodies)
|
@@ -132,8 +138,10 @@ module HashDelegatorSelf
|
|
132
138
|
# delete the current line if it is empty and the previous is also empty
|
133
139
|
def delete_consecutive_blank_lines!(blocks_menu)
|
134
140
|
blocks_menu.process_and_conditionally_delete! do |prev_item, current_item, _next_item|
|
135
|
-
prev_item&.fetch(:chrome, nil) &&
|
136
|
-
|
141
|
+
prev_item&.fetch(:chrome, nil) &&
|
142
|
+
!(prev_item && prev_item.oname.present?) &&
|
143
|
+
current_item&.fetch(:chrome, nil) &&
|
144
|
+
!(current_item && current_item.oname.present?)
|
137
145
|
end
|
138
146
|
end
|
139
147
|
|
@@ -188,13 +196,14 @@ module HashDelegatorSelf
|
|
188
196
|
merged.empty? ? [] : merged
|
189
197
|
end
|
190
198
|
|
191
|
-
def next_link_state(block_name_from_cli:, was_using_cli:, block_state:,
|
199
|
+
def next_link_state(block_name_from_cli:, was_using_cli:, block_state:,
|
200
|
+
block_name: nil)
|
192
201
|
# Set block_name based on block_name_from_cli
|
193
202
|
block_name = @cli_block_name if block_name_from_cli
|
194
203
|
|
195
204
|
# 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.
|
205
|
+
# 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.
|
206
|
+
breaker = !block_name && !block_name_from_cli && was_using_cli && block_state.block.shell == BlockType::BASH
|
198
207
|
|
199
208
|
# Reset block_name_from_cli if the conditions are not met
|
200
209
|
block_name_from_cli ||= false
|
@@ -282,7 +291,8 @@ module HashDelegatorSelf
|
|
282
291
|
# @param fcb [Object] The fcb object whose attributes are to be updated.
|
283
292
|
# @param selected_messages [Array<Symbol>] A list of message types to determine if yielding is applicable.
|
284
293
|
# @param block [Block] An optional block to yield to if conditions are met.
|
285
|
-
def update_menu_attrib_yield_selected(fcb:, messages:, configuration: {},
|
294
|
+
def update_menu_attrib_yield_selected(fcb:, messages:, configuration: {},
|
295
|
+
&block)
|
286
296
|
initialize_fcb_names(fcb)
|
287
297
|
return unless fcb.body
|
288
298
|
|
@@ -429,7 +439,9 @@ class StringWrapper
|
|
429
439
|
words.each.with_index do |word, index|
|
430
440
|
trial_length = word.length
|
431
441
|
trial_length += @first_indent.length if index.zero?
|
432
|
-
|
442
|
+
if index != 0
|
443
|
+
trial_length += current_line.length + 1 + @rest_indent.length
|
444
|
+
end
|
433
445
|
if trial_length > max_line_length && (words.count != 0)
|
434
446
|
lines << current_line
|
435
447
|
current_line = word
|
@@ -472,6 +484,7 @@ module MarkdownExec
|
|
472
484
|
|
473
485
|
extend HashDelegatorSelf
|
474
486
|
include CompactionHelpers
|
487
|
+
include TextAnalyzer
|
475
488
|
|
476
489
|
def initialize(delegate_object = {})
|
477
490
|
@delegate_object = delegate_object
|
@@ -480,7 +493,8 @@ module MarkdownExec
|
|
480
493
|
@most_recent_loaded_filename = nil
|
481
494
|
@pass_args = []
|
482
495
|
@run_state = OpenStruct.new(
|
483
|
-
link_history: []
|
496
|
+
link_history: [],
|
497
|
+
source: OpenStruct.new
|
484
498
|
)
|
485
499
|
@link_history = LinkHistory.new
|
486
500
|
@fout = FOut.new(@delegate_object) ### slice only relevant keys
|
@@ -506,13 +520,18 @@ module MarkdownExec
|
|
506
520
|
def add_menu_chrome_blocks!(menu_blocks:, link_state:)
|
507
521
|
return unless @delegate_object[:menu_link_format].present?
|
508
522
|
|
509
|
-
|
523
|
+
if @delegate_object[:menu_with_inherited_lines]
|
524
|
+
add_inherited_lines(menu_blocks: menu_blocks,
|
525
|
+
link_state: link_state)
|
526
|
+
end
|
510
527
|
|
511
528
|
# back before exit
|
512
529
|
add_back_option(menu_blocks: menu_blocks) if should_add_back_option?
|
513
530
|
|
514
531
|
# exit after other options
|
515
|
-
|
532
|
+
if @delegate_object[:menu_with_exit]
|
533
|
+
add_exit_option(menu_blocks: menu_blocks)
|
534
|
+
end
|
516
535
|
|
517
536
|
add_dividers(menu_blocks: menu_blocks)
|
518
537
|
end
|
@@ -588,6 +607,20 @@ module MarkdownExec
|
|
588
607
|
else
|
589
608
|
menu_blocks.push(chrome_block)
|
590
609
|
end
|
610
|
+
|
611
|
+
chrome_block
|
612
|
+
end
|
613
|
+
|
614
|
+
# Appends a formatted divider to the specified position in a menu block array.
|
615
|
+
# The method checks for the presence of formatting options before appending.
|
616
|
+
#
|
617
|
+
# @param menu_blocks [Array] The array of menu block elements.
|
618
|
+
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
619
|
+
def append_divider(menu_blocks:, position:)
|
620
|
+
return unless divider_formatting_present?(position)
|
621
|
+
|
622
|
+
divider = create_divider(position)
|
623
|
+
position == :initial ? menu_blocks.unshift(divider) : menu_blocks.push(divider)
|
591
624
|
end
|
592
625
|
|
593
626
|
# Appends a formatted divider to the specified position in a menu block array.
|
@@ -596,10 +629,10 @@ module MarkdownExec
|
|
596
629
|
# @param menu_blocks [Array] The array of menu block elements.
|
597
630
|
# @param position [Symbol] The position to insert the divider (:initial or :final).
|
598
631
|
def append_inherited_lines(menu_blocks:, link_state:, position: top)
|
599
|
-
return unless link_state.
|
632
|
+
return unless link_state.inherited_lines_present?
|
600
633
|
|
601
634
|
insert_at_top = @delegate_object[:menu_inherited_lines_at_top]
|
602
|
-
chrome_blocks = link_state.
|
635
|
+
chrome_blocks = link_state.inherited_lines_map do |line|
|
603
636
|
formatted = format(@delegate_object[:menu_inherited_lines_format],
|
604
637
|
{ line: line })
|
605
638
|
FCB.new(
|
@@ -623,18 +656,6 @@ module MarkdownExec
|
|
623
656
|
HashDelegator.error_handler('append_inherited_lines')
|
624
657
|
end
|
625
658
|
|
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
659
|
# private
|
639
660
|
|
640
661
|
# Applies shell color options to the given string if applicable.
|
@@ -650,6 +671,16 @@ module MarkdownExec
|
|
650
671
|
end
|
651
672
|
end
|
652
673
|
|
674
|
+
def apply_tree_decorations(text, color_method, decor_patterns)
|
675
|
+
tree = HierarchyString.new([{ text: text, color: color_method }])
|
676
|
+
decor_patterns.each do |pc|
|
677
|
+
analyzed_hierarchy = TextAnalyzer.analyze_hierarchy(tree.substrings, pc[:pattern],
|
678
|
+
color_method, pc[:color_method])
|
679
|
+
tree = HierarchyString.new(analyzed_hierarchy)
|
680
|
+
end
|
681
|
+
tree.decorate
|
682
|
+
end
|
683
|
+
|
653
684
|
def assign_key_value_in_bash(key, value)
|
654
685
|
if value =~ /["$\\`]/
|
655
686
|
# requiring ShellWords to write into Bash scripts
|
@@ -667,12 +698,13 @@ module MarkdownExec
|
|
667
698
|
# @return [Array<FCB>] An array of FCB objects representing the blocks.
|
668
699
|
def blocks_from_nested_files
|
669
700
|
register_console_attributes(@delegate_object)
|
701
|
+
@decor_patterns_from_delegate_object_for_block_create = collect_line_decor_patterns(@delegate_object)
|
670
702
|
|
671
703
|
blocks = []
|
672
704
|
iter_blocks_from_nested_files do |btype, fcb|
|
673
705
|
process_block_based_on_type(blocks, btype, fcb)
|
674
706
|
end
|
675
|
-
# &
|
707
|
+
# &bt blocks.count
|
676
708
|
blocks
|
677
709
|
rescue StandardError
|
678
710
|
HashDelegator.error_handler('blocks_from_nested_files')
|
@@ -682,9 +714,8 @@ module MarkdownExec
|
|
682
714
|
# if matched, the block returned has properties that it is from cli and not ui
|
683
715
|
def block_state_for_name_from_cli(block_name)
|
684
716
|
SelectedBlockMenuState.new(
|
685
|
-
@dml_blocks_in_file
|
686
|
-
|
687
|
-
end&.merge(
|
717
|
+
blocks_find_by_block_name(@dml_blocks_in_file, block_name),
|
718
|
+
OpenStruct.new(
|
688
719
|
block_name_from_cli: true,
|
689
720
|
block_name_from_ui: false
|
690
721
|
),
|
@@ -692,18 +723,28 @@ module MarkdownExec
|
|
692
723
|
)
|
693
724
|
end
|
694
725
|
|
726
|
+
def blocks_find_by_block_name(blocks, block_name)
|
727
|
+
@dml_blocks_in_file.find do |item|
|
728
|
+
# 2024-08-04 match oname for long block names
|
729
|
+
# 2024-08-04 match nickname for long block names
|
730
|
+
block_name == item.pub_name || block_name == item.nickname || block_name == item.oname
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
695
734
|
# private
|
696
735
|
|
697
736
|
def calc_logged_stdout_filename(block_name:)
|
698
737
|
return unless @delegate_object[:saved_stdout_folder]
|
699
738
|
|
700
739
|
@delegate_object[:logged_stdout_filename] =
|
701
|
-
SavedAsset.new(
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
740
|
+
SavedAsset.new(
|
741
|
+
blockname: block_name,
|
742
|
+
filename: @delegate_object[:filename],
|
743
|
+
prefix: @delegate_object[:logged_stdout_filename_prefix],
|
744
|
+
time: Time.now.utc,
|
745
|
+
exts: '.out.txt',
|
746
|
+
saved_asset_format: shell_escape_asset_format(@dml_link_state)
|
747
|
+
).generate_name
|
707
748
|
|
708
749
|
@logged_stdout_filespec =
|
709
750
|
@delegate_object[:logged_stdout_filespec] =
|
@@ -731,19 +772,37 @@ module MarkdownExec
|
|
731
772
|
true
|
732
773
|
end
|
733
774
|
|
775
|
+
def collect_line_decor_patterns(delegate_object)
|
776
|
+
extract_patterns = lambda do |key|
|
777
|
+
return [] unless delegate_object[key].present?
|
778
|
+
|
779
|
+
HashDelegator.safeval(delegate_object[key]).map do |pc|
|
780
|
+
{
|
781
|
+
color_method: pc[:color_method].to_sym,
|
782
|
+
pattern: Regexp.new(pc[:pattern])
|
783
|
+
}
|
784
|
+
end
|
785
|
+
end
|
786
|
+
|
787
|
+
%i[line_decor_pre line_decor_main line_decor_post].flat_map do |key|
|
788
|
+
extract_patterns.call(key)
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
734
792
|
# Collects required code lines based on the selected block and the delegate object's configuration.
|
735
793
|
# If the block type is VARS, it also sets environment variables based on the block's content.
|
736
794
|
#
|
737
795
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
738
796
|
# @param selected [Hash] The selected block.
|
739
797
|
# @return [Array<String>] Required code blocks as an array of lines.
|
740
|
-
def collect_required_code_lines(mdoc:, selected:, block_source:,
|
798
|
+
def collect_required_code_lines(mdoc:, selected:, block_source:,
|
799
|
+
link_state: LinkState.new)
|
741
800
|
required = mdoc.collect_recursively_required_code(
|
742
801
|
anyname: selected.pub_name,
|
743
802
|
label_format_above: @delegate_object[:shell_code_label_format_above],
|
744
803
|
label_format_below: @delegate_object[:shell_code_label_format_below],
|
745
804
|
block_source: block_source
|
746
|
-
)
|
805
|
+
) # &bt 'required'
|
747
806
|
dependencies = (link_state&.inherited_dependencies || {}).merge(required[:dependencies] || {})
|
748
807
|
required[:unmet_dependencies] =
|
749
808
|
(required[:unmet_dependencies] || []) - (link_state&.inherited_block_names || [])
|
@@ -755,14 +814,19 @@ module MarkdownExec
|
|
755
814
|
runtime_exception(:runtime_exception_error_level,
|
756
815
|
'unmet_dependencies, flag: runtime_exception_error_level',
|
757
816
|
required[:unmet_dependencies])
|
758
|
-
|
817
|
+
elsif false ### use option 2024-08-02
|
759
818
|
warn format_and_highlight_dependencies(dependencies,
|
760
819
|
highlight: [@delegate_object[:block_name]])
|
761
820
|
end
|
762
821
|
|
763
|
-
|
764
|
-
|
765
|
-
|
822
|
+
if selected[:shell] == BlockType::OPTS
|
823
|
+
# body of blocks is returned as a list of lines to be read an YAML
|
824
|
+
HashDelegator.code_merge(required[:blocks].map(&:body).flatten(1))
|
825
|
+
else
|
826
|
+
code_lines = selected.shell == BlockType::VARS ? set_environment_variables_for_block(selected) : []
|
827
|
+
HashDelegator.code_merge(link_state&.inherited_lines,
|
828
|
+
required[:code] + code_lines)
|
829
|
+
end
|
766
830
|
end
|
767
831
|
|
768
832
|
def command_execute(command, args: [])
|
@@ -783,7 +847,8 @@ module MarkdownExec
|
|
783
847
|
else
|
784
848
|
@run_state.in_own_window = false
|
785
849
|
execute_command_with_streams(
|
786
|
-
[@delegate_object[:shell], '-c', command,
|
850
|
+
[@delegate_object[:shell], '-c', command,
|
851
|
+
@delegate_object[:filename], *args]
|
787
852
|
)
|
788
853
|
end
|
789
854
|
|
@@ -793,14 +858,16 @@ module MarkdownExec
|
|
793
858
|
@run_state.aborted_at = Time.now.utc
|
794
859
|
@run_state.error_message = err.message
|
795
860
|
@run_state.error = err
|
796
|
-
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
861
|
+
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
862
|
+
@run_state.error_message)
|
797
863
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
798
864
|
rescue SignalException => err
|
799
865
|
# Handle SignalException
|
800
866
|
@run_state.aborted_at = Time.now.utc
|
801
867
|
@run_state.error_message = 'SIGTERM'
|
802
868
|
@run_state.error = err
|
803
|
-
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
869
|
+
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR,
|
870
|
+
@run_state.error_message)
|
804
871
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
805
872
|
end
|
806
873
|
|
@@ -830,18 +897,25 @@ module MarkdownExec
|
|
830
897
|
# @param mdoc [Object] The markdown document object containing code blocks.
|
831
898
|
# @param selected [Hash] The selected item from the menu to be executed.
|
832
899
|
# @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:,
|
900
|
+
def compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:,
|
901
|
+
link_state: nil)
|
834
902
|
required_lines = collect_required_code_lines(mdoc: mdoc, selected: selected, link_state: link_state,
|
835
903
|
block_source: block_source)
|
836
904
|
output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
|
837
|
-
|
905
|
+
if output_or_approval
|
906
|
+
display_required_code(required_lines: required_lines)
|
907
|
+
end
|
838
908
|
allow_execution = if @delegate_object[:user_must_approve]
|
839
|
-
prompt_for_user_approval(required_lines: required_lines,
|
909
|
+
prompt_for_user_approval(required_lines: required_lines,
|
910
|
+
selected: selected)
|
840
911
|
else
|
841
912
|
true
|
842
913
|
end
|
843
914
|
|
844
|
-
|
915
|
+
if allow_execution
|
916
|
+
execute_required_lines(required_lines: required_lines,
|
917
|
+
selected: selected)
|
918
|
+
end
|
845
919
|
|
846
920
|
link_state.block_name = nil
|
847
921
|
LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
@@ -883,6 +957,7 @@ module MarkdownExec
|
|
883
957
|
format_option:, color_method:,
|
884
958
|
case_conversion: nil,
|
885
959
|
center: nil,
|
960
|
+
decor_patterns: [],
|
886
961
|
wrap: nil)
|
887
962
|
line_cap = match_data.named_captures.transform_keys(&:to_sym)
|
888
963
|
|
@@ -933,11 +1008,14 @@ module MarkdownExec
|
|
933
1008
|
# format expects :line to be text only
|
934
1009
|
line_obj[:line] = line_obj[:text]
|
935
1010
|
oname = format(format_option, line_obj)
|
1011
|
+
|
1012
|
+
decorated = apply_tree_decorations(oname, color_method, decor_patterns)
|
1013
|
+
|
936
1014
|
line_obj[:line] = line_obj[:indent] + line_obj[:text]
|
937
1015
|
blocks.push FCB.new(
|
938
1016
|
chrome: true,
|
939
1017
|
disabled: '',
|
940
|
-
dname: line_obj[:indent] +
|
1018
|
+
dname: line_obj[:indent] + decorated,
|
941
1019
|
oname: line_obj[:text]
|
942
1020
|
)
|
943
1021
|
end
|
@@ -951,6 +1029,7 @@ module MarkdownExec
|
|
951
1029
|
# @param opts [Hash] Options containing configuration for line processing.
|
952
1030
|
# @param use_chrome [Boolean] Indicates if the chrome styling should be applied.
|
953
1031
|
def create_and_add_chrome_blocks(blocks, fcb)
|
1032
|
+
# rubocop:disable Layout/LineLength
|
954
1033
|
match_criteria = [
|
955
1034
|
{ color: :menu_heading1_color, format: :menu_heading1_format, match: :heading1_match, center: true, case_conversion: :upcase, wrap: true },
|
956
1035
|
{ color: :menu_heading2_color, format: :menu_heading2_format, match: :heading2_match, center: true, wrap: true },
|
@@ -959,6 +1038,7 @@ module MarkdownExec
|
|
959
1038
|
{ color: :menu_note_color, format: :menu_note_format, match: :menu_note_match, wrap: true },
|
960
1039
|
{ color: :menu_task_color, format: :menu_task_format, match: :menu_task_match, wrap: true }
|
961
1040
|
]
|
1041
|
+
# rubocop:enable Layout/LineLength
|
962
1042
|
# rubocop:enable Style/UnlessElse
|
963
1043
|
match_criteria.each do |criteria|
|
964
1044
|
unless @delegate_object[criteria[:match]].present? &&
|
@@ -971,6 +1051,7 @@ module MarkdownExec
|
|
971
1051
|
case_conversion: criteria[:case_conversion],
|
972
1052
|
center: criteria[:center],
|
973
1053
|
color_method: @delegate_object[criteria[:color]].to_sym,
|
1054
|
+
decor_patterns: @decor_patterns_from_delegate_object_for_block_create,
|
974
1055
|
format_option: @delegate_object[criteria[:format]],
|
975
1056
|
match_data: mbody,
|
976
1057
|
wrap: criteria[:wrap]
|
@@ -999,10 +1080,12 @@ module MarkdownExec
|
|
999
1080
|
return true unless @delegate_object[:debounce_execution]
|
1000
1081
|
|
1001
1082
|
# filter block if selected in menu
|
1002
|
-
return true if @run_state.block_name_from_cli
|
1083
|
+
return true if @run_state.source.block_name_from_cli
|
1003
1084
|
|
1004
1085
|
# return false if @prior_execution_block == @delegate_object[:block_name]
|
1005
|
-
|
1086
|
+
if @prior_execution_block == @delegate_object[:block_name]
|
1087
|
+
return @allowed_execution_block == @prior_execution_block || prompt_approve_repeat
|
1088
|
+
end
|
1006
1089
|
|
1007
1090
|
@prior_execution_block = @delegate_object[:block_name]
|
1008
1091
|
@allowed_execution_block = nil
|
@@ -1019,17 +1102,21 @@ module MarkdownExec
|
|
1019
1102
|
# @param selected_option [Hash] The selected menu option.
|
1020
1103
|
# @return [SelectedBlockMenuState] An object representing the state of the selected block.
|
1021
1104
|
def determine_block_state(selected_option)
|
1022
|
-
option_name = selected_option
|
1105
|
+
option_name = selected_option[:oname]
|
1023
1106
|
if option_name == menu_chrome_formatted_option(:menu_option_exit_name)
|
1024
1107
|
return SelectedBlockMenuState.new(nil,
|
1108
|
+
OpenStruct.new,
|
1025
1109
|
MenuState::EXIT)
|
1026
1110
|
end
|
1027
1111
|
if option_name == menu_chrome_formatted_option(:menu_option_back_name)
|
1028
1112
|
return SelectedBlockMenuState.new(selected_option,
|
1113
|
+
OpenStruct.new,
|
1029
1114
|
MenuState::BACK)
|
1030
1115
|
end
|
1031
1116
|
|
1032
|
-
SelectedBlockMenuState.new(selected_option,
|
1117
|
+
SelectedBlockMenuState.new(selected_option,
|
1118
|
+
OpenStruct.new,
|
1119
|
+
MenuState::CONTINUE)
|
1033
1120
|
end
|
1034
1121
|
|
1035
1122
|
# Displays the required lines of code with color formatting for the preview section.
|
@@ -1068,9 +1155,9 @@ module MarkdownExec
|
|
1068
1155
|
block_name: @delegate_object[:block_name],
|
1069
1156
|
document_filename: @delegate_object[:filename]
|
1070
1157
|
)
|
1071
|
-
@run_state.block_name_from_cli = @dml_link_state.block_name.present?
|
1158
|
+
@run_state.source.block_name_from_cli = @dml_link_state.block_name.present?
|
1072
1159
|
@cli_block_name = @dml_link_state.block_name
|
1073
|
-
@dml_now_using_cli = @run_state.block_name_from_cli
|
1160
|
+
@dml_now_using_cli = @run_state.source.block_name_from_cli
|
1074
1161
|
@dml_menu_default_dname = nil
|
1075
1162
|
@dml_block_state = SelectedBlockMenuState.new
|
1076
1163
|
@doc_saved_lines_files = []
|
@@ -1078,18 +1165,28 @@ module MarkdownExec
|
|
1078
1165
|
## load file with code lines per options
|
1079
1166
|
#
|
1080
1167
|
if @menu_base_options[:load_code].present?
|
1081
|
-
@dml_link_state.inherited_lines =
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1168
|
+
@dml_link_state.inherited_lines =
|
1169
|
+
@menu_base_options[:load_code].split(':').map do |path|
|
1170
|
+
File.readlines(path, chomp: true)
|
1171
|
+
end.flatten(1)
|
1085
1172
|
|
1086
1173
|
inherited_block_names = []
|
1087
1174
|
inherited_dependencies = {}
|
1088
|
-
selected =
|
1089
|
-
pop_add_current_code_to_head_and_trigger_load(@dml_link_state, inherited_block_names,
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1175
|
+
selected = FCB.new(oname: 'load_code')
|
1176
|
+
pop_add_current_code_to_head_and_trigger_load(@dml_link_state, inherited_block_names,
|
1177
|
+
code_lines, inherited_dependencies, selected)
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
fdo = ->(option) {
|
1181
|
+
name = format(@delegate_object[:menu_link_format],
|
1182
|
+
HashDelegator.safeval(@delegate_object[option]))
|
1183
|
+
OpenStruct.new(
|
1184
|
+
dname: name,
|
1185
|
+
oname: name,
|
1186
|
+
name: name,
|
1187
|
+
pub_name: name.pub_name
|
1188
|
+
)
|
1189
|
+
}
|
1093
1190
|
item_back = fdo.call(:menu_option_back_name)
|
1094
1191
|
item_edit = fdo.call(:menu_option_edit_name)
|
1095
1192
|
item_history = fdo.call(:menu_option_history_name)
|
@@ -1101,36 +1198,65 @@ module MarkdownExec
|
|
1101
1198
|
@run_state.batch_random = Random.new.rand
|
1102
1199
|
@run_state.batch_index = 0
|
1103
1200
|
|
1201
|
+
@run_state.files = StreamsOut.new
|
1202
|
+
|
1104
1203
|
InputSequencer.new(
|
1105
1204
|
@delegate_object[:filename],
|
1106
1205
|
@delegate_object[:input_cli_rest]
|
1107
1206
|
).run do |msg, data|
|
1207
|
+
# &bt msg
|
1108
1208
|
case msg
|
1109
1209
|
when :parse_document # once for each menu
|
1110
1210
|
# puts "@ - parse document #{data}"
|
1111
1211
|
inpseq_parse_document(data)
|
1112
1212
|
|
1113
1213
|
if @delegate_object[:menu_for_history]
|
1114
|
-
history_files.tap do |files|
|
1115
|
-
|
1214
|
+
history_files(@dml_link_state).tap do |files|
|
1215
|
+
if files.count.positive?
|
1216
|
+
menu_enable_option(item_history.oname, files.count, 'files',
|
1217
|
+
menu_state: MenuState::HISTORY)
|
1218
|
+
end
|
1116
1219
|
end
|
1117
1220
|
end
|
1118
1221
|
|
1119
1222
|
if @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present?
|
1120
1223
|
|
1121
|
-
sf = document_name_in_glob_as_file_name(
|
1224
|
+
sf = document_name_in_glob_as_file_name(
|
1225
|
+
@dml_link_state.document_filename,
|
1226
|
+
@delegate_object[:document_saved_lines_glob]
|
1227
|
+
)
|
1122
1228
|
files = sf ? Dir.glob(sf) : []
|
1123
1229
|
@doc_saved_lines_files = files.count.positive? ? files : []
|
1124
1230
|
|
1125
|
-
lines_count = @dml_link_state.
|
1231
|
+
lines_count = @dml_link_state.inherited_lines_count
|
1126
1232
|
|
1127
1233
|
# add menu items (glob, load, save) and enable selectively
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1234
|
+
if files.count.positive? || lines_count.positive?
|
1235
|
+
menu_add_disabled_option(sf)
|
1236
|
+
end
|
1237
|
+
if files.count.positive?
|
1238
|
+
menu_enable_option(item_load.dname, files.count, 'files',
|
1239
|
+
menu_state: MenuState::LOAD)
|
1240
|
+
end
|
1241
|
+
if lines_count.positive?
|
1242
|
+
menu_enable_option(item_edit.dname, lines_count, 'lines',
|
1243
|
+
menu_state: MenuState::EDIT)
|
1244
|
+
end
|
1245
|
+
if lines_count.positive?
|
1246
|
+
menu_enable_option(item_save.dname, 1, '',
|
1247
|
+
menu_state: MenuState::SAVE)
|
1248
|
+
end
|
1249
|
+
if lines_count.positive?
|
1250
|
+
menu_enable_option(item_view.dname, 1, '',
|
1251
|
+
menu_state: MenuState::VIEW)
|
1252
|
+
end
|
1253
|
+
if @delegate_object[:menu_with_shell]
|
1254
|
+
menu_enable_option(item_shell.dname, 1, '',
|
1255
|
+
menu_state: MenuState::SHELL)
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
# # reflect new menu items
|
1259
|
+
# @dml_mdoc = MDoc.new(@dml_menu_blocks)
|
1134
1260
|
end
|
1135
1261
|
|
1136
1262
|
when :display_menu
|
@@ -1142,9 +1268,8 @@ module MarkdownExec
|
|
1142
1268
|
when :user_choice
|
1143
1269
|
if @dml_link_state.block_name.present?
|
1144
1270
|
# @prior_block_was_link = true
|
1145
|
-
@dml_block_state.block = @dml_blocks_in_file
|
1146
|
-
|
1147
|
-
end
|
1271
|
+
@dml_block_state.block = blocks_find_by_block_name(@dml_blocks_in_file,
|
1272
|
+
@dml_link_state.block_name)
|
1148
1273
|
@dml_link_state.block_name = nil
|
1149
1274
|
else
|
1150
1275
|
# puts "? - Select a block to execute (or type #{$texit} to exit):"
|
@@ -1156,7 +1281,7 @@ module MarkdownExec
|
|
1156
1281
|
|
1157
1282
|
when :execute_block
|
1158
1283
|
case (block_name = data)
|
1159
|
-
when item_back
|
1284
|
+
when item_back.pub_name
|
1160
1285
|
debounce_reset
|
1161
1286
|
@menu_user_clicked_back_link = true
|
1162
1287
|
load_file_link_state = pop_link_history_and_trigger_load
|
@@ -1171,64 +1296,94 @@ module MarkdownExec
|
|
1171
1296
|
)
|
1172
1297
|
)
|
1173
1298
|
|
1174
|
-
when item_edit
|
1299
|
+
when item_edit.pub_name
|
1175
1300
|
debounce_reset
|
1176
|
-
edited = edit_text(@dml_link_state.
|
1301
|
+
edited = edit_text(@dml_link_state.inherited_lines_block)
|
1177
1302
|
@dml_link_state.inherited_lines = edited.split("\n") if edited
|
1178
1303
|
|
1179
1304
|
return :break if pause_user_exit
|
1180
1305
|
|
1181
1306
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1182
1307
|
|
1183
|
-
when item_history
|
1308
|
+
when item_history.pub_name
|
1184
1309
|
debounce_reset
|
1185
|
-
files = history_files
|
1310
|
+
files = history_files(@dml_link_state)
|
1186
1311
|
files_table_rows = files.map do |file|
|
1187
1312
|
if Regexp.new(@delegate_object[:saved_asset_match]) =~ file
|
1188
|
-
|
1313
|
+
begin
|
1314
|
+
OpenStruct.new(
|
1315
|
+
file: file,
|
1316
|
+
row: format(
|
1317
|
+
@delegate_object[:saved_history_format],
|
1318
|
+
# create with default '*' so unknown parameters are given a wildcard
|
1319
|
+
$~.names.each_with_object(Hash.new('*')) do |name, hash|
|
1320
|
+
hash[name.to_sym] = $~[name]
|
1321
|
+
end
|
1322
|
+
)
|
1323
|
+
)
|
1324
|
+
rescue KeyError
|
1325
|
+
# pp $!, $@
|
1326
|
+
warn "Cannot format with: #{@delegate_object[:saved_history_format]}"
|
1327
|
+
error_handler('saved_history_format')
|
1328
|
+
break
|
1329
|
+
end
|
1189
1330
|
else
|
1190
1331
|
warn "Cannot parse name: #{file}"
|
1191
1332
|
next
|
1192
1333
|
end
|
1193
|
-
end
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1334
|
+
end&.compact
|
1335
|
+
|
1336
|
+
return :break unless files_table_rows
|
1337
|
+
|
1338
|
+
# repeat select+display until user exits
|
1339
|
+
row_attrib = :row
|
1340
|
+
loop do
|
1341
|
+
# menu with Back and Facet options at top
|
1342
|
+
case (name = prompt_select_code_filename(
|
1343
|
+
[@delegate_object[:prompt_filespec_back],
|
1344
|
+
@delegate_object[:prompt_filespec_facet]] +
|
1345
|
+
files_table_rows.map(&row_attrib),
|
1346
|
+
string: @delegate_object[:prompt_select_history_file],
|
1347
|
+
color_sym: :prompt_color_after_script_execution
|
1348
|
+
))
|
1349
|
+
when @delegate_object[:prompt_filespec_back]
|
1350
|
+
break
|
1351
|
+
when @delegate_object[:prompt_filespec_facet]
|
1352
|
+
row_attrib = row_attrib == :row ? :file : :row
|
1353
|
+
else
|
1354
|
+
file = files_table_rows.select { |ftr| ftr.row == name }&.first
|
1355
|
+
info = file_info(file.file)
|
1356
|
+
warn "#{file.file} - #{info[:lines]} lines / #{info[:size]} bytes"
|
1357
|
+
warn(File.readlines(file.file,
|
1358
|
+
chomp: false).map.with_index do |line, ind|
|
1359
|
+
format(' %s. %s', format('% 4d', ind + 1).violet, line)
|
1360
|
+
end)
|
1361
|
+
end
|
1210
1362
|
end
|
1211
1363
|
|
1212
1364
|
return :break if pause_user_exit
|
1213
1365
|
|
1214
1366
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1215
1367
|
|
1216
|
-
when item_load
|
1368
|
+
when item_load.pub_name
|
1217
1369
|
debounce_reset
|
1218
|
-
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1370
|
+
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1371
|
+
@delegate_object[:document_saved_lines_glob])
|
1219
1372
|
load_filespec = load_filespec_from_expression(sf)
|
1220
1373
|
if load_filespec
|
1221
|
-
@dml_link_state.
|
1222
|
-
|
1374
|
+
@dml_link_state.inherited_lines_append(
|
1375
|
+
File.readlines(load_filespec, chomp: true)
|
1376
|
+
)
|
1223
1377
|
end
|
1224
1378
|
|
1225
1379
|
return :break if pause_user_exit
|
1226
1380
|
|
1227
1381
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1228
1382
|
|
1229
|
-
when item_save
|
1383
|
+
when item_save.pub_name
|
1230
1384
|
debounce_reset
|
1231
|
-
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1385
|
+
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1386
|
+
@delegate_object[:document_saved_lines_glob])
|
1232
1387
|
save_filespec = save_filespec_from_expression(sf)
|
1233
1388
|
if save_filespec && !write_file_with_directory_creation(
|
1234
1389
|
save_filespec,
|
@@ -1240,7 +1395,7 @@ module MarkdownExec
|
|
1240
1395
|
|
1241
1396
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1242
1397
|
|
1243
|
-
when item_shell
|
1398
|
+
when item_shell.pub_name
|
1244
1399
|
debounce_reset
|
1245
1400
|
loop do
|
1246
1401
|
command = prompt_for_command(":MDE #{Time.now.strftime('%FT%TZ')}> ".bgreen)
|
@@ -1261,9 +1416,9 @@ module MarkdownExec
|
|
1261
1416
|
|
1262
1417
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1263
1418
|
|
1264
|
-
when item_view
|
1419
|
+
when item_view.pub_name
|
1265
1420
|
debounce_reset
|
1266
|
-
warn @dml_link_state.
|
1421
|
+
warn @dml_link_state.inherited_lines_block
|
1267
1422
|
|
1268
1423
|
return :break if pause_user_exit
|
1269
1424
|
|
@@ -1271,28 +1426,28 @@ module MarkdownExec
|
|
1271
1426
|
|
1272
1427
|
else
|
1273
1428
|
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1274
|
-
if @dml_block_state.block && @dml_block_state.block.
|
1429
|
+
if @dml_block_state.block && @dml_block_state.block.shell == BlockType::OPTS
|
1275
1430
|
debounce_reset
|
1276
1431
|
link_state = LinkState.new
|
1277
1432
|
options_state = read_show_options_and_trigger_reuse(
|
1278
|
-
|
1279
|
-
|
1433
|
+
link_state: link_state,
|
1434
|
+
mdoc: @dml_mdoc,
|
1435
|
+
selected: @dml_block_state.block
|
1280
1436
|
)
|
1281
1437
|
|
1282
|
-
|
1283
|
-
@delegate_object.merge!(options_state.options)
|
1438
|
+
update_menu_base(options_state.options)
|
1284
1439
|
options_state.load_file_link_state.link_state
|
1285
1440
|
else
|
1286
1441
|
inpseq_execute_block(block_name)
|
1287
1442
|
|
1288
|
-
if prompt_user_exit(block_name_from_cli: @run_state.block_name_from_cli,
|
1443
|
+
if prompt_user_exit(block_name_from_cli: @run_state.source.block_name_from_cli,
|
1289
1444
|
selected: @dml_block_state.block)
|
1290
1445
|
return :break
|
1291
1446
|
end
|
1292
1447
|
|
1293
1448
|
## order of block name processing: link block, cli, from user
|
1294
1449
|
#
|
1295
|
-
@dml_link_state.block_name, @run_state.block_name_from_cli, cli_break =
|
1450
|
+
@dml_link_state.block_name, @run_state.source.block_name_from_cli, cli_break =
|
1296
1451
|
HashDelegator.next_link_state(
|
1297
1452
|
block_name: @dml_link_state.block_name,
|
1298
1453
|
block_name_from_cli: @dml_now_using_cli,
|
@@ -1300,14 +1455,14 @@ module MarkdownExec
|
|
1300
1455
|
was_using_cli: @dml_now_using_cli
|
1301
1456
|
)
|
1302
1457
|
|
1303
|
-
if !@dml_block_state.
|
1458
|
+
if !@dml_block_state.source.block_name_from_ui && cli_break
|
1304
1459
|
# &bsp '!block_name_from_ui + cli_break -> break'
|
1305
1460
|
return :break
|
1306
1461
|
end
|
1307
1462
|
|
1308
1463
|
InputSequencer.next_link_state(
|
1309
1464
|
block_name: @dml_link_state.block_name,
|
1310
|
-
prior_block_was_link: @dml_block_state.block.
|
1465
|
+
prior_block_was_link: @dml_block_state.block.shell != BlockType::BASH
|
1311
1466
|
)
|
1312
1467
|
end
|
1313
1468
|
end
|
@@ -1328,9 +1483,13 @@ module MarkdownExec
|
|
1328
1483
|
# remove leading "./"
|
1329
1484
|
# replace characters: / : . * (space) with: (underscore)
|
1330
1485
|
def document_name_in_glob_as_file_name(document_filename, glob)
|
1331
|
-
|
1486
|
+
if document_filename.nil? || document_filename.empty?
|
1487
|
+
return document_filename
|
1488
|
+
end
|
1332
1489
|
|
1333
|
-
format(glob,
|
1490
|
+
format(glob,
|
1491
|
+
{ document_filename: document_filename.gsub(%r{^\./}, '').gsub(/[\/:\.\* ]/,
|
1492
|
+
'_') })
|
1334
1493
|
end
|
1335
1494
|
|
1336
1495
|
def dump_and_warn_block_state(selected:)
|
@@ -1351,7 +1510,10 @@ module MarkdownExec
|
|
1351
1510
|
# @param menu_blocks [Hash] Hash of menu blocks.
|
1352
1511
|
# @param link_state [LinkState] Current state of the link.
|
1353
1512
|
def dump_delobj(blocks_in_file, menu_blocks, link_state)
|
1354
|
-
|
1513
|
+
if @delegate_object[:dump_delegate_object]
|
1514
|
+
warn format_and_highlight_hash(@delegate_object,
|
1515
|
+
label: '@delegate_object')
|
1516
|
+
end
|
1355
1517
|
|
1356
1518
|
if @delegate_object[:dump_blocks_in_file]
|
1357
1519
|
warn format_and_highlight_dependencies(compact_and_index_hash(blocks_in_file),
|
@@ -1363,11 +1525,18 @@ module MarkdownExec
|
|
1363
1525
|
label: 'menu_blocks')
|
1364
1526
|
end
|
1365
1527
|
|
1366
|
-
|
1367
|
-
|
1528
|
+
if @delegate_object[:dump_inherited_block_names]
|
1529
|
+
warn format_and_highlight_lines(link_state.inherited_block_names,
|
1530
|
+
label: 'inherited_block_names')
|
1531
|
+
end
|
1532
|
+
if @delegate_object[:dump_inherited_dependencies]
|
1533
|
+
warn format_and_highlight_lines(link_state.inherited_dependencies,
|
1534
|
+
label: 'inherited_dependencies')
|
1535
|
+
end
|
1368
1536
|
return unless @delegate_object[:dump_inherited_lines]
|
1369
1537
|
|
1370
|
-
warn format_and_highlight_lines(link_state.inherited_lines,
|
1538
|
+
warn format_and_highlight_lines(link_state.inherited_lines,
|
1539
|
+
label: 'inherited_lines')
|
1371
1540
|
end
|
1372
1541
|
|
1373
1542
|
# Opens text in an editor for user modification and returns the modified text.
|
@@ -1432,7 +1601,7 @@ module MarkdownExec
|
|
1432
1601
|
|
1433
1602
|
# if the same menu is being displayed, collect the display name of the selected menu item for use as the default item
|
1434
1603
|
[lfls.link_state,
|
1435
|
-
lfls.load_file == LoadFile::LOAD ? nil : selected
|
1604
|
+
lfls.load_file == LoadFile::LOAD ? nil : selected.dname]
|
1436
1605
|
#.tap { |ret| pp [__FILE__,__LINE__,'exec_bash_next_state()',ret] }
|
1437
1606
|
end
|
1438
1607
|
|
@@ -1453,17 +1622,20 @@ module MarkdownExec
|
|
1453
1622
|
|
1454
1623
|
Open3.popen3(*command) do |stdin, stdout, stderr, exec_thread|
|
1455
1624
|
# Handle stdout stream
|
1456
|
-
handle_stream(stream: stdout,
|
1625
|
+
handle_stream(stream: stdout,
|
1626
|
+
file_type: ExecutionStreams::STD_OUT) do |line|
|
1457
1627
|
yield nil, line, nil, exec_thread if block_given?
|
1458
1628
|
end
|
1459
1629
|
|
1460
1630
|
# Handle stderr stream
|
1461
|
-
handle_stream(stream: stderr,
|
1631
|
+
handle_stream(stream: stderr,
|
1632
|
+
file_type: ExecutionStreams::STD_ERR) do |line|
|
1462
1633
|
yield nil, nil, line, exec_thread if block_given?
|
1463
1634
|
end
|
1464
1635
|
|
1465
1636
|
# Handle stdin stream
|
1466
|
-
input_thread = handle_stream(stream: $stdin,
|
1637
|
+
input_thread = handle_stream(stream: $stdin,
|
1638
|
+
file_type: ExecutionStreams::STD_IN) do |line|
|
1467
1639
|
stdin.puts(line)
|
1468
1640
|
yield line, nil, nil, exec_thread if block_given?
|
1469
1641
|
end
|
@@ -1490,8 +1662,13 @@ module MarkdownExec
|
|
1490
1662
|
# @param required_lines [Array<String>] The lines of code to be executed.
|
1491
1663
|
# @param selected [FCB] The selected functional code block object.
|
1492
1664
|
def execute_required_lines(required_lines: [], selected: FCB.new)
|
1493
|
-
|
1494
|
-
|
1665
|
+
if @delegate_object[:save_executed_script]
|
1666
|
+
write_command_file(required_lines: required_lines,
|
1667
|
+
selected: selected)
|
1668
|
+
end
|
1669
|
+
if @dml_block_state
|
1670
|
+
calc_logged_stdout_filename(block_name: @dml_block_state.block.oname)
|
1671
|
+
end
|
1495
1672
|
format_and_execute_command(code_lines: required_lines)
|
1496
1673
|
post_execution_process
|
1497
1674
|
end
|
@@ -1505,10 +1682,11 @@ module MarkdownExec
|
|
1505
1682
|
# @param opts [Hash] Options hash containing configuration settings.
|
1506
1683
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
1507
1684
|
#
|
1508
|
-
def execute_shell_type(selected:, mdoc:, block_source:,
|
1509
|
-
|
1685
|
+
def execute_shell_type(selected:, mdoc:, block_source:,
|
1686
|
+
link_state: LinkState.new)
|
1687
|
+
if selected.shell == BlockType::LINK
|
1510
1688
|
debounce_reset
|
1511
|
-
push_link_history_and_trigger_load(link_block_body: selected.
|
1689
|
+
push_link_history_and_trigger_load(link_block_body: selected.body,
|
1512
1690
|
mdoc: mdoc,
|
1513
1691
|
selected: selected,
|
1514
1692
|
link_state: link_state,
|
@@ -1518,46 +1696,34 @@ module MarkdownExec
|
|
1518
1696
|
debounce_reset
|
1519
1697
|
pop_link_history_and_trigger_load
|
1520
1698
|
|
1521
|
-
elsif selected
|
1699
|
+
elsif selected.shell == BlockType::OPTS
|
1522
1700
|
debounce_reset
|
1523
|
-
block_names = []
|
1524
1701
|
code_lines = []
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
@delegate_object.merge!(options_state.options)
|
1702
|
+
options_state = read_show_options_and_trigger_reuse(
|
1703
|
+
link_state: link_state,
|
1704
|
+
mdoc: @dml_mdoc,
|
1705
|
+
selected: selected
|
1706
|
+
)
|
1707
|
+
update_menu_base(options_state.options)
|
1532
1708
|
|
1533
1709
|
### options_state.load_file_link_state
|
1534
1710
|
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
|
-
)
|
1711
|
+
next_state_append_code(selected, link_state, code_lines)
|
1545
1712
|
|
1546
|
-
elsif selected
|
1713
|
+
elsif selected.shell == BlockType::PORT
|
1547
1714
|
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
|
1715
|
+
required_lines = collect_required_code_lines(
|
1716
|
+
mdoc: @dml_mdoc,
|
1717
|
+
selected: selected,
|
1718
|
+
link_state: link_state,
|
1719
|
+
block_source: block_source
|
1560
1720
|
)
|
1721
|
+
next_state_set_code(selected, link_state, required_lines)
|
1722
|
+
|
1723
|
+
elsif selected.shell == BlockType::VARS
|
1724
|
+
debounce_reset
|
1725
|
+
next_state_append_code(selected, link_state,
|
1726
|
+
set_environment_variables_for_block(selected))
|
1561
1727
|
|
1562
1728
|
elsif debounce_allows
|
1563
1729
|
compile_execute_and_trigger_reuse(mdoc: mdoc,
|
@@ -1646,6 +1812,16 @@ module MarkdownExec
|
|
1646
1812
|
expr.include?('%{') ? format_expression(expr) : expr
|
1647
1813
|
end
|
1648
1814
|
|
1815
|
+
def generate_temp_filename(ext = '.sh')
|
1816
|
+
filename = begin
|
1817
|
+
Dir::Tmpname.make_tmpname(['x', ext], nil)
|
1818
|
+
rescue NoMethodError
|
1819
|
+
require 'securerandom'
|
1820
|
+
"#{SecureRandom.urlsafe_base64}#{ext}"
|
1821
|
+
end
|
1822
|
+
File.join(Dir.tmpdir, filename)
|
1823
|
+
end
|
1824
|
+
|
1649
1825
|
# Processes a block to generate its summary, modifying its attributes based on various matching criteria.
|
1650
1826
|
# It handles special formatting for bash blocks, extracting and setting properties like call, stdin, stdout, and dname.
|
1651
1827
|
#
|
@@ -1659,7 +1835,7 @@ module MarkdownExec
|
|
1659
1835
|
bm = extract_named_captures_from_option(titlexcall,
|
1660
1836
|
@delegate_object[:block_name_match])
|
1661
1837
|
|
1662
|
-
shell_color_option = SHELL_COLOR_OPTIONS[fcb
|
1838
|
+
shell_color_option = SHELL_COLOR_OPTIONS[fcb.shell]
|
1663
1839
|
|
1664
1840
|
if @delegate_object[:block_name_nick_match].present? && fcb.oname =~ Regexp.new(@delegate_object[:block_name_nick_match])
|
1665
1841
|
fcb.nickname = $~[0]
|
@@ -1670,9 +1846,10 @@ module MarkdownExec
|
|
1670
1846
|
|
1671
1847
|
fcb.dname = HashDelegator.indent_all_lines(
|
1672
1848
|
apply_shell_color_option(fcb.oname, shell_color_option),
|
1673
|
-
fcb.
|
1849
|
+
fcb.indent
|
1674
1850
|
)
|
1675
|
-
|
1851
|
+
|
1852
|
+
fcb # &br
|
1676
1853
|
end
|
1677
1854
|
|
1678
1855
|
# Updates the delegate object's state based on the provided block state.
|
@@ -1695,13 +1872,13 @@ module MarkdownExec
|
|
1695
1872
|
Thread.new do
|
1696
1873
|
stream.each_line do |line|
|
1697
1874
|
line.strip!
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
# print line
|
1702
|
-
puts line
|
1875
|
+
if @run_state.files.streams
|
1876
|
+
@run_state.files.append_stream_line(file_type,
|
1877
|
+
line)
|
1703
1878
|
end
|
1704
1879
|
|
1880
|
+
puts line if @delegate_object[:output_stdout]
|
1881
|
+
|
1705
1882
|
yield line if block_given?
|
1706
1883
|
end
|
1707
1884
|
rescue IOError
|
@@ -1712,25 +1889,40 @@ module MarkdownExec
|
|
1712
1889
|
end
|
1713
1890
|
end
|
1714
1891
|
|
1715
|
-
def history_files
|
1716
|
-
Dir.glob(
|
1892
|
+
def history_files(link_state, order: :chronological, direction: :reverse)
|
1893
|
+
files = Dir.glob(
|
1717
1894
|
File.join(
|
1718
1895
|
@delegate_object[:saved_script_folder],
|
1719
|
-
SavedAsset.new(
|
1720
|
-
|
1896
|
+
SavedAsset.new(
|
1897
|
+
filename: @delegate_object[:filename],
|
1898
|
+
saved_asset_format: shell_escape_asset_format(link_state)
|
1899
|
+
).generate_name
|
1721
1900
|
)
|
1722
1901
|
)
|
1902
|
+
|
1903
|
+
sorted_files = case order
|
1904
|
+
when :alphabetical
|
1905
|
+
files.sort
|
1906
|
+
when :chronological
|
1907
|
+
files.sort_by { |file| File.mtime(file) }
|
1908
|
+
else
|
1909
|
+
raise ArgumentError, "Invalid order: #{order}"
|
1910
|
+
end
|
1911
|
+
|
1912
|
+
direction == :reverse ? sorted_files.reverse : sorted_files
|
1723
1913
|
end
|
1724
1914
|
|
1725
1915
|
# Initializes variables for regex and other states
|
1726
1916
|
def initial_state
|
1727
1917
|
{
|
1728
|
-
fenced_start_and_end_regex:
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1918
|
+
fenced_start_and_end_regex:
|
1919
|
+
Regexp.new(@delegate_object.fetch(
|
1920
|
+
:fenced_start_and_end_regex, '^(?<indent> *)`{3,}'
|
1921
|
+
)),
|
1922
|
+
fenced_start_extended_regex:
|
1923
|
+
Regexp.new(@delegate_object.fetch(
|
1924
|
+
:fenced_start_and_end_regex, '^(?<indent> *)`{3,}'
|
1925
|
+
)),
|
1734
1926
|
fcb: MarkdownExec::FCB.new,
|
1735
1927
|
in_fenced_block: false,
|
1736
1928
|
headings: []
|
@@ -1740,7 +1932,7 @@ module MarkdownExec
|
|
1740
1932
|
def inpseq_execute_block(block_name)
|
1741
1933
|
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1742
1934
|
dump_and_warn_block_state(selected: @dml_block_state.block)
|
1743
|
-
@dml_link_state, @dml_menu_default_dname =
|
1935
|
+
@dml_link_state, @dml_menu_default_dname =
|
1744
1936
|
exec_bash_next_state(
|
1745
1937
|
selected: @dml_block_state.block,
|
1746
1938
|
mdoc: @dml_mdoc,
|
@@ -1757,8 +1949,8 @@ module MarkdownExec
|
|
1757
1949
|
@run_state.in_own_window = false
|
1758
1950
|
|
1759
1951
|
# &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,
|
1952
|
+
@run_state.source.block_name_from_cli, @dml_now_using_cli, @dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc =
|
1953
|
+
set_delobj_menu_loop_vars(block_name_from_cli: @run_state.source.block_name_from_cli,
|
1762
1954
|
now_using_cli: @dml_now_using_cli,
|
1763
1955
|
link_state: @dml_link_state)
|
1764
1956
|
end
|
@@ -1767,7 +1959,7 @@ module MarkdownExec
|
|
1767
1959
|
@dml_block_state = load_cli_or_user_selected_block(all_blocks: @dml_blocks_in_file,
|
1768
1960
|
menu_blocks: @dml_menu_blocks,
|
1769
1961
|
default: @dml_menu_default_dname)
|
1770
|
-
# &bsp '@run_state.block_name_from_cli:',@run_state.block_name_from_cli
|
1962
|
+
# &bsp '@run_state.source.block_name_from_cli:',@run_state.source.block_name_from_cli
|
1771
1963
|
if !@dml_block_state
|
1772
1964
|
HashDelegator.error_handler('block_state missing', { abort: true })
|
1773
1965
|
elsif @dml_block_state.state == MenuState::EXIT
|
@@ -1793,8 +1985,10 @@ module MarkdownExec
|
|
1793
1985
|
end
|
1794
1986
|
end
|
1795
1987
|
|
1796
|
-
def link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
1797
|
-
|
1988
|
+
def link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
1989
|
+
block_source:)
|
1990
|
+
all_code = HashDelegator.code_merge(link_state&.inherited_lines,
|
1991
|
+
code_lines)
|
1798
1992
|
output_lines = []
|
1799
1993
|
|
1800
1994
|
Tempfile.open do |file|
|
@@ -1813,7 +2007,8 @@ module MarkdownExec
|
|
1813
2007
|
#
|
1814
2008
|
output_lines = process_string_array(
|
1815
2009
|
output_lines,
|
1816
|
-
begin_pattern: @delegate_object.fetch(:output_assignment_begin,
|
2010
|
+
begin_pattern: @delegate_object.fetch(:output_assignment_begin,
|
2011
|
+
nil),
|
1817
2012
|
end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
|
1818
2013
|
scan1: @delegate_object.fetch(:output_assignment_match, nil),
|
1819
2014
|
format1: @delegate_object.fetch(:output_assignment_format, nil)
|
@@ -1824,7 +2019,10 @@ module MarkdownExec
|
|
1824
2019
|
end
|
1825
2020
|
end
|
1826
2021
|
|
1827
|
-
|
2022
|
+
unless output_lines
|
2023
|
+
HashDelegator.error_handler('all_code eval output_lines is nil',
|
2024
|
+
{ abort: true })
|
2025
|
+
end
|
1828
2026
|
|
1829
2027
|
label_format_above = @delegate_object[:shell_code_label_format_above]
|
1830
2028
|
label_format_below = @delegate_object[:shell_code_label_format_below]
|
@@ -1833,7 +2031,11 @@ module MarkdownExec
|
|
1833
2031
|
block_source.merge({ block_name: selected.pub_name }))] +
|
1834
2032
|
output_lines.map do |line|
|
1835
2033
|
re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
|
1836
|
-
|
2034
|
+
next unless re =~ line
|
2035
|
+
|
2036
|
+
re.gsub_format(line,
|
2037
|
+
link_block_data.fetch('format',
|
2038
|
+
'%{line}'))
|
1837
2039
|
end.compact +
|
1838
2040
|
[label_format_below && format(label_format_below,
|
1839
2041
|
block_source.merge({ block_name: selected.pub_name }))]
|
@@ -1882,34 +2084,41 @@ module MarkdownExec
|
|
1882
2084
|
# Executes a specified block once per filename.
|
1883
2085
|
# @param all_blocks [Array] Array of all block elements.
|
1884
2086
|
# @return [Boolean, nil] True if values were modified, nil otherwise.
|
1885
|
-
def load_auto_opts_block(all_blocks)
|
2087
|
+
def load_auto_opts_block(all_blocks, mdoc:)
|
1886
2088
|
block_name = @delegate_object[:document_load_opts_block_name]
|
1887
|
-
|
2089
|
+
unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
2090
|
+
return
|
2091
|
+
end
|
1888
2092
|
|
1889
2093
|
block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1890
2094
|
return unless block
|
1891
2095
|
|
1892
|
-
options_state = read_show_options_and_trigger_reuse(
|
1893
|
-
|
1894
|
-
|
2096
|
+
options_state = read_show_options_and_trigger_reuse(
|
2097
|
+
mdoc: mdoc,
|
2098
|
+
selected: block
|
2099
|
+
)
|
2100
|
+
update_menu_base(options_state.options)
|
1895
2101
|
|
1896
2102
|
@most_recent_loaded_filename = @delegate_object[:filename]
|
1897
2103
|
true
|
1898
2104
|
end
|
1899
2105
|
|
1900
|
-
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [],
|
2106
|
+
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [],
|
2107
|
+
default: nil)
|
1901
2108
|
if @delegate_object[:block_name].present?
|
1902
2109
|
block = all_blocks.find do |item|
|
1903
2110
|
item.pub_name == @delegate_object[:block_name]
|
1904
|
-
end
|
2111
|
+
end
|
2112
|
+
source = OpenStruct.new(block_name_from_ui: false)
|
1905
2113
|
else
|
1906
2114
|
block_state = wait_for_user_selected_block(all_blocks, menu_blocks,
|
1907
2115
|
default)
|
1908
|
-
block = block_state.block
|
2116
|
+
block = block_state.block
|
2117
|
+
source = OpenStruct.new(block_name_from_ui: true)
|
1909
2118
|
state = block_state.state
|
1910
2119
|
end
|
1911
2120
|
|
1912
|
-
SelectedBlockMenuState.new(block, state)
|
2121
|
+
SelectedBlockMenuState.new(block, source, state)
|
1913
2122
|
rescue StandardError
|
1914
2123
|
HashDelegator.error_handler('load_cli_or_user_selected_block')
|
1915
2124
|
end
|
@@ -1932,7 +2141,8 @@ module MarkdownExec
|
|
1932
2141
|
def load_filespec_wildcard_expansion(expr, auto_load_single: false)
|
1933
2142
|
files = find_files(expr)
|
1934
2143
|
if files.count.zero?
|
1935
|
-
HashDelegator.error_handler("no files found with '#{expr}' ",
|
2144
|
+
HashDelegator.error_handler("no files found with '#{expr}' ",
|
2145
|
+
{ abort: true })
|
1936
2146
|
elsif auto_load_single && files.count == 1
|
1937
2147
|
files.first
|
1938
2148
|
else
|
@@ -1966,20 +2176,22 @@ module MarkdownExec
|
|
1966
2176
|
|
1967
2177
|
# recreate menu with new options
|
1968
2178
|
#
|
1969
|
-
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(
|
2179
|
+
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(
|
2180
|
+
all_blocks, mdoc: mdoc
|
2181
|
+
)
|
1970
2182
|
|
1971
2183
|
menu_blocks = mdoc.fcbs_per_options(@delegate_object)
|
1972
2184
|
add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
|
1973
2185
|
### compress empty lines
|
1974
2186
|
HashDelegator.delete_consecutive_blank_lines!(menu_blocks)
|
1975
|
-
[all_blocks, menu_blocks, mdoc]
|
2187
|
+
[all_blocks, menu_blocks, mdoc] # &br
|
1976
2188
|
end
|
1977
2189
|
|
1978
2190
|
def menu_add_disabled_option(name)
|
1979
2191
|
raise unless name.present?
|
1980
2192
|
raise if @dml_menu_blocks.nil?
|
1981
2193
|
|
1982
|
-
block = @dml_menu_blocks.find { |item| item
|
2194
|
+
block = @dml_menu_blocks.find { |item| item.oname == name }
|
1983
2195
|
|
1984
2196
|
# create menu item when it is needed (count > 0)
|
1985
2197
|
#
|
@@ -2017,7 +2229,9 @@ module MarkdownExec
|
|
2017
2229
|
# @param option_symbol [Symbol] The symbol key for the menu option in the delegate object.
|
2018
2230
|
# @return [String] The formatted or original value of the menu option.
|
2019
2231
|
def menu_chrome_formatted_option(option_symbol = :menu_option_back_name)
|
2020
|
-
option_value = HashDelegator.safeval(@delegate_object.fetch(
|
2232
|
+
option_value = HashDelegator.safeval(@delegate_object.fetch(
|
2233
|
+
option_symbol, ''
|
2234
|
+
))
|
2021
2235
|
|
2022
2236
|
if @delegate_object[:menu_chrome_format]
|
2023
2237
|
format(@delegate_object[:menu_chrome_format], option_value)
|
@@ -2030,20 +2244,20 @@ module MarkdownExec
|
|
2030
2244
|
raise unless name.present?
|
2031
2245
|
raise if @dml_menu_blocks.nil?
|
2032
2246
|
|
2033
|
-
item = @dml_menu_blocks.find { |block| block
|
2247
|
+
item = @dml_menu_blocks.find { |block| block.oname == name }
|
2034
2248
|
|
2035
2249
|
# create menu item when it is needed (count > 0)
|
2036
2250
|
#
|
2037
2251
|
if item.nil? && count.positive?
|
2038
|
-
append_chrome_block(menu_blocks: @dml_menu_blocks,
|
2039
|
-
|
2252
|
+
item = append_chrome_block(menu_blocks: @dml_menu_blocks,
|
2253
|
+
menu_state: menu_state)
|
2040
2254
|
end
|
2041
2255
|
|
2042
2256
|
# update item if it exists
|
2043
2257
|
#
|
2044
2258
|
return unless item
|
2045
2259
|
|
2046
|
-
item
|
2260
|
+
item.dname = type.present? ? "#{name} (#{count} #{type})" : name
|
2047
2261
|
if count.positive?
|
2048
2262
|
item.delete(:disabled)
|
2049
2263
|
else
|
@@ -2051,14 +2265,15 @@ module MarkdownExec
|
|
2051
2265
|
end
|
2052
2266
|
end
|
2053
2267
|
|
2054
|
-
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:,
|
2268
|
+
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:,
|
2269
|
+
link_state:)
|
2055
2270
|
if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name]
|
2056
2271
|
# &bsp 'pause cli control, allow user to select block'
|
2057
2272
|
block_name_from_cli = false
|
2058
2273
|
now_using_cli = false
|
2059
|
-
@menu_base_options[:block_name] =
|
2274
|
+
@menu_base_options[:block_name] =
|
2060
2275
|
@delegate_object[:block_name] = \
|
2061
|
-
link_state.block_name =
|
2276
|
+
link_state.block_name =
|
2062
2277
|
@cli_block_name = nil
|
2063
2278
|
end
|
2064
2279
|
|
@@ -2079,6 +2294,27 @@ module MarkdownExec
|
|
2079
2294
|
end
|
2080
2295
|
end
|
2081
2296
|
|
2297
|
+
def next_state_append_code(selected, link_state, code_lines)
|
2298
|
+
next_state_set_code(selected, link_state, HashDelegator.code_merge(
|
2299
|
+
link_state&.inherited_lines, code_lines
|
2300
|
+
))
|
2301
|
+
end
|
2302
|
+
|
2303
|
+
def next_state_set_code(selected, link_state, code_lines)
|
2304
|
+
block_names = []
|
2305
|
+
dependencies = {}
|
2306
|
+
link_history_push_and_next(
|
2307
|
+
curr_block_name: selected.pub_name,
|
2308
|
+
curr_document_filename: @delegate_object[:filename],
|
2309
|
+
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2310
|
+
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2311
|
+
inherited_lines: HashDelegator.code_merge(code_lines),
|
2312
|
+
next_block_name: '',
|
2313
|
+
next_document_filename: @delegate_object[:filename],
|
2314
|
+
next_load_file: LoadFile::REUSE
|
2315
|
+
)
|
2316
|
+
end
|
2317
|
+
|
2082
2318
|
def output_color_formatted(data_sym, color_sym)
|
2083
2319
|
formatted_string = string_send_color(@delegate_object[data_sym],
|
2084
2320
|
color_sym)
|
@@ -2159,9 +2395,12 @@ module MarkdownExec
|
|
2159
2395
|
link_history_push_and_next(
|
2160
2396
|
curr_block_name: selected.pub_name,
|
2161
2397
|
curr_document_filename: @delegate_object[:filename],
|
2162
|
-
inherited_block_names:
|
2163
|
-
|
2164
|
-
|
2398
|
+
inherited_block_names:
|
2399
|
+
((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2400
|
+
inherited_dependencies:
|
2401
|
+
(link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2402
|
+
inherited_lines:
|
2403
|
+
HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
2165
2404
|
next_block_name: next_block_name,
|
2166
2405
|
next_document_filename: @delegate_object[:filename], # not next_document_filename
|
2167
2406
|
next_load_file: LoadFile::REUSE # not next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD
|
@@ -2177,12 +2416,15 @@ module MarkdownExec
|
|
2177
2416
|
def pop_link_history_and_trigger_load
|
2178
2417
|
pop = @link_history.pop
|
2179
2418
|
peek = @link_history.peek
|
2180
|
-
LoadFileLinkState.new(
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2419
|
+
LoadFileLinkState.new(
|
2420
|
+
LoadFile::LOAD,
|
2421
|
+
LinkState.new(
|
2422
|
+
document_filename: pop.document_filename,
|
2423
|
+
inherited_block_names: peek.inherited_block_names,
|
2424
|
+
inherited_dependencies: peek.inherited_dependencies,
|
2425
|
+
inherited_lines: peek.inherited_lines
|
2426
|
+
)
|
2427
|
+
)
|
2186
2428
|
end
|
2187
2429
|
|
2188
2430
|
def post_execution_process
|
@@ -2198,20 +2440,21 @@ module MarkdownExec
|
|
2198
2440
|
# @return [Array<Hash>] The updated blocks menu.
|
2199
2441
|
def prepare_blocks_menu(menu_blocks)
|
2200
2442
|
menu_blocks.map do |fcb|
|
2201
|
-
next if Filter.prepared_not_in_menu?(
|
2202
|
-
|
2443
|
+
next if Filter.prepared_not_in_menu?(
|
2444
|
+
@delegate_object,
|
2445
|
+
fcb,
|
2446
|
+
%i[block_name_include_match block_name_wrapper_match]
|
2447
|
+
)
|
2203
2448
|
|
2204
|
-
fcb.
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
title: fcb[:title]
|
2214
|
-
)
|
2449
|
+
fcb.name = fcb.dname
|
2450
|
+
fcb.label = BlockLabel.make(
|
2451
|
+
body: fcb.body,
|
2452
|
+
filename: @delegate_object[:filename],
|
2453
|
+
headings: fcb.headings,
|
2454
|
+
menu_blocks_with_docname: @delegate_object[:menu_blocks_with_docname],
|
2455
|
+
menu_blocks_with_headings: @delegate_object[:menu_blocks_with_headings],
|
2456
|
+
text: fcb.text,
|
2457
|
+
title: fcb.title
|
2215
2458
|
)
|
2216
2459
|
fcb.to_h
|
2217
2460
|
end.compact
|
@@ -2232,7 +2475,9 @@ module MarkdownExec
|
|
2232
2475
|
when :filter
|
2233
2476
|
%i[blocks line]
|
2234
2477
|
when :line
|
2235
|
-
|
2478
|
+
unless @delegate_object[:no_chrome]
|
2479
|
+
create_and_add_chrome_blocks(blocks, fcb)
|
2480
|
+
end
|
2236
2481
|
end
|
2237
2482
|
end
|
2238
2483
|
|
@@ -2305,7 +2550,8 @@ module MarkdownExec
|
|
2305
2550
|
# @param filespec [String] the wildcard expression to be substituted
|
2306
2551
|
# @return [String, nil] the resolved path or substituted expression, or nil if interrupted
|
2307
2552
|
def prompt_for_filespec_with_wildcard(filespec)
|
2308
|
-
puts format(@delegate_object[:prompt_show_expr_format],
|
2553
|
+
puts format(@delegate_object[:prompt_show_expr_format],
|
2554
|
+
{ expr: filespec })
|
2309
2555
|
puts @delegate_object[:prompt_enter_filespec]
|
2310
2556
|
|
2311
2557
|
begin
|
@@ -2362,26 +2608,40 @@ module MarkdownExec
|
|
2362
2608
|
|
2363
2609
|
# public
|
2364
2610
|
|
2365
|
-
def prompt_select_code_filename(
|
2611
|
+
def prompt_select_code_filename(
|
2612
|
+
filenames,
|
2613
|
+
color_sym: :prompt_color_after_script_execution,
|
2614
|
+
cycle: true,
|
2615
|
+
enum: false,
|
2616
|
+
quiet: true,
|
2617
|
+
string: @delegate_object[:prompt_select_code_file]
|
2618
|
+
)
|
2366
2619
|
@prompt.select(
|
2367
2620
|
string_send_color(string, color_sym),
|
2368
|
-
|
2369
|
-
|
2621
|
+
cycle: cycle,
|
2622
|
+
filter: !enum,
|
2623
|
+
per_page: @delegate_object[:select_page_height],
|
2624
|
+
quiet: quiet
|
2370
2625
|
) do |menu|
|
2371
|
-
|
2372
|
-
|
2626
|
+
menu.enum '.' if enum
|
2627
|
+
filenames.each.with_index do |filename, ind|
|
2628
|
+
if enum
|
2629
|
+
menu.choice filename, ind + 1
|
2630
|
+
else
|
2631
|
+
menu.choice filename
|
2632
|
+
end
|
2373
2633
|
end
|
2374
2634
|
end
|
2375
2635
|
rescue TTY::Reader::InputInterrupt
|
2376
2636
|
exit 1
|
2377
2637
|
end
|
2378
2638
|
|
2379
|
-
def prompt_select_continue
|
2639
|
+
def prompt_select_continue(filter: true, quiet: true)
|
2380
2640
|
sel = @prompt.select(
|
2381
2641
|
string_send_color(@delegate_object[:prompt_after_script_execution],
|
2382
2642
|
:prompt_color_after_script_execution),
|
2383
|
-
filter:
|
2384
|
-
quiet:
|
2643
|
+
filter: filter,
|
2644
|
+
quiet: quiet
|
2385
2645
|
) do |menu|
|
2386
2646
|
menu.choice @delegate_object[:prompt_yes]
|
2387
2647
|
menu.choice @delegate_object[:prompt_exit]
|
@@ -2394,7 +2654,7 @@ module MarkdownExec
|
|
2394
2654
|
# user prompt to exit if the menu will be displayed again
|
2395
2655
|
#
|
2396
2656
|
def prompt_user_exit(block_name_from_cli:, selected:)
|
2397
|
-
selected
|
2657
|
+
selected.shell == BlockType::BASH &&
|
2398
2658
|
@delegate_object[:pause_after_script_execution] &&
|
2399
2659
|
prompt_select_continue == MenuState::EXIT
|
2400
2660
|
end
|
@@ -2443,18 +2703,26 @@ module MarkdownExec
|
|
2443
2703
|
#
|
2444
2704
|
if (load_expr = link_block_data.fetch(LinkKeys::LOAD, '')).present?
|
2445
2705
|
load_filespec = load_filespec_from_expression(load_expr)
|
2446
|
-
|
2706
|
+
if load_filespec
|
2707
|
+
code_lines += File.readlines(load_filespec,
|
2708
|
+
chomp: true)
|
2709
|
+
end
|
2447
2710
|
end
|
2448
2711
|
|
2449
2712
|
# if an eval link block, evaluate code_lines and return its standard output
|
2450
2713
|
#
|
2451
2714
|
if link_block_data.fetch(LinkKeys::EVAL,
|
2452
|
-
false) || link_block_data.fetch(LinkKeys::EXEC,
|
2453
|
-
|
2715
|
+
false) || link_block_data.fetch(LinkKeys::EXEC,
|
2716
|
+
false)
|
2717
|
+
code_lines = link_block_data_eval(link_state, code_lines, selected, link_block_data,
|
2718
|
+
block_source: block_source)
|
2454
2719
|
end
|
2455
2720
|
|
2456
|
-
next_document_filename = write_inherited_lines_to_file(link_state,
|
2457
|
-
|
2721
|
+
next_document_filename = write_inherited_lines_to_file(link_state,
|
2722
|
+
link_block_data)
|
2723
|
+
next_block_name = link_block_data.fetch(LinkKeys::NEXT_BLOCK,
|
2724
|
+
nil) || link_block_data.fetch(LinkKeys::BLOCK,
|
2725
|
+
nil) || ''
|
2458
2726
|
|
2459
2727
|
if link_block_data[LinkKeys::RETURN]
|
2460
2728
|
pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
|
@@ -2466,7 +2734,9 @@ module MarkdownExec
|
|
2466
2734
|
curr_document_filename: @delegate_object[:filename],
|
2467
2735
|
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2468
2736
|
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2469
|
-
inherited_lines: HashDelegator.code_merge(
|
2737
|
+
inherited_lines: HashDelegator.code_merge(
|
2738
|
+
link_state&.inherited_lines, code_lines
|
2739
|
+
),
|
2470
2740
|
next_block_name: next_block_name,
|
2471
2741
|
next_document_filename: next_document_filename,
|
2472
2742
|
next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD
|
@@ -2487,14 +2757,29 @@ module MarkdownExec
|
|
2487
2757
|
# @param selected [Hash] Selected item from the menu containing a YAML body.
|
2488
2758
|
# @param tgt2 [Hash, nil] An optional target hash to update with YAML data.
|
2489
2759
|
# @return [LoadFileLinkState] An instance indicating the next action for loading files.
|
2490
|
-
def read_show_options_and_trigger_reuse(selected:,
|
2760
|
+
def read_show_options_and_trigger_reuse(selected:,
|
2761
|
+
mdoc:, link_state: LinkState.new)
|
2491
2762
|
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
2763
|
|
2497
|
-
|
2764
|
+
# concatenated body of all required blocks loaded a YAML
|
2765
|
+
data = YAML.load(
|
2766
|
+
collect_required_code_lines(
|
2767
|
+
mdoc: mdoc, selected: selected,
|
2768
|
+
link_state: link_state, block_source: {}
|
2769
|
+
).join("\n")
|
2770
|
+
).transform_keys(&:to_sym)
|
2771
|
+
|
2772
|
+
if selected.shell == BlockType::OPTS
|
2773
|
+
obj = data
|
2774
|
+
else
|
2775
|
+
(data || []).each do |key, value|
|
2776
|
+
sym_key = key.to_sym
|
2777
|
+
obj[sym_key] = value
|
2778
|
+
|
2779
|
+
if @delegate_object[:menu_opts_set_format].present?
|
2780
|
+
print_formatted_option(key, value)
|
2781
|
+
end
|
2782
|
+
end
|
2498
2783
|
end
|
2499
2784
|
|
2500
2785
|
link_state.block_name = nil
|
@@ -2526,11 +2811,19 @@ module MarkdownExec
|
|
2526
2811
|
resize_terminal
|
2527
2812
|
end
|
2528
2813
|
|
2529
|
-
|
2814
|
+
if resized || !opts[:console_width]
|
2815
|
+
opts[:console_height], opts[:console_width] = opts[:console_winsize] =
|
2816
|
+
IO.console.winsize
|
2817
|
+
end
|
2530
2818
|
|
2531
|
-
|
2819
|
+
unless opts[:select_page_height]&.positive?
|
2820
|
+
opts[:per_page] =
|
2821
|
+
opts[:select_page_height] =
|
2822
|
+
[opts[:console_height] - 3, 4].max
|
2823
|
+
end
|
2532
2824
|
rescue StandardError
|
2533
|
-
HashDelegator.error_handler('register_console_attributes',
|
2825
|
+
HashDelegator.error_handler('register_console_attributes',
|
2826
|
+
{ abort: true })
|
2534
2827
|
end
|
2535
2828
|
|
2536
2829
|
# Check if the delegate object responds to a given method.
|
@@ -2542,7 +2835,8 @@ module MarkdownExec
|
|
2542
2835
|
true
|
2543
2836
|
elsif @delegate_object.respond_to?(method_name, include_private)
|
2544
2837
|
true
|
2545
|
-
elsif method_name.to_s.end_with?('=') && @delegate_object.respond_to?(:[]=,
|
2838
|
+
elsif method_name.to_s.end_with?('=') && @delegate_object.respond_to?(:[]=,
|
2839
|
+
include_private)
|
2546
2840
|
true
|
2547
2841
|
else
|
2548
2842
|
@delegate_object.respond_to?(method_name, include_private)
|
@@ -2593,7 +2887,8 @@ module MarkdownExec
|
|
2593
2887
|
# input into path with wildcard for easy entry
|
2594
2888
|
#
|
2595
2889
|
case (name = prompt_select_code_filename(
|
2596
|
-
[@delegate_object[:prompt_filespec_back],
|
2890
|
+
[@delegate_object[:prompt_filespec_back],
|
2891
|
+
@delegate_object[:prompt_filespec_other]] + files,
|
2597
2892
|
string: @delegate_object[:prompt_select_code_file],
|
2598
2893
|
color_sym: :prompt_color_after_script_execution
|
2599
2894
|
))
|
@@ -2613,37 +2908,46 @@ module MarkdownExec
|
|
2613
2908
|
end
|
2614
2909
|
|
2615
2910
|
# Presents a TTY prompt to select an option or exit, returns metadata including option and selected
|
2616
|
-
def select_option_with_metadata(prompt_text,
|
2911
|
+
def select_option_with_metadata(prompt_text, menu_items, opts = {})
|
2617
2912
|
## configure to environment
|
2618
2913
|
#
|
2619
2914
|
register_console_attributes(opts)
|
2620
2915
|
|
2621
2916
|
# crashes if all menu options are disabled
|
2622
2917
|
selection = @prompt.select(prompt_text,
|
2623
|
-
|
2918
|
+
menu_items,
|
2624
2919
|
opts.merge(filter: true))
|
2625
|
-
|
2920
|
+
|
2921
|
+
selected = menu_items.find do |item|
|
2626
2922
|
if item.instance_of?(Hash)
|
2627
|
-
item[:dname] == selection
|
2923
|
+
(item[:name] || item[:dname]) == selection
|
2924
|
+
elsif item.instance_of?(MarkdownExec::FCB)
|
2925
|
+
item.dname == selection
|
2628
2926
|
else
|
2629
2927
|
item == selection
|
2630
2928
|
end
|
2631
2929
|
end
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2930
|
+
if selected.instance_of?(String)
|
2931
|
+
selected = FCB.new(dname: selected)
|
2932
|
+
elsif selected.instance_of?(Hash)
|
2933
|
+
selected = FCB.new(selected)
|
2934
|
+
end
|
2935
|
+
unless selected
|
2936
|
+
HashDelegator.error_handler('select_option_with_metadata',
|
2937
|
+
error: 'menu item not found')
|
2635
2938
|
exit 1
|
2636
2939
|
end
|
2637
2940
|
|
2638
|
-
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
2941
|
+
if selection == menu_chrome_colored_option(:menu_option_back_name)
|
2942
|
+
selected.option = selection
|
2943
|
+
selected.shell = BlockType::LINK
|
2944
|
+
elsif selection == menu_chrome_colored_option(:menu_option_exit_name)
|
2945
|
+
selected.option = selection
|
2946
|
+
else
|
2947
|
+
selected.selected = selection
|
2948
|
+
end
|
2949
|
+
|
2950
|
+
selected
|
2647
2951
|
rescue TTY::Reader::InputInterrupt
|
2648
2952
|
exit 1
|
2649
2953
|
rescue StandardError
|
@@ -2663,8 +2967,9 @@ module MarkdownExec
|
|
2663
2967
|
block_name_from_cli ? @cli_block_name : link_state.block_name
|
2664
2968
|
end
|
2665
2969
|
|
2666
|
-
def set_delobj_menu_loop_vars(block_name_from_cli:, now_using_cli:,
|
2667
|
-
|
2970
|
+
def set_delobj_menu_loop_vars(block_name_from_cli:, now_using_cli:,
|
2971
|
+
link_state:)
|
2972
|
+
block_name_from_cli, now_using_cli =
|
2668
2973
|
manage_cli_selection_state(block_name_from_cli: block_name_from_cli,
|
2669
2974
|
now_using_cli: now_using_cli,
|
2670
2975
|
link_state: link_state)
|
@@ -2681,7 +2986,7 @@ module MarkdownExec
|
|
2681
2986
|
|
2682
2987
|
def set_environment_variables_for_block(selected)
|
2683
2988
|
code_lines = []
|
2684
|
-
YAML.load(selected
|
2989
|
+
YAML.load(selected.body.join("\n"))&.each do |key, value|
|
2685
2990
|
ENV[key] = value.to_s
|
2686
2991
|
|
2687
2992
|
require 'shellwords'
|
@@ -2696,6 +3001,29 @@ module MarkdownExec
|
|
2696
3001
|
code_lines
|
2697
3002
|
end
|
2698
3003
|
|
3004
|
+
def shell_escape_asset_format(link_state)
|
3005
|
+
raw = @delegate_object[:saved_asset_format]
|
3006
|
+
|
3007
|
+
return raw unless @delegate_object[:shell_parameter_expansion]
|
3008
|
+
|
3009
|
+
# unchanged if no parameter expansion takes place
|
3010
|
+
return raw unless /$/ =~ raw
|
3011
|
+
|
3012
|
+
filespec = generate_temp_filename
|
3013
|
+
cmd = [@delegate_object[:shell], '-c', filespec].join(' ')
|
3014
|
+
|
3015
|
+
marker = Random.new.rand.to_s
|
3016
|
+
|
3017
|
+
code = (link_state&.inherited_lines || []) + ["echo -n \"#{marker}#{raw}\""]
|
3018
|
+
# &bt code
|
3019
|
+
File.write filespec, HashDelegator.join_code_lines(code)
|
3020
|
+
File.chmod 0o755, filespec
|
3021
|
+
|
3022
|
+
out = `#{cmd}`.sub(/.*?#{marker}/m, '')
|
3023
|
+
File.delete filespec
|
3024
|
+
out # &br
|
3025
|
+
end
|
3026
|
+
|
2699
3027
|
def should_add_back_option?
|
2700
3028
|
@delegate_object[:menu_with_back] && @link_history.prior_state_exist?
|
2701
3029
|
end
|
@@ -2818,6 +3146,13 @@ module MarkdownExec
|
|
2818
3146
|
end
|
2819
3147
|
end
|
2820
3148
|
|
3149
|
+
## apply options to current state
|
3150
|
+
#
|
3151
|
+
def update_menu_base(options)
|
3152
|
+
@menu_base_options.merge!(options)
|
3153
|
+
@delegate_object.merge!(options)
|
3154
|
+
end
|
3155
|
+
|
2821
3156
|
def wait_for_stream_processing
|
2822
3157
|
@process_mutex.synchronize do
|
2823
3158
|
@process_cv.wait(@process_mutex)
|
@@ -2839,8 +3174,11 @@ module MarkdownExec
|
|
2839
3174
|
@delegate_object[:prompt_select_block].to_s, :prompt_color_after_script_execution
|
2840
3175
|
)
|
2841
3176
|
|
2842
|
-
|
2843
|
-
|
3177
|
+
menu_items = prepare_blocks_menu(menu_blocks)
|
3178
|
+
if menu_items.empty?
|
3179
|
+
return SelectedBlockMenuState.new(nil, OpenStruct.new,
|
3180
|
+
MenuState::EXIT)
|
3181
|
+
end
|
2844
3182
|
|
2845
3183
|
# default value may not match if color is different from originating menu (opts changed while processing)
|
2846
3184
|
selection_opts = if default && menu_blocks.map(&:dname).include?(default)
|
@@ -2852,7 +3190,7 @@ module MarkdownExec
|
|
2852
3190
|
sph = @delegate_object[:select_page_height]
|
2853
3191
|
selection_opts.merge!(per_page: sph)
|
2854
3192
|
|
2855
|
-
selected_option = select_option_with_metadata(prompt_title,
|
3193
|
+
selected_option = select_option_with_metadata(prompt_title, menu_items,
|
2856
3194
|
selection_opts)
|
2857
3195
|
determine_block_state(selected_option)
|
2858
3196
|
end
|
@@ -2867,7 +3205,7 @@ module MarkdownExec
|
|
2867
3205
|
exts: '.sh',
|
2868
3206
|
filename: @delegate_object[:filename],
|
2869
3207
|
prefix: @delegate_object[:saved_script_filename_prefix],
|
2870
|
-
saved_asset_format: @
|
3208
|
+
saved_asset_format: shell_escape_asset_format(@dml_link_state),
|
2871
3209
|
time: time_now).generate_name
|
2872
3210
|
@run_state.saved_filespec =
|
2873
3211
|
File.join(@delegate_object[:saved_script_folder],
|
@@ -2918,7 +3256,8 @@ module MarkdownExec
|
|
2918
3256
|
save_expr = link_block_data.fetch(LinkKeys::SAVE, '')
|
2919
3257
|
if save_expr.present?
|
2920
3258
|
save_filespec = save_filespec_from_expression(save_expr)
|
2921
|
-
File.write(save_filespec,
|
3259
|
+
File.write(save_filespec,
|
3260
|
+
HashDelegator.join_code_lines(link_state&.inherited_lines))
|
2922
3261
|
@delegate_object[:filename]
|
2923
3262
|
else
|
2924
3263
|
link_block_data[LinkKeys::FILE] || @delegate_object[:filename]
|
@@ -2950,7 +3289,11 @@ module MarkdownExec
|
|
2950
3289
|
obj[key] = cleaned_value if value.is_a?(Hash) || value.is_a?(Struct)
|
2951
3290
|
end
|
2952
3291
|
|
2953
|
-
|
3292
|
+
if obj.is_a?(Hash)
|
3293
|
+
obj.reject! do |_key, value|
|
3294
|
+
[nil, '', [], {}, nil].include?(value)
|
3295
|
+
end
|
3296
|
+
end
|
2954
3297
|
|
2955
3298
|
obj
|
2956
3299
|
end
|
@@ -3014,7 +3357,8 @@ module MarkdownExec
|
|
3014
3357
|
|
3015
3358
|
# Test case for empty body
|
3016
3359
|
def test_next_link_state
|
3017
|
-
@hd.next_link_state(block_name_from_cli: nil, was_using_cli: nil, block_state: nil,
|
3360
|
+
@hd.next_link_state(block_name_from_cli: nil, was_using_cli: nil, block_state: nil,
|
3361
|
+
block_name: nil)
|
3018
3362
|
end
|
3019
3363
|
end
|
3020
3364
|
|
@@ -3061,15 +3405,18 @@ module MarkdownExec
|
|
3061
3405
|
# Test case for non-empty body with 'file' key
|
3062
3406
|
def test_push_link_history_and_trigger_load_with_file_key
|
3063
3407
|
body = ["file: sample_file\nblock: sample_block\nvars:\n KEY: VALUE"]
|
3064
|
-
expected_result = LoadFileLinkState.new(
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3408
|
+
expected_result = LoadFileLinkState.new(
|
3409
|
+
LoadFile::LOAD,
|
3410
|
+
LinkState.new(block_name: 'sample_block',
|
3411
|
+
document_filename: 'sample_file',
|
3412
|
+
inherited_dependencies: {},
|
3413
|
+
inherited_lines: ['# ', 'KEY="VALUE"'])
|
3414
|
+
)
|
3069
3415
|
assert_equal expected_result,
|
3070
3416
|
@hd.push_link_history_and_trigger_load(
|
3071
3417
|
link_block_body: body,
|
3072
|
-
selected: FCB.new(block_name: 'sample_block',
|
3418
|
+
selected: FCB.new(block_name: 'sample_block',
|
3419
|
+
filename: 'sample_file')
|
3073
3420
|
)
|
3074
3421
|
end
|
3075
3422
|
|
@@ -3178,20 +3525,21 @@ module MarkdownExec
|
|
3178
3525
|
end
|
3179
3526
|
|
3180
3527
|
def test_block_find_with_match
|
3181
|
-
blocks = [
|
3182
|
-
result = HashDelegator.block_find(blocks, :
|
3183
|
-
assert_equal(
|
3528
|
+
blocks = [FCB.new(text: 'value1'), FCB.new(text: 'value2')]
|
3529
|
+
result = HashDelegator.block_find(blocks, :text, 'value1')
|
3530
|
+
assert_equal('value1', result.text)
|
3184
3531
|
end
|
3185
3532
|
|
3186
3533
|
def test_block_find_without_match
|
3187
|
-
blocks = [
|
3188
|
-
result = HashDelegator.block_find(blocks, :
|
3534
|
+
blocks = [FCB.new(text: 'value1'), FCB.new(text: 'value2')]
|
3535
|
+
result = HashDelegator.block_find(blocks, :text, 'missing_value')
|
3189
3536
|
assert_nil result
|
3190
3537
|
end
|
3191
3538
|
|
3192
3539
|
def test_block_find_with_default
|
3193
|
-
blocks = [
|
3194
|
-
result = HashDelegator.block_find(blocks, :
|
3540
|
+
blocks = [FCB.new(text: 'value1'), FCB.new(text: 'value2')]
|
3541
|
+
result = HashDelegator.block_find(blocks, :text, 'missing_value',
|
3542
|
+
'default')
|
3195
3543
|
assert_equal 'default', result
|
3196
3544
|
end
|
3197
3545
|
end
|
@@ -3227,7 +3575,7 @@ module MarkdownExec
|
|
3227
3575
|
@hd = HashDelegator.new
|
3228
3576
|
@hd.instance_variable_set(:@delegate_object, {})
|
3229
3577
|
@mdoc = mock('YourMDocClass')
|
3230
|
-
@selected =
|
3578
|
+
@selected = FCB.new(shell: BlockType::VARS, body: ['key: value'])
|
3231
3579
|
HashDelegator.stubs(:read_required_blocks_from_temp_file).returns([])
|
3232
3580
|
@hd.stubs(:string_send_color)
|
3233
3581
|
@hd.stubs(:print)
|
@@ -3236,7 +3584,8 @@ module MarkdownExec
|
|
3236
3584
|
def test_collect_required_code_lines_with_vars
|
3237
3585
|
YAML.stubs(:load).returns({ 'key' => 'value' })
|
3238
3586
|
@mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
|
3239
|
-
result = @hd.collect_required_code_lines(mdoc: @mdoc, selected: @selected,
|
3587
|
+
result = @hd.collect_required_code_lines(mdoc: @mdoc, selected: @selected,
|
3588
|
+
block_source: {})
|
3240
3589
|
|
3241
3590
|
assert_equal ['code line', 'key="value"'], result
|
3242
3591
|
end
|
@@ -3257,18 +3606,24 @@ module MarkdownExec
|
|
3257
3606
|
|
3258
3607
|
result = @hd.load_cli_or_user_selected_block(all_blocks: all_blocks)
|
3259
3608
|
|
3260
|
-
assert_equal all_blocks.first
|
3609
|
+
assert_equal all_blocks.first,
|
3610
|
+
result.block
|
3611
|
+
assert_equal OpenStruct.new(block_name_from_ui: false),
|
3612
|
+
result.source
|
3261
3613
|
assert_nil result.state
|
3262
3614
|
end
|
3263
3615
|
|
3264
3616
|
def test_user_selected_block
|
3265
|
-
block_state = SelectedBlockMenuState.new({ oname: 'block2' },
|
3617
|
+
block_state = SelectedBlockMenuState.new({ oname: 'block2' }, OpenStruct.new,
|
3266
3618
|
:some_state)
|
3267
3619
|
@hd.stubs(:wait_for_user_selected_block).returns(block_state)
|
3268
3620
|
|
3269
3621
|
result = @hd.load_cli_or_user_selected_block
|
3270
3622
|
|
3271
|
-
assert_equal block_state.block
|
3623
|
+
assert_equal block_state.block,
|
3624
|
+
result.block
|
3625
|
+
assert_equal OpenStruct.new(block_name_from_ui: true),
|
3626
|
+
result.source
|
3272
3627
|
assert_equal :some_state, result.state
|
3273
3628
|
end
|
3274
3629
|
end
|
@@ -3351,7 +3706,7 @@ module MarkdownExec
|
|
3351
3706
|
end
|
3352
3707
|
|
3353
3708
|
def test_determine_block_state_exit
|
3354
|
-
selected_option =
|
3709
|
+
selected_option = FCB.new(oname: 'Formatted Option')
|
3355
3710
|
@hd.stubs(:menu_chrome_formatted_option).with(:menu_option_exit_name).returns('Formatted Option')
|
3356
3711
|
|
3357
3712
|
result = @hd.determine_block_state(selected_option)
|
@@ -3361,7 +3716,7 @@ module MarkdownExec
|
|
3361
3716
|
end
|
3362
3717
|
|
3363
3718
|
def test_determine_block_state_back
|
3364
|
-
selected_option =
|
3719
|
+
selected_option = FCB.new(oname: 'Formatted Back Option')
|
3365
3720
|
@hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('Formatted Back Option')
|
3366
3721
|
result = @hd.determine_block_state(selected_option)
|
3367
3722
|
|
@@ -3370,7 +3725,7 @@ module MarkdownExec
|
|
3370
3725
|
end
|
3371
3726
|
|
3372
3727
|
def test_determine_block_state_continue
|
3373
|
-
selected_option =
|
3728
|
+
selected_option = FCB.new(oname: 'Other Option')
|
3374
3729
|
|
3375
3730
|
result = @hd.determine_block_state(selected_option)
|
3376
3731
|
|
@@ -3480,7 +3835,8 @@ module MarkdownExec
|
|
3480
3835
|
def test_format_execution_stream_with_empty_key
|
3481
3836
|
@hd.instance_variable_get(:@run_state).stubs(:files).returns({})
|
3482
3837
|
|
3483
|
-
result = HashDelegator.format_execution_stream(nil,
|
3838
|
+
result = HashDelegator.format_execution_stream(nil,
|
3839
|
+
ExecutionStreams::STD_ERR)
|
3484
3840
|
|
3485
3841
|
assert_equal '', result
|
3486
3842
|
end
|
@@ -3639,7 +3995,8 @@ module MarkdownExec
|
|
3639
3995
|
end
|
3640
3996
|
|
3641
3997
|
def test_iter_blocks_from_nested_files
|
3642
|
-
@hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'],
|
3998
|
+
@hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'],
|
3999
|
+
import_paths: nil)
|
3643
4000
|
selected_messages = ['filtered message']
|
3644
4001
|
|
3645
4002
|
result = @hd.iter_blocks_from_nested_files { selected_messages }
|
@@ -3745,7 +4102,8 @@ module MarkdownExec
|
|
3745
4102
|
|
3746
4103
|
def test_yield_line_if_selected_with_line
|
3747
4104
|
block_called = false
|
3748
|
-
HashDelegator.yield_line_if_selected('Test line',
|
4105
|
+
HashDelegator.yield_line_if_selected('Test line',
|
4106
|
+
[:line]) do |type, content|
|
3749
4107
|
block_called = true
|
3750
4108
|
assert_equal :line, type
|
3751
4109
|
assert_equal 'Test line', content.body[0]
|
@@ -3780,15 +4138,18 @@ module MarkdownExec
|
|
3780
4138
|
def test_update_menu_attrib_yield_selected_with_body
|
3781
4139
|
HashDelegator.expects(:initialize_fcb_names).with(@fcb)
|
3782
4140
|
HashDelegator.expects(:default_block_title_from_body).with(@fcb)
|
3783
|
-
Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message],
|
4141
|
+
Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message],
|
4142
|
+
{})
|
3784
4143
|
|
3785
|
-
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4144
|
+
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4145
|
+
messages: [:some_message])
|
3786
4146
|
end
|
3787
4147
|
|
3788
4148
|
def test_update_menu_attrib_yield_selected_without_body
|
3789
4149
|
@fcb.stubs(:body).returns(nil)
|
3790
4150
|
HashDelegator.expects(:initialize_fcb_names).with(@fcb)
|
3791
|
-
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4151
|
+
HashDelegator.update_menu_attrib_yield_selected(fcb: @fcb,
|
4152
|
+
messages: [:some_message])
|
3792
4153
|
end
|
3793
4154
|
end
|
3794
4155
|
|
@@ -3864,28 +4225,35 @@ module MarkdownExec
|
|
3864
4225
|
def test_absolute_path_returns_unchanged
|
3865
4226
|
absolute_path = '/usr/local/bin'
|
3866
4227
|
expression = 'path/to/*/directory'
|
3867
|
-
assert_equal absolute_path,
|
4228
|
+
assert_equal absolute_path,
|
4229
|
+
PathUtils.resolve_path_or_substitute(absolute_path,
|
4230
|
+
expression)
|
3868
4231
|
end
|
3869
4232
|
|
3870
4233
|
def test_relative_path_gets_substituted
|
3871
4234
|
relative_path = 'my_folder'
|
3872
4235
|
expression = 'path/to/*/directory'
|
3873
4236
|
expected_output = 'path/to/my_folder/directory'
|
3874
|
-
assert_equal expected_output,
|
4237
|
+
assert_equal expected_output,
|
4238
|
+
PathUtils.resolve_path_or_substitute(relative_path,
|
4239
|
+
expression)
|
3875
4240
|
end
|
3876
4241
|
|
3877
4242
|
def test_path_with_no_slash_substitutes_correctly
|
3878
4243
|
relative_path = 'data'
|
3879
4244
|
expression = 'path/to/*/directory'
|
3880
4245
|
expected_output = 'path/to/data/directory'
|
3881
|
-
assert_equal expected_output,
|
4246
|
+
assert_equal expected_output,
|
4247
|
+
PathUtils.resolve_path_or_substitute(relative_path,
|
4248
|
+
expression)
|
3882
4249
|
end
|
3883
4250
|
|
3884
4251
|
def test_empty_path_substitution
|
3885
4252
|
empty_path = ''
|
3886
4253
|
expression = 'path/to/*/directory'
|
3887
4254
|
expected_output = 'path/to//directory'
|
3888
|
-
assert_equal expected_output,
|
4255
|
+
assert_equal expected_output,
|
4256
|
+
PathUtils.resolve_path_or_substitute(empty_path, expression)
|
3889
4257
|
end
|
3890
4258
|
|
3891
4259
|
# Test formatting a string containing UTF-8 characters
|
@@ -3934,7 +4302,8 @@ module MarkdownExec
|
|
3934
4302
|
private
|
3935
4303
|
|
3936
4304
|
def prompt_for_filespec_with_wildcard(filespec)
|
3937
|
-
puts format(@delegate_object[:prompt_show_expr_format],
|
4305
|
+
puts format(@delegate_object[:prompt_show_expr_format],
|
4306
|
+
{ expr: filespec })
|
3938
4307
|
puts @delegate_object[:prompt_enter_filespec]
|
3939
4308
|
|
3940
4309
|
begin
|